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.

Utils.ts 3.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import * as uuid from "uuid/v4"
  2. import * as T from "./Types";
  3. import * as I from "./Interfaces";
  4. export const rpcToRpcinfo = (rpc : T.RPC, owner: T.Owner):T.RpcInfo => {
  5. switch (typeof rpc){
  6. case "object":
  7. switch(rpc.type){
  8. case "Call" :
  9. return {
  10. owner: owner,
  11. argNames: extractArgs(rpc.call),
  12. type: rpc.type,
  13. name: rpc.name,
  14. call: rpc.call,
  15. }
  16. case "Unhook" :
  17. return {
  18. owner: owner,
  19. argNames: extractArgs(rpc.unhook),
  20. type: rpc.type,
  21. name: rpc.name,
  22. unhook: rpc.unhook,
  23. }
  24. case "Hook" :
  25. const generator = hookGenerator(rpc)
  26. return {
  27. owner: owner,
  28. argNames: extractArgs(generator(undefined)),
  29. type: rpc.type,
  30. name: rpc.name,
  31. unhook: rpc.unhook,
  32. generator: generator,
  33. }
  34. }
  35. break;
  36. case "function":
  37. if(!rpc.name) throw new Error(`
  38. RPC did not provide a name.
  39. \nUse funtion name(..){ .. } syntax instead.
  40. \n
  41. \n<------------OFFENDING RPC:
  42. \n`+rpc.toString()+`
  43. \n>------------OFFENDING RPC`)
  44. return {
  45. type: "Call",
  46. owner : owner,
  47. argNames: extractArgs(rpc),
  48. call: async(...args) => rpc.apply({}, args),
  49. name: rpc.name
  50. }
  51. }
  52. throw new Error("Bad socketIORPC type "+ typeof rpc)
  53. }
  54. export function rpcHooker(socket: I.Socket, exporter:I.Exporter, makeUnique = true):T.ExtendedRpcInfo[]{
  55. const owner = exporter.name
  56. const RPCs = [...exporter.exportRPCs()]
  57. const suffix = makeUnique?"-"+uuid().substr(0,4):""
  58. return RPCs.map(rpc => rpcToRpcinfo(rpc, owner))
  59. .map(info => {
  60. const ret:any = info
  61. ret.uniqueName = info.name+suffix
  62. switch(info.type){
  63. case "Hook":
  64. socket.hook(ret.uniqueName, info.generator(socket))
  65. break;
  66. case "Unhook":
  67. socket.hook(ret.uniqueName, info.unhook)
  68. break;
  69. case "Call":
  70. socket.hook(ret.uniqueName, info.call)
  71. break;
  72. }
  73. socket.on('close', () => socket.unhook(info.name))
  74. return ret
  75. })
  76. }
  77. const hookGenerator = (rpc:T.HookRPC): T.HookInfo['generator'] => {
  78. const argsArr = extractArgs(rpc.hook)
  79. argsArr.pop()
  80. const args = argsArr.join(',')
  81. return eval(`(socket) => async (`+args+`) => {
  82. const res = await rpc.hook(`+args+(args.length!==0?',':'')+` (x) => {
  83. socket.call(res.uid, x)
  84. })
  85. if(res.result == 'Success'){
  86. socket.on('close', async () => {
  87. const unhookRes = await rpc.unhook(res.uid)
  88. console.log("Specific close handler for", rpc.name, res.uid, unhookRes)
  89. })
  90. }
  91. return res
  92. }`)
  93. }
  94. const extractArgs = (f:Function):T.Arg[] => {
  95. let fn = String(f)
  96. let args = fn.substr(0, fn.indexOf(")"))
  97. args = args.substr(fn.indexOf("(")+1)
  98. let ret = args.split(",")
  99. return ret
  100. }