You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RPCaller.ts 3.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. import { ExtendedRpcInfo, UnhookFunction, callbackFunction, AsyncFunction } from "../backend/RPCSocketServer";
  2. var bsock = require('bsock')
  3. //fix args with defaults like "force = true" -> "force"
  4. function stripAfterEquals(str:string){
  5. return str.split("=")[0]
  6. }
  7. type RPCReceiver = {
  8. [RPCGroup in string]: any
  9. }
  10. /**
  11. * Dynamic library to communicate with FrontblockService remotely
  12. *
  13. * This will be automatically injected into the webpages served by FrontblockService
  14. * Will ask it's service for available RPCs and parse them into methods of this object
  15. * for convenient access.
  16. */
  17. export class RPCaller implements RPCReceiver{
  18. private socket
  19. constructor(port:number, server: string, tls: boolean = false){
  20. this.socket = bsock.connect(port, server, tls)
  21. }
  22. async connect(){
  23. const info:ExtendedRpcInfo[] = await this.info()
  24. info.forEach(i => {
  25. let f: any
  26. switch (i.type) {
  27. case 'call':
  28. f = this.callGenerator(i.uniqueName, i.argNames)
  29. break
  30. case 'hook':
  31. f = this.hookGenerator(i.uniqueName, i.argNames)
  32. break
  33. case 'unhook':
  34. f = this.unhookGenerator(i.uniqueName, i.argNames)
  35. break
  36. }
  37. if(this[i.owner] == null)
  38. this[i.owner] = {}
  39. this[i.owner][i.name] = f
  40. this[i.owner][i.name].bind(this)
  41. })
  42. }
  43. async info(){
  44. return await this.socket.call('info')
  45. }
  46. private callGenerator(fnName, fnArgs:string[]): AsyncFunction{
  47. const headerArgs = fnArgs.join(",")
  48. const argParams = fnArgs.map(stripAfterEquals).join(",")
  49. return eval( '( () => async ('+headerArgs+') => { return await this.socket.call("'+fnName+'", '+argParams+')} )()' )
  50. }
  51. private hookGenerator(fnName, fnArgs:string[]): callbackFunction{
  52. const headerArgs = fnArgs.join(",")
  53. const argParams = fnArgs.map(stripAfterEquals).join(",")
  54. return eval( `( () => async (`+headerArgs+(headerArgs.length!==0?",":"")+` callback) => {
  55. const r = await this.socket.call("`+fnName+`", `+argParams+`)
  56. if(r.uid != null){
  57. this.socket.hook(res.uid, callback)
  58. }
  59. return res
  60. } )()` )
  61. }
  62. private unhookGenerator(fnName, fnArgs:string[]): UnhookFunction{
  63. const headerArgs = fnArgs.join(",")
  64. const argParams = fnArgs.map(stripAfterEquals).join(",")
  65. if(fnArgs.length != 1)
  66. console.error("UnhookFunction", fnName, "specified more than one argument: ("+headerArgs+")")
  67. return eval( `( () => async (`+headerArgs+`) => {
  68. const r = await this.socket.call("`+fnName+`", `+argParams+`)
  69. this.socket.unhook(`+argParams+`)
  70. return res
  71. } )()` )
  72. }
  73. }