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

index.js 9.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.Decoder = exports.Encoder = exports.PacketType = exports.protocol = void 0;
  4. const component_emitter_1 = require("@socket.io/component-emitter");
  5. const binary_js_1 = require("./binary.js");
  6. const is_binary_js_1 = require("./is-binary.js");
  7. const debug_1 = require("debug"); // debug()
  8. const debug = debug_1.default("socket.io-parser"); // debug()
  9. /**
  10. * Protocol version.
  11. *
  12. * @public
  13. */
  14. exports.protocol = 5;
  15. var PacketType;
  16. (function (PacketType) {
  17. PacketType[PacketType["CONNECT"] = 0] = "CONNECT";
  18. PacketType[PacketType["DISCONNECT"] = 1] = "DISCONNECT";
  19. PacketType[PacketType["EVENT"] = 2] = "EVENT";
  20. PacketType[PacketType["ACK"] = 3] = "ACK";
  21. PacketType[PacketType["CONNECT_ERROR"] = 4] = "CONNECT_ERROR";
  22. PacketType[PacketType["BINARY_EVENT"] = 5] = "BINARY_EVENT";
  23. PacketType[PacketType["BINARY_ACK"] = 6] = "BINARY_ACK";
  24. })(PacketType = exports.PacketType || (exports.PacketType = {}));
  25. /**
  26. * A socket.io Encoder instance
  27. */
  28. class Encoder {
  29. /**
  30. * Encoder constructor
  31. *
  32. * @param {function} replacer - custom replacer to pass down to JSON.parse
  33. */
  34. constructor(replacer) {
  35. this.replacer = replacer;
  36. }
  37. /**
  38. * Encode a packet as a single string if non-binary, or as a
  39. * buffer sequence, depending on packet type.
  40. *
  41. * @param {Object} obj - packet object
  42. */
  43. encode(obj) {
  44. debug("encoding packet %j", obj);
  45. if (obj.type === PacketType.EVENT || obj.type === PacketType.ACK) {
  46. if (is_binary_js_1.hasBinary(obj)) {
  47. obj.type =
  48. obj.type === PacketType.EVENT
  49. ? PacketType.BINARY_EVENT
  50. : PacketType.BINARY_ACK;
  51. return this.encodeAsBinary(obj);
  52. }
  53. }
  54. return [this.encodeAsString(obj)];
  55. }
  56. /**
  57. * Encode packet as string.
  58. */
  59. encodeAsString(obj) {
  60. // first is type
  61. let str = "" + obj.type;
  62. // attachments if we have them
  63. if (obj.type === PacketType.BINARY_EVENT ||
  64. obj.type === PacketType.BINARY_ACK) {
  65. str += obj.attachments + "-";
  66. }
  67. // if we have a namespace other than `/`
  68. // we append it followed by a comma `,`
  69. if (obj.nsp && "/" !== obj.nsp) {
  70. str += obj.nsp + ",";
  71. }
  72. // immediately followed by the id
  73. if (null != obj.id) {
  74. str += obj.id;
  75. }
  76. // json data
  77. if (null != obj.data) {
  78. str += JSON.stringify(obj.data, this.replacer);
  79. }
  80. debug("encoded %j as %s", obj, str);
  81. return str;
  82. }
  83. /**
  84. * Encode packet as 'buffer sequence' by removing blobs, and
  85. * deconstructing packet into object with placeholders and
  86. * a list of buffers.
  87. */
  88. encodeAsBinary(obj) {
  89. const deconstruction = binary_js_1.deconstructPacket(obj);
  90. const pack = this.encodeAsString(deconstruction.packet);
  91. const buffers = deconstruction.buffers;
  92. buffers.unshift(pack); // add packet info to beginning of data list
  93. return buffers; // write all the buffers
  94. }
  95. }
  96. exports.Encoder = Encoder;
  97. /**
  98. * A socket.io Decoder instance
  99. *
  100. * @return {Object} decoder
  101. */
  102. class Decoder extends component_emitter_1.Emitter {
  103. /**
  104. * Decoder constructor
  105. *
  106. * @param {function} reviver - custom reviver to pass down to JSON.stringify
  107. */
  108. constructor(reviver) {
  109. super();
  110. this.reviver = reviver;
  111. }
  112. /**
  113. * Decodes an encoded packet string into packet JSON.
  114. *
  115. * @param {String} obj - encoded packet
  116. */
  117. add(obj) {
  118. let packet;
  119. if (typeof obj === "string") {
  120. if (this.reconstructor) {
  121. throw new Error("got plaintext data when reconstructing a packet");
  122. }
  123. packet = this.decodeString(obj);
  124. if (packet.type === PacketType.BINARY_EVENT ||
  125. packet.type === PacketType.BINARY_ACK) {
  126. // binary packet's json
  127. this.reconstructor = new BinaryReconstructor(packet);
  128. // no attachments, labeled binary but no binary data to follow
  129. if (packet.attachments === 0) {
  130. super.emitReserved("decoded", packet);
  131. }
  132. }
  133. else {
  134. // non-binary full packet
  135. super.emitReserved("decoded", packet);
  136. }
  137. }
  138. else if (is_binary_js_1.isBinary(obj) || obj.base64) {
  139. // raw binary data
  140. if (!this.reconstructor) {
  141. throw new Error("got binary data when not reconstructing a packet");
  142. }
  143. else {
  144. packet = this.reconstructor.takeBinaryData(obj);
  145. if (packet) {
  146. // received final buffer
  147. this.reconstructor = null;
  148. super.emitReserved("decoded", packet);
  149. }
  150. }
  151. }
  152. else {
  153. throw new Error("Unknown type: " + obj);
  154. }
  155. }
  156. /**
  157. * Decode a packet String (JSON data)
  158. *
  159. * @param {String} str
  160. * @return {Object} packet
  161. */
  162. decodeString(str) {
  163. let i = 0;
  164. // look up type
  165. const p = {
  166. type: Number(str.charAt(0)),
  167. };
  168. if (PacketType[p.type] === undefined) {
  169. throw new Error("unknown packet type " + p.type);
  170. }
  171. // look up attachments if type binary
  172. if (p.type === PacketType.BINARY_EVENT ||
  173. p.type === PacketType.BINARY_ACK) {
  174. const start = i + 1;
  175. while (str.charAt(++i) !== "-" && i != str.length) { }
  176. const buf = str.substring(start, i);
  177. if (buf != Number(buf) || str.charAt(i) !== "-") {
  178. throw new Error("Illegal attachments");
  179. }
  180. p.attachments = Number(buf);
  181. }
  182. // look up namespace (if any)
  183. if ("/" === str.charAt(i + 1)) {
  184. const start = i + 1;
  185. while (++i) {
  186. const c = str.charAt(i);
  187. if ("," === c)
  188. break;
  189. if (i === str.length)
  190. break;
  191. }
  192. p.nsp = str.substring(start, i);
  193. }
  194. else {
  195. p.nsp = "/";
  196. }
  197. // look up id
  198. const next = str.charAt(i + 1);
  199. if ("" !== next && Number(next) == next) {
  200. const start = i + 1;
  201. while (++i) {
  202. const c = str.charAt(i);
  203. if (null == c || Number(c) != c) {
  204. --i;
  205. break;
  206. }
  207. if (i === str.length)
  208. break;
  209. }
  210. p.id = Number(str.substring(start, i + 1));
  211. }
  212. // look up json data
  213. if (str.charAt(++i)) {
  214. const payload = this.tryParse(str.substr(i));
  215. if (Decoder.isPayloadValid(p.type, payload)) {
  216. p.data = payload;
  217. }
  218. else {
  219. throw new Error("invalid payload");
  220. }
  221. }
  222. debug("decoded %s as %j", str, p);
  223. return p;
  224. }
  225. tryParse(str) {
  226. try {
  227. return JSON.parse(str, this.reviver);
  228. }
  229. catch (e) {
  230. return false;
  231. }
  232. }
  233. static isPayloadValid(type, payload) {
  234. switch (type) {
  235. case PacketType.CONNECT:
  236. return typeof payload === "object";
  237. case PacketType.DISCONNECT:
  238. return payload === undefined;
  239. case PacketType.CONNECT_ERROR:
  240. return typeof payload === "string" || typeof payload === "object";
  241. case PacketType.EVENT:
  242. case PacketType.BINARY_EVENT:
  243. return Array.isArray(payload) && payload.length > 0;
  244. case PacketType.ACK:
  245. case PacketType.BINARY_ACK:
  246. return Array.isArray(payload);
  247. }
  248. }
  249. /**
  250. * Deallocates a parser's resources
  251. */
  252. destroy() {
  253. if (this.reconstructor) {
  254. this.reconstructor.finishedReconstruction();
  255. }
  256. }
  257. }
  258. exports.Decoder = Decoder;
  259. /**
  260. * A manager of a binary event's 'buffer sequence'. Should
  261. * be constructed whenever a packet of type BINARY_EVENT is
  262. * decoded.
  263. *
  264. * @param {Object} packet
  265. * @return {BinaryReconstructor} initialized reconstructor
  266. */
  267. class BinaryReconstructor {
  268. constructor(packet) {
  269. this.packet = packet;
  270. this.buffers = [];
  271. this.reconPack = packet;
  272. }
  273. /**
  274. * Method to be called when binary data received from connection
  275. * after a BINARY_EVENT packet.
  276. *
  277. * @param {Buffer | ArrayBuffer} binData - the raw binary data received
  278. * @return {null | Object} returns null if more binary data is expected or
  279. * a reconstructed packet object if all buffers have been received.
  280. */
  281. takeBinaryData(binData) {
  282. this.buffers.push(binData);
  283. if (this.buffers.length === this.reconPack.attachments) {
  284. // done with buffer list
  285. const packet = binary_js_1.reconstructPacket(this.reconPack, this.buffers);
  286. this.finishedReconstruction();
  287. return packet;
  288. }
  289. return null;
  290. }
  291. /**
  292. * Cleans up binary packet reconstruction variables.
  293. */
  294. finishedReconstruction() {
  295. this.reconPack = null;
  296. this.buffers = [];
  297. }
  298. }