Browse Source

socketio drop in for bsock

master
peter 3 years ago
parent
commit
2a67927306
12 changed files with 782 additions and 152 deletions
  1. 377
    7
      package-lock.json
  2. 5
    1
      package.json
  3. 53
    0
      scratchpad.ts
  4. 14
    24
      src/Backend.ts
  5. 42
    23
      src/Frontend.ts
  6. 12
    17
      src/Interfaces.ts
  7. 38
    0
      src/PromiseIO/Client.ts
  8. 57
    0
      src/PromiseIO/Server.ts
  9. 7
    1
      src/Types.ts
  10. 130
    45
      src/Utils.ts
  11. 46
    33
      test/Test.ts
  12. 1
    1
      tsconfig.json

+ 377
- 7
package-lock.json View File

@@ -1,6 +1,6 @@
1 1
 {
2 2
   "name": "rpclibrary",
3
-  "version": "1.9.2",
3
+  "version": "1.10.2",
4 4
   "lockfileVersion": 1,
5 5
   "requires": true,
6 6
   "dependencies": {
@@ -247,6 +247,14 @@
247 247
       "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
248 248
       "dev": true
249 249
     },
250
+    "@types/engine.io": {
251
+      "version": "3.1.4",
252
+      "resolved": "https://registry.npmjs.org/@types/engine.io/-/engine.io-3.1.4.tgz",
253
+      "integrity": "sha512-98rXVukLD6/ozrQ2O80NAlWDGA4INg+tqsEReWJldqyi2fulC9V7Use/n28SWgROXKm6003ycWV4gZHoF8GA6w==",
254
+      "requires": {
255
+        "@types/node": "*"
256
+      }
257
+    },
250 258
     "@types/expect": {
251 259
       "version": "1.20.4",
252 260
       "resolved": "https://registry.npmjs.org/@types/expect/-/expect-1.20.4.tgz",
@@ -275,8 +283,21 @@
275 283
     "@types/node": {
276 284
       "version": "11.15.2",
277 285
       "resolved": "https://registry.npmjs.org/@types/node/-/node-11.15.2.tgz",
278
-      "integrity": "sha512-BqCU9uIFkUH9Sgo2uLYbmIiFB1T+VBiM8AI/El3LIAI5KzwtckeSG+3WOYZr9aMoX4UIvRFBWBeSaOu6hFue2Q==",
279
-      "dev": true
286
+      "integrity": "sha512-BqCU9uIFkUH9Sgo2uLYbmIiFB1T+VBiM8AI/El3LIAI5KzwtckeSG+3WOYZr9aMoX4UIvRFBWBeSaOu6hFue2Q=="
287
+    },
288
+    "@types/socket.io": {
289
+      "version": "2.1.8",
290
+      "resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-2.1.8.tgz",
291
+      "integrity": "sha512-NIQfh9WwJuJKlgmby4NgwMpoBOmNPCDgaRNPiLYZBtkbHkszK/9R52B5yGkd5a34rbVdAADuo8FhOS/5AZDemw==",
292
+      "requires": {
293
+        "@types/engine.io": "*",
294
+        "@types/node": "*"
295
+      }
296
+    },
297
+    "@types/socket.io-client": {
298
+      "version": "1.4.33",
299
+      "resolved": "https://registry.npmjs.org/@types/socket.io-client/-/socket.io-client-1.4.33.tgz",
300
+      "integrity": "sha512-m4LnxkljsI9fMsjwpW5QhRpMixo2BeeLpFmg0AE+sS4H1pzAd/cs/ftTiL60FLZgfFa8PFRPx5KsHu8O0bADKQ=="
280 301
     },
281 302
     "@webassemblyjs/ast": {
282 303
       "version": "1.8.5",
@@ -466,12 +487,26 @@
466 487
       "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
467 488
       "dev": true
468 489
     },
490
+    "accepts": {
491
+      "version": "1.3.7",
492
+      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
493
+      "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
494
+      "requires": {
495
+        "mime-types": "~2.1.24",
496
+        "negotiator": "0.6.2"
497
+      }
498
+    },
469 499
     "acorn": {
470 500
       "version": "6.4.1",
471 501
       "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz",
472 502
       "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==",
473 503
       "dev": true
474 504
     },
505
+    "after": {
506
+      "version": "0.8.2",
507
+      "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
508
+      "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8="
509
+    },
475 510
     "aggregate-error": {
476 511
       "version": "3.0.1",
477 512
       "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz",
@@ -602,6 +637,11 @@
602 637
       "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
603 638
       "dev": true
604 639
     },
640
+    "arraybuffer.slice": {
641
+      "version": "0.0.7",
642
+      "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
643
+      "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog=="
644
+    },
605 645
     "arrify": {
606 646
       "version": "1.0.1",
607 647
       "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
@@ -658,6 +698,11 @@
658 698
       "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
659 699
       "dev": true
660 700
     },
701
+    "async-limiter": {
702
+      "version": "1.0.1",
703
+      "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
704
+      "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ=="
705
+    },
661 706
     "atob": {
662 707
       "version": "2.1.2",
663 708
       "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
@@ -673,6 +718,11 @@
673 718
         "underscore": ">=1.8.3"
674 719
       }
675 720
     },
721
+    "backo2": {
722
+      "version": "1.0.2",
723
+      "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
724
+      "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc="
725
+    },
676 726
     "balanced-match": {
677 727
       "version": "1.0.0",
678 728
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@@ -734,12 +784,30 @@
734 784
         }
735 785
       }
736 786
     },
787
+    "base64-arraybuffer": {
788
+      "version": "0.1.5",
789
+      "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
790
+      "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg="
791
+    },
737 792
     "base64-js": {
738 793
       "version": "1.3.1",
739 794
       "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
740 795
       "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==",
741 796
       "dev": true
742 797
     },
798
+    "base64id": {
799
+      "version": "2.0.0",
800
+      "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
801
+      "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="
802
+    },
803
+    "better-assert": {
804
+      "version": "1.0.2",
805
+      "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
806
+      "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
807
+      "requires": {
808
+        "callsite": "1.0.0"
809
+      }
810
+    },
743 811
     "big.js": {
744 812
       "version": "5.2.2",
745 813
       "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
@@ -752,6 +820,11 @@
752 820
       "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
753 821
       "dev": true
754 822
     },
823
+    "blob": {
824
+      "version": "0.0.5",
825
+      "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz",
826
+      "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig=="
827
+    },
755 828
     "bluebird": {
756 829
       "version": "3.7.2",
757 830
       "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
@@ -1013,6 +1086,11 @@
1013 1086
         }
1014 1087
       }
1015 1088
     },
1089
+    "callsite": {
1090
+      "version": "1.0.0",
1091
+      "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
1092
+      "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA="
1093
+    },
1016 1094
     "camelcase": {
1017 1095
       "version": "5.3.1",
1018 1096
       "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
@@ -1191,11 +1269,20 @@
1191 1269
       "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
1192 1270
       "dev": true
1193 1271
     },
1272
+    "component-bind": {
1273
+      "version": "1.0.0",
1274
+      "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
1275
+      "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E="
1276
+    },
1194 1277
     "component-emitter": {
1195 1278
       "version": "1.3.0",
1196 1279
       "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
1197
-      "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
1198
-      "dev": true
1280
+      "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
1281
+    },
1282
+    "component-inherit": {
1283
+      "version": "0.0.3",
1284
+      "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
1285
+      "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM="
1199 1286
     },
