Created
June 13, 2018 05:19
-
-
Save wspl/6fe8feced1eef4d67654631f70b12381 to your computer and use it in GitHub Desktop.
Synx - Electron application global state synchronization library (with mobx).
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { ipcMain, ipcRenderer, WebContents } from 'electron' | |
import { autorun, toJS } from 'mobx' | |
import { PLStore } from './PLStore' | |
enum SynxActionType { | |
Subscribe, | |
Update | |
} | |
interface ISynxAction { | |
type: SynxActionType | |
key: string | |
value: any | |
kvs: {key: string, value: any}[] | |
} | |
export interface ISynxInterface<T> { | |
sx_onRestore: (handler: () => void) => void | |
} | |
export interface ISynxPersistenceOptions { | |
keyAlias?: { [key: string]: string } | |
fileAlias?: string | |
exclude?: string[] | |
include?: string[] | |
} | |
export function Synxify<T>(constructor: { new(): T }, name: string, persistence?: ISynxPersistenceOptions): T & ISynxInterface<T> { | |
if (process.type === 'renderer') { | |
return SynxifyRenderer(constructor, name) | |
} else { | |
return SynxifyMain(constructor, name, persistence) | |
} | |
} | |
function SynxifyMain<T>(constructor: { new(): T }, name: string, persistence?: ISynxPersistenceOptions): T & ISynxInterface<T> { | |
const instance = new constructor() as T & ISynxInterface<T> | |
const keys = Object.keys(constructor.prototype.__mobxDecorators) | |
let store: PLStore | |
if (persistence) { | |
store = new PLStore(name, instance) | |
keys.forEach(key => { | |
if (persistence.include && persistence.include.indexOf(key) === -1) return | |
if (persistence.exclude && persistence.exclude.indexOf(key) > -1) return | |
store.addKeyMapping(key, (persistence.keyAlias && persistence.keyAlias[key]) || key) | |
}) | |
store.load() | |
} | |
const clients = new Set<WebContents>() | |
let lastUpdateClient: WebContents | |
ipcMain.on(`synx::${name}`, (event, action: ISynxAction) => { | |
switch (action.type) { | |
case SynxActionType.Subscribe: | |
const sender: WebContents = event.sender | |
clients.add(sender) | |
sender.send(`synx::${name}`, <ISynxAction> { | |
type: SynxActionType.Update, | |
kvs: JSON.parse(JSON.stringify(keys.map(key => ({key, value: instance[key]})))) | |
}) | |
break | |
case SynxActionType.Update: | |
lastUpdateClient = event.sender | |
instance[action.key] = action.value | |
break | |
} | |
}) | |
keys.forEach(key => { | |
autorun(() => { | |
const value = toJS(instance[key]) | |
store && store.save() | |
clients.forEach(wc => { | |
// avoid send update action to data provider | |
if (lastUpdateClient === wc) { | |
return | |
} | |
wc.send(`synx::${name}`, <ISynxAction> { | |
type: SynxActionType.Update, | |
key, | |
value: JSON.parse(JSON.stringify(value)) | |
}) | |
}) | |
}) | |
}) | |
return instance | |
} | |
function SynxifyRenderer<T>(constructor: { new(): T }, name: string): T & ISynxInterface<T> { | |
let restoreHandler: () => void | |
const instance = new constructor() as T & ISynxInterface<T> | |
instance.sx_onRestore = (handler) => { | |
restoreHandler = handler | |
} | |
const keys = Object.keys(constructor.prototype.__mobxDecorators) | |
const updateSelfKey = new Set<string>() | |
ipcRenderer.send(`synx::${name}`, <ISynxAction>{type: SynxActionType.Subscribe}) | |
ipcRenderer.on(`synx::${name}`, (event, action: ISynxAction) => { | |
switch (action.type) { | |
case SynxActionType.Update: | |
if (action.kvs) { | |
// first update | |
action.kvs.forEach(({key, value}) => { | |
updateSelfKey.add(key) | |
instance[key] = value | |
}) | |
restoreHandler && restoreHandler() | |
keys.forEach(key => { | |
autorun(() => { | |
const value = toJS(instance[key]) | |
if (updateSelfKey.has(key)) { | |
updateSelfKey.delete(key) | |
return | |
} | |
ipcRenderer.send(`synx::${name}`, <ISynxAction> { | |
type: SynxActionType.Update, | |
key, | |
value: JSON.parse(JSON.stringify(value)) | |
}) | |
}) | |
}) | |
} else { | |
updateSelfKey.add(action.key) | |
instance[action.key] = action.value | |
} | |
break | |
} | |
}) | |
return instance | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment