import { parseSubResponse, parseResponse } from "frontblock-generic/Types"; import { ExtendedRpcInfo, UnhookFunction, callbackFunction, AsyncFunction } from "frontblock-generic/RPC"; var bsock = require('bsock') //fix args with defaults like "force = true" -> "force" function stripAfterEquals(str:string){ return str.split("=")[0] } /** * Dynamic library to communicate with FrontblockService remotely * * This will be automatically injected into the webpages served by FrontblockService * Will ask it's service for available RPCs and parse them into methods of this object * for convenient access. */ export class FrontblockConfigLib{ private socket constructor(){ this.socket = bsock.connect(20000, 'localhost', false/*tls*/) this.init() } // need this-context for eval-magic below // DO NOT REMOVE. They're not really unused private parseSubResponse = parseSubResponse private parseResponse = parseResponse private async init(){ const info:ExtendedRpcInfo[] = await this.info() info.forEach(i => { let f: any switch (i.type) { case 'call': f = this.callGenerator(i.uniqueName, i.argNames) break case 'hook': f = this.hookGenerator(i.uniqueName, i.argNames) break case 'unhook': f = this.unhookGenerator(i.uniqueName, i.argNames) break } if(this[i.owner] == null) this[i.owner] = {} this[i.owner][i.name] = f this[i.owner][i.name].bind(this) }) } async info(){ return await this.socket.call('info') } private callGenerator(fnName, fnArgs:string[]): AsyncFunction{ const headerArgs = fnArgs.join(",") const argParams = fnArgs.map(stripAfterEquals).join(",") return eval( '( () => async ('+headerArgs+') => { return await this.socket.call("'+fnName+'", '+argParams+')} )()' ) } private hookGenerator(fnName, fnArgs:string[]): callbackFunction{ const headerArgs = fnArgs.join(",") const argParams = fnArgs.map(stripAfterEquals).join(",") return eval( `( () => async (`+headerArgs+(headerArgs.length!==0?",":"")+` callback) => { const r = await this.socket.call("`+fnName+`", `+argParams+`) const res = await this.parseSubResponse(r); if(res.uid != null){ this.socket.hook(res.uid, callback) } return res } )()` ) } private unhookGenerator(fnName, fnArgs:string[]): UnhookFunction{ const headerArgs = fnArgs.join(",") const argParams = fnArgs.map(stripAfterEquals).join(",") if(fnArgs.length != 1) console.error("UnhookFunction", fnName, "specified more than one argument: ("+headerArgs+")") return eval( `( () => async (`+headerArgs+`) => { const r = await this.socket.call("`+fnName+`", `+argParams+`) const res = await this.parseResponse(r) this.socket.unhook(`+argParams+`) return res } )()` ) } } window['fb'] = new FrontblockConfigLib() declare const fb:{UpdateManager:any} window['setup'] = async() => { const i = await Promise.all([ fb.UpdateManager.installPlugin("ApiClient"), fb.UpdateManager.installPlugin("HtmlSupplier"), fb.UpdateManager.installPlugin("PaymentManager"), fb.UpdateManager.installPlugin("Wallet"), ]) console.log(i) const s = await Promise.all([ fb.UpdateManager.startPlugin("ApiClient"), fb.UpdateManager.startPlugin("HtmlSupplier"), fb.UpdateManager.startPlugin("PaymentManager"), fb.UpdateManager.startPlugin("Wallet"), ]) console.log(s) }