1200 1287
     "concat-map": {
1201 1288
       "version": "0.0.1",
@@ -1236,6 +1323,11 @@
1236 1323
         "safe-buffer": "~5.1.1"
1237 1324
       }
1238 1325
     },
1326
+    "cookie": {
1327
+      "version": "0.3.1",
1328
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
1329
+      "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
1330
+    },
1239 1331
     "copy-concurrently": {
1240 1332
       "version": "1.0.5",
1241 1333
       "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz",
@@ -1517,6 +1609,77 @@
1517 1609
         "once": "^1.4.0"
1518 1610
       }
1519 1611
     },
1612
+    "engine.io": {
1613
+      "version": "3.4.2",
1614
+      "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.4.2.tgz",
1615
+      "integrity": "sha512-b4Q85dFkGw+TqgytGPrGgACRUhsdKc9S9ErRAXpPGy/CXKs4tYoHDkvIRdsseAF7NjfVwjRFIn6KTnbw7LwJZg==",
1616
+      "requires": {
1617
+        "accepts": "~1.3.4",
1618
+        "base64id": "2.0.0",
1619
+        "cookie": "0.3.1",
1620
+        "debug": "~4.1.0",
1621
+        "engine.io-parser": "~2.2.0",
1622
+        "ws": "^7.1.2"
1623
+      },
1624
+      "dependencies": {
1625
+        "debug": {
1626
+          "version": "4.1.1",
1627
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
1628
+          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
1629
+          "requires": {
1630
+            "ms": "^2.1.1"
1631
+          }
1632
+        }
1633
+      }
1634
+    },
1635
+    "engine.io-client": {
1636
+      "version": "3.4.3",
1637
+      "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.4.3.tgz",
1638
+      "integrity": "sha512-0NGY+9hioejTEJCaSJZfWZLk4FPI9dN+1H1C4+wj2iuFba47UgZbJzfWs4aNFajnX/qAaYKbe2lLTfEEWzCmcw==",
1639
+      "requires": {
1640
+        "component-emitter": "~1.3.0",
1641
+        "component-inherit": "0.0.3",
1642
+        "debug": "~4.1.0",
1643
+        "engine.io-parser": "~2.2.0",
1644
+        "has-cors": "1.1.0",
1645
+        "indexof": "0.0.1",
1646
+        "parseqs": "0.0.5",
1647
+        "parseuri": "0.0.5",
1648
+        "ws": "~6.1.0",
1649
+        "xmlhttprequest-ssl": "~1.5.4",
1650
+        "yeast": "0.1.2"
1651
+      },
1652
+      "dependencies": {
1653
+        "debug": {
1654
+          "version": "4.1.1",
1655
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
1656
+          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
1657
+          "requires": {
1658
+            "ms": "^2.1.1"
1659
+          }
1660
+        },
1661
+        "ws": {
1662
+          "version": "6.1.4",
1663
+          "resolved": "https://registry.npmjs.org/ws/-/ws-6.1.4.tgz",
1664
+          "integrity": "sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA==",
1665
+          "requires": {
1666
+            "async-limiter": "~1.0.0"
1667
+          }
1668
+        }
1669
+      }
1670
+    },
1671
+    "engine.io-parser": {
1672
+      "version": "2.2.0",
1673
+      "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.0.tgz",
1674
+      "integrity": "sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w==",
1675
+      "requires": {
1676
+        "after": "0.8.2",
1677
+        "arraybuffer.slice": "~0.0.7",
1678
+        "base64-arraybuffer": "0.1.5",
1679
+        "blob": "0.0.5",
1680
+        "has-binary2": "~1.0.2"
1681
+      }
1682
+    },
1520 1683
     "enhanced-resolve": {
1521 1684
       "version": "4.1.1",
1522 1685
       "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz",
@@ -2694,6 +2857,26 @@
2694 2857
         "function-bind": "^1.1.1"
2695 2858
       }
2696 2859
     },
2860
+    "has-binary2": {
2861
+      "version": "1.0.3",
2862
+      "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz",
2863
+      "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==",
2864
+      "requires": {
2865
+        "isarray": "2.0.1"
2866
+      },
2867
+      "dependencies": {
2868
+        "isarray": {
2869
+          "version": "2.0.1",
2870
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
2871
+          "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
2872
+        }
2873
+      }
2874
+    },
2875
+    "has-cors": {
2876
+      "version": "1.1.0",
2877
+      "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
2878
+      "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk="
2879
+    },
2697 2880
     "has-flag": {
2698 2881
       "version": "3.0.0",
2699 2882
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
@@ -2865,6 +3048,11 @@
2865 3048
       "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
2866 3049
       "dev": true
2867 3050
     },
3051
+    "indexof": {
3052
+      "version": "0.0.1",
3053
+      "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
3054
+      "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10="
3055
+    },
2868 3056
     "infer-owner": {
2869 3057
       "version": "1.0.4",
2870 3058
       "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
@@ -3585,6 +3773,19 @@
3585 3773
         "brorand": "^1.0.1"
3586 3774
       }
3587 3775
     },
3776
+    "mime-db": {
3777
+      "version": "1.44.0",
3778
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
3779
+      "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg=="
3780
+    },
3781
+    "mime-types": {
3782
+      "version": "2.1.27",
3783
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
3784
+      "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
3785
+      "requires": {
3786
+        "mime-db": "1.44.0"
3787
+      }
3788
+    },
3588 3789
     "mimic-fn": {
3589 3790
       "version": "2.1.0",
3590 3791
       "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
@@ -3714,8 +3915,7 @@
3714 3915
     "ms": {
3715 3916
       "version": "2.1.1",
3716 3917
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
3717
-      "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
3718
-      "dev": true
3918
+      "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
3719 3919
     },
3720 3920
     "nan": {
3721 3921
       "version": "2.14.0",
@@ -3743,6 +3943,11 @@
3743 3943
         "to-regex": "^3.0.1"
3744 3944
       }
3745 3945
     },
3946
+    "negotiator": {
3947
+      "version": "0.6.2",
3948
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
3949
+      "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
3950
+    },
3746 3951
     "neo-async": {
3747 3952
       "version": "2.6.1",
3748 3953
       "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz",
@@ -4084,6 +4289,11 @@
4084 4289
       "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
4085 4290
       "dev": true
4086 4291
     },
4292
+    "object-component": {
4293
+      "version": "0.0.3",
4294
+      "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",
4295
+      "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE="
4296
+    },
4087 4297
     "object-copy": {
4088 4298
       "version": "0.1.0",
4089 4299
       "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
@@ -4309,6 +4519,22 @@
4309 4519
       "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=",
4310 4520
       "dev": true
4311 4521
     },
4522
+    "parseqs": {
4523
+      "version": "0.0.5",
4524
+      "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
4525
+      "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
4526
+      "requires": {
4527
+        "better-assert": "~1.0.0"
4528
+      }
4529
+    },
4530
+    "parseuri": {
4531
+      "version": "0.0.5",
4532
+      "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
4533
+      "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
4534
+      "requires": {
4535
+        "better-assert": "~1.0.0"
4536
+      }
4537
+    },
4312 4538
     "pascalcase": {
4313 4539
       "version": "0.1.1",
4314 4540
       "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
@@ -4922,6 +5148,130 @@
4922 5148
         }
