From 6f71ccff7329bca93bbceb2bd01e0444c9ba2215 Mon Sep 17 00:00:00 2001 From: Darin Dimitrov Date: Mon, 21 Jan 2019 10:02:57 +0200 Subject: [PATCH] Use MessagePack to encode large sessions --- .vscode/settings.json | 10 ++ package-lock.json | 198 ++++++++++++++++++++---------- package.json | 5 +- src/models/file-payload.ts | 6 +- src/models/sdk-callbacks.ts | 2 +- src/services/helpers-service.ts | 119 ++++++++++++++---- src/services/messaging-service.ts | 123 +++++++++++++++---- 7 files changed, 341 insertions(+), 122 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..3b2b49e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,10 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "files.exclude": { + "**/.git": true, + "**/node_modules": true, + "**/.npm": true, + "**/*.js": { "when": "$(basename).ts" }, + "**/*.js.map": true + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index fae596f..dd1c4f4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "nativescript-preview-sdk", - "version": "0.3.4", + "version": "0.4.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -12,6 +12,12 @@ "axios": "*" } }, + "@types/node": { + "version": "10.12.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz", + "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==", + "dev": true + }, "@types/pubnub": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/pubnub/-/pubnub-4.0.2.tgz", @@ -31,9 +37,9 @@ } }, "agentkeepalive": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.1.tgz", - "integrity": "sha512-Cte/sTY9/XcygXjJ0q58v//SnEQ7ViWExKyJpLJlLqomDbQyMLh6Is4KuWJ/wmxzhiwkGRple7Gqv1zf6Syz5w==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", + "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", "requires": { "humanize-ms": "^1.2.1" } @@ -49,9 +55,9 @@ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" }, "ast-types": { - "version": "0.11.5", - "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.11.5.tgz", - "integrity": "sha512-oJjo+5e7/vEc2FBK8gUalV0pba4L3VdBIs2EKhOLHLcOd2FgQIVQN9xb0eZ9IjEWyAL7vq6fGJxOvVvdCHNyMw==" + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.11.7.tgz", + "integrity": "sha512-2mP3TwtkY/aTv5X3ZsMpNAbOnyoC/aMJwJSoaELPkHId0nSQgFcnU4dRW3isxiz7+zBexk0ym3WNVjMiQBnJSw==" }, "asynckit": { "version": "0.4.0", @@ -60,7 +66,7 @@ }, "axios": { "version": "0.18.0", - "resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz", "integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=", "requires": { "follow-redirects": "^1.3.0", @@ -103,7 +109,7 @@ }, "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "requires": { "ansi-styles": "^2.2.1", @@ -119,22 +125,22 @@ "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" }, "colors": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.2.tgz", - "integrity": "sha512-rhP0JSBGYvpcNQj4s5AdShMeE5ahMop96cTeDl/v9qQQm2fYClE2QXZRi8wLzc+GmXSxdIqqbOIAhyObEXDbfQ==" + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", + "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==" }, "combined-stream": { - "version": "1.0.6", - "resolved": "http://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", - "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", "requires": { "delayed-stream": "~1.0.0" } }, "commander": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.18.0.tgz", - "integrity": "sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ==" + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz", + "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==" }, "component-emitter": { "version": "1.2.1", @@ -157,9 +163,19 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "data-uri-to-buffer": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz", - "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.0.tgz", + "integrity": "sha512-YbKCNLPPP4inc0E5If4OaalBc7gpaM2MRv77Pv2VThVComLKfbGYtJcdDCViDyp1Wd4SebhHLz94vp91zbK6bw==", + "requires": { + "@types/node": "^8.0.7" + }, + "dependencies": { + "@types/node": { + "version": "8.10.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.39.tgz", + "integrity": "sha512-rE7fktr02J8ybFf6eysife+WF+L4sAHWzw09DgdCebEu+qDwMvv4zl6Bc+825ttGZP73kCKxa3dhJOoGJ8+5mA==" + } + } }, "debug": { "version": "3.1.0", @@ -244,6 +260,11 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, + "event-lite": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/event-lite/-/event-lite-0.1.2.tgz", + "integrity": "sha512-HnSYx1BsJ87/p6swwzv+2v6B4X+uxUteoDfRxsAb1S1BePzQqOLevVmkdA15GHJVd9A9Ok6wygUR18Hu0YeV9g==" + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -260,20 +281,20 @@ "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" }, "follow-redirects": { - "version": "1.5.8", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.8.tgz", - "integrity": "sha512-sy1mXPmv7kLAMKW/8XofG7o9T+6gAjzdZK4AJF6ryqQYUa/hnzgiypoeUecZ53x7XiqKNEpNqLtS97MshW2nxg==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.6.1.tgz", + "integrity": "sha512-t2JCjbzxQpWvbhts3l6SH1DKzSrx8a+SsaVf4h6bG4kOXUuPYS/kg2Lr4gQSb7eemaHqJkOThF1BGyjlUkO1GQ==", "requires": { "debug": "=3.1.0" } }, "form-data": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", - "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "requires": { "asynckit": "^0.4.0", - "combined-stream": "1.0.6", + "combined-stream": "^1.0.6", "mime-types": "^2.1.12" } }, @@ -303,7 +324,7 @@ }, "readable-stream": { "version": "1.1.14", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "requires": { "core-util-is": "~1.0.0", @@ -320,24 +341,39 @@ } }, "get-uri": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.2.tgz", - "integrity": "sha512-ZD325dMZOgerGqF/rF6vZXyFGTAay62svjQIT+X/oU2PtxYpFxvSkbsdi+oxIrsNxlZVd4y8wUDqkaExWTI/Cw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.3.tgz", + "integrity": "sha512-x5j6Ks7FOgLD/GlvjKwgu7wdmMR55iuRHhn8hj/+gA+eSbxQvZ+AEomq+3MgVEZj1vpi738QahGbCCSIDtXtkw==", "requires": { - "data-uri-to-buffer": "1", - "debug": "2", - "extend": "3", + "data-uri-to-buffer": "2", + "debug": "4", + "extend": "~3.0.2", "file-uri-to-path": "1", "ftp": "~0.3.10", - "readable-stream": "2" + "readable-stream": "3" }, "dependencies": { "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "readable-stream": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.1.1.tgz", + "integrity": "sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } } } @@ -365,7 +401,7 @@ }, "http-errors": { "version": "1.6.3", - "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", "requires": { "depd": "~1.1.2", @@ -408,6 +444,11 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ieee754": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.12.tgz", + "integrity": "sha512-GguP+DRY+pJ3soyIiGPTvdiVXjZ+DbXOxGpXn3eMvNW4x4irjqXm4wHKscC+TfxSJ0yw/S1F24tqdMNsMZTiLA==" + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -422,6 +463,11 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "int64-buffer": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/int64-buffer/-/int64-buffer-0.1.10.tgz", + "integrity": "sha1-J3siiofZWtd30HwTgyAiQGpHNCM=" + }, "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", @@ -437,6 +483,11 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, + "js-md5": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/js-md5/-/js-md5-0.7.3.tgz", + "integrity": "sha512-ZC41vPSTLKGwIRjqDh8DfXoCrdQIyBgspJVPXHBGu4nZlAEvG3nf+jO9avM9RmLiGakg7vz974ms99nEV0tmTQ==" + }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -457,9 +508,9 @@ "integrity": "sha1-+e3PI/AOQr9D8PhD2Y2LU/M0HxY=" }, "lru-cache": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", - "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "requires": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" @@ -476,16 +527,16 @@ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" }, "mime-db": { - "version": "1.36.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", - "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" + "version": "1.37.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", + "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==" }, "mime-types": { - "version": "2.1.20", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", - "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", + "version": "2.1.21", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", + "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", "requires": { - "mime-db": "~1.36.0" + "mime-db": "~1.37.0" } }, "minimatch": { @@ -501,10 +552,21 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "msgpack-lite": { + "version": "0.1.26", + "resolved": "https://registry.npmjs.org/msgpack-lite/-/msgpack-lite-0.1.26.tgz", + "integrity": "sha1-3TxQsm8FnyXn7e42REGDWOKprYk=", + "requires": { + "event-lite": "^0.1.1", + "ieee754": "^1.1.8", + "int64-buffer": "^0.1.9", + "isarray": "^1.0.0" + } + }, "nanoid": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-1.2.6.tgz", - "integrity": "sha512-um9vXiM407BaRbBNa0aKPzFBSD2fDbVmmA9TzCWWlxZvEBzTbixM7ss6GDS4G/cNMYeZSNFx5SzAgWoG1uHU9g==" + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-1.3.4.tgz", + "integrity": "sha512-4ug4BsuHxiVHoRUe1ud6rUFT3WUMmjXt1W0quL0CviZQANdan7D8kqN5/maw53hmAApY/jfzMRkC57BNNs60ZQ==" }, "netmask": { "version": "1.0.6", @@ -581,7 +643,7 @@ }, "proxy-agent": { "version": "2.3.1", - "resolved": "http://registry.npmjs.org/proxy-agent/-/proxy-agent-2.3.1.tgz", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-2.3.1.tgz", "integrity": "sha512-CNKuhC1jVtm8KJYFTS2ZRO71VCBx3QSA92So/e6NrY6GoJonkx3Irnk4047EsCcswczwqAekRj3s8qLRGahSKg==", "requires": { "agent-base": "^4.2.0", @@ -616,9 +678,9 @@ } }, "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.6.0.tgz", + "integrity": "sha512-KIJqT9jQJDQx5h5uAVPimw6yVg2SekOKu959OCtktD3FjzbpvaPr8i4zzg07DOMz+igA4W/aNM7OV8H37pFYfA==" }, "raw-body": { "version": "2.3.3", @@ -633,7 +695,7 @@ }, "readable-stream": { "version": "2.3.6", - "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -646,11 +708,11 @@ } }, "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", + "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", "requires": { - "path-parse": "^1.0.5" + "path-parse": "^1.0.6" } }, "safe-buffer": { @@ -664,9 +726,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "semver": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", - "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==" + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" }, "setprototypeof": { "version": "1.1.0", @@ -725,7 +787,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" @@ -750,7 +812,7 @@ }, "superagent-proxy": { "version": "1.0.3", - "resolved": "http://registry.npmjs.org/superagent-proxy/-/superagent-proxy-1.0.3.tgz", + "resolved": "https://registry.npmjs.org/superagent-proxy/-/superagent-proxy-1.0.3.tgz", "integrity": "sha512-79Ujg1lRL2ICfuHUdX+H2MjIw73kB7bXsIkxLwHURz3j0XUmEEEoJ+u/wq+mKwna21Uejsm2cGR3OESA00TIjA==", "requires": { "debug": "^3.1.0", diff --git a/package.json b/package.json index c6b4a14..f76593a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nativescript-preview-sdk", - "version": "0.3.4", + "version": "0.4.0", "description": "Handles the communication to the NativeScript Preview Apps", "main": "src/nativescript-preview-sdk", "typings": "src/nativescript-preview-sdk.d.ts", @@ -27,11 +27,14 @@ "@types/shortid": "0.0.29", "axios": "0.18.0", "btoa": "1.2.1", + "js-md5": "0.7.3", + "msgpack-lite": "0.1.26", "pubnub": "4.21.2", "shortid": "2.2.12", "tslint": "5.4.3" }, "devDependencies": { + "@types/node": "^10.12.18", "typescript": "3.0.3" }, "scripts": { diff --git a/src/models/file-payload.ts b/src/models/file-payload.ts index 8b8b4ba..5d696db 100644 --- a/src/models/file-payload.ts +++ b/src/models/file-payload.ts @@ -1,7 +1,9 @@ export class FilePayload { event: string; - file: string; - originalFile?: string; + file: string; + originalFile?: string; fileContents: string; binary?: boolean; + hash?: string; + hmrHash?: string; }; diff --git a/src/models/sdk-callbacks.ts b/src/models/sdk-callbacks.ts index fbce377..6b3f03b 100644 --- a/src/models/sdk-callbacks.ts +++ b/src/models/sdk-callbacks.ts @@ -4,5 +4,5 @@ import { ConnectedDevices } from "./connected-devices"; export class SdkCallbacks extends DeviceCallbacks { onLogSdkMessage: (log: string) => void; onConnectedDevicesChange: (connectedDevices: ConnectedDevices) => void; - onBiggerFilesUpload: (filesData: string, callback: (location: string, error: Error) => void) => void; + onBiggerFilesUpload: (filesData: Uint8Array, callback: (location: string, error: Error) => void) => void; } diff --git a/src/services/helpers-service.ts b/src/services/helpers-service.ts index 75e9c56..c031a7c 100644 --- a/src/services/helpers-service.ts +++ b/src/services/helpers-service.ts @@ -1,33 +1,34 @@ import * as shortId from "shortid"; import * as nodeBtoa from "btoa"; +import * as md5 from "js-md5"; declare function escape(s: string): string; declare function unescape(s: string): string; export class HelpersService { - private getHiddenProperty(): string { - var prefixes = ['webkit', 'moz', 'ms', 'o']; - if ('hidden' in document) { - return 'hidden'; - } - for (var i = 0; i < prefixes.length; i++) { - if ((prefixes[i] + 'Hidden') in document) - return prefixes[i] + 'Hidden'; - } - return null; - } + private getHiddenProperty(): string { + var prefixes = ['webkit', 'moz', 'ms', 'o']; + if ('hidden' in document) { + return 'hidden'; + } + for (var i = 0; i < prefixes.length; i++) { + if ((prefixes[i] + 'Hidden') in document) + return prefixes[i] + 'Hidden'; + } + return null; + } - isBrowserTabActive() { - if(!this.isBrowser()) { - // not in browser - return true; - } + isBrowserTabActive() { + if(!this.isBrowser()) { + // not in browser + return true; + } - var property = this.getHiddenProperty(); - if (!property) return true; + var property = this.getHiddenProperty(); + if (!property) return true; - return !document[property]; - } + return !document[property]; + } areCaseInsensitiveEqual(value1: string, value2: string): boolean { return (value1 || "").toLowerCase() == (value2 || "").toLowerCase(); @@ -35,18 +36,84 @@ export class HelpersService { shortId(): string { return shortId.generate(); - } + } - isBrowser(): boolean { - return (typeof window !== "undefined"); - } + isBrowser(): boolean { + return (typeof window !== "undefined"); + } base64Encode(input: string): string { if (this.isBrowser()) { return window.btoa(unescape(encodeURIComponent(input))) - } - else { + } else { return nodeBtoa(unescape(encodeURIComponent(input))); } } + + base64Decode(input: string): string { + if (this.isBrowser()) { + return decodeURIComponent(escape(window.atob(input))); + } else { + return decodeURIComponent(escape(Buffer.from(input, "base64").toString())); + } + } + + // https://github.com/google/closure-library/blob/8598d87242af59aac233270742c8984e2b2bdbe0/closure/goog/crypt/crypt.js#L117-L143 + stringToByteArray(str: string, base64Encoded: boolean = false): Uint8Array { + if (base64Encoded === true) { + var raw = this.isBrowser() ? window.atob(str) : Buffer.from(str, "base64").toString(); + var rawLength = raw.length; + var array = new Uint8Array(new ArrayBuffer(rawLength)); + for (var i = 0; i < rawLength; i++) { + array[i] = raw.charCodeAt(i); + } + return array; + } + + if ("TextEncoder" in window) { + return new TextEncoder().encode(str); + } + + var out = [], p = 0; + for (var i = 0; i < str.length; i++) { + var c = str.charCodeAt(i); + if (c < 128) { + out[p++] = c; + } else if (c < 2048) { + out[p++] = (c >> 6) | 192; + out[p++] = (c & 63) | 128; + } else if (((c & 0xFC00) == 0xD800) && (i + 1) < str.length && ((str.charCodeAt(i + 1) & 0xFC00) == 0xDC00)) { + // Surrogate Pair + c = 0x10000 + ((c & 0x03FF) << 10) + (str.charCodeAt(++i) & 0x03FF); + out[p++] = (c >> 18) | 240; + out[p++] = ((c >> 12) & 63) | 128; + out[p++] = ((c >> 6) & 63) | 128; + out[p++] = (c & 63) | 128; + } else { + out[p++] = (c >> 12) | 224; + out[p++] = ((c >> 6) & 63) | 128; + out[p++] = (c & 63) | 128; + } + } + + return new Uint8Array(out); + } + + concatenateArrays(...arrays: Uint8Array[]): Uint8Array { + let totalLength = 0; + for (let arr of arrays) { + totalLength += arr.length; + } + let result = new Uint8Array(totalLength); + let offset = 0; + for (let arr of arrays) { + result.set(arr, offset); + offset += arr.length; + } + return result; + } + + calculateMD5(str: string|Uint8Array): string { + return md5(str); + } } \ No newline at end of file diff --git a/src/services/messaging-service.ts b/src/services/messaging-service.ts index 25c7607..1cfac0e 100644 --- a/src/services/messaging-service.ts +++ b/src/services/messaging-service.ts @@ -1,3 +1,6 @@ +import * as PubNub from "pubnub"; +import * as msgpack from "msgpack-lite"; + import { HelpersService } from "./helpers-service"; import { DevicesService } from "./devices-service"; import { Config } from "../models/config"; @@ -9,13 +12,18 @@ import { HereNowResponse } from "../models/here-now-response"; import { DevicePlatform } from "../models/device-platform"; import { FilePayload } from "../models/file-payload"; import { FilesPayload } from "../models/files-payload"; -import * as PubNub from "pubnub"; import { SdkCallbacks } from "../models/sdk-callbacks"; import { SendFilesStatus } from "../models/send-files-status"; import { PreviewAppVersionsService } from "./preview-app-versions-service"; import { AppContentManager } from "./app-content-manager"; export class MessagingService { + // NOTE: The current LARGE_SESSIONS_PROTOCOL implementation is suitable for the Playground because there's a limitation + // on the maximum size of a given session. To take full advantage of the MessagePack streaming mechanism we should + // provide an alternative implementation for the CLI which works directly with file streams and avoid loading their serialized + // content in-memory. We need to revisit the "sendFilesInChunks" method which currently works with the FilesPayload parameter. + public static LARGE_SESSIONS_PROTOCOL = "msg-pack"; + private static HMR_HASH_PATTERN = new RegExp("var\\s+hotCurrentHash\\s+=\\s*\\\"([^\"]*)\\\";", "g"); private static PubNubInitialized = false; private pubNub: PubNub; @@ -37,7 +45,7 @@ export class MessagingService { this.connectedDevicesTimeouts = {}; } - public async initialize(config: Config): Promise { + public async initialize(config: Config, largeFilesProtocol: string): Promise { this.config = config; this.ensureValidConfig(); @@ -60,7 +68,7 @@ export class MessagingService { }, message: (data: any) => { if (data.message.type == "send files") { - this.handleSendInitialFiles(data, this.config.instanceId, 0); + this.handleSendInitialFiles(data, this.config.instanceId, 0, largeFilesProtocol); } else if (data.message.type == "restart app") { this.config.callbacks.onLogSdkMessage(`${this.config.instanceId} message received: restart app`); this.config.callbacks.onRestartMessage(); @@ -123,8 +131,8 @@ export class MessagingService { } } - public applyChanges(instanceId: string, filesPayload: FilesPayload, done: (err: Error) => void): void { - this.sendFilesInChunks(this.getDevicesChannel(instanceId), "files chunk", filesPayload, filesPayload.deviceId) + public applyChanges(instanceId: string, filesPayload: FilesPayload, largeFilesProtocol: string, done: (err: Error) => void): void { + this.sendFilesInChunks(this.getDevicesChannel(instanceId), "files chunk", filesPayload, largeFilesProtocol, filesPayload.deviceId) .then(() => done(null)) .catch(e => done(e)); } @@ -172,8 +180,8 @@ export class MessagingService { } } - sendInitialFiles(instanceId: string, hmrMode?: number) { - this.handleSendInitialFiles({}, instanceId, 0, true, hmrMode); + sendInitialFiles(instanceId: string, largeFilesProtocol: string, hmrMode?: number) { + this.handleSendInitialFiles({}, instanceId, 0, largeFilesProtocol, true, hmrMode); } getConnectedDevices(instanceId: string): Promise { @@ -240,12 +248,12 @@ export class MessagingService { }); } - private sendFilesInChunks(channel: string, messageType: string, filesPayload: FilesPayload, deviceIdMeta?: string): Promise { + private sendFilesInChunks(channel: string, messageType: string, filesPayload: FilesPayload, protocol: string, deviceIdMeta?: string): Promise { let finalFilesPayload = this.getFinalFilesPayload(filesPayload); let chunks = this.getChunks(finalFilesPayload); this.config.callbacks.onSendingChange(true); return new Promise((resolve, reject) => { - this.getPublishPromise(channel, messageType, chunks, deviceIdMeta, filesPayload.platform, filesPayload.hmrMode) + this.getPublishPromise(channel, messageType, chunks, deviceIdMeta, filesPayload.platform, protocol, filesPayload.hmrMode) .then(() => { this.config.callbacks.onSendingChange(false); resolve({ error: false }); @@ -270,7 +278,7 @@ export class MessagingService { return finalFiles; } - private getPublishPromise(channel: string, messageType: string, chunks: FileChunk[], deviceIdMeta: string, platform: string, hmrMode?: number): Promise { + private getPublishPromise(channel: string, messageType: string, chunks: FileChunk[], deviceIdMeta: string, platform: string, protocol: string, hmrMode?: number): Promise { return new Promise((resolve, reject) => { if (!chunks.length) { return resolve(); @@ -297,23 +305,64 @@ export class MessagingService { } }); } else { - let data = chunks.map(chunk => chunk.data); - this.pubNub.publish({ message: { "type": "large session" }, channel: channel, meta: meta }); - this.config.callbacks.onBiggerFilesUpload(data.join(""), (uploadedFilesLocation, error) => { + let data = chunks.map(chunk => chunk.data).join(""); + + let requestBody: Uint8Array; + if (protocol === MessagingService.LARGE_SESSIONS_PROTOCOL) { + let decoded = this.helpersService.base64Decode(data); + let parts: FilePayload[] = JSON.parse(decoded); + + let options = { codec: msgpack.createCodec({ binarraybuffer: true }) }; + let header = parts.map(part => { + let result = { + file: part.file, + event: part.event, + binary: part.binary, + hash: part.binary === true + ? this.helpersService.calculateMD5(this.helpersService.stringToByteArray(part.fileContents, true)) + : this.helpersService.calculateMD5(part.fileContents) + }; + + let hmrHash = this.getHMRHash(part); + if (hmrHash) { + result["hmrHash"] = hmrHash; + } + + return result; + }); + let encodedHeader = msgpack.encode(header, options); + + let payloads = parts + .filter(part => part.event == "change" || part.event == "add") + .map(part => this.helpersService.stringToByteArray(part.fileContents, part.binary).buffer); + let encodedPayloads = payloads.map(payload => msgpack.encode(payload, options)); + + requestBody = this.helpersService.concatenateArrays(encodedHeader, ...encodedPayloads); + } else { + requestBody = this.helpersService.stringToByteArray(data); + } + + this.config.callbacks.onBiggerFilesUpload(requestBody, (uploadedFilesLocation, error) => { if (error) { reject(error); } else { + let message = { + "type": messageType, + "remoteDataUrl": uploadedFilesLocation, + }; + + if (typeof protocol !== "undefined") { + message["protocol"] = protocol; + } + this.pubNub.publish({ - message: { - "type": messageType, - "remoteDataUrl": uploadedFilesLocation - }, + message: message, channel: channel, meta: meta }, (status) => { @@ -369,7 +418,7 @@ export class MessagingService { return chunks; } - private async handleSendInitialFiles(data: any, instanceId: string, retries: number, skipDeviceCheck: boolean = false, hmrMode?: number): Promise { + private async handleSendInitialFiles(data: any, instanceId: string, retries: number, protocol: string, skipDeviceCheck: boolean = false, hmrMode?: number): Promise { let device: Device = null; if (retries > 10) { this.config.callbacks.onLogSdkMessage(`${instanceId} Exception: didn't receive device connected message after ${retries} retries`); @@ -381,7 +430,7 @@ export class MessagingService { if (!skipDeviceCheck) { let deviceConnectedMessage = this.config.connectedDevices[data.publisher]; if (!deviceConnectedMessage) { - setTimeout(() => this.handleSendInitialFiles(data, instanceId, ++retries, false, hmrMode), 1000); + setTimeout(() => this.handleSendInitialFiles(data, instanceId, ++retries, protocol, false, hmrMode), 1000); return; } @@ -390,14 +439,27 @@ export class MessagingService { const minimumSupportedVersion = isAndroid ? this.minSupportedVersions.android : this.minSupportedVersions.ios; const showDeprecatedPage = !deviceConnectedMessage.version || !deviceConnectedMessage.platform || deviceConnectedMessage.version < minimumSupportedVersion; if (showDeprecatedPage) { +<<<<<<< HEAD const payloads = this.appContentManager.getDeprecatedAppPayloads(this.config.previewAppStoreId, this.config.previewAppGooglePlayId); await this.showPage(devicesChannel, device, payloads, { hmrMode, publisher: data.publisher }); +======= + const payloads = this.appContentManager.getDeprecatedAppPayloads(); + await this.showPage(devicesChannel, device, payloads, protocol, { hmrMode, publisher: data.publisher }); +>>>>>>> Use MessagePack to encode large sessions return; } this.config.callbacks.onLogSdkMessage(`${instanceId} message received: send files`); } +<<<<<<< HEAD +======= + if (this.config.showLoadingPage) { + const payloads = this.appContentManager.getLoadingAppPayloads(); + await this.showPage(devicesChannel, device, payloads, protocol, { hmrMode, publisher: data.publisher }); + } + +>>>>>>> Use MessagePack to encode large sessions const initialPayload = await this.config.getInitialFiles(device); if (initialPayload && initialPayload.files && initialPayload.files.length) { if (!initialPayload.deviceId && device) { @@ -407,12 +469,12 @@ export class MessagingService { if (initialPayload.hmrMode === undefined || initialPayload.hmrMode === null) { initialPayload.hmrMode = hmrMode; } - await this.sendFilesInChunks(devicesChannel, Constants.InitialSyncMessageType, initialPayload, initialPayload.deviceId); + await this.sendFilesInChunks(devicesChannel, Constants.InitialSyncMessageType, initialPayload, protocol, initialPayload.deviceId); } } private getConnectedDevicesDelayed(presenceEvent: any, delay: number, retryCount: number): void { - this.connectedDevicesTimeouts[presenceEvent.uuid] = setTimeout(() => { + this.connectedDevicesTimeouts[presenceEvent.uuid] = setTimeout((() => { if (!this.helpersService.isBrowserTabActive()) { //Page not visible, retrying in 2 seconds return this.getConnectedDevicesDelayed(presenceEvent, 2000, retryCount); @@ -430,17 +492,17 @@ export class MessagingService { this.getConnectedDevicesDelayed(presenceEvent, 1000 * (retryCount + 1), ++retryCount); } }); - }, delay); + }), delay); } - private async showPage(devicesChannel: string, device: Device, files: FilePayload[], opts: { hmrMode: number, publisher: string }): Promise { + private async showPage(devicesChannel: string, device: Device, files: FilePayload[], protocol: string, opts: { hmrMode: number, publisher: string }): Promise { const payload = { files, hmrMode: opts.hmrMode, platform: device.platform, deviceId: device.id }; - await this.sendFilesInChunks(devicesChannel, Constants.InitialSyncMessageType, payload, opts.publisher); + await this.sendFilesInChunks(devicesChannel, Constants.InitialSyncMessageType, payload, protocol, opts.publisher); } private getDevicesChannel(instanceId: string): string { @@ -450,4 +512,17 @@ export class MessagingService { private getBrowserChannel(instanceId: string): string { return `b-ch-${instanceId}`; } + + private getHMRHash(part: FilePayload): string { + if (!part || !part.fileContents || !part.file || !part.file.toLowerCase().endsWith("bundle.js")) { + return null; + } + + let matches = MessagingService.HMR_HASH_PATTERN.exec(part.fileContents); + if (!matches || matches.length < 2) { + return null; + } + + return matches[1]; + } }