mirror of
https://github.com/socketio/socket.io.git
synced 2026-04-30 03:00:39 -04:00
Compare commits
72 Commits
socket.io-
...
socket.io-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
164ba2a11e | ||
|
|
b0e6400c93 | ||
|
|
d9db4737a3 | ||
|
|
6a5a004d1e | ||
|
|
b6c824f824 | ||
|
|
dcc70d9678 | ||
|
|
3b78117bf6 | ||
|
|
0841bd5623 | ||
|
|
28dd668502 | ||
|
|
22c42e3545 | ||
|
|
ae8dd88995 | ||
|
|
9143aa4c8e | ||
|
|
194a9b762e | ||
|
|
a9758da4be | ||
|
|
f0af8834f8 | ||
|
|
5a2ccff9d1 | ||
|
|
b5d0cb7dc5 | ||
|
|
c7514b5aa6 | ||
|
|
931f1526a4 | ||
|
|
6c9cb27aeb | ||
|
|
b08bc1a93e | ||
|
|
aed252c742 | ||
|
|
89209fa22a | ||
|
|
0a3b556de3 | ||
|
|
7f6b262ac8 | ||
|
|
8e8346b706 | ||
|
|
ea86f413ed | ||
|
|
eb708d1936 | ||
|
|
5ad3e5cc4b | ||
|
|
388c616a92 | ||
|
|
75530b4dcd | ||
|
|
57324f3048 | ||
|
|
af1b23ca85 | ||
|
|
1c220ddbf4 | ||
|
|
444520d6cd | ||
|
|
b076dbb722 | ||
|
|
7c380d38eb | ||
|
|
f2098b031d | ||
|
|
66973a340c | ||
|
|
4efa005846 | ||
|
|
c04443375f | ||
|
|
e339323654 | ||
|
|
412769fd18 | ||
|
|
db1d27432d | ||
|
|
e3d272f542 | ||
|
|
64b6648236 | ||
|
|
58b3d09f1c | ||
|
|
285e7cd0d8 | ||
|
|
7fc3c42234 | ||
|
|
78f9fc2999 | ||
|
|
9eb8561cbc | ||
|
|
091d25edf1 | ||
|
|
ccadd5a462 | ||
|
|
c04d7f5c47 | ||
|
|
9e601c6940 | ||
|
|
cfdc4794f6 | ||
|
|
28d4f0309b | ||
|
|
fe33ff7c87 | ||
|
|
00e73598a0 | ||
|
|
dd7cd60ba2 | ||
|
|
aeae87c220 | ||
|
|
567c0ca965 | ||
|
|
c327acbc3c | ||
|
|
b23576a73e | ||
|
|
ea41f225ee | ||
|
|
6a59237ed0 | ||
|
|
a8130ce3a9 | ||
|
|
dcb942d24d | ||
|
|
a5d04354e6 | ||
|
|
652402a856 | ||
|
|
9b3572ea23 | ||
|
|
de1fd36dc9 |
56
.github/workflows/ci.yml
vendored
Normal file
56
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test-node:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [14, 16]
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Run tests
|
||||
run: npm test
|
||||
|
||||
test-browser:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Use Node.js 16
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- run: npm test
|
||||
env:
|
||||
BROWSERS: 1
|
||||
SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
|
||||
SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,3 +1,3 @@
|
||||
node_modules
|
||||
build
|
||||
components
|
||||
dist/
|
||||
build/
|
||||
|
||||
22
.travis.yml
22
.travis.yml
@@ -1,22 +0,0 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
node_js:
|
||||
- '8'
|
||||
- '10'
|
||||
git:
|
||||
depth: 1
|
||||
matrix:
|
||||
include:
|
||||
- node_js: node
|
||||
env: BROWSERS=1
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
env:
|
||||
global:
|
||||
- secure: >-
|
||||
Ea4P/R9UlWzDlHSP5ynmLiD/YgLjecIvCviOcRTle9mV3P1j2k94Ay1LVu1Jw4whlNmWLq2Z/p8M63L92ODPMlarPsuME8HlP4zGr41whFhRbFdda4k3zrHfUhZBlnhY1MVWXTtVm/l7DOzpBrNh+wKecxZB3yyyEaA+PSG3qcQ=
|
||||
- secure: >-
|
||||
JmPf38qx5Rb6K+WYOMwb5YmESkDmVJ6tgggiJIuyRfHsgQVOO7XBwZuspIKGTSFolUIMaqwQe79Kd+Ehs2ZZ/0lUyF2/6xW3FqFnASUusYJcZdfRjypmBFWs6BRdtEORM8HL0dgBx4O4u/e4ZvtygumbPahjQbMDaqN+MvlpjD0=
|
||||
- secure: >-
|
||||
c3pnLhy3VDJqMl16ABA+8vt3I623aNa2wkLceLXb2V1Dc6eiZeulDH2ekwmdVo/r2WwGIKP3Y6B0mq/xP4W0hg4uT+xWh0AmFHclVyM/yp/AqfXrDUv17Vm0vB7OIgp332OiAlK6Dr13YDbWW8iZxmID41O2+2qohLGPn5JMncg=
|
||||
258
CHANGELOG.md
Normal file
258
CHANGELOG.md
Normal file
@@ -0,0 +1,258 @@
|
||||
# History
|
||||
|
||||
## 2023
|
||||
|
||||
- [4.2.4](#424-2023-05-31) (May 2023)
|
||||
- [3.4.3](#343-2023-05-22) (May 2023) (from the [3.4.x](https://github.com/socketio/socket.io-parser/tree/3.4.x) branch)
|
||||
- [4.2.3](#423-2023-05-22) (May 2023)
|
||||
- [4.2.2](#422-2023-01-19) (Jan 2023)
|
||||
|
||||
## 2022
|
||||
|
||||
- [3.3.3](#333-2022-11-09) (Nov 2022) (from the [3.3.x](https://github.com/socketio/socket.io-parser/tree/3.3.x) branch)
|
||||
- [3.4.2](#342-2022-11-09) (Nov 2022) (from the [3.4.x](https://github.com/socketio/socket.io-parser/tree/3.4.x) branch)
|
||||
- [4.0.5](#405-2022-06-27) (Jun 2022) (from the [4.0.x](https://github.com/socketio/socket.io-parser/tree/4.0.x) branch)
|
||||
- [4.2.1](#421-2022-06-27) (Jun 2022)
|
||||
- [4.2.0](#420-2022-04-17) (Apr 2022)
|
||||
- [4.1.2](#412-2022-02-17) (Feb 2022)
|
||||
|
||||
## 2021
|
||||
|
||||
- [4.1.1](#411-2021-10-14) (Oct 2021)
|
||||
- [4.1.0](#410-2021-10-11) (Oct 2021)
|
||||
- [4.0.4](#404-2021-01-15) (Jan 2021)
|
||||
- [3.3.2](#332-2021-01-09) (Jan 2021) (from the [3.3.x](https://github.com/socketio/socket.io-parser/tree/3.3.x) branch)
|
||||
- [4.0.3](#403-2021-01-05) (Jan 2021)
|
||||
|
||||
## 2020
|
||||
|
||||
- [4.0.2](#402-2020-11-25) (Nov 2020)
|
||||
- [4.0.1](#401-2020-11-05) (Nov 2020)
|
||||
- [3.3.1](#331-2020-09-30) (Sep 2020) (from the [3.3.x](https://github.com/socketio/socket.io-parser/tree/3.3.x) branch)
|
||||
- [**4.0.0**](#400-2020-09-28) (Sep 2020)
|
||||
- [3.4.1](#341-2020-05-13) (May 2020)
|
||||
|
||||
## 2019
|
||||
|
||||
- [3.4.0](#340-2019-09-20) (Sep 2019)
|
||||
|
||||
## 2018
|
||||
|
||||
- [3.3.0](#330-2018-11-07) (Nov 2018)
|
||||
|
||||
|
||||
|
||||
# Release notes
|
||||
|
||||
## [4.2.4](https://github.com/socketio/socket.io-parser/compare/4.2.3...4.2.4) (2023-05-31)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* ensure reserved events cannot be used as event names ([d9db473](https://github.com/socketio/socket.io-parser/commit/d9db4737a3c8ce5f1f49ecc8d928a74f3da591f7))
|
||||
* properly detect plain objects ([b0e6400](https://github.com/socketio/socket.io-parser/commit/b0e6400c93b5c4aa25e6a629d6448b8627275213))
|
||||
|
||||
|
||||
|
||||
## [3.4.3](https://github.com/socketio/socket.io-parser/compare/3.4.2...3.4.3) (2023-05-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* check the format of the event name ([2dc3c92](https://github.com/socketio/socket.io-parser/commit/2dc3c92622dad113b8676be06f23b1ed46b02ced))
|
||||
|
||||
|
||||
|
||||
## [4.2.3](https://github.com/socketio/socket.io-parser/compare/4.2.2...4.2.3) (2023-05-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* check the format of the event name ([3b78117](https://github.com/socketio/socket.io-parser/commit/3b78117bf6ba7e99d7a5cfc1ba54d0477554a7f3))
|
||||
|
||||
|
||||
|
||||
## [4.2.2](https://github.com/socketio/socket.io-parser/compare/4.2.1...4.2.2) (2023-01-19)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* calling destroy() should clear all internal state ([22c42e3](https://github.com/socketio/socket.io-parser/commit/22c42e3545e4adbc5931276c378f5d62c8b3854a))
|
||||
* do not modify the input packet upon encoding ([ae8dd88](https://github.com/socketio/socket.io-parser/commit/ae8dd88995dbd7f89c97e5cc15e5b489fa0efece))
|
||||
|
||||
|
||||
|
||||
## [3.3.3](https://github.com/Automattic/socket.io-parser/compare/3.3.2...3.3.3) (2022-11-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* check the format of the index of each attachment ([fb21e42](https://github.com/Automattic/socket.io-parser/commit/fb21e422fc193b34347395a33e0f625bebc09983))
|
||||
|
||||
|
||||
|
||||
## [3.4.2](https://github.com/socketio/socket.io-parser/compare/3.4.1...3.4.2) (2022-11-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* check the format of the index of each attachment ([04d23ce](https://github.com/socketio/socket.io-parser/commit/04d23cecafe1b859fb03e0cbf6ba3b74dff56d14))
|
||||
|
||||
|
||||
|
||||
## [4.2.1](https://github.com/socketio/socket.io-parser/compare/4.2.0...4.2.1) (2022-06-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* check the format of the index of each attachment ([b5d0cb7](https://github.com/socketio/socket.io-parser/commit/b5d0cb7dc56a0601a09b056beaeeb0e43b160050))
|
||||
|
||||
|
||||
|
||||
## [4.0.5](https://github.com/socketio/socket.io-parser/compare/4.0.4...4.0.5) (2022-06-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* check the format of the index of each attachment ([b559f05](https://github.com/socketio/socket.io-parser/commit/b559f050ee02bd90bd853b9823f8de7fa94a80d4))
|
||||
|
||||
|
||||
|
||||
## [4.2.0](https://github.com/socketio/socket.io-parser/compare/4.1.2...4.2.0) (2022-04-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* allow the usage of custom replacer and reviver ([#112](https://github.com/socketio/socket.io-parser/issues/112)) ([b08bc1a](https://github.com/socketio/socket.io-parser/commit/b08bc1a93e8e3194b776c8a0bdedee1e29333680))
|
||||
|
||||
|
||||
|
||||
## [4.1.2](https://github.com/socketio/socket.io-parser/compare/4.1.1...4.1.2) (2022-02-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* allow objects with a null prototype in binary packets ([#114](https://github.com/socketio/socket.io-parser/issues/114)) ([7f6b262](https://github.com/socketio/socket.io-parser/commit/7f6b262ac83bdf43c53a7eb02417e56e0cf491c8))
|
||||
|
||||
|
||||
|
||||
## [4.1.1](https://github.com/socketio/socket.io-parser/compare/4.1.0...4.1.1) (2021-10-14)
|
||||
|
||||
|
||||
## [4.1.0](https://github.com/socketio/socket.io-parser/compare/4.0.4...4.1.0) (2021-10-11)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* provide an ESM build with and without debug ([388c616](https://github.com/socketio/socket.io-parser/commit/388c616a9221e4341945f8487e729e93a81d2da5))
|
||||
|
||||
|
||||
## [4.0.4](https://github.com/socketio/socket.io-parser/compare/4.0.3...4.0.4) (2021-01-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* allow integers as event names ([1c220dd](https://github.com/socketio/socket.io-parser/commit/1c220ddbf45ea4b44bc8dbf6f9ae245f672ba1b9))
|
||||
|
||||
|
||||
|
||||
## [3.3.2](https://github.com/Automattic/socket.io-parser/compare/3.3.1...3.3.2) (2021-01-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* prevent DoS (OOM) via massive packets ([#95](https://github.com/Automattic/socket.io-parser/issues/95)) ([89197a0](https://github.com/Automattic/socket.io-parser/commit/89197a05c43b18cc4569fd178d56e7bb8f403865))
|
||||
|
||||
|
||||
|
||||
## [4.0.3](https://github.com/socketio/socket.io-parser/compare/4.0.2...4.0.3) (2021-01-05)
|
||||
|
||||
|
||||
## [4.0.2](https://github.com/socketio/socket.io-parser/compare/4.0.1...4.0.2) (2020-11-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* move @types/component-emitter to dependencies ([#99](https://github.com/socketio/socket.io-parser/issues/99)) ([4efa005](https://github.com/socketio/socket.io-parser/commit/4efa005846ae15ecc7fb0a7f27141439113b1179))
|
||||
|
||||
|
||||
## [4.0.1](https://github.com/socketio/socket.io-parser/compare/3.4.1...4.0.1) (2020-11-05)
|
||||
|
||||
### Features
|
||||
|
||||
* move binary detection back to the parser ([285e7cd](https://github.com/socketio/socket.io-parser/commit/285e7cd0d837adfc911c999e7294788681226ae1))
|
||||
* add support for a payload in a CONNECT packet ([78f9fc2](https://github.com/socketio/socket.io-parser/commit/78f9fc2999b15804b02f2c22a2b4007734a26af9))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* do not catch encoding errors ([aeae87c](https://github.com/socketio/socket.io-parser/commit/aeae87c220287197cb78370dbd86b950a7dd29eb))
|
||||
* throw upon invalid payload format ([c327acb](https://github.com/socketio/socket.io-parser/commit/c327acbc3c3c2d0b2b439136cbcb56c81db173d6))
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* the encode method is now synchronous ([28d4f03](https://github.com/socketio/socket.io-parser/commit/28d4f0309bdd9e306b78d1946d3e1760941d6544))
|
||||
|
||||
|
||||
|
||||
## [4.0.1-rc3](https://github.com/socketio/socket.io-parser/compare/4.0.1-rc2...4.0.1-rc3) (2020-10-25)
|
||||
|
||||
|
||||
|
||||
## [4.0.1-rc2](https://github.com/socketio/socket.io-parser/compare/4.0.1-rc1...4.0.1-rc2) (2020-10-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* move binary detection back to the parser ([285e7cd](https://github.com/socketio/socket.io-parser/commit/285e7cd0d837adfc911c999e7294788681226ae1))
|
||||
|
||||
|
||||
|
||||
## [4.0.1-rc1](https://github.com/socketio/socket.io-parser/compare/4.0.0...4.0.1-rc1) (2020-10-12)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add support for a payload in a CONNECT packet ([78f9fc2](https://github.com/socketio/socket.io-parser/commit/78f9fc2999b15804b02f2c22a2b4007734a26af9))
|
||||
|
||||
|
||||
|
||||
## [3.3.1](https://github.com/socketio/socket.io-parser/compare/3.3.0...3.3.1) (2020-09-30)
|
||||
|
||||
|
||||
## [4.0.0](https://github.com/socketio/socket.io-parser/compare/3.4.1...4.0.0) (2020-09-28)
|
||||
|
||||
This release will be included in Socket.IO v3.
|
||||
|
||||
There is a breaking API change (see below), but the exchange [protocol](https://github.com/socketio/socket.io-protocol) is left untouched and thus stays in version 4.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* do not catch encoding errors ([aeae87c](https://github.com/socketio/socket.io-parser/commit/aeae87c220287197cb78370dbd86b950a7dd29eb))
|
||||
* throw upon invalid payload format ([c327acb](https://github.com/socketio/socket.io-parser/commit/c327acbc3c3c2d0b2b439136cbcb56c81db173d6))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* the encode method is now synchronous ([28d4f03](https://github.com/socketio/socket.io-parser/commit/28d4f0309bdd9e306b78d1946d3e1760941d6544))
|
||||
|
||||
|
||||
|
||||
## [3.4.1](https://github.com/socketio/socket.io-parser/compare/3.4.0...3.4.1) (2020-05-13)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* prevent DoS (OOM) via massive packets ([#95](https://github.com/socketio/socket.io-parser/issues/95)) ([dcb942d](https://github.com/socketio/socket.io-parser/commit/dcb942d24db97162ad16a67c2a0cf30875342d55))
|
||||
|
||||
|
||||
|
||||
## [3.4.0](https://github.com/socketio/socket.io-parser/compare/3.3.0...3.4.0) (2019-09-20)
|
||||
|
||||
|
||||
|
||||
## [3.3.0](https://github.com/socketio/socket.io-parser/compare/3.2.0...3.3.0) (2018-11-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove any reference to the `global` variable ([b47efb2](https://github.com/socketio/socket.io-parser/commit/b47efb2))
|
||||
14
Makefile
14
Makefile
@@ -1,14 +0,0 @@
|
||||
|
||||
help: ## print this message
|
||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
|
||||
|
||||
test: ## run tests either in the browser or in Node.js, based on the `BROWSERS` variable
|
||||
@if [ "x$(BROWSERS)" = "x" ]; then make test-node; else make test-zuul; fi
|
||||
|
||||
test-node: ## run tests in Node.js
|
||||
@./node_modules/.bin/mocha --reporter dot --bail test/index.js
|
||||
|
||||
test-zuul: ## run tests in the browser
|
||||
@./node_modules/zuul/bin/zuul test/index.js
|
||||
|
||||
.PHONY: help test test-node test-zuul
|
||||
14
Readme.md
14
Readme.md
@@ -1,14 +1,22 @@
|
||||
|
||||
# socket.io-parser
|
||||
|
||||
[](http://travis-ci.org/socketio/socket.io-parser)
|
||||
[](https://github.com/socketio/socket.io-parser/actions)
|
||||
[](http://badge.fury.io/js/socket.io-parser)
|
||||
|
||||
A socket.io encoder and decoder written in JavaScript complying with version `3`
|
||||
A socket.io encoder and decoder written in JavaScript complying with version `5`
|
||||
of [socket.io-protocol](https://github.com/socketio/socket.io-protocol).
|
||||
Used by [socket.io](https://github.com/automattic/socket.io) and
|
||||
[socket.io-client](https://github.com/automattic/socket.io-client).
|
||||
|
||||
Compatibility table:
|
||||
|
||||
| Parser version | Socket.IO server version | Protocol revision |
|
||||
|----------------| ------------------------ | ----------------- |
|
||||
| 3.x | 1.x / 2.x | 4 |
|
||||
| 4.x | 3.x | 5 |
|
||||
|
||||
|
||||
## Parser API
|
||||
|
||||
socket.io-parser is the reference implementation of socket.io-protocol. Read
|
||||
@@ -48,7 +56,7 @@ var parser = require('socket.io-parser');
|
||||
var encoder = new parser.Encoder();
|
||||
var packet = {
|
||||
type: parser.BINARY_EVENT,
|
||||
data: {i: new Buffer(1234), j: new Blob([new ArrayBuffer(2)])}
|
||||
data: {i: new Buffer(1234), j: new Blob([new ArrayBuffer(2)])},
|
||||
id: 15
|
||||
};
|
||||
encoder.encode(packet, function(encodedPackets) {
|
||||
|
||||
3
babel.config.js
Normal file
3
babel.config.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
presets: [["@babel/preset-env"]],
|
||||
};
|
||||
@@ -1,10 +0,0 @@
|
||||
var bencher = require('./index');
|
||||
bencher(function(benchmark) {
|
||||
function logMean(test) {
|
||||
console.log(test.name + ' mean run time: ' + test.stats.mean);
|
||||
}
|
||||
|
||||
for (var i = 0; i < benchmark.length; i++) {
|
||||
logMean(benchmark[i]);
|
||||
}
|
||||
});
|
||||
@@ -1,20 +1,21 @@
|
||||
var Benchmark = require('benchmark');
|
||||
var parser = require('../index');
|
||||
const Benchmark = require('benchmark');
|
||||
const parser = require('..');
|
||||
|
||||
function test(packet, deferred) {
|
||||
var encoder = new parser.Encoder();
|
||||
var decoder = new parser.Decoder();
|
||||
encoder.encode(packet, function(encodedPackets) {
|
||||
var decoder = new parser.Decoder();
|
||||
decoder.on('decoded', function(packet) {
|
||||
const encoder = new parser.Encoder();
|
||||
encoder.encode(packet, encodedPackets => {
|
||||
const decoder = new parser.Decoder();
|
||||
decoder.on('decoded', packet => {
|
||||
deferred.resolve();
|
||||
});
|
||||
|
||||
decoder.add(encodedPackets[0]);
|
||||
for (const encodedPacket of encodedPackets) {
|
||||
decoder.add(encodedPacket);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var dataObject = {
|
||||
const dataObject = [{
|
||||
'a': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17],
|
||||
'b': 'xxxyyyzzzalsdfalskdjfalksdjfalksdjfalksdjfjjfjfjfjjfjfjfj',
|
||||
'data': {
|
||||
@@ -25,57 +26,54 @@ var dataObject = {
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
var bigArray = [];
|
||||
for (var i = 0; i < 250; i++) {
|
||||
}];
|
||||
const bigArray = [];
|
||||
for (let i = 0; i < 250; i++) {
|
||||
bigArray.push(dataObject);
|
||||
}
|
||||
|
||||
const suite = new Benchmark.Suite();
|
||||
|
||||
|
||||
module.exports = function(callback) {
|
||||
var suite = new Benchmark.Suite();
|
||||
|
||||
suite.add('small json parse', {defer: true, fn: function(deferred) {
|
||||
var packet = {
|
||||
suite
|
||||
.add('small json parse', {defer: true, fn: deferred => {
|
||||
const packet = {
|
||||
type: parser.EVENT,
|
||||
nsp: '/bench',
|
||||
data: dataObject
|
||||
};
|
||||
test(packet, deferred);
|
||||
}})
|
||||
.add('big json parse', {defer: true, fn: function(deferred) {
|
||||
var packet = {
|
||||
.add('big json parse', {defer: true, fn: deferred => {
|
||||
const packet = {
|
||||
type: parser.EVENT,
|
||||
nsp: '/bench',
|
||||
data: bigArray
|
||||
};
|
||||
test(packet, deferred);
|
||||
}})
|
||||
.add('json with small binary parse', {defer: true, fn: function(deferred) {
|
||||
var packet = {
|
||||
type: parser.EVENT,
|
||||
.add('json with small binary parse', {defer: true, fn: deferred => {
|
||||
const packet = {
|
||||
type: parser.BINARY_EVENT,
|
||||
nsp: '/bench',
|
||||
data: {'a': [1, 2, 3], 'b': 'xxxyyyzzz', 'data': new Buffer(1000)}
|
||||
data: [{'a': [1, 2, 3], 'b': 'xxxyyyzzz', 'data': Buffer.allocUnsafe(1000)}]
|
||||
};
|
||||
test(packet, deferred);
|
||||
}})
|
||||
.add('json with big binary parse', {defer: true, fn: function(deferred) {
|
||||
var bigBinaryData = {
|
||||
bin1: new Buffer(10000),
|
||||
.add('json with big binary parse', {defer: true, fn: deferred => {
|
||||
const bigBinaryData = [{
|
||||
bin1: Buffer.allocUnsafe(10000),
|
||||
arr: bigArray,
|
||||
bin2: new Buffer(10000),
|
||||
bin3: new Buffer(10000)
|
||||
};
|
||||
var packet = {
|
||||
type: parser.EVENT,
|
||||
bin2: Buffer.allocUnsafe(10000),
|
||||
bin3: Buffer.allocUnsafe(10000)
|
||||
}];
|
||||
const packet = {
|
||||
type: parser.BINARY_EVENT,
|
||||
nsp: '/bench',
|
||||
data: bigBinaryData
|
||||
};
|
||||
test(packet, deferred);
|
||||
}})
|
||||
.on('complete', function() {
|
||||
callback(this);
|
||||
.on('cycle', function(event) {
|
||||
console.log(String(event.target));
|
||||
})
|
||||
.run({'async': true});
|
||||
};
|
||||
|
||||
4
bench/results.md
Normal file
4
bench/results.md
Normal file
@@ -0,0 +1,4 @@
|
||||
small json parse x 67,893 ops/sec ±4.30% (76 runs sampled)
|
||||
big json parse x 1,507 ops/sec ±1.72% (82 runs sampled)
|
||||
json with small binary parse x 62,367 ops/sec ±6.03% (74 runs sampled)
|
||||
json with big binary parse x 572 ops/sec ±1.25% (86 runs sampled)
|
||||
141
binary.js
141
binary.js
@@ -1,141 +0,0 @@
|
||||
/*global Blob,File*/
|
||||
|
||||
/**
|
||||
* Module requirements
|
||||
*/
|
||||
|
||||
var isArray = require('isarray');
|
||||
var isBuf = require('./is-buffer');
|
||||
var toString = Object.prototype.toString;
|
||||
var withNativeBlob = typeof Blob === 'function' || (typeof Blob !== 'undefined' && toString.call(Blob) === '[object BlobConstructor]');
|
||||
var withNativeFile = typeof File === 'function' || (typeof File !== 'undefined' && toString.call(File) === '[object FileConstructor]');
|
||||
|
||||
/**
|
||||
* Replaces every Buffer | ArrayBuffer in packet with a numbered placeholder.
|
||||
* Anything with blobs or files should be fed through removeBlobs before coming
|
||||
* here.
|
||||
*
|
||||
* @param {Object} packet - socket.io event packet
|
||||
* @return {Object} with deconstructed packet and list of buffers
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.deconstructPacket = function(packet) {
|
||||
var buffers = [];
|
||||
var packetData = packet.data;
|
||||
var pack = packet;
|
||||
pack.data = _deconstructPacket(packetData, buffers);
|
||||
pack.attachments = buffers.length; // number of binary 'attachments'
|
||||
return {packet: pack, buffers: buffers};
|
||||
};
|
||||
|
||||
function _deconstructPacket(data, buffers) {
|
||||
if (!data) return data;
|
||||
|
||||
if (isBuf(data)) {
|
||||
var placeholder = { _placeholder: true, num: buffers.length };
|
||||
buffers.push(data);
|
||||
return placeholder;
|
||||
} else if (isArray(data)) {
|
||||
var newData = new Array(data.length);
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
newData[i] = _deconstructPacket(data[i], buffers);
|
||||
}
|
||||
return newData;
|
||||
} else if (typeof data === 'object' && !(data instanceof Date)) {
|
||||
var newData = {};
|
||||
for (var key in data) {
|
||||
newData[key] = _deconstructPacket(data[key], buffers);
|
||||
}
|
||||
return newData;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconstructs a binary packet from its placeholder packet and buffers
|
||||
*
|
||||
* @param {Object} packet - event packet with placeholders
|
||||
* @param {Array} buffers - binary buffers to put in placeholder positions
|
||||
* @return {Object} reconstructed packet
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.reconstructPacket = function(packet, buffers) {
|
||||
packet.data = _reconstructPacket(packet.data, buffers);
|
||||
packet.attachments = undefined; // no longer useful
|
||||
return packet;
|
||||
};
|
||||
|
||||
function _reconstructPacket(data, buffers) {
|
||||
if (!data) return data;
|
||||
|
||||
if (data && data._placeholder) {
|
||||
return buffers[data.num]; // appropriate buffer (should be natural order anyway)
|
||||
} else if (isArray(data)) {
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
data[i] = _reconstructPacket(data[i], buffers);
|
||||
}
|
||||
} else if (typeof data === 'object') {
|
||||
for (var key in data) {
|
||||
data[key] = _reconstructPacket(data[key], buffers);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously removes Blobs or Files from data via
|
||||
* FileReader's readAsArrayBuffer method. Used before encoding
|
||||
* data as msgpack. Calls callback with the blobless data.
|
||||
*
|
||||
* @param {Object} data
|
||||
* @param {Function} callback
|
||||
* @api private
|
||||
*/
|
||||
|
||||
exports.removeBlobs = function(data, callback) {
|
||||
function _removeBlobs(obj, curKey, containingObject) {
|
||||
if (!obj) return obj;
|
||||
|
||||
// convert any blob
|
||||
if ((withNativeBlob && obj instanceof Blob) ||
|
||||
(withNativeFile && obj instanceof File)) {
|
||||
pendingBlobs++;
|
||||
|
||||
// async filereader
|
||||
var fileReader = new FileReader();
|
||||
fileReader.onload = function() { // this.result == arraybuffer
|
||||
if (containingObject) {
|
||||
containingObject[curKey] = this.result;
|
||||
}
|
||||
else {
|
||||
bloblessData = this.result;
|
||||
}
|
||||
|
||||
// if nothing pending its callback time
|
||||
if(! --pendingBlobs) {
|
||||
callback(bloblessData);
|
||||
}
|
||||
};
|
||||
|
||||
fileReader.readAsArrayBuffer(obj); // blob -> arraybuffer
|
||||
} else if (isArray(obj)) { // handle array
|
||||
for (var i = 0; i < obj.length; i++) {
|
||||
_removeBlobs(obj[i], i, obj);
|
||||
}
|
||||
} else if (typeof obj === 'object' && !isBuf(obj)) { // and object
|
||||
for (var key in obj) {
|
||||
_removeBlobs(obj[key], key, obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var pendingBlobs = 0;
|
||||
var bloblessData = data;
|
||||
_removeBlobs(bloblessData);
|
||||
if (!pendingBlobs) {
|
||||
callback(bloblessData);
|
||||
}
|
||||
};
|
||||
415
index.js
415
index.js
@@ -1,415 +0,0 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
|
||||
var debug = require('debug')('socket.io-parser');
|
||||
var Emitter = require('component-emitter');
|
||||
var binary = require('./binary');
|
||||
var isArray = require('isarray');
|
||||
var isBuf = require('./is-buffer');
|
||||
|
||||
/**
|
||||
* Protocol version.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.protocol = 4;
|
||||
|
||||
/**
|
||||
* Packet types.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.types = [
|
||||
'CONNECT',
|
||||
'DISCONNECT',
|
||||
'EVENT',
|
||||
'ACK',
|
||||
'ERROR',
|
||||
'BINARY_EVENT',
|
||||
'BINARY_ACK'
|
||||
];
|
||||
|
||||
/**
|
||||
* Packet type `connect`.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.CONNECT = 0;
|
||||
|
||||
/**
|
||||
* Packet type `disconnect`.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.DISCONNECT = 1;
|
||||
|
||||
/**
|
||||
* Packet type `event`.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.EVENT = 2;
|
||||
|
||||
/**
|
||||
* Packet type `ack`.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.ACK = 3;
|
||||
|
||||
/**
|
||||
* Packet type `error`.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.ERROR = 4;
|
||||
|
||||
/**
|
||||
* Packet type 'binary event'
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.BINARY_EVENT = 5;
|
||||
|
||||
/**
|
||||
* Packet type `binary ack`. For acks with binary arguments.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.BINARY_ACK = 6;
|
||||
|
||||
/**
|
||||
* Encoder constructor.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.Encoder = Encoder;
|
||||
|
||||
/**
|
||||
* Decoder constructor.
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
exports.Decoder = Decoder;
|
||||
|
||||
/**
|
||||
* A socket.io Encoder instance
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function Encoder() {}
|
||||
|
||||
var ERROR_PACKET = exports.ERROR + '"encode error"';
|
||||
|
||||
/**
|
||||
* Encode a packet as a single string if non-binary, or as a
|
||||
* buffer sequence, depending on packet type.
|
||||
*
|
||||
* @param {Object} obj - packet object
|
||||
* @param {Function} callback - function to handle encodings (likely engine.write)
|
||||
* @return Calls callback with Array of encodings
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Encoder.prototype.encode = function(obj, callback){
|
||||
debug('encoding packet %j', obj);
|
||||
|
||||
if (exports.BINARY_EVENT === obj.type || exports.BINARY_ACK === obj.type) {
|
||||
encodeAsBinary(obj, callback);
|
||||
} else {
|
||||
var encoding = encodeAsString(obj);
|
||||
callback([encoding]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Encode packet as string.
|
||||
*
|
||||
* @param {Object} packet
|
||||
* @return {String} encoded
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function encodeAsString(obj) {
|
||||
|
||||
// first is type
|
||||
var str = '' + obj.type;
|
||||
|
||||
// attachments if we have them
|
||||
if (exports.BINARY_EVENT === obj.type || exports.BINARY_ACK === obj.type) {
|
||||
str += obj.attachments + '-';
|
||||
}
|
||||
|
||||
// if we have a namespace other than `/`
|
||||
// we append it followed by a comma `,`
|
||||
if (obj.nsp && '/' !== obj.nsp) {
|
||||
str += obj.nsp + ',';
|
||||
}
|
||||
|
||||
// immediately followed by the id
|
||||
if (null != obj.id) {
|
||||
str += obj.id;
|
||||
}
|
||||
|
||||
// json data
|
||||
if (null != obj.data) {
|
||||
var payload = tryStringify(obj.data);
|
||||
if (payload !== false) {
|
||||
str += payload;
|
||||
} else {
|
||||
return ERROR_PACKET;
|
||||
}
|
||||
}
|
||||
|
||||
debug('encoded %j as %s', obj, str);
|
||||
return str;
|
||||
}
|
||||
|
||||
function tryStringify(str) {
|
||||
try {
|
||||
return JSON.stringify(str);
|
||||
} catch(e){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode packet as 'buffer sequence' by removing blobs, and
|
||||
* deconstructing packet into object with placeholders and
|
||||
* a list of buffers.
|
||||
*
|
||||
* @param {Object} packet
|
||||
* @return {Buffer} encoded
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function encodeAsBinary(obj, callback) {
|
||||
|
||||
function writeEncoding(bloblessData) {
|
||||
var deconstruction = binary.deconstructPacket(bloblessData);
|
||||
var pack = encodeAsString(deconstruction.packet);
|
||||
var buffers = deconstruction.buffers;
|
||||
|
||||
buffers.unshift(pack); // add packet info to beginning of data list
|
||||
callback(buffers); // write all the buffers
|
||||
}
|
||||
|
||||
binary.removeBlobs(obj, writeEncoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* A socket.io Decoder instance
|
||||
*
|
||||
* @return {Object} decoder
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function Decoder() {
|
||||
this.reconstructor = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix in `Emitter` with Decoder.
|
||||
*/
|
||||
|
||||
Emitter(Decoder.prototype);
|
||||
|
||||
/**
|
||||
* Decodes an encoded packet string into packet JSON.
|
||||
*
|
||||
* @param {String} obj - encoded packet
|
||||
* @return {Object} packet
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Decoder.prototype.add = function(obj) {
|
||||
var packet;
|
||||
if (typeof obj === 'string') {
|
||||
packet = decodeString(obj);
|
||||
if (exports.BINARY_EVENT === packet.type || exports.BINARY_ACK === packet.type) { // binary packet's json
|
||||
this.reconstructor = new BinaryReconstructor(packet);
|
||||
|
||||
// no attachments, labeled binary but no binary data to follow
|
||||
if (this.reconstructor.reconPack.attachments === 0) {
|
||||
this.emit('decoded', packet);
|
||||
}
|
||||
} else { // non-binary full packet
|
||||
this.emit('decoded', packet);
|
||||
}
|
||||
} else if (isBuf(obj) || obj.base64) { // raw binary data
|
||||
if (!this.reconstructor) {
|
||||
throw new Error('got binary data when not reconstructing a packet');
|
||||
} else {
|
||||
packet = this.reconstructor.takeBinaryData(obj);
|
||||
if (packet) { // received final buffer
|
||||
this.reconstructor = null;
|
||||
this.emit('decoded', packet);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Error('Unknown type: ' + obj);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Decode a packet String (JSON data)
|
||||
*
|
||||
* @param {String} str
|
||||
* @return {Object} packet
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function decodeString(str) {
|
||||
var i = 0;
|
||||
// look up type
|
||||
var p = {
|
||||
type: Number(str.charAt(0))
|
||||
};
|
||||
|
||||
if (null == exports.types[p.type]) {
|
||||
return error('unknown packet type ' + p.type);
|
||||
}
|
||||
|
||||
// look up attachments if type binary
|
||||
if (exports.BINARY_EVENT === p.type || exports.BINARY_ACK === p.type) {
|
||||
var buf = '';
|
||||
while (str.charAt(++i) !== '-') {
|
||||
buf += str.charAt(i);
|
||||
if (i == str.length) break;
|
||||
}
|
||||
if (buf != Number(buf) || str.charAt(i) !== '-') {
|
||||
throw new Error('Illegal attachments');
|
||||
}
|
||||
p.attachments = Number(buf);
|
||||
}
|
||||
|
||||
// look up namespace (if any)
|
||||
if ('/' === str.charAt(i + 1)) {
|
||||
p.nsp = '';
|
||||
while (++i) {
|
||||
var c = str.charAt(i);
|
||||
if (',' === c) break;
|
||||
p.nsp += c;
|
||||
if (i === str.length) break;
|
||||
}
|
||||
} else {
|
||||
p.nsp = '/';
|
||||
}
|
||||
|
||||
// look up id
|
||||
var next = str.charAt(i + 1);
|
||||
if ('' !== next && Number(next) == next) {
|
||||
p.id = '';
|
||||
while (++i) {
|
||||
var c = str.charAt(i);
|
||||
if (null == c || Number(c) != c) {
|
||||
--i;
|
||||
break;
|
||||
}
|
||||
p.id += str.charAt(i);
|
||||
if (i === str.length) break;
|
||||
}
|
||||
p.id = Number(p.id);
|
||||
}
|
||||
|
||||
// look up json data
|
||||
if (str.charAt(++i)) {
|
||||
var payload = tryParse(str.substr(i));
|
||||
var isPayloadValid = payload !== false && (p.type === exports.ERROR || isArray(payload));
|
||||
if (isPayloadValid) {
|
||||
p.data = payload;
|
||||
} else {
|
||||
return error('invalid payload');
|
||||
}
|
||||
}
|
||||
|
||||
debug('decoded %s as %j', str, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
function tryParse(str) {
|
||||
try {
|
||||
return JSON.parse(str);
|
||||
} catch(e){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deallocates a parser's resources
|
||||
*
|
||||
* @api public
|
||||
*/
|
||||
|
||||
Decoder.prototype.destroy = function() {
|
||||
if (this.reconstructor) {
|
||||
this.reconstructor.finishedReconstruction();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A manager of a binary event's 'buffer sequence'. Should
|
||||
* be constructed whenever a packet of type BINARY_EVENT is
|
||||
* decoded.
|
||||
*
|
||||
* @param {Object} packet
|
||||
* @return {BinaryReconstructor} initialized reconstructor
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function BinaryReconstructor(packet) {
|
||||
this.reconPack = packet;
|
||||
this.buffers = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to be called when binary data received from connection
|
||||
* after a BINARY_EVENT packet.
|
||||
*
|
||||
* @param {Buffer | ArrayBuffer} binData - the raw binary data received
|
||||
* @return {null | Object} returns null if more binary data is expected or
|
||||
* a reconstructed packet object if all buffers have been received.
|
||||
* @api private
|
||||
*/
|
||||
|
||||
BinaryReconstructor.prototype.takeBinaryData = function(binData) {
|
||||
this.buffers.push(binData);
|
||||
if (this.buffers.length === this.reconPack.attachments) { // done with buffer list
|
||||
var packet = binary.reconstructPacket(this.reconPack, this.buffers);
|
||||
this.finishedReconstruction();
|
||||
return packet;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Cleans up binary packet reconstruction variables.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
BinaryReconstructor.prototype.finishedReconstruction = function() {
|
||||
this.reconPack = null;
|
||||
this.buffers = [];
|
||||
};
|
||||
|
||||
function error(msg) {
|
||||
return {
|
||||
type: exports.ERROR,
|
||||
data: 'parser error: ' + msg
|
||||
};
|
||||
}
|
||||
20
is-buffer.js
20
is-buffer.js
@@ -1,20 +0,0 @@
|
||||
|
||||
module.exports = isBuf;
|
||||
|
||||
var withNativeBuffer = typeof Buffer === 'function' && typeof Buffer.isBuffer === 'function';
|
||||
var withNativeArrayBuffer = typeof ArrayBuffer === 'function';
|
||||
|
||||
var isView = function (obj) {
|
||||
return typeof ArrayBuffer.isView === 'function' ? ArrayBuffer.isView(obj) : (obj.buffer instanceof ArrayBuffer);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if obj is a buffer or an arraybuffer.
|
||||
*
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function isBuf(obj) {
|
||||
return (withNativeBuffer && Buffer.isBuffer(obj)) ||
|
||||
(withNativeArrayBuffer && (obj instanceof ArrayBuffer || isView(obj)));
|
||||
}
|
||||
86
lib/binary.ts
Normal file
86
lib/binary.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import { isBinary } from "./is-binary.js";
|
||||
|
||||
/**
|
||||
* Replaces every Buffer | ArrayBuffer | Blob | File in packet with a numbered placeholder.
|
||||
*
|
||||
* @param {Object} packet - socket.io event packet
|
||||
* @return {Object} with deconstructed packet and list of buffers
|
||||
* @public
|
||||
*/
|
||||
|
||||
export function deconstructPacket(packet) {
|
||||
const buffers = [];
|
||||
const packetData = packet.data;
|
||||
const pack = packet;
|
||||
pack.data = _deconstructPacket(packetData, buffers);
|
||||
pack.attachments = buffers.length; // number of binary 'attachments'
|
||||
return { packet: pack, buffers: buffers };
|
||||
}
|
||||
|
||||
function _deconstructPacket(data, buffers) {
|
||||
if (!data) return data;
|
||||
|
||||
if (isBinary(data)) {
|
||||
const placeholder = { _placeholder: true, num: buffers.length };
|
||||
buffers.push(data);
|
||||
return placeholder;
|
||||
} else if (Array.isArray(data)) {
|
||||
const newData = new Array(data.length);
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
newData[i] = _deconstructPacket(data[i], buffers);
|
||||
}
|
||||
return newData;
|
||||
} else if (typeof data === "object" && !(data instanceof Date)) {
|
||||
const newData = {};
|
||||
for (const key in data) {
|
||||
if (Object.prototype.hasOwnProperty.call(data, key)) {
|
||||
newData[key] = _deconstructPacket(data[key], buffers);
|
||||
}
|
||||
}
|
||||
return newData;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reconstructs a binary packet from its placeholder packet and buffers
|
||||
*
|
||||
* @param {Object} packet - event packet with placeholders
|
||||
* @param {Array} buffers - binary buffers to put in placeholder positions
|
||||
* @return {Object} reconstructed packet
|
||||
* @public
|
||||
*/
|
||||
|
||||
export function reconstructPacket(packet, buffers) {
|
||||
packet.data = _reconstructPacket(packet.data, buffers);
|
||||
delete packet.attachments; // no longer useful
|
||||
return packet;
|
||||
}
|
||||
|
||||
function _reconstructPacket(data, buffers) {
|
||||
if (!data) return data;
|
||||
|
||||
if (data && data._placeholder === true) {
|
||||
const isIndexValid =
|
||||
typeof data.num === "number" &&
|
||||
data.num >= 0 &&
|
||||
data.num < buffers.length;
|
||||
if (isIndexValid) {
|
||||
return buffers[data.num]; // appropriate buffer (should be natural order anyway)
|
||||
} else {
|
||||
throw new Error("illegal attachments");
|
||||
}
|
||||
} else if (Array.isArray(data)) {
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
data[i] = _reconstructPacket(data[i], buffers);
|
||||
}
|
||||
} else if (typeof data === "object") {
|
||||
for (const key in data) {
|
||||
if (Object.prototype.hasOwnProperty.call(data, key)) {
|
||||
data[key] = _reconstructPacket(data[key], buffers);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
361
lib/index.ts
Normal file
361
lib/index.ts
Normal file
@@ -0,0 +1,361 @@
|
||||
import { Emitter } from "@socket.io/component-emitter";
|
||||
import { deconstructPacket, reconstructPacket } from "./binary.js";
|
||||
import { isBinary, hasBinary } from "./is-binary.js";
|
||||
import debugModule from "debug"; // debug()
|
||||
|
||||
const debug = debugModule("socket.io-parser"); // debug()
|
||||
|
||||
/**
|
||||
* These strings must not be used as event names, as they have a special meaning.
|
||||
*/
|
||||
const RESERVED_EVENTS = [
|
||||
"connect", // used on the client side
|
||||
"connect_error", // used on the client side
|
||||
"disconnect", // used on both sides
|
||||
"disconnecting", // used on the server side
|
||||
"newListener", // used by the Node.js EventEmitter
|
||||
"removeListener", // used by the Node.js EventEmitter
|
||||
];
|
||||
|
||||
/**
|
||||
* Protocol version.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
|
||||
export const protocol: number = 5;
|
||||
|
||||
export enum PacketType {
|
||||
CONNECT,
|
||||
DISCONNECT,
|
||||
EVENT,
|
||||
ACK,
|
||||
CONNECT_ERROR,
|
||||
BINARY_EVENT,
|
||||
BINARY_ACK,
|
||||
}
|
||||
|
||||
export interface Packet {
|
||||
type: PacketType;
|
||||
nsp: string;
|
||||
data?: any;
|
||||
id?: number;
|
||||
attachments?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* A socket.io Encoder instance
|
||||
*/
|
||||
|
||||
export class Encoder {
|
||||
/**
|
||||
* Encoder constructor
|
||||
*
|
||||
* @param {function} replacer - custom replacer to pass down to JSON.parse
|
||||
*/
|
||||
constructor(private replacer?: (this: any, key: string, value: any) => any) {}
|
||||
/**
|
||||
* Encode a packet as a single string if non-binary, or as a
|
||||
* buffer sequence, depending on packet type.
|
||||
*
|
||||
* @param {Object} obj - packet object
|
||||
*/
|
||||
public encode(obj: Packet) {
|
||||
debug("encoding packet %j", obj);
|
||||
|
||||
if (obj.type === PacketType.EVENT || obj.type === PacketType.ACK) {
|
||||
if (hasBinary(obj)) {
|
||||
return this.encodeAsBinary({
|
||||
type:
|
||||
obj.type === PacketType.EVENT
|
||||
? PacketType.BINARY_EVENT
|
||||
: PacketType.BINARY_ACK,
|
||||
nsp: obj.nsp,
|
||||
data: obj.data,
|
||||
id: obj.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
return [this.encodeAsString(obj)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode packet as string.
|
||||
*/
|
||||
|
||||
private encodeAsString(obj: Packet) {
|
||||
// first is type
|
||||
let str = "" + obj.type;
|
||||
|
||||
// attachments if we have them
|
||||
if (
|
||||
obj.type === PacketType.BINARY_EVENT ||
|
||||
obj.type === PacketType.BINARY_ACK
|
||||
) {
|
||||
str += obj.attachments + "-";
|
||||
}
|
||||
|
||||
// if we have a namespace other than `/`
|
||||
// we append it followed by a comma `,`
|
||||
if (obj.nsp && "/" !== obj.nsp) {
|
||||
str += obj.nsp + ",";
|
||||
}
|
||||
|
||||
// immediately followed by the id
|
||||
if (null != obj.id) {
|
||||
str += obj.id;
|
||||
}
|
||||
|
||||
// json data
|
||||
if (null != obj.data) {
|
||||
str += JSON.stringify(obj.data, this.replacer);
|
||||
}
|
||||
|
||||
debug("encoded %j as %s", obj, str);
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode packet as 'buffer sequence' by removing blobs, and
|
||||
* deconstructing packet into object with placeholders and
|
||||
* a list of buffers.
|
||||
*/
|
||||
|
||||
private encodeAsBinary(obj: Packet) {
|
||||
const deconstruction = deconstructPacket(obj);
|
||||
const pack = this.encodeAsString(deconstruction.packet);
|
||||
const buffers = deconstruction.buffers;
|
||||
|
||||
buffers.unshift(pack); // add packet info to beginning of data list
|
||||
return buffers; // write all the buffers
|
||||
}
|
||||
}
|
||||
|
||||
// see https://stackoverflow.com/questions/8511281/check-if-a-value-is-an-object-in-javascript
|
||||
function isObject(value: any): boolean {
|
||||
return Object.prototype.toString.call(value) === "[object Object]";
|
||||
}
|
||||
|
||||
interface DecoderReservedEvents {
|
||||
decoded: (packet: Packet) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* A socket.io Decoder instance
|
||||
*
|
||||
* @return {Object} decoder
|
||||
*/
|
||||
export class Decoder extends Emitter<{}, {}, DecoderReservedEvents> {
|
||||
private reconstructor: BinaryReconstructor;
|
||||
|
||||
/**
|
||||
* Decoder constructor
|
||||
*
|
||||
* @param {function} reviver - custom reviver to pass down to JSON.stringify
|
||||
*/
|
||||
constructor(private reviver?: (this: any, key: string, value: any) => any) {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes an encoded packet string into packet JSON.
|
||||
*
|
||||
* @param {String} obj - encoded packet
|
||||
*/
|
||||
|
||||
public add(obj: any) {
|
||||
let packet;
|
||||
if (typeof obj === "string") {
|
||||
if (this.reconstructor) {
|
||||
throw new Error("got plaintext data when reconstructing a packet");
|
||||
}
|
||||
packet = this.decodeString(obj);
|
||||
const isBinaryEvent = packet.type === PacketType.BINARY_EVENT;
|
||||
if (isBinaryEvent || packet.type === PacketType.BINARY_ACK) {
|
||||
packet.type = isBinaryEvent ? PacketType.EVENT : PacketType.ACK;
|
||||
// binary packet's json
|
||||
this.reconstructor = new BinaryReconstructor(packet);
|
||||
|
||||
// no attachments, labeled binary but no binary data to follow
|
||||
if (packet.attachments === 0) {
|
||||
super.emitReserved("decoded", packet);
|
||||
}
|
||||
} else {
|
||||
// non-binary full packet
|
||||
super.emitReserved("decoded", packet);
|
||||
}
|
||||
} else if (isBinary(obj) || obj.base64) {
|
||||
// raw binary data
|
||||
if (!this.reconstructor) {
|
||||
throw new Error("got binary data when not reconstructing a packet");
|
||||
} else {
|
||||
packet = this.reconstructor.takeBinaryData(obj);
|
||||
if (packet) {
|
||||
// received final buffer
|
||||
this.reconstructor = null;
|
||||
super.emitReserved("decoded", packet);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Error("Unknown type: " + obj);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a packet String (JSON data)
|
||||
*
|
||||
* @param {String} str
|
||||
* @return {Object} packet
|
||||
*/
|
||||
private decodeString(str): Packet {
|
||||
let i = 0;
|
||||
// look up type
|
||||
const p: any = {
|
||||
type: Number(str.charAt(0)),
|
||||
};
|
||||
|
||||
if (PacketType[p.type] === undefined) {
|
||||
throw new Error("unknown packet type " + p.type);
|
||||
}
|
||||
|
||||
// look up attachments if type binary
|
||||
if (
|
||||
p.type === PacketType.BINARY_EVENT ||
|
||||
p.type === PacketType.BINARY_ACK
|
||||
) {
|
||||
const start = i + 1;
|
||||
while (str.charAt(++i) !== "-" && i != str.length) {}
|
||||
const buf = str.substring(start, i);
|
||||
if (buf != Number(buf) || str.charAt(i) !== "-") {
|
||||
throw new Error("Illegal attachments");
|
||||
}
|
||||
p.attachments = Number(buf);
|
||||
}
|
||||
|
||||
// look up namespace (if any)
|
||||
if ("/" === str.charAt(i + 1)) {
|
||||
const start = i + 1;
|
||||
while (++i) {
|
||||
const c = str.charAt(i);
|
||||
if ("," === c) break;
|
||||
if (i === str.length) break;
|
||||
}
|
||||
p.nsp = str.substring(start, i);
|
||||
} else {
|
||||
p.nsp = "/";
|
||||
}
|
||||
|
||||
// look up id
|
||||
const next = str.charAt(i + 1);
|
||||
if ("" !== next && Number(next) == next) {
|
||||
const start = i + 1;
|
||||
while (++i) {
|
||||
const c = str.charAt(i);
|
||||
if (null == c || Number(c) != c) {
|
||||
--i;
|
||||
break;
|
||||
}
|
||||
if (i === str.length) break;
|
||||
}
|
||||
p.id = Number(str.substring(start, i + 1));
|
||||
}
|
||||
|
||||
// look up json data
|
||||
if (str.charAt(++i)) {
|
||||
const payload = this.tryParse(str.substr(i));
|
||||
if (Decoder.isPayloadValid(p.type, payload)) {
|
||||
p.data = payload;
|
||||
} else {
|
||||
throw new Error("invalid payload");
|
||||
}
|
||||
}
|
||||
|
||||
debug("decoded %s as %j", str, p);
|
||||
return p;
|
||||
}
|
||||
|
||||
private tryParse(str) {
|
||||
try {
|
||||
return JSON.parse(str, this.reviver);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static isPayloadValid(type: PacketType, payload: any): boolean {
|
||||
switch (type) {
|
||||
case PacketType.CONNECT:
|
||||
return isObject(payload);
|
||||
case PacketType.DISCONNECT:
|
||||
return payload === undefined;
|
||||
case PacketType.CONNECT_ERROR:
|
||||
return typeof payload === "string" || isObject(payload);
|
||||
case PacketType.EVENT:
|
||||
case PacketType.BINARY_EVENT:
|
||||
return (
|
||||
Array.isArray(payload) &&
|
||||
(typeof payload[0] === "number" ||
|
||||
(typeof payload[0] === "string" &&
|
||||
RESERVED_EVENTS.indexOf(payload[0]) === -1))
|
||||
);
|
||||
case PacketType.ACK:
|
||||
case PacketType.BINARY_ACK:
|
||||
return Array.isArray(payload);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deallocates a parser's resources
|
||||
*/
|
||||
public destroy() {
|
||||
if (this.reconstructor) {
|
||||
this.reconstructor.finishedReconstruction();
|
||||
this.reconstructor = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A manager of a binary event's 'buffer sequence'. Should
|
||||
* be constructed whenever a packet of type BINARY_EVENT is
|
||||
* decoded.
|
||||
*
|
||||
* @param {Object} packet
|
||||
* @return {BinaryReconstructor} initialized reconstructor
|
||||
*/
|
||||
|
||||
class BinaryReconstructor {
|
||||
private reconPack;
|
||||
private buffers: Array<Buffer | ArrayBuffer> = [];
|
||||
|
||||
constructor(readonly packet: Packet) {
|
||||
this.reconPack = packet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to be called when binary data received from connection
|
||||
* after a BINARY_EVENT packet.
|
||||
*
|
||||
* @param {Buffer | ArrayBuffer} binData - the raw binary data received
|
||||
* @return {null | Object} returns null if more binary data is expected or
|
||||
* a reconstructed packet object if all buffers have been received.
|
||||
*/
|
||||
public takeBinaryData(binData) {
|
||||
this.buffers.push(binData);
|
||||
if (this.buffers.length === this.reconPack.attachments) {
|
||||
// done with buffer list
|
||||
const packet = reconstructPacket(this.reconPack, this.buffers);
|
||||
this.finishedReconstruction();
|
||||
return packet;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up binary packet reconstruction variables.
|
||||
*/
|
||||
public finishedReconstruction() {
|
||||
this.reconPack = null;
|
||||
this.buffers = [];
|
||||
}
|
||||
}
|
||||
66
lib/is-binary.ts
Normal file
66
lib/is-binary.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
const withNativeArrayBuffer: boolean = typeof ArrayBuffer === "function";
|
||||
|
||||
const isView = (obj: any) => {
|
||||
return typeof ArrayBuffer.isView === "function"
|
||||
? ArrayBuffer.isView(obj)
|
||||
: obj.buffer instanceof ArrayBuffer;
|
||||
};
|
||||
|
||||
const toString = Object.prototype.toString;
|
||||
const withNativeBlob =
|
||||
typeof Blob === "function" ||
|
||||
(typeof Blob !== "undefined" &&
|
||||
toString.call(Blob) === "[object BlobConstructor]");
|
||||
const withNativeFile =
|
||||
typeof File === "function" ||
|
||||
(typeof File !== "undefined" &&
|
||||
toString.call(File) === "[object FileConstructor]");
|
||||
|
||||
/**
|
||||
* Returns true if obj is a Buffer, an ArrayBuffer, a Blob or a File.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
|
||||
export function isBinary(obj: any) {
|
||||
return (
|
||||
(withNativeArrayBuffer && (obj instanceof ArrayBuffer || isView(obj))) ||
|
||||
(withNativeBlob && obj instanceof Blob) ||
|
||||
(withNativeFile && obj instanceof File)
|
||||
);
|
||||
}
|
||||
|
||||
export function hasBinary(obj: any, toJSON?: boolean) {
|
||||
if (!obj || typeof obj !== "object") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
for (let i = 0, l = obj.length; i < l; i++) {
|
||||
if (hasBinary(obj[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isBinary(obj)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
obj.toJSON &&
|
||||
typeof obj.toJSON === "function" &&
|
||||
arguments.length === 1
|
||||
) {
|
||||
return hasBinary(obj.toJSON(), true);
|
||||
}
|
||||
|
||||
for (const key in obj) {
|
||||
if (Object.prototype.hasOwnProperty.call(obj, key) && hasBinary(obj[key])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
14475
package-lock.json
generated
Normal file
14475
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
55
package.json
55
package.json
@@ -1,31 +1,58 @@
|
||||
{
|
||||
"name": "socket.io-parser",
|
||||
"version": "3.3.0",
|
||||
"version": "4.2.4",
|
||||
"description": "socket.io protocol parser",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Automattic/socket.io-parser.git"
|
||||
"url": "https://github.com/socketio/socket.io-parser.git"
|
||||
},
|
||||
"files": [
|
||||
"binary.js",
|
||||
"index.js",
|
||||
"is-buffer.js"
|
||||
"build/"
|
||||
],
|
||||
"main": "./build/cjs/index.js",
|
||||
"module": "./build/esm/index.js",
|
||||
"types": "./build/esm/index.d.ts",
|
||||
"exports": {
|
||||
"import": {
|
||||
"node": "./build/esm-debug/index.js",
|
||||
"default": "./build/esm/index.js"
|
||||
},
|
||||
"require": "./build/cjs/index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": "~3.1.0",
|
||||
"component-emitter": "1.2.1",
|
||||
"isarray": "2.0.1"
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "~7.9.6",
|
||||
"@babel/preset-env": "~7.9.6",
|
||||
"@babel/register": "^7.18.9",
|
||||
"@types/debug": "^4.1.5",
|
||||
"@types/node": "^14.11.1",
|
||||
"@wdio/cli": "^7.26.0",
|
||||
"@wdio/local-runner": "^7.26.0",
|
||||
"@wdio/mocha-framework": "^7.26.0",
|
||||
"@wdio/sauce-service": "^7.26.0",
|
||||
"@wdio/spec-reporter": "^7.26.0",
|
||||
"benchmark": "2.1.2",
|
||||
"expect.js": "0.3.1",
|
||||
"mocha": "3.2.0",
|
||||
"socket.io-browsers": "^1.0.0",
|
||||
"zuul": "3.11.1",
|
||||
"zuul-ngrok": "4.0.0"
|
||||
"mocha": "^10.1.0",
|
||||
"prettier": "^2.1.2",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.0.3",
|
||||
"wdio-geckodriver-service": "^4.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "make test"
|
||||
"compile": "rimraf ./build && tsc && tsc -p tsconfig.esm.json && ./postcompile.sh",
|
||||
"test": "npm run format:check && npm run compile && if test \"$BROWSERS\" = \"1\" ; then npm run test:browser; else npm run test:node; fi",
|
||||
"test:node": "mocha --reporter dot --bail test/index.js",
|
||||
"test:browser": "wdio",
|
||||
"format:fix": "prettier --write --parser typescript '*.js' 'lib/**/*.ts' 'test/**/*.js'",
|
||||
"format:check": "prettier --check --parser typescript '*.js' 'lib/**/*.ts' 'test/**/*.js'",
|
||||
"prepack": "npm run compile"
|
||||
},
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
}
|
||||
|
||||
8
postcompile.sh
Executable file
8
postcompile.sh
Executable file
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
|
||||
cp ./support/package.cjs.json ./build/cjs/package.json
|
||||
cp ./support/package.esm.json ./build/esm/package.json
|
||||
|
||||
cp -r ./build/esm/ ./build/esm-debug/
|
||||
|
||||
sed -i '/debug(/d' ./build/esm/*.js
|
||||
3
support/package.cjs.json
Normal file
3
support/package.cjs.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "commonjs"
|
||||
}
|
||||
3
support/package.esm.json
Normal file
3
support/package.esm.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "module"
|
||||
}
|
||||
@@ -1,70 +1,87 @@
|
||||
var parser = require('../index.js');
|
||||
var expect = require('expect.js');
|
||||
var helpers = require('./helpers.js');
|
||||
var encoder = new parser.Encoder();
|
||||
const { PacketType, Decoder, Encoder } = require("..");
|
||||
const expect = require("expect.js");
|
||||
const helpers = require("./helpers.js");
|
||||
const encoder = new Encoder();
|
||||
|
||||
describe('parser', function() {
|
||||
it('encodes an ArrayBuffer', function() {
|
||||
var packet = {
|
||||
type: parser.BINARY_EVENT,
|
||||
data: ['a', new ArrayBuffer(2)],
|
||||
describe("ArrayBuffer", () => {
|
||||
it("encodes an ArrayBuffer", () => {
|
||||
const packet = {
|
||||
type: PacketType.EVENT,
|
||||
data: ["a", new ArrayBuffer(2)],
|
||||
id: 0,
|
||||
nsp: '/'
|
||||
nsp: "/",
|
||||
};
|
||||
helpers.test_bin(packet);
|
||||
return helpers.test_bin(packet);
|
||||
});
|
||||
|
||||
it('encodes a TypedArray', function() {
|
||||
var array = new Uint8Array(5);
|
||||
for (var i = 0; i < array.length; i++) array[i] = i;
|
||||
|
||||
var packet = {
|
||||
type: parser.BINARY_EVENT,
|
||||
data: ['a', array],
|
||||
it("encodes an ArrayBuffer into an object with a null prototype", () => {
|
||||
const packet = {
|
||||
type: PacketType.EVENT,
|
||||
data: [
|
||||
"a",
|
||||
Object.create(null, {
|
||||
array: { value: new ArrayBuffer(2), enumerable: true },
|
||||
}),
|
||||
],
|
||||
id: 0,
|
||||
nsp: '/'
|
||||
nsp: "/",
|
||||
};
|
||||
helpers.test_bin(packet);
|
||||
return helpers.test_bin(packet);
|
||||
});
|
||||
|
||||
it('encodes ArrayBuffers deep in JSON', function() {
|
||||
var packet = {
|
||||
type: parser.BINARY_EVENT,
|
||||
data: ['a', {a: 'hi', b: {why: new ArrayBuffer(3)}, c: {a: 'bye', b: { a: new ArrayBuffer(6)}}}],
|
||||
it("encodes a TypedArray", () => {
|
||||
const array = new Uint8Array(5);
|
||||
for (let i = 0; i < array.length; i++) array[i] = i;
|
||||
|
||||
const packet = {
|
||||
type: PacketType.EVENT,
|
||||
data: ["a", array],
|
||||
id: 0,
|
||||
nsp: "/",
|
||||
};
|
||||
return helpers.test_bin(packet);
|
||||
});
|
||||
|
||||
it("encodes ArrayBuffers deep in JSON", () => {
|
||||
const packet = {
|
||||
type: PacketType.EVENT,
|
||||
data: [
|
||||
"a",
|
||||
{
|
||||
a: "hi",
|
||||
b: { why: new ArrayBuffer(3) },
|
||||
c: { a: "bye", b: { a: new ArrayBuffer(6) } },
|
||||
},
|
||||
],
|
||||
id: 999,
|
||||
nsp: '/deep'
|
||||
nsp: "/deep",
|
||||
};
|
||||
helpers.test_bin(packet);
|
||||
return helpers.test_bin(packet);
|
||||
});
|
||||
|
||||
it('encodes deep binary JSON with null values', function() {
|
||||
var packet = {
|
||||
type: parser.BINARY_EVENT,
|
||||
data: ['a', {a: 'b', c: 4, e: {g: null}, h: new ArrayBuffer(9)}],
|
||||
nsp: '/',
|
||||
id: 600
|
||||
it("encodes deep binary JSON with null values", () => {
|
||||
const packet = {
|
||||
type: PacketType.EVENT,
|
||||
data: ["a", { a: "b", c: 4, e: { g: null }, h: new ArrayBuffer(9) }],
|
||||
nsp: "/",
|
||||
id: 600,
|
||||
};
|
||||
helpers.test_bin(packet);
|
||||
return helpers.test_bin(packet);
|
||||
});
|
||||
|
||||
it('cleans itself up on close', function() {
|
||||
var packet = {
|
||||
type: parser.BINARY_EVENT,
|
||||
data: [new ArrayBuffer(2), new ArrayBuffer(3)],
|
||||
id: 0,
|
||||
nsp: '/'
|
||||
it("should not modify the input packet", () => {
|
||||
const packet = {
|
||||
type: PacketType.EVENT,
|
||||
nsp: "/",
|
||||
data: ["a", Uint8Array.of(1, 2, 3), Uint8Array.of(4, 5, 6)],
|
||||
};
|
||||
|
||||
encoder.encode(packet, function(encodedPackets) {
|
||||
var decoder = new parser.Decoder();
|
||||
decoder.on('decoded', function(packet) {
|
||||
throw new Error("received a packet when not all binary data was sent.");
|
||||
});
|
||||
encoder.encode(packet);
|
||||
|
||||
decoder.add(encodedPackets[0]); // add metadata
|
||||
decoder.add(encodedPackets[1]); // add first attachment
|
||||
decoder.destroy(); // destroy before all data added
|
||||
expect(decoder.reconstructor.buffers.length).to.be(0); // expect that buffer is clean
|
||||
expect(packet).to.eql({
|
||||
type: PacketType.EVENT,
|
||||
nsp: "/",
|
||||
data: ["a", Uint8Array.of(1, 2, 3), Uint8Array.of(4, 5, 6)],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
77
test/blob.js
77
test/blob.js
@@ -1,67 +1,72 @@
|
||||
var parser = require('../index.js');
|
||||
var helpers = require('./helpers.js');
|
||||
const { PacketType } = require("..");
|
||||
const helpers = require("./helpers.js");
|
||||
|
||||
var BlobBuilder = typeof BlobBuilder !== 'undefined' ? BlobBuilder :
|
||||
typeof WebKitBlobBuilder !== 'undefined' ? WebKitBlobBuilder :
|
||||
typeof MSBlobBuilder !== 'undefined' ? MSBlobBuilder :
|
||||
typeof MozBlobBuilder !== 'undefined' ? MozBlobBuilder : false;
|
||||
const BlobBuilderImpl =
|
||||
typeof BlobBuilder !== "undefined"
|
||||
? BlobBuilder
|
||||
: typeof WebKitBlobBuilder !== "undefined"
|
||||
? WebKitBlobBuilder
|
||||
: typeof MSBlobBuilder !== "undefined"
|
||||
? MSBlobBuilder
|
||||
: typeof MozBlobBuilder !== "undefined"
|
||||
? MozBlobBuilder
|
||||
: false;
|
||||
|
||||
describe('parser', function() {
|
||||
it('encodes a Blob', function() {
|
||||
var data;
|
||||
if (BlobBuilder) {
|
||||
var bb = new BlobBuilder();
|
||||
describe("Blob", () => {
|
||||
it("encodes a Blob", () => {
|
||||
let data;
|
||||
if (BlobBuilderImpl) {
|
||||
const bb = new BlobBuilderImpl();
|
||||
bb.append(new ArrayBuffer(2));
|
||||
data = bb.getBlob();
|
||||
} else {
|
||||
data = new Blob([new ArrayBuffer(2)]);
|
||||
}
|
||||
|
||||
var packet = {
|
||||
type: parser.BINARY_EVENT,
|
||||
data: data,
|
||||
const packet = {
|
||||
type: PacketType.EVENT,
|
||||
data: ["a", data],
|
||||
id: 0,
|
||||
nsp: '/'
|
||||
nsp: "/",
|
||||
};
|
||||
helpers.test_bin(packet);
|
||||
return helpers.test_bin(packet);
|
||||
});
|
||||
|
||||
it('encodes an Blob deep in JSON', function() {
|
||||
var data;
|
||||
if (BlobBuilder) {
|
||||
var bb = new BlobBuilder();
|
||||
it("encodes an Blob deep in JSON", () => {
|
||||
let data;
|
||||
if (BlobBuilderImpl) {
|
||||
const bb = new BlobBuilderImpl();
|
||||
bb.append(new ArrayBuffer(2));
|
||||
data = bb.getBlob();
|
||||
} else {
|
||||
data = new Blob([new ArrayBuffer(2)]);
|
||||
}
|
||||
|
||||
var packet = {
|
||||
type: parser.BINARY_EVENT,
|
||||
data: {a: 'hi', b: { why: data }, c: 'bye'},
|
||||
const packet = {
|
||||
type: PacketType.EVENT,
|
||||
data: ["a", { a: "hi", b: { why: data }, c: "bye" }],
|
||||
id: 999,
|
||||
nsp: '/deep'
|
||||
nsp: "/deep",
|
||||
};
|
||||
helpers.test_bin(packet);
|
||||
return helpers.test_bin(packet);
|
||||
});
|
||||
|
||||
it('encodes a binary ack with a blob', function() {
|
||||
var data;
|
||||
if (BlobBuilder) {
|
||||
var bb = new BlobBuilder();
|
||||
it("encodes a binary ack with a blob", () => {
|
||||
let data;
|
||||
if (BlobBuilderImpl) {
|
||||
const bb = new BlobBuilderImpl();
|
||||
bb.append(new ArrayBuffer(2));
|
||||
data = bb.getBlob();
|
||||
} else {
|
||||
data = new Blob([new ArrayBuffer(2)]);
|
||||
}
|
||||
|
||||
var packet = {
|
||||
type: parser.BINARY_ACK,
|
||||
data: {a: 'hi ack', b: { why: data }, c: 'bye ack'},
|
||||
const packet = {
|
||||
type: PacketType.ACK,
|
||||
data: [{ a: "hi ack", b: { why: data }, c: "bye ack" }],
|
||||
id: 999,
|
||||
nsp: '/deep'
|
||||
nsp: "/deep",
|
||||
};
|
||||
helpers.test_bin(packet);
|
||||
})
|
||||
|
||||
return helpers.test_bin(packet);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,25 +1,67 @@
|
||||
var parser = require('../index.js');
|
||||
var expect = require('expect.js');
|
||||
var helpers = require('./helpers.js');
|
||||
var encode = parser.encode;
|
||||
var decode = parser.decode;
|
||||
const { PacketType, Decoder } = require("../");
|
||||
const helpers = require("./helpers.js");
|
||||
const expect = require("expect.js");
|
||||
|
||||
describe('parser', function() {
|
||||
it('encodes a Buffer', function() {
|
||||
helpers.test_bin({
|
||||
type: parser.BINARY_EVENT,
|
||||
data: ['a', new Buffer('abc', 'utf8')],
|
||||
id: 23,
|
||||
nsp: '/cool'
|
||||
});
|
||||
describe("Buffer", () => {
|
||||
it("encodes a Buffer", () => {
|
||||
return helpers.test_bin({
|
||||
type: PacketType.EVENT,
|
||||
data: ["a", Buffer.from("abc", "utf8")],
|
||||
id: 23,
|
||||
nsp: "/cool",
|
||||
});
|
||||
});
|
||||
|
||||
it('encodes a binary ack with Buffer', function() {
|
||||
helpers.test_bin({
|
||||
type: parser.BINARY_ACK,
|
||||
data: ['a', new Buffer('xxx', 'utf8'), {}],
|
||||
it("encodes a nested Buffer", () => {
|
||||
return helpers.test_bin({
|
||||
type: PacketType.EVENT,
|
||||
data: ["a", { b: ["c", Buffer.from("abc", "utf8")] }],
|
||||
id: 23,
|
||||
nsp: "/cool",
|
||||
});
|
||||
});
|
||||
|
||||
it("encodes a binary ack with Buffer", () => {
|
||||
return helpers.test_bin({
|
||||
type: PacketType.ACK,
|
||||
data: ["a", Buffer.from("xxx", "utf8"), {}],
|
||||
id: 127,
|
||||
nsp: '/back'
|
||||
})
|
||||
nsp: "/back",
|
||||
});
|
||||
});
|
||||
|
||||
it("throws an error when adding an attachment with an invalid 'num' attribute (string)", () => {
|
||||
const decoder = new Decoder();
|
||||
|
||||
expect(() => {
|
||||
decoder.add('51-["hello",{"_placeholder":true,"num":"splice"}]');
|
||||
decoder.add(Buffer.from("world"));
|
||||
}).to.throwException(/^illegal attachments$/);
|
||||
});
|
||||
|
||||
it("throws an error when adding an attachment with an invalid 'num' attribute (out-of-bound)", () => {
|
||||
const decoder = new Decoder();
|
||||
|
||||
expect(() => {
|
||||
decoder.add('51-["hello",{"_placeholder":true,"num":1}]');
|
||||
decoder.add(Buffer.from("world"));
|
||||
}).to.throwException(/^illegal attachments$/);
|
||||
});
|
||||
|
||||
it("throws an error when adding an attachment without header", () => {
|
||||
const decoder = new Decoder();
|
||||
|
||||
expect(() => {
|
||||
decoder.add(Buffer.from("world"));
|
||||
}).to.throwException(/^got binary data when not reconstructing a packet$/);
|
||||
});
|
||||
|
||||
it("throws an error when decoding a binary event without attachments", () => {
|
||||
const decoder = new Decoder();
|
||||
|
||||
expect(() => {
|
||||
decoder.add('51-["hello",{"_placeholder":true,"num":0}]');
|
||||
decoder.add('2["hello"]');
|
||||
}).to.throwException(/^got plaintext data when reconstructing a packet$/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,46 +1,35 @@
|
||||
var parser = require('../index.js');
|
||||
var expect = require('expect.js');
|
||||
var encoder = new parser.Encoder();
|
||||
const parser = require("..");
|
||||
const expect = require("expect.js");
|
||||
const encoder = new parser.Encoder();
|
||||
|
||||
// tests encoding and decoding a single packet
|
||||
module.exports.test = function(obj){
|
||||
encoder.encode(obj, function(encodedPackets) {
|
||||
var decoder = new parser.Decoder();
|
||||
decoder.on('decoded', function(packet) {
|
||||
module.exports.test = (obj) => {
|
||||
return new Promise((resolve) => {
|
||||
const encodedPackets = encoder.encode(obj);
|
||||
|
||||
const decoder = new parser.Decoder();
|
||||
decoder.on("decoded", (packet) => {
|
||||
expect(packet).to.eql(obj);
|
||||
resolve();
|
||||
});
|
||||
|
||||
decoder.add(encodedPackets[0]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// tests encoding of binary packets
|
||||
module.exports.test_bin = function test_bin(obj) {
|
||||
var originalData = obj.data;
|
||||
encoder.encode(obj, function(encodedPackets) {
|
||||
var decoder = new parser.Decoder();
|
||||
decoder.on('decoded', function(packet) {
|
||||
obj.data = originalData;
|
||||
obj.attachments = undefined;
|
||||
module.exports.test_bin = (obj) => {
|
||||
return new Promise((resolve) => {
|
||||
const encodedPackets = encoder.encode(obj);
|
||||
|
||||
const decoder = new parser.Decoder();
|
||||
decoder.on("decoded", (packet) => {
|
||||
expect(obj).to.eql(packet);
|
||||
resolve();
|
||||
});
|
||||
|
||||
for (var i = 0; i < encodedPackets.length; i++) {
|
||||
for (let i = 0; i < encodedPackets.length; i++) {
|
||||
decoder.add(encodedPackets[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// array buffer's slice is native code that is not transported across
|
||||
// socket.io via msgpack, so regular .eql fails
|
||||
module.exports.testArrayBuffers = function(buf1, buf2) {
|
||||
buf1.slice = undefined;
|
||||
buf2.slice = undefined;
|
||||
expect(buf1).to.eql(buf2);
|
||||
}
|
||||
|
||||
module.exports.testPacketMetadata = function(p1, p2) {
|
||||
expect(p1.type).to.eql(p2.type);
|
||||
expect(p1.id).to.eql(p2.id);
|
||||
expect(p1.nsp).to.eql(p2.nsp);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,33 +1,41 @@
|
||||
var env = require('./support/env.js');
|
||||
const env = require("./support/env.js");
|
||||
|
||||
var blobSupported = (function() {
|
||||
const blobSupported = (function () {
|
||||
try {
|
||||
new Blob(['hi']);
|
||||
new Blob(["hi"]);
|
||||
return true;
|
||||
} catch(e) {}
|
||||
} catch (e) {}
|
||||
return false;
|
||||
})();
|
||||
|
||||
/**
|
||||
* Create a blob builder even when vendor prefixes exist
|
||||
*/
|
||||
const BlobBuilderImpl =
|
||||
typeof BlobBuilder !== "undefined"
|
||||
? BlobBuilder
|
||||
: typeof WebKitBlobBuilder !== "undefined"
|
||||
? WebKitBlobBuilder
|
||||
: typeof MSBlobBuilder !== "undefined"
|
||||
? MSBlobBuilder
|
||||
: typeof MozBlobBuilder !== "undefined"
|
||||
? MozBlobBuilder
|
||||
: false;
|
||||
const blobBuilderSupported =
|
||||
!!BlobBuilderImpl &&
|
||||
!!BlobBuilderImpl.prototype.append &&
|
||||
!!BlobBuilderImpl.prototype.getBlob;
|
||||
|
||||
var BlobBuilder = typeof BlobBuilder !== 'undefined' ? BlobBuilder :
|
||||
typeof WebKitBlobBuilder !== 'undefined' ? WebKitBlobBuilder :
|
||||
typeof MSBlobBuilder !== 'undefined' ? MSBlobBuilder :
|
||||
typeof MozBlobBuilder !== 'undefined' ? MozBlobBuilder : false;
|
||||
var blobBuilderSupported = !!BlobBuilder && !!BlobBuilder.prototype.append && !!BlobBuilder.prototype.getBlob;
|
||||
|
||||
require('./parser.js');
|
||||
require("./parser.js");
|
||||
|
||||
if (!env.browser) {
|
||||
require('./buffer.js');
|
||||
require("./buffer.js");
|
||||
}
|
||||
|
||||
if (typeof ArrayBuffer !== 'undefined') {
|
||||
require('./arraybuffer.js');
|
||||
if (typeof ArrayBuffer !== "undefined") {
|
||||
require("./arraybuffer.js");
|
||||
}
|
||||
|
||||
if (blobSupported || blobBuilderSupported) {
|
||||
require('./blob.js');
|
||||
require("./blob.js");
|
||||
}
|
||||
|
||||
174
test/parser.js
174
test/parser.js
@@ -1,97 +1,151 @@
|
||||
var parser = require('../index.js');
|
||||
var expect = require('expect.js');
|
||||
var helpers = require('./helpers.js');
|
||||
const { PacketType, Decoder, Encoder } = require("..");
|
||||
const expect = require("expect.js");
|
||||
const helpers = require("./helpers.js");
|
||||
|
||||
describe('parser', function(){
|
||||
|
||||
it('exposes types', function(){
|
||||
expect(parser.CONNECT).to.be.a('number');
|
||||
expect(parser.DISCONNECT).to.be.a('number');
|
||||
expect(parser.EVENT).to.be.a('number');
|
||||
expect(parser.ACK).to.be.a('number');
|
||||
expect(parser.ERROR).to.be.a('number');
|
||||
expect(parser.BINARY_EVENT).to.be.a('number');
|
||||
expect(parser.BINARY_ACK).to.be.a('number');
|
||||
describe("socket.io-parser", () => {
|
||||
it("exposes types", () => {
|
||||
expect(PacketType.CONNECT).to.be.a("number");
|
||||
expect(PacketType.DISCONNECT).to.be.a("number");
|
||||
expect(PacketType.EVENT).to.be.a("number");
|
||||
expect(PacketType.ACK).to.be.a("number");
|
||||
expect(PacketType.CONNECT_ERROR).to.be.a("number");
|
||||
expect(PacketType.BINARY_EVENT).to.be.a("number");
|
||||
expect(PacketType.BINARY_ACK).to.be.a("number");
|
||||
});
|
||||
|
||||
it('encodes connection', function(){
|
||||
helpers.test({
|
||||
type: parser.CONNECT,
|
||||
nsp: '/woot'
|
||||
it("encodes connection", () => {
|
||||
return helpers.test({
|
||||
type: PacketType.CONNECT,
|
||||
nsp: "/woot",
|
||||
data: {
|
||||
token: "123",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('encodes disconnection', function(){
|
||||
helpers.test({
|
||||
type: parser.DISCONNECT,
|
||||
nsp: '/woot'
|
||||
it("encodes disconnection", () => {
|
||||
return helpers.test({
|
||||
type: PacketType.DISCONNECT,
|
||||
nsp: "/woot",
|
||||
});
|
||||
});
|
||||
|
||||
it('encodes an event', function(){
|
||||
helpers.test({
|
||||
type: parser.EVENT,
|
||||
data: ['a', 1, {}],
|
||||
nsp: '/'
|
||||
it("encodes an event", () => {
|
||||
return helpers.test({
|
||||
type: PacketType.EVENT,
|
||||
data: ["a", 1, {}],
|
||||
nsp: "/",
|
||||
});
|
||||
helpers.test({
|
||||
type: parser.EVENT,
|
||||
data: ['a', 1, {}],
|
||||
});
|
||||
|
||||
it("encodes an event (with an integer as event name)", () => {
|
||||
return helpers.test({
|
||||
type: PacketType.EVENT,
|
||||
data: [1, "a", {}],
|
||||
nsp: "/",
|
||||
});
|
||||
});
|
||||
|
||||
it("encodes an event (with ack)", () => {
|
||||
return helpers.test({
|
||||
type: PacketType.EVENT,
|
||||
data: ["a", 1, {}],
|
||||
id: 1,
|
||||
nsp: '/test'
|
||||
nsp: "/test",
|
||||
});
|
||||
});
|
||||
|
||||
it('encodes an ack', function(){
|
||||
helpers.test({
|
||||
type: parser.ACK,
|
||||
data: ['a', 1, {}],
|
||||
it("encodes an ack", () => {
|
||||
return helpers.test({
|
||||
type: PacketType.ACK,
|
||||
data: ["a", 1, {}],
|
||||
id: 123,
|
||||
nsp: '/'
|
||||
nsp: "/",
|
||||
});
|
||||
});
|
||||
|
||||
it('encodes an error', function(){
|
||||
helpers.test({
|
||||
type: parser.ERROR,
|
||||
data: 'Unauthorized',
|
||||
nsp: '/'
|
||||
it("encodes an connect error", () => {
|
||||
return helpers.test({
|
||||
type: PacketType.CONNECT_ERROR,
|
||||
data: "Unauthorized",
|
||||
nsp: "/",
|
||||
});
|
||||
});
|
||||
|
||||
it('properly handles circular objects', function() {
|
||||
var a = {};
|
||||
it("encodes an connect error (with object)", () => {
|
||||
return helpers.test({
|
||||
type: PacketType.CONNECT_ERROR,
|
||||
data: {
|
||||
message: "Unauthorized",
|
||||
},
|
||||
nsp: "/",
|
||||
});
|
||||
});
|
||||
|
||||
it("throws an error when encoding circular objects", () => {
|
||||
const a = {};
|
||||
a.b = a;
|
||||
|
||||
var data = {
|
||||
type: parser.EVENT,
|
||||
const data = {
|
||||
type: PacketType.EVENT,
|
||||
data: a,
|
||||
id: 1,
|
||||
nsp: '/'
|
||||
}
|
||||
nsp: "/",
|
||||
};
|
||||
|
||||
var encoder = new parser.Encoder();
|
||||
const encoder = new Encoder();
|
||||
|
||||
encoder.encode(data, function(encodedPackets) {
|
||||
expect(encodedPackets[0]).to.be('4"encode error"');
|
||||
});
|
||||
expect(() => encoder.encode(data)).to.throwException();
|
||||
});
|
||||
|
||||
it('decodes a bad binary packet', function(){
|
||||
it("decodes a bad binary packet", () => {
|
||||
try {
|
||||
var decoder = new parser.Decoder();
|
||||
decoder.add('5');
|
||||
} catch(e){
|
||||
const decoder = new Decoder();
|
||||
decoder.add("5");
|
||||
} catch (e) {
|
||||
expect(e.message).to.match(/Illegal/);
|
||||
}
|
||||
});
|
||||
|
||||
it('returns an error packet on parsing error', function(done){
|
||||
var decoder = new parser.Decoder();
|
||||
decoder.on('decoded', function(packet) {
|
||||
expect(packet).to.eql({ type: 4, data: 'parser error: invalid payload' });
|
||||
done();
|
||||
it("throw an error upon parsing error", () => {
|
||||
const isInvalidPayload = (str) =>
|
||||
expect(() => new Decoder().add(str)).to.throwException(
|
||||
/^invalid payload$/
|
||||
);
|
||||
|
||||
isInvalidPayload('442["some","data"');
|
||||
isInvalidPayload('0/admin,"invalid"');
|
||||
isInvalidPayload("0[]");
|
||||
isInvalidPayload("1/admin,{}");
|
||||
isInvalidPayload('2/admin,"invalid');
|
||||
isInvalidPayload("2/admin,{}");
|
||||
isInvalidPayload('2[{"toString":"foo"}]');
|
||||
isInvalidPayload('2[true,"foo"]');
|
||||
isInvalidPayload('2[null,"bar"]');
|
||||
isInvalidPayload('2["connect"]');
|
||||
isInvalidPayload('2["disconnect","123"]');
|
||||
|
||||
expect(() => new Decoder().add("999")).to.throwException(
|
||||
/^unknown packet type 9$/
|
||||
);
|
||||
|
||||
expect(() => new Decoder().add(999)).to.throwException(
|
||||
/^Unknown type: 999$/
|
||||
);
|
||||
});
|
||||
|
||||
it("should resume decoding after calling destroy()", () => {
|
||||
return new Promise((resolve) => {
|
||||
const decoder = new Decoder();
|
||||
|
||||
decoder.on("decoded", (packet) => {
|
||||
expect(packet.data).to.eql(["hello"]);
|
||||
resolve();
|
||||
});
|
||||
|
||||
decoder.add('51-["hello"]');
|
||||
decoder.destroy();
|
||||
decoder.add('2["hello"]');
|
||||
});
|
||||
decoder.add('442["some","data"');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
// we only do this in our tests because we need to test engine.io-client
|
||||
// support in browsers and in node.js
|
||||
// some tests do not yet work in both
|
||||
module.exports.browser = typeof window !== 'undefined';
|
||||
module.exports.browser = typeof window !== "undefined";
|
||||
|
||||
12
tsconfig.esm.json
Normal file
12
tsconfig.esm.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "build/esm/",
|
||||
"target": "es2018",
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"declaration": true
|
||||
},
|
||||
"include": [
|
||||
"./lib/**/*"
|
||||
]
|
||||
}
|
||||
11
tsconfig.json
Normal file
11
tsconfig.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "build/cjs/",
|
||||
"target": "es2018", // Node.js 10 (https://github.com/microsoft/TypeScript/wiki/Node-Target-Mapping)
|
||||
"module": "commonjs",
|
||||
"declaration": true
|
||||
},
|
||||
"include": [
|
||||
"./lib/**/*"
|
||||
]
|
||||
}
|
||||
94
wdio.conf.js
Normal file
94
wdio.conf.js
Normal file
@@ -0,0 +1,94 @@
|
||||
const BASE_SAUCE_OPTIONS = {
|
||||
build: process.env.GITHUB_RUN_ID || "local",
|
||||
name: "socket.io-parser",
|
||||
};
|
||||
|
||||
const config = {
|
||||
specs: ["./test/index.js"],
|
||||
|
||||
capabilities: [
|
||||
{
|
||||
browserName: "chrome",
|
||||
},
|
||||
],
|
||||
|
||||
maxInstances: 5,
|
||||
logLevel: "warn",
|
||||
bail: 0,
|
||||
baseUrl: "http://localhost",
|
||||
|
||||
reporters: ["spec"],
|
||||
framework: "mocha",
|
||||
mochaOpts: {
|
||||
ui: "bdd",
|
||||
timeout: 60000,
|
||||
},
|
||||
};
|
||||
|
||||
if (process.env.CI === "true") {
|
||||
config.services = ["sauce"];
|
||||
config.user = process.env.SAUCE_USERNAME;
|
||||
config.key = process.env.SAUCE_ACCESS_KEY;
|
||||
|
||||
// https://saucelabs.com/platform/platform-configurator#/
|
||||
config.capabilities = [
|
||||
{
|
||||
browserName: "chrome",
|
||||
browserVersion: "latest",
|
||||
platformName: "Windows 11",
|
||||
"sauce:options": BASE_SAUCE_OPTIONS,
|
||||
},
|
||||
{
|
||||
browserName: "MicrosoftEdge",
|
||||
browserVersion: "latest",
|
||||
platformName: "Windows 11",
|
||||
"sauce:options": BASE_SAUCE_OPTIONS,
|
||||
},
|
||||
{
|
||||
browserName: "firefox",
|
||||
browserVersion: "latest",
|
||||
platformName: "Windows 11",
|
||||
"sauce:options": BASE_SAUCE_OPTIONS,
|
||||
},
|
||||
{
|
||||
browserName: "internet explorer",
|
||||
browserVersion: "10",
|
||||
platformName: "Windows 7",
|
||||
"sauce:options": BASE_SAUCE_OPTIONS,
|
||||
},
|
||||
{
|
||||
browserName: "safari",
|
||||
browserVersion: "latest",
|
||||
platformName: "macOS 12",
|
||||
"sauce:options": BASE_SAUCE_OPTIONS,
|
||||
},
|
||||
{
|
||||
platformName: "Android",
|
||||
browserName: "Chrome",
|
||||
"appium:deviceName": "Android GoogleAPI Emulator",
|
||||
"appium:platformVersion": "latest",
|
||||
"appium:automationName": "UiAutomator2",
|
||||
"sauce:options": Object.assign(
|
||||
{
|
||||
appiumVersion: "1.22.1",
|
||||
},
|
||||
BASE_SAUCE_OPTIONS
|
||||
),
|
||||
},
|
||||
{
|
||||
platformName: "iOS",
|
||||
browserName: "Safari",
|
||||
"appium:deviceName": "iPhone Simulator",
|
||||
"appium:platformVersion": "latest",
|
||||
"appium:automationName": "XCUITest",
|
||||
"sauce:options": Object.assign(
|
||||
{
|
||||
appiumVersion: "2.0.0",
|
||||
},
|
||||
BASE_SAUCE_OPTIONS
|
||||
),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
exports.config = config;
|
||||
@@ -1,29 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var browsers = require('socket.io-browsers');
|
||||
|
||||
var zuulConfig = module.exports = {
|
||||
ui: 'mocha-bdd',
|
||||
|
||||
// test on localhost by default
|
||||
local: true,
|
||||
|
||||
concurrency: 2, // ngrok only accepts two tunnels by default
|
||||
// if browser does not sends output in 120s since last output:
|
||||
// stop testing, something is wrong
|
||||
browser_output_timeout: 120 * 1000,
|
||||
browser_open_timeout: 60 * 4 * 1000,
|
||||
// we want to be notified something is wrong asap, so no retry
|
||||
browser_retries: 1
|
||||
};
|
||||
|
||||
if (process.env.CI === 'true') {
|
||||
zuulConfig.local = false;
|
||||
zuulConfig.tunnel = {
|
||||
type: 'ngrok',
|
||||
bind_tls: true
|
||||
};
|
||||
}
|
||||
|
||||
var isPullRequest = process.env.TRAVIS_PULL_REQUEST && process.env.TRAVIS_PULL_REQUEST !== 'false';
|
||||
zuulConfig.browsers = isPullRequest ? browsers.pullRequest : browsers.all;
|
||||
Reference in New Issue
Block a user