4923 5149
       }
4924 5150
     },
5151
+    "socket.io": {
5152
+      "version": "2.3.0",
5153
+      "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.3.0.tgz",
5154
+      "integrity": "sha512-2A892lrj0GcgR/9Qk81EaY2gYhCBxurV0PfmmESO6p27QPrUK1J3zdns+5QPqvUYK2q657nSj0guoIil9+7eFg==",
5155
+      "requires": {
5156
+        "debug": "~4.1.0",
5157
+        "engine.io": "~3.4.0",
5158
+        "has-binary2": "~1.0.2",
5159
+        "socket.io-adapter": "~1.1.0",
5160
+        "socket.io-client": "2.3.0",
5161
+        "socket.io-parser": "~3.4.0"
5162
+      },
5163
+      "dependencies": {
5164
+        "debug": {
5165
+          "version": "4.1.1",
5166
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
5167
+          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
5168
+          "requires": {
5169
+            "ms": "^2.1.1"
5170
+          }
5171
+        }
5172
+      }
5173
+    },
5174
+    "socket.io-adapter": {
5175
+      "version": "1.1.2",
5176
+      "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz",
5177
+      "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g=="
5178
+    },
5179
+    "socket.io-client": {
5180
+      "version": "2.3.0",
5181
+      "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.3.0.tgz",
5182
+      "integrity": "sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA==",
5183
+      "requires": {
5184
+        "backo2": "1.0.2",
5185
+        "base64-arraybuffer": "0.1.5",
5186
+        "component-bind": "1.0.0",
5187
+        "component-emitter": "1.2.1",
5188
+        "debug": "~4.1.0",
5189
+        "engine.io-client": "~3.4.0",
5190
+        "has-binary2": "~1.0.2",
5191
+        "has-cors": "1.1.0",
5192
+        "indexof": "0.0.1",
5193
+        "object-component": "0.0.3",
5194
+        "parseqs": "0.0.5",
5195
+        "parseuri": "0.0.5",
5196
+        "socket.io-parser": "~3.3.0",
5197
+        "to-array": "0.1.4"
5198
+      },
5199
+      "dependencies": {
5200
+        "component-emitter": {
5201
+          "version": "1.2.1",
5202
+          "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
5203
+          "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
5204
+        },
5205
+        "debug": {
5206
+          "version": "4.1.1",
5207
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
5208
+          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
5209
+          "requires": {
5210
+            "ms": "^2.1.1"
5211
+          }
5212
+        },
5213
+        "isarray": {
5214
+          "version": "2.0.1",
5215
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
5216
+          "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
5217
+        },
5218
+        "socket.io-parser": {
5219
+          "version": "3.3.0",
5220
+          "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.0.tgz",
5221
+          "integrity": "sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng==",
5222
+          "requires": {
5223
+            "component-emitter": "1.2.1",
5224
+            "debug": "~3.1.0",
5225
+            "isarray": "2.0.1"
5226
+          },
5227
+          "dependencies": {
5228
+            "debug": {
5229
+              "version": "3.1.0",
5230
+              "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
5231
+              "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
5232
+              "requires": {
5233
+                "ms": "2.0.0"
5234
+              }
5235
+            },
5236
+            "ms": {
5237
+              "version": "2.0.0",
5238
+              "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
5239
+              "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
5240
+            }
5241
+          }
5242
+        }
5243
+      }
5244
+    },
5245
+    "socket.io-parser": {
5246
+      "version": "3.4.1",
5247
+      "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.1.tgz",
5248
+      "integrity": "sha512-11hMgzL+WCLWf1uFtHSNvliI++tcRUWdoeYuwIl+Axvwy9z2gQM+7nJyN3STj1tLj5JyIUH8/gpDGxzAlDdi0A==",
5249
+      "requires": {
5250
+        "component-emitter": "1.2.1",
5251
+        "debug": "~4.1.0",
5252
+        "isarray": "2.0.1"
5253
+      },
5254
+      "dependencies": {
5255
+        "component-emitter": {
5256
+          "version": "1.2.1",
5257
+          "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
5258
+          "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
5259
+        },
5260
+        "debug": {
5261
+          "version": "4.1.1",
5262
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
5263
+          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
5264
+          "requires": {
5265
+            "ms": "^2.1.1"
5266
+          }
5267
+        },
5268
+        "isarray": {
5269
+          "version": "2.0.1",
5270
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz",
5271
+          "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
5272
+        }
5273
+      }
5274
+    },
4925 5275
     "source-list-map": {
4926 5276
       "version": "2.0.1",
4927 5277
       "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
@@ -5282,6 +5632,11 @@
5282 5632
         "setimmediate": "^1.0.4"
5283 5633
       }
5284 5634
     },
5635
+    "to-array": {
5636
+      "version": "0.1.4",
5637
+      "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
5638
+      "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA="
5639
+    },
5285 5640
     "to-arraybuffer": {
5286 5641
       "version": "1.0.1",
5287 5642
       "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
@@ -5958,6 +6313,16 @@
5958 6313
         "typedarray-to-buffer": "^3.1.5"
5959 6314
       }
5960 6315
     },
6316
+    "ws": {
6317
+      "version": "7.3.0",
6318
+      "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.0.tgz",
6319
+      "integrity": "sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w=="
6320
+    },
6321
+    "xmlhttprequest-ssl": {
6322
+      "version": "1.5.5",
6323
+      "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz",
6324
+      "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4="
6325
+    },
5961 6326
     "xtend": {
5962 6327
       "version": "4.0.2",
5963 6328
       "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
@@ -6043,6 +6408,11 @@
6043 6408
         "yargs": "^13.3.0"
6044 6409
       }
6045 6410
     },
