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.

demo.ts 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import { RPCServer, RPCSocket } from './Index'
  2. import { RPCExporter } from './src/Interfaces'
  3. import { RPCInterface } from './src/Types'
  4. // TL;DR
  5. const echo = (text: string) => text
  6. const add = (a: number, b: number) : number => a + b
  7. const getAsync = async () : Promise<{topic: string, message:string}>=> await new Promise((res, _) => {
  8. setTimeout(() => {
  9. res({
  10. topic: "Hey!!",
  11. message: "Hello World Async!"
  12. })
  13. }, 250)
  14. })
  15. const getCallback = (callback: Function) : string => {
  16. setTimeout(() => {
  17. try{
  18. callback({
  19. topic: "Hey!!",
  20. message: "Hello World Callback!"
  21. })
  22. }catch(e){
  23. console.log(String(e))
  24. }
  25. }, 250)
  26. return "Please wait for a callback :)"
  27. }
  28. new RPCServer(20000, [{
  29. name: 'MyRPCGroup1',
  30. exportRPCs: () => [
  31. echo,
  32. add,
  33. getAsync,
  34. {
  35. name: 'getCallback',
  36. hook: getCallback,
  37. onClose: (response, rpc) => { /* ... */ },
  38. onCallback: (...callbackArgs) => { /* ... */ }
  39. }
  40. ]
  41. }])
  42. new RPCSocket(20000, 'localhost').connect().then(async sock => {
  43. try{
  44. const RPCs = sock['MyRPCGroup1']
  45. await RPCs.echo("hello!").then(console.log)
  46. await RPCs.add(1, Math.PI).then(console.log)
  47. await RPCs.getAsync().then(console.log)
  48. await RPCs.getCallback(console.log).then(console.log)
  49. }catch(e){
  50. console.log(String(e))
  51. }
  52. })
  53. //Hooks and events
  54. new RPCServer(20001, [{
  55. name: 'MyRPCGroup1',
  56. exportRPCs: () => [
  57. echo,
  58. add,
  59. getAsync,
  60. {
  61. name: 'getCallback',
  62. hook: getCallback,
  63. onClose: (response, rpc) => { /* client disconnected */ },
  64. onCallback: (...callbackArgs) => { /* callback triggered */ }
  65. }
  66. ],
  67. }], {
  68. visibility: '127.0.0.1', //0.0.0.0
  69. closeHandler: (socket) => { /* global close handler */ },
  70. connectionHandler: (socket) => { /* new connection made */ },
  71. errorHandler: (socket, error, rpcname, argArr) => { /* An error occured inside a RPC */ },
  72. })
  73. const sock = new RPCSocket(20001, 'localhost')
  74. sock.on('error', (e) => { /* handle error */ })
  75. sock.on('close', () => { /* handle close event */ })
  76. sock.hook('RPCName', (/* arg0, arg1, ..., argN */) => { /* bind client-side RPCs */ })
  77. //Retrieve the socket from connectionHandler (Server-side) and trigger with
  78. //socket.call('RPCName', arg0, arg1, ..., argN)
  79. sock.connect().then(_ => { /* ... */})
  80. //Restricting access
  81. new RPCServer(20002, [{
  82. name: 'MyRPCGroup1',
  83. exportRPCs: () => [
  84. echo,
  85. add,
  86. getAsync,
  87. {
  88. name: 'getCallback',
  89. hook: getCallback,
  90. }
  91. ],
  92. }], {
  93. sesame: "sesame open",
  94. /*
  95. OR check sesame dynamically
  96. and refine permissioning with accessfilter (optional)
  97. */
  98. //sesame: (sesame) => true
  99. //accessFilter: (sesame, exporter) => { return exporter.name === "MyRPCGroup1" && sesame === "sesame open" },
  100. })
  101. new RPCSocket(20002, 'localhost').connect("sesame open").then(async sock => {
  102. try{
  103. const RPCs = sock['MyRPCGroup1']
  104. await RPCs.echo("hello!").then(console.log)
  105. await RPCs.add(1, Math.PI).then(console.log)
  106. await RPCs.getAsync().then(console.log)
  107. await RPCs.getCallback(console.log).then(console.log)
  108. }catch(e){
  109. console.log(String(e))
  110. }
  111. })
  112. //TypeScript and pseudo-interfaces
  113. type MyInterface = {
  114. MyRPCGroup1: {
  115. echo: (x: string) => string
  116. add: (a: number, b: number) => number
  117. getAsync: () => Promise<{ topic: string, message: string }>
  118. getCallback: (callback:Function) => string
  119. }
  120. };
  121. /*
  122. exportRPCs is now type safe. Try swapping echo for badEcho.
  123. Sadly TSC's stack traces aren't the best, but try to scroll to the bottom of them to find useful info like
  124. Type '(x: boolean) => number' is not assignable to type '(x: string) => string'
  125. */
  126. const badEcho = (x: boolean) : number => 3
  127. new RPCServer<MyInterface>(20003, [{
  128. name: 'MyRPCGroup1',
  129. exportRPCs: () => [
  130. //badEcho,
  131. echo,
  132. add,
  133. getAsync,
  134. {
  135. name: 'getCallback',
  136. hook: getCallback,
  137. }
  138. ],
  139. }])
  140. new RPCSocket<MyInterface>(20003, 'localhost').connect().then(async sock => {
  141. try{
  142. await sock.MyRPCGroup1.echo("hello!").then(console.log)
  143. await sock.MyRPCGroup1.add(1, Math.PI).then(console.log)
  144. await sock.MyRPCGroup1.getAsync().then(console.log)
  145. await sock.MyRPCGroup1.getCallback(console.log).then(console.log)
  146. }catch(e){
  147. console.log(String(e))
  148. }
  149. })
  150. //Class-based pattern
  151. interface IMyImplementation {
  152. echo: (x: string) => string
  153. add: (a: number, b: number) => number
  154. getAsync: () => Promise<{ topic: string, message: string }>
  155. getCallback: (callback:Function) => string
  156. }
  157. type IfcGenerator<Name extends string, Interface, keys extends keyof Interface = keyof Interface> = {
  158. [name in Name]: {
  159. [key in keys] : Interface[key]
  160. }
  161. }
  162. type MyIfc = IfcGenerator<"MyRPCGroup1", IMyImplementation>
  163. class MyImplementation implements IMyImplementation, RPCExporter<MyIfc>{
  164. //"X" as "X" syntax is required to satisfy the type system (as it assumes string)
  165. name = "MyRpcGroup11" as "MyRPCGroup1"
  166. //List the functions you declared in MyIfc
  167. exportRPCs = () => [
  168. this.echo,
  169. this.add,
  170. this.getAsync,
  171. this.getCallback
  172. ]
  173. //Write your implementations as you normally would
  174. echo = (text: string) => text
  175. add = (a: number, b: number) : number => a + b
  176. getAsync = async () : Promise<{topic: string, message:string}>=> await new Promise((res, _) => {
  177. setTimeout(() => {
  178. res({
  179. topic: "Hey!!",
  180. message: "Hello World Async!"
  181. })
  182. }, 250)
  183. })
  184. getCallback = (callback: Function) : string => {
  185. setTimeout(() => {
  186. try{
  187. callback({
  188. topic: "Hey!!",
  189. message: "Hello World Callback!"
  190. })
  191. }catch(e){
  192. console.log(String(e))
  193. }
  194. }, 250)
  195. return "Please wait for a callback :)"
  196. }
  197. }
  198. new RPCServer<MyIfc>(20004, [new MyImplementation(), /* ... other RPCExporters */])
  199. new RPCSocket<MyIfc>(20004, 'localhost').connect().then(async sock => {
  200. try{
  201. await sock.MyRPCGroup1.echo("hello!").then(console.log)
  202. await sock.MyRPCGroup1.add(1, Math.PI).then(console.log)
  203. await sock.MyRPCGroup1.getAsync().then(console.log)
  204. await sock.MyRPCGroup1.getCallback(console.log).then(console.log)
  205. }catch(e){
  206. console.log(String(e))
  207. }
  208. })