Skip to content
This repository has been archived by the owner on Jan 24, 2025. It is now read-only.

Commit

Permalink
refactor(docz-core): split data server into actions
Browse files Browse the repository at this point in the history
  • Loading branch information
pedronauck committed Jul 31, 2018
1 parent 8fbd173 commit 69d6c9a
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 109 deletions.
119 changes: 21 additions & 98 deletions packages/docz-core/src/DataServer.ts
Original file line number Diff line number Diff line change
@@ -1,117 +1,40 @@
import { load, finds } from 'load-cfg'
import chokidar from 'chokidar'
import WS from 'ws'

import { Config } from './commands/args'
import { Entries, EntryMap } from './Entries'
export type Send = (type: string, payload: any) => void

const isSocketOpened = (socket: WS) => socket.readyState === WS.OPEN
const send = (socket: WS) => (type: string, payload: any) => {
socket.send(JSON.stringify({ type, payload }))
}

export interface DataServerOpts {
server: any
config: Config
interface Action {
onStart: (send: Send, socket: WS) => void
onClose?: () => void
onError?: () => void
}

export class DataServer {
private server: WS.Server
private config: Config

constructor({ server, config }: DataServerOpts) {
this.config = config
this.server = new WS.Server({
server,
port: config.websocketPort,
host: config.websocketHost,
})
}

public async processEntries(entries: Entries): Promise<void> {
const watcher = chokidar.watch(this.config.files, {
ignored: /(^|[\/\\])\../,
})

const handleConnection = async (socket: WS) => {
const update = this.updateEntries(entries, socket)
const map = await entries.get()

watcher.on('change', async () => update(this.config))
watcher.on('unlink', async () => update(this.config))
watcher.on('raw', async (event: string, path: string, details: any) => {
if (details.event === 'moved' && details.type === 'directory') {
await update(this.config)
}
})

socket.send(this.entriesData(map))
await Entries.writeImports(map)
}

this.server.on('connection', handleConnection)
this.server.on('close', () => watcher.close())
}
private actions: Set<Action>

public async processThemeConfig(): Promise<void> {
const watcher = chokidar.watch(finds('docz'))

const handleConnection = async (socket: WS) => {
const update = this.updateConfig(socket)

watcher.on('add', () => update())
watcher.on('change', () => update())
watcher.on('unlink', () => update())

update()
}

this.server.on('connection', handleConnection)
this.server.on('close', () => watcher.close())
constructor(server: any, port: number, host: string) {
this.actions = new Set()
this.server = new WS.Server({ server, port, host })
}

private dataObj(type: string, data: any): string {
return JSON.stringify({ type, data })
public dispatch(action: Action): void {
this.actions.add(action)
}

private entriesData(entries: EntryMap): string {
return this.dataObj('docz.entries', entries)
public init(): void {
this.server.on('connection', socket => this.handleConnection(socket))
this.server.on('close', () => this.handleClose())
}

private configData(config: Config): string {
return this.dataObj('docz.config', {
...config.themeConfig,
title: config.title,
description: config.description,
ordering: config.ordering,
})
private async handleConnection(socket: WS): Promise<void> {
this.actions.forEach(async ({ onStart }) => onStart(send(socket), socket))
}

private updateEntries(
entries: Entries,
socket: WS
): (config: Config) => Promise<void> {
return async config => {
if (isSocketOpened(socket)) {
const map = await entries.get()

await Entries.writeImports(map)
socket.send(this.entriesData(map))
}
}
}

private updateConfig(socket: WS): () => void {
const initialConfig = {
title: this.config.title,
description: this.config.description,
themeConfig: this.config.themeConfig,
ordering: this.config.ordering,
}

return () => {
const config = load('docz', initialConfig, true)

if (isSocketOpened(socket)) {
socket.send(this.configData(config))
}
}
private async handleClose(): Promise<void> {
this.actions.forEach(async ({ onClose }) => onClose && onClose())
}
}
2 changes: 2 additions & 0 deletions packages/docz-core/src/actions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { parseEntries } from './parse-entries'
export { parseConfig } from './parse-config'
47 changes: 47 additions & 0 deletions packages/docz-core/src/actions/parse-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { load, finds } from 'load-cfg'
import chokidar from 'chokidar'
import WS from 'ws'

import { Send } from '../DataServer'
import { Config, ThemeConfig } from '../commands/args'

const PARSE_CONFIG = 'PARSE_CONFIG'

const isSocketOpened = (socket: WS) => socket.readyState === WS.OPEN

interface Payload {
title: string
description: string
ordering: string
themeConfig: ThemeConfig
}

const getInitialConfig = (config: Config): Payload => ({
title: config.title,
description: config.description,
themeConfig: config.themeConfig,
ordering: config.ordering,
})

const updateConfig = (initial: Payload, send: Send, socket: WS) => () => {
const config = load('docz', initial, true)
if (isSocketOpened(socket)) send(PARSE_CONFIG, config)
}

export const parseConfig = (config: Config) => {
const watcher = chokidar.watch(finds('docz'))

return {
onClose: () => watcher.close(),
onStart: async (send: Send, socket: WS) => {
const initialConfig = getInitialConfig(config)
const update = updateConfig(initialConfig, send, socket)

watcher.on('add', () => update())
watcher.on('change', () => update())
watcher.on('unlink', () => update())

update()
},
}
}
50 changes: 50 additions & 0 deletions packages/docz-core/src/actions/parse-entries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import chokidar from 'chokidar'
import WS from 'ws'

import { Send } from '../DataServer'
import { Entries } from '../Entries'
import { Config } from '../commands/args'

const LOADING = 'LOADING'
const PARSE_ENTRIES = 'PARSE_ENTRIES'

const isSocketOpened = (socket: WS) => socket.readyState === WS.OPEN

const updateEntries = (
entries: Entries,
send: Send,
socket: WS
) => async () => {
if (isSocketOpened(socket)) {
const map = await entries.get()

await Entries.writeImports(map)
send(PARSE_ENTRIES, map)
}
}

export const parseEntries = (entries: Entries, config: Config) => {
const watcher = chokidar.watch(config.files, {
ignored: /(^|[\/\\])\../,
})

return {
onClose: () => watcher.close(),
onStart: async (send: Send, socket: WS) => {
send(LOADING, true)

const update = updateEntries(entries, send, socket)

watcher.on('change', async () => update())
watcher.on('unlink', async () => update())
watcher.on('raw', async (event: string, path: string, details: any) => {
if (details.event === 'moved' && details.type === 'directory') {
await update()
}
})

update()
send(LOADING, false)
},
}
}
18 changes: 11 additions & 7 deletions packages/docz-core/src/commands/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import detectPort from 'detect-port'
import envDotProp from 'env-dot-prop'

import * as paths from '../config/paths'
import * as actions from '../actions'

import { Config } from './args'
import { DataServer } from '../DataServer'
import { webpack } from '../bundlers'
Expand All @@ -22,10 +24,11 @@ export const dev = async (args: Config) => {
const { app } = await server.start()

const newConfig = { ...config, websocketPort }
const dataServer = new DataServer({
server: app.server,
config: newConfig,
})
const dataServer = new DataServer(
app.server,
config.websocketPort,
config.websocketHost
)

try {
logger.info('Removing old app files')
Expand All @@ -35,9 +38,10 @@ export const dev = async (args: Config) => {
await Entries.writeApp(newConfig, true)
await Entries.writeImports(await entries.get())

logger.info(`Setup entries websockets server on port ${websocketPort}`)
await dataServer.processEntries(entries)
await dataServer.processThemeConfig()
logger.info(`Setup data server on port ${websocketPort}`)
dataServer.dispatch(actions.parseEntries(entries, newConfig))
dataServer.dispatch(actions.parseConfig(newConfig))
dataServer.init()
} catch (err) {
logger.fatal('Failed to process your server:', err)
process.exit(1)
Expand Down
8 changes: 4 additions & 4 deletions packages/docz-core/templates/root.tpl.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ class Root extends React.Component {
socket.onmessage = ev => {
const message = JSON.parse(ev.data)

if (message.type === 'docz.entries') {
this.setState({ entries: message.data })
if (message.type === 'PARSE_ENTRIES') {
this.setState({ entries: message.payload })
}

if (message.type === 'docz.config') {
this.setState({ config: message.data })
if (message.type === 'PARSE_CONFIG') {
this.setState({ config: message.payload })
}
}
}
Expand Down

0 comments on commit 69d6c9a

Please sign in to comment.