6411
+    "yeast": {
6412
+      "version": "0.1.2",
6413
+      "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
6414
+      "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk="
6415
+    },
6046 6416
     "yn": {
6047 6417
       "version": "2.0.0",
6048 6418
       "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz",

+ 5
- 1
package.json View File

@@ -1,6 +1,6 @@
1 1
 {
2 2
   "name": "rpclibrary",
3
-  "version": "1.10.2",
3
+  "version": "1.11.0",
4 4
   "description": "rpclibrary is a websocket on steroids!",
5 5
   "main": "./js/Index.js",
6 6
   "repository": {
@@ -50,9 +50,13 @@
50 50
     "why-is-node-running": "^2.1.2"
51 51
   },
52 52
   "dependencies": {
53
+    "@types/socket.io": "^2.1.8",
54
+    "@types/socket.io-client": "^1.4.33",
53 55
     "bsock": "^0.1.9",
54 56
     "crypto-js": "^4.0.0",
55 57
     "http": "0.0.0",
58
+    "socket.io": "^2.3.0",
59
+    "socket.io-client": "^2.3.0",
56 60
     "uuid": "^3.3.3"
57 61
   },
58 62
   "files": [

+ 53
- 0
scratchpad.ts View File

@@ -0,0 +1,53 @@
1
+import { RPCSocket, RPCServer } from "./Index"
2
+
3
+
4
+// TL;DR
5
+const echo = (text: string) => {throw new Error("XD")}
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 = (cbb: Function) : string => {
16
+    setTimeout(() => {
17
+        try{
18
+            cbb({
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
+
43
+
44
+new RPCSocket(20000, 'localhost').connect()
45
+.then(async sock => {
46
+    try{
47
+        const val = await sock.call('ABCD', 12345)
48
+        console.log("VAL",val);
49
+        
50
+    }catch(e){
51
+        console.log("RPC error "+e)
52
+    }
53
+}).catch(e => console.log("connect err: "+e))

+ 14
- 24
src/Backend.ts View File

@@ -1,17 +1,17 @@
1 1
 'use strict'
2 2
 
3 3
 import http = require('http');
4
-import bsock = require('bsock');
4
+import { PromiseIO } from "./PromiseIO/Server";
5 5
 import * as T from './Types';
6 6
 import * as U from './Utils';
7 7
 import * as I from './Interfaces';
8 8
 
9 9
 export class RPCServer<
10 10
     InterfaceT extends T.RPCInterface = T.RPCInterface,
11
-> implements I.Destroyable {
11
+> {
12 12
 
13 13
     private ws = http.createServer()
14
-    private io = bsock.createServer()
14
+    private pio = PromiseIO.createServer()
15 15
     private visibility: T.Visibility
16 16
     private closeHandler: T.CloseHandler
17 17
     private errorHandler: T.ErrorHandler
@@ -42,7 +42,7 @@ export class RPCServer<
42 42
         })
43 43
 
44 44
 
45
-        this.errorHandler = (socket: I.Socket) => (error: any, rpcName: string, args: any[]) => {
45
+        this.errorHandler = (socket: I.Socket | PromiseIO) => (error: any, rpcName: string, args: any[]) => {
46 46
             if (conf.errorHandler) conf.errorHandler(socket, error, rpcName, args)
47 47
             else throw error
48 48
         }
@@ -72,20 +72,24 @@ export class RPCServer<
72 72
 
73 73
     private startWebsocket() {
74 74
         try {
75
-            this.io.attach(this.ws)
76
-            this.io.on('socket', (socket: I.Socket) => {
75
+            this.pio.attach(this.ws)
76
+            
77
+            this.pio.on('socket', (socket: I.Socket) => {
77 78
                 socket.on('error', (err) => this.errorHandler(socket, err, "system", []))
78 79
                 socket.on('close', () => this.closeHandler(socket))
79 80
                 this.connectionHandler(socket)
80 81
                 this.initRPCs(socket)
81 82
             })
82
-            this.ws = this.ws.listen(this.port, this.visibility)
83
+
84
+            this.pio.listen(this.port)
85
+
83 86
         } catch (e) {
84
-            this.errorHandler(this.io, e, 'system', [])
87
+            this.errorHandler(this.pio, e, 'system', [])
85 88
         }
86 89
     }
87 90
 
88 91
     protected initRPCs(socket: I.Socket) {
92
+        
89 93
         socket.hook('info', async (sesame?: string) => {
90 94
             const rpcs = await Promise.all(this.exporters.map(async exp => {
91 95
                 const allowed = await this.accessFilter(sesame, exp)
@@ -96,22 +100,8 @@ export class RPCServer<
96 100
         })
97 101
     }
98 102
 
99
-    /**
100
-     * Publishes a new list of Exporters. This destroys and restarts the socket
101
-     * @param exporters the exporters to publish
102
-    public setExporters(exporters: T.ExporterArray<InterfaceT>): any {
103
-        exporters.forEach(U.fixNames)
104
-        this.destroy()
105
-        this.ws = http.createServer()
106
-        this.io = bsock.createServer()
107
-        this.exporters = exporters
108
-        this.startWebsocket()
109
-    }
110
-    */
111
-
112
-
113
-    destroy(): void {
114
-        this.io.close()
103
+    close(): void {
104
+        this.pio.close()
115 105
         this.ws.close()
116 106
     }
117 107
 }

+ 42
- 23
src/Frontend.ts View File

@@ -1,7 +1,6 @@
1 1
 'use strict'
2 2
 
3
-import bsock = require('bsock');
4
-
3
+import { PromiseIOClient } from './PromiseIO/Client'
5 4
 import * as T from './Types'; 
6 5
 import * as I from './Interfaces';
7 6
 import { stripAfterEquals, appendComma } from './Utils';
@@ -18,8 +17,12 @@ export class RPCSocket<Ifc extends T.RPCInterface = T.RPCInterface> implements I
18 17
     }
19 18
 
20 19
     private socket: I.Socket
21
-    private closeHandlers: T.FrontEndHandlerType['close'][] = []
22
-    private errorHandlers: T.FrontEndHandlerType['error'][] = []
20
+    private handlers : {
21
+        [name in string]: T.AnyFunction[]
22
+    } = {
23
+        error: [],
24
+        close: []
25
+    }
23 26
     private hooks : {[name in string]: T.AnyFunction} = {} 
24 27
 
25 28
     /**
@@ -45,6 +48,19 @@ export class RPCSocket<Ifc extends T.RPCInterface = T.RPCInterface> implements I
45 48
         }
46 49
     }
47 50
 
51
+    /**
52
+     * Hooks a handler to a function name. Use {@link call} to trigger it.
53
+     * @param name The function name to listen on
54
+     * @param handler The handler to attach
55
+     */
56
+    public bind(name: string, handler: (...args:any[]) => any | Promise<any>){
57
+        if(!this.socket){
58
+            this.hooks[name] = handler
59
+        }else{
60
+            this.socket.bind(name, handler)
61
+        }
62
+    }
63
+
48 64
     /**
49 65
      * Removes a {@link hook} listener by name.
50 66
      * @param name The function name 
@@ -62,13 +78,12 @@ export class RPCSocket<Ifc extends T.RPCInterface = T.RPCInterface> implements I
62 78
      * @param type 'error' or 'close'
63 79
      * @param f The listener to attach
64 80
      */
65
-    public on<T extends "error" | "close">(type: T, f: T.FrontEndHandlerType[T]){
81
+    public on(type: string, f: T.AnyFunction){
66 82
         if(!this.socket){
67
-            switch(type){
68
-                case "error": this.errorHandlers.push(<T.FrontEndHandlerType['error']> f); break;
69
-                case "close": this.closeHandlers.push(<T.FrontEndHandlerType['close']> f); break;
70
-                default: throw new Error('socket.on only supports ´error´ and ´close´ as first parameter. Got: ´'+type+'´')
71
-            }
83
+            if(!this.handlers[type]) 
84
+                this.handlers[type] = []
85
+
86
+            this.handlers[type].push(f)
72 87
         }else{
73 88
             this.socket.on(type, f)
74 89
         }
@@ -84,14 +99,6 @@ export class RPCSocket<Ifc extends T.RPCInterface = T.RPCInterface> implements I
84 99
         this.socket.emit(eventName, data)
85 100
     }
86 101
 
87
-    /**
88
-     * Destroys the socket
89
-     */
90
-    public destroy(){
91
-        if(!this.socket) return;
92
-        this.socket.destroy()
93
-    }
94
-
95 102
     /**
96 103
      * Closes the socket. It may attempt to reconnect.
97 104
      */
@@ -108,7 +115,8 @@ export class RPCSocket<Ifc extends T.RPCInterface = T.RPCInterface> implements I
108 115
     public async call (rpcname: string, ...args: any[]) : Promise<any>{
109 116
         if(!this.socket) throw new Error("The socket is not connected! Use socket.connect() first")
110 117
         try{
111
-            return await this.socket.call.apply(this.socket, [rpcname, ...args])
118
+            const val = await this.socket.call.apply(this.socket, [rpcname, ...args])
119
+            return val
112 120
         }catch(e){
113 121
             this.emit('error', e)
114 122
             throw e
@@ -129,14 +137,23 @@ export class RPCSocket<Ifc extends T.RPCInterface = T.RPCInterface> implements I
129 137
      * Connects to the server and attaches available RPCs to this object
130 138
      */
131 139
     public async connect( sesame?: string ) : Promise<T.ConnectedSocket<Ifc>> {
132
-        this.socket = await bsock.connect(this.port, this.server, this.conf.tls?this.conf.tls:false)
133
-        this.errorHandlers.forEach(h => this.socket.on('error', h))
134
-        this.closeHandlers.forEach(h => this.socket.on('close', h))
140
+
141
+        try{
142
+            this.socket = await PromiseIOClient.connect(this.port, this.server, /*this.conf.tls?this.conf.tls:false*/)
143
+        }catch(e){
144
+            this.handlers['error'].forEach(h => h(e))
145
+            throw e
146
+        }
147
+
148
+        Object.entries(this.handlers).forEach(([k,v])=>{
149
+            v.forEach(h => this.socket.on(k, h))
150
+        })
151
+
135 152
         Object.entries(this.hooks).forEach((kv: [string, T.AnyFunction]) => {
136 153
             this.socket.hook(kv[0], kv[1])
137 154
         })
138
-
139 155
         const info:T.ExtendedRpcInfo[] = await this.info(sesame)
156
+
140 157
         info.forEach(i => {
141 158
             let f: any
142 159
             
@@ -153,6 +170,8 @@ export class RPCSocket<Ifc extends T.RPCInterface = T.RPCInterface> implements I
153 170
             this[i.owner][i.name] = f
154 171
             this[i.owner][i.name].bind(this)
155 172
         })
173
+        
174
+        
156 175
         return <T.ConnectedSocket<Ifc>> (this as any) 
157 176
     }
158 177
 

+ 12
- 17
src/Interfaces.ts View File

@@ -12,20 +12,15 @@ export type RPCExporter<
12 12
     exportRPCs() : T.RPCDefinitions<Ifc>[Name]
13 13
 }
14 14
 
15
-/**
16
- * Generic socket interface that can apply to bsock as well as RPCSocket
17
- */
18
-export interface Socket extends Destroyable {
19
-    port: number
20
-    hook: (rpcname: string, handler: T.AnyFunction) => void
21
-    unhook: (rpcname:string) => void
22
-    call: (rpcname:string, ...args: any[]) => Promise<any>
23
-    fire: (rpcname:string, ...args: any[]) => Promise<any>
24
-    on: T.OnFunction
25
-    emit: (eventName: string, data:any) => void    
26
-    close() : void
27
-}
28
-
29
-export interface Destroyable{
30
-    destroy() : void
31
-}
15
+export interface Socket {
16
+    id?: string
17
+    bind: (name: string, listener: T.PioBindListener) => void
18
+  
19
+    hook: (rpcname: string, handler: T.PioHookListener) => void
20
+    unhook: (rpcname: string, listener?:T.AnyFunction) => void
21
+    call: (rpcname: string, ...args: any[]) => Promise<any>
22
+    fire: (rpcname: string, ...args: any[]) => Promise<any>
23
+    on: (type: string, f: T.AnyFunction)=>any
24
+    emit: (eventName: string, data: any) => void
25
+    close(): void
26
+  }

+ 38
- 0
src/PromiseIO/Client.ts View File

@@ -0,0 +1,38 @@
1
+import { Socket } from "socket.io"
2
+import * as U from '../Utils'
3
+import * as I from '../Interfaces'
4
+import * as socketio from 'socket.io-client'
5
+
6
+export class PromiseIOClient {
7
+    
8
+    static connect = (port: number, host = "localhost"): Promise<I.Socket> => new Promise((res, rej) => {
9
+        try {
10
+            const socket = socketio(`http://${host}:${port}`, {
11
+                reconnectionAttempts: 2,
12
+                reconnectionDelay: 200,
13
+                timeout: 450,
14
+                reconnection: false
15
+            })
16
+            socket.on('connect_error', e => {
17
+                sock.emit('error', e)
18
+                rej(e) 
19
+            })
20
+
21
+            const sock = U.makePioSocket(socket)
22
+            socket.on('connect', ()=>{ res(sock) })
23
+
24
+
25
+            /*
26
+            socket.on('connect_timeout', ()=>console.log('connect_timeout'))
27
+            socket.on('disconnect', ()=>console.log('disconnect'))
28
+            socket.on('reconnect', ()=>console.log('reconnect'))
29
+            socket.on('reconnect_attempt', ()=>console.log('reconnect_attempt'))
30
+            socket.on('reconnecting', ()=>console.log('reconnecting'));
31
+            socket.on('reconnect_failed', ()=>console.log('reconnect_failed'));
32
+            socket.on('reconnecting', ()=>console.log('reconnecting'));
33
+            */
34
+        } catch (e) {
35
+            rej(e)
36
+        }
37
+    })
38
+}

+ 57
- 0
src/PromiseIO/Server.ts View File

@@ -0,0 +1,57 @@
1
+import { Server, Socket } from "socket.io"
2
+import { Server as httpServer } from "http"
3
+import * as U from '../Utils'
4
+import * as T from '../Types'
5
+const socketio = require('socket.io')
6
+
7
+export class PromiseIO {
8
+    io?: Server
9
+    private listeners: { [eventName in string]: ((...args: any) => void)[] } = {
10
+        socket: [],
11
+        connect: []
12
+    }
13
+
14
+    static createServer(): PromiseIO {
15
+        return new PromiseIO();
16
+    }
17
+
18
+    attach(httpServer: httpServer) {
19
+        this.io = socketio(httpServer)
20
+    }
21
+
22
+    listen(port: number) {
23
+        this.io!.on('connection', (sock: Socket) => {
24
+            const pioSock = U.makePioSocket(sock)
25
+            this.listeners['socket'].forEach(listener => listener(pioSock))
26
+            this.listeners['connect'].forEach(listener => listener(pioSock))
27
+            /*
28
+            pioSock.on('error', ()=>console.log('error'));
29
+
30
+            pioSock.on('connect_timeout', ()=>console.log('connect_timeout'))
31
+            pioSock.on('disconnect', ()=>console.log('disconnect'))
32
+            pioSock.on('reconnect', ()=>console.log('reconnect'))
33
+            pioSock.on('reconnect_attempt', ()=>console.log('reconnect_attempt'))
34
+            pioSock.on('reconnecting', ()=>console.log('reconnecting'));
35
+            pioSock.on('reconnect_failed', ()=>console.log('reconnect_failed'));
36
+            pioSock.on('reconnecting', ()=>console.log('reconnecting'));
37
+            */
38
+        })
39
+        this.io!.listen(port)
40
+    }
41
+
42
+    on(eventName: string, listener: T.AnyFunction) {
43
+        if (this.listeners[eventName] == null) {
44
+            this.listeners[eventName] = []
45
+        }
46
+        this.listeners[eventName].push(listener)
47
+    }
48
+
49
+    close = () => {
50
+        if(this.io){
51
+            this.io.engine.ws.close()
52
+            this.io.close()
53
+            this.io = undefined
54
+        }
55
+    }
56
+
57
+}

+ 7
- 1
src/Types.ts View File

@@ -1,12 +1,18 @@
1 1
 import * as I from "./Interfaces";
2 2
 import { RPCSocket } from "./Frontend";
3
+import { PromiseIO } from "./PromiseIO/Server";
4
+
5
+export type PioBindListener = (...args: any) => void
6
+export type PioHookListener = AnyFunction
7
+
8
+
3 9
 
4 10
 export type AnyFunction = (...args:any) => any
5 11
 export type HookFunction = AnyFunction
6 12
 export type AccessFilter<InterfaceT extends RPCInterface = RPCInterface> = (sesame:string|undefined, exporter: I.RPCExporter<InterfaceT, keyof InterfaceT>) => Promise<boolean> | boolean
7 13
 export type Visibility = "127.0.0.1" | "0.0.0.0"
8 14
 export type ConnectionHandler = (socket:I.Socket) => void
9
-export type ErrorHandler = (socket:I.Socket, error:any, rpcName: string, args: any[]) => void
15
+export type ErrorHandler = (socket:I.Socket | PromiseIO, error:any, rpcName: string, args: any[]) => void
10 16
 export type CloseHandler = (socket:I.Socket) =>  void
11 17
 export type SesameFunction = (sesame : string) => boolean
12 18
 export type SesameConf = {

+ 130
- 45
src/Utils.ts View File

@@ -2,6 +2,8 @@ import * as uuidv4 from "uuid/v4"
2 2
 
3 3
 import * as T from "./Types";
4 4
 import * as I from "./Interfaces";
5
+import { Server as ioServer, Socket as ioSocket, Socket } from "socket.io"
6
+import { Socket as ioClientSocket } from "socket.io-client"
5 7
 
6 8
 /**
7 9
  * Translate an RPC to RPCInfo for serialization.
@@ -11,18 +13,18 @@ import * as I from "./Interfaces";
11 13
  * @param sesame optional sesame phrase to prepend before all RPC arguments 
12 14
  * @throws Error on RPC without name property
13 15
  */
14
-export const rpcToRpcinfo = (socket: I.Socket, rpc : T.RPC<any, any>, owner: string, errorHandler: T.ErrorHandler, sesame?:T.SesameFunction):T.RpcInfo => {
15
-    switch (typeof rpc){
16
-        case  "object":
17
-            if(rpc['call']){
16
+export const rpcToRpcinfo = (socket: I.Socket, rpc: T.RPC<any, any>, owner: string, errorHandler: T.ErrorHandler, sesame?: T.SesameFunction): T.RpcInfo => {
17
+    switch (typeof rpc) {
18
+        case "object":
19
+            if (rpc['call']) {
18 20
                 return {
19 21
                     owner: owner,
20 22
                     argNames: extractArgs(rpc['call']),
21 23
                     type: "Call",
22 24
                     name: rpc.name,
23
-                    call: sesame?async (_sesame, ...args) => {if(sesame(_sesame)) return await rpc['call'].apply({}, args); socket.destroy()}:rpc['call'], // check & remove sesame 
25
+                    call: sesame ? async (_sesame, ...args) => { if (sesame(_sesame)) return await rpc['call'].apply({}, args); socket.close() } : rpc['call'], // check & remove sesame 
24 26
                 }
25
-            }else{
27
+            } else {
26 28
                 const generator = hookGenerator(<T.HookRPC<any, any>>rpc, errorHandler, sesame)
27 29
                 return {
28 30
                     owner: owner,
@@ -33,7 +35,7 @@ export const rpcToRpcinfo = (socket: I.Socket, rpc : T.RPC<any, any>, owner: str
33 35
                 }
34 36
             }
35 37
         case "function":
36
-            if(!rpc.name) throw new Error(`
38
+            if (!rpc.name) throw new Error(`
37 39
 RPC did not provide a name. 
38 40
 \nUse 'funtion name(..){ .. }' syntax instead.
39 41
 \n
@@ -41,14 +43,14 @@ RPC did not provide a name.
41 43
 \n${rpc.toString()}
42 44
 \n>------------OFFENDING RPC`)
43 45
             return {
44
-                owner : owner,
46
+                owner: owner,
45 47
                 argNames: extractArgs(rpc),
46 48
                 type: "Call",
47 49
                 name: rpc.name,
48
-                call: sesame?async (_sesame, ...args) => {if(sesame(_sesame)) return await rpc.apply({}, args); throw makeError(rpc.name)}:rpc, // check & remove sesame 
50
+                call: sesame ? async (_sesame, ...args) => { if (sesame(_sesame)) return await rpc.apply({}, args); throw makeError(rpc.name) } : rpc, // check & remove sesame 
49 51
             }
50 52
     }
51
-    throw new Error("Bad socketIORPC type "+ typeof rpc)
53
+    throw new Error("Bad socketIORPC type " + typeof rpc)
52 54
 }
53 55
 
54 56
 /**
@@ -57,37 +59,37 @@ RPC did not provide a name.
57 59
  * @param exporter The exporter
58 60
  * @param makeUnique @default true Attach a suffix to RPC names
59 61
  */
60
-export function rpcHooker(socket: I.Socket, exporter:I.RPCExporter<any, any>, errorHandler: T.ErrorHandler, sesame?:T.SesameFunction, makeUnique = true):T.ExtendedRpcInfo[]{
62
+export function rpcHooker(socket: I.Socket, exporter: I.RPCExporter<any, any>, errorHandler: T.ErrorHandler, sesame?: T.SesameFunction, makeUnique = true): T.ExtendedRpcInfo[] {
61 63
     const owner = exporter.name
62 64
     const RPCs = exporter.exportRPCs()
63 65
 
64 66
     return RPCs.map(rpc => rpcToRpcinfo(socket, rpc, owner, errorHandler, sesame))
65
-    .map(info => {
66
-        const suffix = makeUnique?"-"+uuidv4().substr(0,4):""
67
-        const ret:any = info
68
-        ret.uniqueName = info.name+suffix
69
-        let rpcFunction = info.type === 'Hook'? info.generator(socket)
70
-                                              : info.call
71
-
72
-        socket.hook(ret.uniqueName, callGenerator(info.name, socket, rpcFunction, errorHandler))
73
-        return ret
74
-    })
67
+        .map(info => {
68
+            const suffix = makeUnique ? "-" + uuidv4().substr(0, 4) : ""
69
+            const ret: any = info
70
+            ret.uniqueName = info.name + suffix
71
+            let rpcFunction = info.type === 'Hook' ? info.generator(socket)
72
+                : info.call
73
+
74
+            socket.hook(ret.uniqueName, callGenerator(info.name, socket, rpcFunction, errorHandler))
75
+            return ret
76
+        })
75 77
 }
76 78
 
77 79
 /**
78 80
  * Decorate an RPC with the error handler
79 81
  * @param rpcFunction the function to decorate
80 82
  */
81
-const callGenerator = (rpcName : string, socket: I.Socket, rpcFunction : T.AnyFunction, errorHandler: T.ErrorHandler) : T.AnyFunction => {
83
+const callGenerator = (rpcName: string, socket: I.Socket, rpcFunction: T.AnyFunction, errorHandler: T.ErrorHandler): T.AnyFunction => {
82 84
     const argsArr = extractArgs(rpcFunction)
83 85
     const args = argsArr.join(',')
84 86
     const argsStr = argsArr.map(stripAfterEquals).join(',')
85 87
 
86
-    return eval(`async (`+args+`) => {
88
+    return eval(`async (` + args + `) => {
87 89
         try{
88
-            return await rpcFunction(`+argsStr+`)
90
+            return await rpcFunction(`+ argsStr + `)
89 91
         }catch(e){
90
-            errorHandler(socket)(e, rpcName, [`+args+`])
92
+            errorHandler(socket)(e, rpcName, [`+ args + `])
91 93
         }
92 94
     }`)
93 95
 }
@@ -96,7 +98,7 @@ const callGenerator = (rpcName : string, socket: I.Socket, rpcFunction : T.AnyFu
96 98
  * Utility function to strip parameters like "a = 3" of their defaults
97 99
  * @param str The parameter to modify
98 100
  */
99
-export function stripAfterEquals(str:string):string{
101
+export function stripAfterEquals(str: string): string {
100 102
     return str.split("=")[0]
101 103
 }
102 104
 
@@ -105,13 +107,14 @@ export function stripAfterEquals(str:string):string{
105 107
  * @param rpc The RPC to transform
106 108
  * @returns A {@link HookFunction}
107 109
  */
108
-const hookGenerator = (rpc:T.HookRPC<any, any>, /*not unused!*/ errorHandler: T.ErrorHandler, sesameFn?: T.SesameFunction): T.HookInfo['generator'] => { 
110
+const hookGenerator = (rpc: T.HookRPC<any, any>, /*not unused!*/ errorHandler: T.ErrorHandler, sesameFn?: T.SesameFunction): T.HookInfo['generator'] => {
111
+
109 112
     let argsArr = extractArgs(rpc.hook)
110 113
     argsArr.pop() //remove 'callback' from the end
111 114
     let callArgs = argsArr.join(',')
112 115
 
113
-    const args = sesameFn?(['sesame', ...argsArr].join(','))
114
-                         :callArgs
116
+    const args = sesameFn ? (['sesame', ...argsArr].join(','))
117
+        : callArgs
115 118
 
116 119
     callArgs = appendComma(callArgs, false)
117 120
 
@@ -139,35 +142,35 @@ const hookGenerator = (rpc:T.HookRPC<any, any>, /*not unused!*/ errorHandler: T.
139 142
 }
140 143
 
141 144
 const makeError = (callName: string) => {
142
-    return new Error("Call not found: "+callName+". ; Zone: <root> ; Task: Promise.then ; Value: Error: Call not found: "+callName)
145
+    return new Error("Call not found: " + callName + ". ; Zone: <root> ; Task: Promise.then ; Value: Error: Call not found: " + callName)
143 146
 }
144 147
 
145 148
 /**
146 149
  * Extract a string list of parameters from a function
147 150
  * @param f The source function
148 151
  */
149
-const extractArgs = (f:Function):string[] => {
150
-    let fn:string
151
-    fn = (fn = String(f)).substr(0, fn.indexOf(")")).substr(fn.indexOf("(")+1)
152
-    return fn!==""?fn.split(',') : []
152
+const extractArgs = (f: Function): string[] => {
153
+    let fn: string
154
+    fn = (fn = String(f)).substr(0, fn.indexOf(")")).substr(fn.indexOf("(") + 1)
155
+    return fn !== "" ? fn.split(',') : []
153 156
 }
154 157
 
155 158
 
156
-export function makeSesameFunction (sesame : T.SesameFunction | string) : T.SesameFunction {
157
-    if(typeof sesame === 'function'){
159
+export function makeSesameFunction(sesame: T.SesameFunction | string): T.SesameFunction {
160
+    if (typeof sesame === 'function') {
158 161
         return sesame
159 162
     }
160 163
 
161
-    return (testSesame : string) => {
162
-        return testSesame === sesame 
164
+    return (testSesame: string) => {
165
+        return testSesame === sesame
163 166
     }
164 167
 }
165 168
 
166 169
 
167
-export function appendComma(s?:string, turnToString = true):string{
168
-    if(turnToString)   
169
-        return s?`'${s}',`:"" 
170
-        return s?`${s},`:"" 
170
+export function appendComma(s?: string, turnToString = true): string {
171
+    if (turnToString)
172
+        return s ? `'${s}',` : ""
173
+    return s ? `${s},` : ""
171 174
 }
172 175
 
173 176
 
@@ -176,12 +179,94 @@ export function appendComma(s?:string, turnToString = true):string{
176 179
  * This was supposedly fixed (https://github.com/microsoft/TypeScript/issues/5611) but it still is the case.
177 180
  * This function sets the name value for all object members that are functions.
178 181
 */
179
-export function fixNames(o:Object):void{
182
+export function fixNames(o: Object): void {
180 183
     Object.keys(o).forEach(key => {
181
-        if(typeof o[key] === 'function' && !o[key].name){
184
+        if (typeof o[key] === 'function' && !o[key].name) {
182 185
             Object.defineProperty(o[key], 'name', {
183 186
                 value: key
184 187
             })
185 188
         }
186 189
     })
187
-}
190
+}
191
+
192
+export const makePioSocket = (socket: any): I.Socket => {
193
+    return {
194
+        bind: (name: string, listener: T.PioBindListener) => socket.on(name, (...args: any) => {
195
+            const ack = args.pop()
196
+            listener.apply(null, args)
197
+            ack()
198
+        }),
199
+
200
+        hook: (name: string, listener: T.PioHookListener) => {
201
+            const args = extractArgs(listener)
202
+            let argNames
203
+            let restParam = args.find(e => e.includes('...'))
204
+            if(!restParam){
205
+                argNames = [...args, '...__args__'].join(',')
206
+                restParam = '__args__'
207
+            }else{
208
+                argNames = [...args].join(',')
209
+                restParam = restParam.replace('...','')
210
+            }
211
+
212
+            const decoratedListener = eval(`(() => async (${argNames}) => {
213
+                const __ack__ = ${restParam}.pop()
214
+                try{
215
+                    const response = await listener.apply(null, [${argNames}])
216
+                    __ack__(response)
217
+                }catch(e){
218
+                    __ack__({
219
+                        ...e,
220
+                        stack: e.stack,
221
+                        message: e.message,
222
+                        name: e.name,
223
+                    })
224
+                }
225
+            })()`)
226
+            socket.on(name, decoratedListener)
227
+        },
228
+
229
+        call: (name: string, ...args: any) => {
230
+            return new Promise((res, rej) => {
231
+                const params: any = [name, ...args, (resp) => {
232
+                    if(isError(resp)){
233
+                        const err = new Error()
234
+                        err.stack = resp.stack
235
+                        err.name = resp.name
236
+                        err.message = resp.message
237
+                        return rej(err)
238
+                    }
239
+                    res(resp)
240
+                }]
241
+                socket.emit.apply(socket, params)                    
242
+            })
243
+        },
244
+
245
+        fire: (name: string, ...args: any) => new Promise((res, rej) => {
246
+            const params: any = [name, ...args]
247
+            socket.emit.apply(socket, params)
248
+            res()
249
+        }),
250
+
251
+        unhook: (name: string, listener?: T.AnyFunction) => {
252
+            if (listener) {
253
+                socket.removeListener(name, listener)
254
+            } else {
255
+                socket.removeAllListeners(name)
256
+            }
257
+        },
258
+
259
+        id: socket.id,
260
+        on: (...args) => socket.on.apply(socket, args),
261
+        emit: (...args) => socket.emit.apply(socket, args),
262
+        close: () => {
263
+            socket
264
+            socket.disconnect(true)
265
+        },
266
+    }
267
+}
268
+
269
+export const isError = function(e){
270
+    return e && e.stack && e.message && typeof e.stack === 'string' 
271
+           && typeof e.message === 'string';
272
+   }

+ 46
- 33
test/Test.ts View File

@@ -68,8 +68,8 @@ describe('RPCServer', () => {
68 68
     })
69 69
     
70 70
     after(done => {
71
-        client.destroy()
72
-        server.destroy()
71
+        client.close()
72
+        server.close()
73 73
 
74 74
         done()
75 75
     })
@@ -116,8 +116,8 @@ describe('RPCSocket', () => {
116 116
     })
117 117
 
118 118
     after(() => {
119
-        client.destroy()
120
-        server.destroy()
119
+        client.close()
120
+        server.close()
121 121
     })
122 122
 
123 123
 
@@ -221,8 +221,8 @@ describe('It should do unhook', () => {
221 221
     })
222 222
 
223 223
     after(() => {
224
-        client.destroy()
225
-        server.destroy()
224
+        client.close()
225
+        server.close()
226 226
     })
227 227
 
228 228
     it('Subscribe with param', (done) => {
@@ -314,8 +314,8 @@ describe('Sesame should unlock the socket', () => {
314 314
     })
315 315
 
316 316
     after(() => {
317
-        client.destroy()
318
-        server.destroy()
317
+        client.close()
318
+        server.close()
319 319
     })
320 320
 
321 321
     it('should work with sesame', (done) => {
@@ -337,8 +337,8 @@ describe('Sesame should unlock the socket', () => {
337 337
             else {
338 338
                 done(new Error("Function supposed to be removed without sesame"))
339 339
             }
340
-            cli.destroy()
341
-            sock.destroy()
340
+            cli.close()
341
+            sock.close()
342 342
         })
343 343
     })
344 344
 
@@ -350,8 +350,8 @@ describe('Sesame should unlock the socket', () => {
350 350
             else {
351 351
                 done(new Error("Function supposed to be removed without sesame"))
352 352
             }
353
-            cli.destroy()
354
-            sock.destroy()
353
+            cli.close()
354
+            sock.close()
355 355
         })
356 356
     })
357 357
 
@@ -405,9 +405,9 @@ describe('Error handling', () => {
405 405
                         done(e)
406 406
                 })
407 407
                 .finally(() => {
408
-                    cli.destroy()
409
-                    sock.destroy()
410
-                    server.destroy()
408
+                    cli.close()
409
+                    sock.close()
410
+                    server.close()
411 411
                 })
412 412
         })
413 413
     })
@@ -440,9 +440,9 @@ describe('Error handling', () => {
440 440
                     done(e)
441 441
                 })
442 442
                 .finally(() => {
443
-                    cli.destroy()
444
-                    sock.destroy()
445
-                    server.destroy()
443
+                    cli.close()
444
+                    sock.close()
445
+                    server.close()
446 446
                 })
447 447
         })
448 448
     })
@@ -484,9 +484,9 @@ describe("Errorhandler functionality", () => {
484 484
                     done(new Error("UNEXPECTED CLIENT ERROR " + e.message))
485 485
                 })
486 486
                 .finally(() => {
487
-                    cli.destroy()
488
-                    sock.destroy()
489
-                    server.destroy()
487
+                    cli.close()
488
+                    sock.close()
489
+                    server.close()
490 490
                 })
491 491
         })
492 492
     })
@@ -523,9 +523,9 @@ describe("Errorhandler functionality", () => {
523 523
                     done(e)
524 524
                 })
525 525
                 .finally(() => {
526
-                    cli.destroy()
527
-                    sock.destroy()
528
-                    server.destroy()
526
+                    cli.close()
527
+                    sock.close()
528
+                    server.close()
529 529
                 })
530 530
         })
531 531
     })
@@ -595,12 +595,12 @@ describe("Class binding", () => {
595 595
     })
596 596
 
597 597
     afterEach((done) => {
598
-        sock.destroy()
598
+        sock.close()
599 599
         done()
600 600
     })
601 601
 
602 602
     after(() => {
603
-        serv.destroy()
603
+        serv.close()
604 604
     })
605 605
 
606 606
     /* The server-side socket will enter a 30s timeout if destroyed by a RPC.
@@ -663,26 +663,38 @@ describe("attaching handlers before connecting", () => {
663 663
         }).catch(e => {
664 664
             //catch clause fires second
665 665
             if (errorHandleCount != 1) {
666
-                console.log("catch clause didn't fire second");
666
+                console.log("catch clause didn't fire second", errorHandleCount);
667 667
             } else {
668
-                sock.destroy()
668
+                sock.close()
669 669
                 done()
670 670
             }
671 671
         })
672 672
     })
673 673
 
674
+    /*
675
+     * ## 1.11.0 breaking ##
676
+     * 
677
+     * API change: Move from bsock to socketio changes underlying API for when errors are thrown.
678
+     * socketio does not throw on unknown listener. This behaviour is considered more consistent with the design 
679
+     * goals of RPClibrary and was thus adopted 
680
+     *
681
+          
682
+     
674 683
     it("fires error if call is unknown", (done) => {
675 684
         const serv = new RPCServer(21004)
676 685
         const sock = new RPCSocket(21004, 'localhost')
677 686
 
678 687
         sock.on('error', (err) => {
679
-            sock.destroy()
680
-            serv.destroy()
688
+            sock.close()
689
+            serv.close()
681 690
             done()
682 691
         })
683 692
 
684 693
         sock.connect().then(_ => {
685
-            sock.call("unknownRPC123", "AAAAA").catch(e => { /* ignore */ })
694
+            sock.call("unknownRPC123", "AAAAA").catch(e => {  }).then(x => {
695
+                console.log("X",x);
696
+                
697
+            })
686 698
         }).catch(e => {
687 699
             console.log("unexpected connect catch clause");
688 700
             done(e)
@@ -695,8 +707,8 @@ describe("attaching handlers before connecting", () => {
695 707
 
696 708
         sock.connect().then(_ => {
697 709
             sock.call("unknownRPC123", "AAAAA").catch(e => {
698
-                sock.destroy()
699
-                serv.destroy()
710
+                sock.close()
711
+                serv.close()
700 712
                 done()
701 713
             })
702 714
         }).catch(e => {
@@ -704,6 +716,7 @@ describe("attaching handlers before connecting", () => {
704 716
             done(e)
705 717
         })
706 718
     })
719
+    */
707 720
 
708 721
 })
709 722
 

+ 1
- 1
tsconfig.json View File

@@ -9,6 +9,6 @@
9 9
       "strict": true,
10 10
       "experimentalDecorators": true
11 11
     },
12
-    "include": ["src/**/*.ts", "test/**/*.ts", "Index.ts", "demo.ts"],
12
+    "include": ["src/**/*.ts", "test/**/*.ts", "Index.ts", "demo.ts", "scratchpad.ts"],
13 13
     "exclude": ["node_modules"]
14 14
   }

Loading…
Cancel
Save