1.4.x_branch #1

Merged
sgraves merged 3 commits from 1.4.x_branch into master 2024-07-19 08:03:13 -05:00
24 changed files with 2747 additions and 2740 deletions

14
.gitignore vendored
View File

@@ -1,7 +1,7 @@
node_modules/
coverage/
.vscode/
dist/
backup/
.idea/
/package-lock.json
node_modules/
coverage/
.vscode/
dist/
backup/
.idea/
/package-lock.json

View File

@@ -1,3 +1,3 @@
set path+=.,src/**
let &makeprg="npm run build"
set path+=.,src/**
let &makeprg="npm run build"

View File

@@ -1,8 +1,8 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"jsxBracketSameLine": true
}
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"jsxBracketSameLine": true
}

5
.vim/coc-settings.json Normal file
View File

@@ -0,0 +1,5 @@
{
"cSpell.words": [
"winfsp"
]
}

View File

@@ -1,14 +1,14 @@
# Changelog
## 1.4.0-r1
- Switched packet encryption to XChaCha20-Poly1305
- Allow external XChaCha20-Poly1305 encryption/decryption
- Support writing base64 string data
- Renamed 'delete/delete_file' to 'remove/remove_file'
## 1.3.1-r3
- Added directory/file exists
- Fix unit tests
## 1.3.1-r2
- Initial release
# Changelog
## 1.4.0-r1
- Switched packet encryption to XChaCha20-Poly1305
- Allow external XChaCha20-Poly1305 encryption/decryption
- Support writing base64 string data
- Renamed 'delete/delete_file' to 'remove/remove_file'
## 1.3.1-r3
- Added directory/file exists
- Fix unit tests
## 1.3.1-r2
- Initial release

View File

@@ -1,18 +1,18 @@
# `repertory-js` MIT License
### Copyright <2021> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# `repertory-js` MIT License
### Copyright <2021> <scott.e.graves@protonmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

394
README.md
View File

@@ -1,197 +1,197 @@
# About
`repertory-js` is a Node.js module for interfacing with `repertory's` remote mount API.
## Installing
```shell
npm i @blockstorage/repertory-js
```
## Repertory Configuration
A Repertory mount must be active with the `EnableRemoteMount` setting enabled. `RemoteToken` should
also be set to a strong, random password.
### Enabling Sia Remote Mount API on Windows Systems
```shell
repertory.exe -unmount
repertory.exe -set RemoteMount.EnableRemoteMount true
repertory.exe -set RemoteMount.RemoteToken "my password"
[Optional - change listening port]
repertory.exe -set RemoteMount.RemotePort 20202
```
### Enabling Sia Remote Mount API on *NIX Systems
```shell
./repertory -unmount
./repertory -set RemoteMount.EnableRemoteMount true
./repertory -set RemoteMount.RemoteToken "my password"
[Optional - change listening port]
./repertory -set RemoteMount.RemotePort 20202
```
### Skynet and ScPrime Mounts
* For Skynet mounts, add `-sk` argument to all commands listed above.
* For ScPrime mounts, add `-sp` argument to all commands listed above.
## Module Environment Variables
* To successfully complete unit tests, a `repertory` mount supporting remote mount needs to be
active. Set the following environment variables prior to running tests:
* `TEST_HOST`
* `TEST_PASSWORD`
* `TEST_PORT`
## Example API Usage
```javascript
import * as rep from "@blockstorage/repertory-js";
//const rep = require("@blockstorage/repertory-js");
// Repertory host settings
const MY_HOST_OR_IP = 'localhost';
const MY_PORT = 20000;
const MY_TOKEN = 'password';
// Progress callback for uploads / downloads
const progress_cb = (local_path, remote_path, progress, completed) => {
console.log(local_path, remote_path, progress, completed);
};
//************************************************************************************************//
// Step 1. Create a connection pool (recommended) //
//************************************************************************************************//
const conn = await rep.create_pool(8, MY_HOST_OR_IP, MY_PORT, MY_TOKEN);
/* Or create a single connection for light operations
const conn = await rep.connect(MY_HOST_OR_IP, MY_PORT, MY_TOKEN);
*/
/* Disconnect when complete
await conn.disconnect();
*/
//************************************************************************************************//
// Step 2. Create an 'api' instance using the connection pool / connection //
//************************************************************************************************//
const api = rep.create_api(conn);
//************************************************************************************************//
// Step 3. Use 'api' //
//************************************************************************************************//
//------------------------------------------------------------------------------------------------//
// *********** Directory Operations *********** //
//------------------------------------------------------------------------------------------------//
// Check if directory exists
const exists = await api.directory.exists('/my_directory');
// List directory contents
await api.directory.list('/', async (remote_path, page_count, get_page) => {
for (let i = 0; i < page_count; i++) {
const items = await get_page(i); // Always 'await'
console.log(items);
}
});
// Asynchronous directory list
const snap = await api.directory.snapshot('/');
try {
for (let i = 0; i < snap.page_count; i++) {
const items = await snap.get_page(i); // Always 'await'
console.log(items);
}
} catch (err) {
console.log(err);
} finally {
await snap.release();
}
// Create new directory
await api.directory.create('/test');
// Remove existing directory
await api.directory.remove('/test')
//------------------------------------------------------------------------------------------------//
// *********** File Operations *********** //
//------------------------------------------------------------------------------------------------//
// Check if file exists
const exists = await api.file.exists('/my_file.txt')
// Remove a file
await api.file.remove('/my_file.txt')
// Download a remote file
await api.file.download('/my_file.txt', 'C:\\my_file.txt', progress_cb);
// Download a remote file and overwrite existing local file
await api.file.download('/my_file.txt', 'C:\\my_file.txt', progress_cb, true);
// Resume failed download
await api.file.download('/my_file.txt', 'C:\\my_file.txt', progress_cb, false, true);
// Upload a local file
await api.file.upload('C:\\my_file.txt', '/my_file.txt', progress_cb);
// Upload a local file and overwrite existing remote file
await api.file.upload('C:\\my_file.txt', '/my_file.txt', progress_cb, true);
// Resume failed upload
await api.file.upload('C:\\my_file.txt', '/my_file.txt', progress_cb, false, true);
//------------------------------------------------------------------------------------------------//
// *********** Low-Level File Operations *********** //
//------------------------------------------------------------------------------------------------//
// Create or open a remote file
{
const f = await api.file.create_or_open('/my_file.txt');
await f.close();
}
// Open an existing remote file
{
const f = await api.file.open('/my_file.txt');
await f.close();
}
// Write to a file
{
const f = await api.file.create_or_open('/my_file.txt');
const b = Buffer.alloc(1);
b[0] = 1;
await f.write(0, b); // write '1' byte at file offset '0'
await f.close();
}
// Read from a file
{
const f = await api.file.create_or_open('/my_file.txt');
const b = await f.read(0, 1); // read '1' byte from file offset '0'
await f.close();
}
// Truncate / resize file
{
const f = await api.file.create_or_open('/my_file.txt');
await f.truncate(10);
await f.close();
}
```
# About
`repertory-js` is a Node.js module for interfacing with `repertory's` remote mount API.
## Installing
```shell
npm i @blockstorage/repertory-js
```
## Repertory Configuration
A Repertory mount must be active with the `EnableRemoteMount` setting enabled. `RemoteToken` should
also be set to a strong, random password.
### Enabling Sia Remote Mount API on Windows Systems
```shell
repertory.exe -unmount
repertory.exe -set RemoteMount.EnableRemoteMount true
repertory.exe -set RemoteMount.RemoteToken "my password"
[Optional - change listening port]
repertory.exe -set RemoteMount.RemotePort 20202
```
### Enabling Sia Remote Mount API on *NIX Systems
```shell
./repertory -unmount
./repertory -set RemoteMount.EnableRemoteMount true
./repertory -set RemoteMount.RemoteToken "my password"
[Optional - change listening port]
./repertory -set RemoteMount.RemotePort 20202
```
### Skynet and ScPrime Mounts
* For Skynet mounts, add `-sk` argument to all commands listed above.
* For ScPrime mounts, add `-sp` argument to all commands listed above.
## Module Environment Variables
* To successfully complete unit tests, a `repertory` mount supporting remote mount needs to be
active. Set the following environment variables prior to running tests:
* `TEST_HOST`
* `TEST_PASSWORD`
* `TEST_PORT`
## Example API Usage
```javascript
import * as rep from "@blockstorage/repertory-js";
//const rep = require("@blockstorage/repertory-js");
// Repertory host settings
const MY_HOST_OR_IP = 'localhost';
const MY_PORT = 20000;
const MY_TOKEN = 'password';
// Progress callback for uploads / downloads
const progress_cb = (local_path, remote_path, progress, completed) => {
console.log(local_path, remote_path, progress, completed);
};
//************************************************************************************************//
// Step 1. Create a connection pool (recommended) //
//************************************************************************************************//
const conn = await rep.create_pool(8, MY_HOST_OR_IP, MY_PORT, MY_TOKEN);
/* Or create a single connection for light operations
const conn = await rep.connect(MY_HOST_OR_IP, MY_PORT, MY_TOKEN);
*/
/* Disconnect when complete
await conn.disconnect();
*/
//************************************************************************************************//
// Step 2. Create an 'api' instance using the connection pool / connection //
//************************************************************************************************//
const api = rep.create_api(conn);
//************************************************************************************************//
// Step 3. Use 'api' //
//************************************************************************************************//
//------------------------------------------------------------------------------------------------//
// *********** Directory Operations *********** //
//------------------------------------------------------------------------------------------------//
// Check if directory exists
const exists = await api.directory.exists('/my_directory');
// List directory contents
await api.directory.list('/', async (remote_path, page_count, get_page) => {
for (let i = 0; i < page_count; i++) {
const items = await get_page(i); // Always 'await'
console.log(items);
}
});
// Asynchronous directory list
const snap = await api.directory.snapshot('/');
try {
for (let i = 0; i < snap.page_count; i++) {
const items = await snap.get_page(i); // Always 'await'
console.log(items);
}
} catch (err) {
console.log(err);
} finally {
await snap.release();
}
// Create new directory
await api.directory.create('/test');
// Remove existing directory
await api.directory.remove('/test')
//------------------------------------------------------------------------------------------------//
// *********** File Operations *********** //
//------------------------------------------------------------------------------------------------//
// Check if file exists
const exists = await api.file.exists('/my_file.txt')
// Remove a file
await api.file.remove('/my_file.txt')
// Download a remote file
await api.file.download('/my_file.txt', 'C:\\my_file.txt', progress_cb);
// Download a remote file and overwrite existing local file
await api.file.download('/my_file.txt', 'C:\\my_file.txt', progress_cb, true);
// Resume failed download
await api.file.download('/my_file.txt', 'C:\\my_file.txt', progress_cb, false, true);
// Upload a local file
await api.file.upload('C:\\my_file.txt', '/my_file.txt', progress_cb);
// Upload a local file and overwrite existing remote file
await api.file.upload('C:\\my_file.txt', '/my_file.txt', progress_cb, true);
// Resume failed upload
await api.file.upload('C:\\my_file.txt', '/my_file.txt', progress_cb, false, true);
//------------------------------------------------------------------------------------------------//
// *********** Low-Level File Operations *********** //
//------------------------------------------------------------------------------------------------//
// Create or open a remote file
{
const f = await api.file.create_or_open('/my_file.txt');
await f.close();
}
// Open an existing remote file
{
const f = await api.file.open('/my_file.txt');
await f.close();
}
// Write to a file
{
const f = await api.file.create_or_open('/my_file.txt');
const b = Buffer.alloc(1);
b[0] = 1;
await f.write(0, b); // write '1' byte at file offset '0'
await f.close();
}
// Read from a file
{
const f = await api.file.create_or_open('/my_file.txt');
const b = await f.read(0, 1); // read '1' byte from file offset '0'
await f.close();
}
// Truncate / resize file
{
const f = await api.file.create_or_open('/my_file.txt');
await f.truncate(10);
await f.close();
}
```

22
fixup
View File

@@ -1,11 +1,11 @@
cat <<EOF >dist/cjs/package.json
{
"type": "commonjs"
}
EOF
cat <<EOF >dist/mjs/package.json
{
"type": "module"
}
EOF
cat <<EOF >dist/cjs/package.json
{
"type": "commonjs"
}
EOF
cat <<EOF >dist/mjs/package.json
{
"type": "module"
}
EOF

View File

@@ -1,69 +1,69 @@
{
"name": "@blockstorage/repertory-js",
"version": "1.4.0-r1",
"description": "A Node.js module for interfacing with Repertory's remote mount API",
"author": "scott.e.graves@protonmail.com",
"license": "MIT",
"homepage": "https://bitbucket.org/blockstorage/repertory-js",
"repository": {
"type": "git",
"url": "https://bitbucket.org/blockstorage/repertory-js.git"
},
"keywords": [
"repertory",
"repertory-ui",
"library",
"mount",
"fuse",
"winfsp",
"blockchain",
"decentralized",
"cloud",
"storage",
"altcoin",
"cryptocurrency"
],
"main": "dist/cjs/index.js",
"module": "dist/mjs/index.js",
"exports": {
".": {
"import": "./dist/mjs/index.js",
"require": "./dist/cjs/index.js"
}
},
"files": [
"dist/cjs",
"dist/mjs"
],
"scripts": {
"build": "rollup -c && ./fixup",
"test": "jest",
"prepublish": "rollup -c --silent && ./fixup"
},
"dependencies": {
"@stablelib/xchacha20poly1305": "^1.0.1",
"int64-buffer": "^1.0.0",
"socket-pool": "^1.2.3",
"text-encoding": "^0.7.0",
"uuid": "^8.3.2"
},
"devDependencies": {
"@babel/core": "^7.14.3",
"@babel/plugin-proposal-class-properties": "^7.13.0",
"@babel/plugin-proposal-private-methods": "^7.13.0",
"@babel/plugin-transform-async-to-generator": "^7.13.0",
"@babel/plugin-transform-regenerator": "^7.13.15",
"@babel/plugin-transform-runtime": "^7.14.3",
"@babel/preset-env": "^7.14.2",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-commonjs": "^15.1.0",
"@rollup/plugin-json": "^4.0.0",
"@rollup/plugin-node-resolve": "^9.0.0",
"@types/jest": "^26.0.23",
"babel-eslint": "^10.1.0",
"jest": "^26.6.3",
"rollup": "^2.50.0",
"rollup-plugin-eslint": "^7.0.0",
"rollup-plugin-terser": "^7.0.2"
}
}
{
"name": "@blockstorage/repertory-js",
"version": "2.0.0-r1",
"description": "A Node.js module for interfacing with Repertory's remote mount API",
"author": "scott.e.graves@protonmail.com",
"license": "MIT",
"homepage": "https://bitbucket.org/blockstorage/repertory-js",
"repository": {
"type": "git",
"url": "https://bitbucket.org/blockstorage/repertory-js.git"
},
"keywords": [
"repertory",
"repertory-ui",
"library",
"mount",
"fuse",
"winfsp",
"blockchain",
"decentralized",
"cloud",
"storage",
"altcoin",
"cryptocurrency"
],
"main": "dist/cjs/index.js",
"module": "dist/mjs/index.js",
"exports": {
".": {
"import": "./dist/mjs/index.js",
"require": "./dist/cjs/index.js"
}
},
"files": [
"dist/cjs",
"dist/mjs"
],
"scripts": {
"build": "rollup -c && ./fixup",
"test": "jest",
"prepublish": "rollup -c --silent && ./fixup"
},
"dependencies": {
"@stablelib/xchacha20poly1305": "^1.0.1",
"int64-buffer": "^1.0.0",
"socket-pool": "^1.2.3",
"text-encoding": "^0.7.0",
"uuid": "^8.3.2"
},
"devDependencies": {
"@babel/core": "^7.14.3",
"@babel/plugin-proposal-class-properties": "^7.13.0",
"@babel/plugin-proposal-private-methods": "^7.13.0",
"@babel/plugin-transform-async-to-generator": "^7.13.0",
"@babel/plugin-transform-regenerator": "^7.13.15",
"@babel/plugin-transform-runtime": "^7.14.3",
"@babel/preset-env": "^7.14.2",
"@rollup/plugin-babel": "^5.3.0",
"@rollup/plugin-commonjs": "^15.1.0",
"@rollup/plugin-json": "^4.0.0",
"@rollup/plugin-node-resolve": "^9.0.0",
"@types/jest": "^26.0.23",
"babel-eslint": "^10.1.0",
"jest": "^26.6.3",
"rollup": "^2.50.0",
"rollup-plugin-eslint": "^7.0.0",
"rollup-plugin-terser": "^7.0.2"
}
}

View File

@@ -1,60 +1,60 @@
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import babel from '@rollup/plugin-babel';
import { terser } from 'rollup-plugin-terser';
import json from '@rollup/plugin-json';
const commonConfig = {
input: 'src/index.js',
output: {
name: 'index',
sourcemap: true,
},
plugins: [
resolve({
customResolveOptions: {
moduleDirectory: 'node_modules',
},
}),
babel({
exclude: 'node_modules/**',
babelHelpers: 'runtime',
}),
commonjs(),
json(),
],
};
// ESM config
const esmConfig = Object.assign({}, commonConfig);
esmConfig.output = Object.assign({}, commonConfig.output, {
file: 'dist/mjs/index.js',
format: 'esm',
});
// ESM prod config
const esmProdConfig = Object.assign({}, esmConfig);
esmProdConfig.output = Object.assign({}, esmConfig.output, {
file: 'dist/mjs/index.min.js',
sourcemap: false,
});
esmProdConfig.plugins = [...esmConfig.plugins, terser()];
// CJS config
const cjsConfig = Object.assign({}, commonConfig);
cjsConfig.output = Object.assign({}, commonConfig.output, {
file: 'dist/cjs/index.js',
format: 'cjs',
});
// CJS prod config
const cjsProdConfig = Object.assign({}, cjsConfig);
cjsProdConfig.output = Object.assign({}, cjsConfig.output, {
file: 'dist/cjs/index.min.js',
sourcemap: false,
});
cjsProdConfig.plugins = [...cjsConfig.plugins, terser()];
let configurations = [];
configurations.push(esmConfig, esmProdConfig, cjsConfig, cjsProdConfig);
export default configurations;
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import babel from '@rollup/plugin-babel';
import { terser } from 'rollup-plugin-terser';
import json from '@rollup/plugin-json';
const commonConfig = {
input: 'src/index.js',
output: {
name: 'index',
sourcemap: true,
},
plugins: [
resolve({
customResolveOptions: {
moduleDirectory: 'node_modules',
},
}),
babel({
exclude: 'node_modules/**',
babelHelpers: 'runtime',
}),
commonjs(),
json(),
],
};
// ESM config
const esmConfig = Object.assign({}, commonConfig);
esmConfig.output = Object.assign({}, commonConfig.output, {
file: 'dist/mjs/index.js',
format: 'esm',
});
// ESM prod config
const esmProdConfig = Object.assign({}, esmConfig);
esmProdConfig.output = Object.assign({}, esmConfig.output, {
file: 'dist/mjs/index.min.js',
sourcemap: false,
});
esmProdConfig.plugins = [...esmConfig.plugins, terser()];
// CJS config
const cjsConfig = Object.assign({}, commonConfig);
cjsConfig.output = Object.assign({}, commonConfig.output, {
file: 'dist/cjs/index.js',
format: 'cjs',
});
// CJS prod config
const cjsProdConfig = Object.assign({}, cjsConfig);
cjsProdConfig.output = Object.assign({}, cjsConfig.output, {
file: 'dist/cjs/index.min.js',
sourcemap: false,
});
cjsProdConfig.plugins = [...cjsConfig.plugins, terser()];
let configurations = [];
configurations.push(esmConfig, esmProdConfig, cjsConfig, cjsProdConfig);
export default configurations;

View File

@@ -1,115 +1,115 @@
import connection from '../networking/connection';
import packet from '../networking/packet';
import Socket from 'net';
test(`connect fails when error occurs during createConnection`, async () => {
const mock_create = (port, host, cb) => {
cb(new Error('mock create error'));
};
jest.spyOn(Socket, 'createConnection').mockImplementation(mock_create);
const conn = new connection('localhost', 20000);
await expect(conn.connect()).rejects.toThrow(Error);
});
test(`socket receive data fails when decryption fails`, async () => {
let cbl = {};
const socket = {
setNoDelay: () => {},
setKeepAlive: () => {},
on: (name, cb) => {
cbl[name] = cb;
},
};
const conn = new connection('', 0, 'b', socket);
let reject;
const mock_reject = jest.fn().mockImplementation((e) => reject(e));
conn.reject = mock_reject;
conn.resolve = jest.fn();
const p = new packet('a');
await p.encrypt();
p.encode_top_ui32(p.buffer.length);
await expect(
new Promise((_, r) => {
reject = r;
cbl['data'](Buffer.from(p.buffer));
})
).rejects.toThrow(Error);
expect(mock_reject.mock.calls.length).toBe(1);
});
test(`disconnect succeeds if an error is thrown`, async () => {
const socket = {
setNoDelay: () => {},
setKeepAlive: () => {},
destroy: () => {
throw new Error('mock destroy error');
},
on: () => {},
};
const conn = new connection('', 0, 'b', socket);
await conn.disconnect();
});
test(`send fails on socket error`, async () => {
let cbl = {};
const socket = {
setNoDelay: () => {},
setKeepAlive: () => {},
on: (name, cb) => {
cbl[name] = cb;
},
};
const conn = new connection('', 0, 'b', socket);
const mock_reject = jest.fn();
conn.reject = mock_reject;
conn.resolve = jest.fn();
cbl['error']('socket error');
expect(mock_reject).toBeCalled();
});
test(`error is thrown when socket is closed`, async () => {
let cbl = {};
const socket = {
setNoDelay: () => {},
setKeepAlive: () => {},
on: (name, cb) => {
cbl[name] = cb;
},
};
const conn = new connection('', 0, 'b', socket);
const mock_reject = jest.fn();
conn.reject = mock_reject;
conn.resolve = jest.fn();
cbl['close']();
expect(mock_reject).toBeCalled();
});
test(`send fails when write error occurs`, async () => {
let cbl = {};
const socket = {
setNoDelay: () => {},
setKeepAlive: () => {},
on: (name, cb) => {
cbl[name] = cb;
},
write: (b, c, cb) => {
cb('mock write error');
},
};
const conn = new connection('', 0, 'b', socket);
try {
await conn.send('c', new packet('b'));
expect('send should fail').toBeNull();
} catch (err) {
expect(err).toBeDefined();
}
});
import connection from '../networking/connection';
import packet from '../networking/packet';
import Socket from 'net';
test(`connect fails when error occurs during createConnection`, async () => {
const mock_create = (port, host, cb) => {
cb(new Error('mock create error'));
};
jest.spyOn(Socket, 'createConnection').mockImplementation(mock_create);
const conn = new connection('localhost', 20000);
await expect(conn.connect()).rejects.toThrow(Error);
});
test(`socket receive data fails when decryption fails`, async () => {
let cbl = {};
const socket = {
setNoDelay: () => {},
setKeepAlive: () => {},
on: (name, cb) => {
cbl[name] = cb;
},
};
const conn = new connection('', 0, 'b', socket);
let reject;
const mock_reject = jest.fn().mockImplementation((e) => reject(e));
conn.reject = mock_reject;
conn.resolve = jest.fn();
const p = new packet('a');
await p.encrypt();
p.encode_top_ui32(p.buffer.length);
await expect(
new Promise((_, r) => {
reject = r;
cbl['data'](Buffer.from(p.buffer));
})
).rejects.toThrow(Error);
expect(mock_reject.mock.calls.length).toBe(1);
});
test(`disconnect succeeds if an error is thrown`, async () => {
const socket = {
setNoDelay: () => {},
setKeepAlive: () => {},
destroy: () => {
throw new Error('mock destroy error');
},
on: () => {},
};
const conn = new connection('', 0, 'b', socket);
await conn.disconnect();
});
test(`send fails on socket error`, async () => {
let cbl = {};
const socket = {
setNoDelay: () => {},
setKeepAlive: () => {},
on: (name, cb) => {
cbl[name] = cb;
},
};
const conn = new connection('', 0, 'b', socket);
const mock_reject = jest.fn();
conn.reject = mock_reject;
conn.resolve = jest.fn();
cbl['error']('socket error');
expect(mock_reject).toBeCalled();
});
test(`error is thrown when socket is closed`, async () => {
let cbl = {};
const socket = {
setNoDelay: () => {},
setKeepAlive: () => {},
on: (name, cb) => {
cbl[name] = cb;
},
};
const conn = new connection('', 0, 'b', socket);
const mock_reject = jest.fn();
conn.reject = mock_reject;
conn.resolve = jest.fn();
cbl['close']();
expect(mock_reject).toBeCalled();
});
test(`send fails when write error occurs`, async () => {
let cbl = {};
const socket = {
setNoDelay: () => {},
setKeepAlive: () => {},
on: (name, cb) => {
cbl[name] = cb;
},
write: (b, c, cb) => {
cb('mock write error');
},
};
const conn = new connection('', 0, 'b', socket);
try {
await conn.send('c', new packet('b'));
expect('send should fail').toBeNull();
} catch (err) {
expect(err).toBeDefined();
}
});

View File

@@ -1,59 +1,59 @@
import connection_pool from '../networking/connection_pool';
import packet from '../networking/packet';
import connection from '../networking/connection';
jest.mock('../networking/connection');
test(`construction fails if pool size is <= 1`, () => {
expect(() => new connection_pool(1)).toThrow(Error);
expect(() => new connection_pool(0)).toThrow(Error);
expect(() => new connection_pool(-1)).toThrow(Error);
});
test(`error on socket release is ignored`, async () => {
const conn = new connection_pool(2, '', 20000);
let invoked = false;
jest.spyOn(conn.pool, 'acquire').mockImplementation(() => {
return {
release: () => {
invoked = true;
throw new Error('mock release error');
},
};
});
const mock_send = jest.fn();
connection.prototype.send = async () => {
return mock_send();
};
mock_send.mockResolvedValue(0);
expect(await conn.send('', new packet())).toEqual(0);
expect(invoked).toBeTruthy();
});
test(`connection pool send fails if socket acquire fails`, async () => {
const conn = new connection_pool(2, '', 20000);
jest.spyOn(conn.pool, 'acquire').mockImplementation(() => {
throw new Error('mock acquire exception');
});
await expect(conn.send('', new packet())).rejects.toThrow(Error);
});
test(`connection pool send fails when connection send fails`, async () => {
const conn = new connection_pool(2, '', 20000);
jest.spyOn(conn.pool, 'acquire').mockImplementation(() => {
return {
release: () => {},
};
});
const mock_send = jest.fn();
connection.prototype.send = async () => {
return mock_send();
};
mock_send.mockRejectedValue(new Error('mock send failed'));
await expect(conn.send('', new packet())).rejects.toThrow(Error);
});
import connection_pool from '../networking/connection_pool';
import packet from '../networking/packet';
import connection from '../networking/connection';
jest.mock('../networking/connection');
test(`construction fails if pool size is <= 1`, () => {
expect(() => new connection_pool(1)).toThrow(Error);
expect(() => new connection_pool(0)).toThrow(Error);
expect(() => new connection_pool(-1)).toThrow(Error);
});
test(`error on socket release is ignored`, async () => {
const conn = new connection_pool(2, '', 20000);
let invoked = false;
jest.spyOn(conn.pool, 'acquire').mockImplementation(() => {
return {
release: () => {
invoked = true;
throw new Error('mock release error');
},
};
});
const mock_send = jest.fn();
connection.prototype.send = async () => {
return mock_send();
};
mock_send.mockResolvedValue(0);
expect(await conn.send('', new packet())).toEqual(0);
expect(invoked).toBeTruthy();
});
test(`connection pool send fails if socket acquire fails`, async () => {
const conn = new connection_pool(2, '', 20000);
jest.spyOn(conn.pool, 'acquire').mockImplementation(() => {
throw new Error('mock acquire exception');
});
await expect(conn.send('', new packet())).rejects.toThrow(Error);
});
test(`connection pool send fails when connection send fails`, async () => {
const conn = new connection_pool(2, '', 20000);
jest.spyOn(conn.pool, 'acquire').mockImplementation(() => {
return {
release: () => {},
};
});
const mock_send = jest.fn();
connection.prototype.send = async () => {
return mock_send();
};
mock_send.mockRejectedValue(new Error('mock send failed'));
await expect(conn.send('', new packet())).rejects.toThrow(Error);
});

View File

@@ -1,18 +1,18 @@
import { get_version, instance_id, package_json } from '../utils/constants';
import * as uuid from 'uuid';
test(`can read 'package.json'`, () => {
console.log(package_json);
expect(package_json).toBeDefined();
});
test(`'instance_id' is valid`, () => {
console.log(instance_id);
expect(instance_id).toBeDefined();
expect(uuid.parse(instance_id)).toBeInstanceOf(Uint8Array);
});
test(`'version' can be read from 'package.json'`, () => {
console.log(get_version());
expect(get_version()).toBe('1.4.0-r1');
});
import { get_version, instance_id, package_json } from '../utils/constants';
import * as uuid from 'uuid';
test(`can read 'package.json'`, () => {
console.log(package_json);
expect(package_json).toBeDefined();
});
test(`'instance_id' is valid`, () => {
console.log(instance_id);
expect(instance_id).toBeDefined();
expect(uuid.parse(instance_id)).toBeInstanceOf(Uint8Array);
});
test(`'version' can be read from 'package.json'`, () => {
console.log(get_version());
expect(get_version()).toBe('1.4.0-r1');
});

View File

@@ -1,47 +1,47 @@
import file from '../io/file';
jest.mock('../ops/index.js', () => ({
...jest.requireActual('../ops/index.js'),
close_file: jest.fn(),
}));
import { close_file } from '../ops/index';
test(`can close a closed file`, async () => {
const f = new file();
expect(await f.close()).toEqual(0);
});
test(`'get_size' fails on closed file`, async () => {
const f = new file();
await expect(f.get_size()).rejects.toThrow(Error);
});
test(`'read' fails on closed file`, async () => {
const f = new file();
await expect(f.read(0, 10)).rejects.toThrow(Error);
});
test(`'truncate' fails on closed file`, async () => {
const f = new file();
await expect(f.truncate(0)).rejects.toThrow(Error);
});
test(`'write' fails on closed file`, async () => {
const f = new file();
await expect(f.write(0, Buffer.alloc(2))).rejects.toThrow(Error);
});
test(`handle is set to null on close`, async () => {
const f = new file(null, 1, '/path');
close_file.mockReturnValue(0);
expect(await f.close()).toEqual(0);
expect(f.handle).toBeNull();
});
test(`handle is not changed on close if return is not 0`, async () => {
const f = new file(null, 1, '/path');
close_file.mockReturnValue(1);
expect(await f.close()).toEqual(1);
expect(f.handle).toBe(1);
});
import file from '../io/file';
jest.mock('../ops/index.js', () => ({
...jest.requireActual('../ops/index.js'),
close_file: jest.fn(),
}));
import { close_file } from '../ops/index';
test(`can close a closed file`, async () => {
const f = new file();
expect(await f.close()).toEqual(0);
});
test(`'get_size' fails on closed file`, async () => {
const f = new file();
await expect(f.get_size()).rejects.toThrow(Error);
});
test(`'read' fails on closed file`, async () => {
const f = new file();
await expect(f.read(0, 10)).rejects.toThrow(Error);
});
test(`'truncate' fails on closed file`, async () => {
const f = new file();
await expect(f.truncate(0)).rejects.toThrow(Error);
});
test(`'write' fails on closed file`, async () => {
const f = new file();
await expect(f.write(0, Buffer.alloc(2))).rejects.toThrow(Error);
});
test(`handle is set to null on close`, async () => {
const f = new file(null, 1, '/path');
close_file.mockReturnValue(0);
expect(await f.close()).toEqual(0);
expect(f.handle).toBeNull();
});
test(`handle is not changed on close if return is not 0`, async () => {
const f = new file(null, 1, '/path');
close_file.mockReturnValue(1);
expect(await f.close()).toEqual(1);
expect(f.handle).toBe(1);
});

View File

@@ -1,19 +1,19 @@
import packet from '../networking/packet';
test('can construct a packet', () => {
const p = new packet('my password');
console.log(p);
expect(p.token).toEqual('my password');
expect(p.buffer).toEqual(new Uint8Array(0));
expect(p.decode_offset).toEqual(0);
});
test('can encrypt and decrypt a packet', async () => {
console.log('testing');
const p = new packet('my password');
p.encode_utf8('moose');
await p.encrypt();
await p.decrypt();
const str = p.decode_utf8();
expect(str).toEqual('moose');
});
import packet from '../networking/packet';
test('can construct a packet', () => {
const p = new packet('my password');
console.log(p);
expect(p.token).toEqual('my password');
expect(p.buffer).toEqual(new Uint8Array(0));
expect(p.decode_offset).toEqual(0);
});
test('can encrypt and decrypt a packet', async () => {
console.log('testing');
const p = new packet('my password');
p.encode_utf8('moose');
await p.encrypt();
await p.decrypt();
const str = p.decode_utf8();
expect(str).toEqual('moose');
});

File diff suppressed because it is too large Load Diff

View File

@@ -1,94 +1,94 @@
import file from './io/file';
import connection from './networking/connection';
import connection_pool from './networking/connection_pool';
import * as ops from './ops';
export * as byte_order from './utils/byte_order';
export { getCustomEncryption, setCustomEncryption } from './utils/constants';
export { default as packet } from './networking/packet';
export const connect = async (host_or_ip, port, password) => {
const conn = new connection(host_or_ip, port, password);
await conn.connect();
return conn;
};
export const create_api = (conn) => {
return {
directory: {
create: async (remote_path) => ops.create_directory(conn, remote_path),
exists: async (remote_path) => {
try {
const info = await ops.get_file_attributes2(conn, remote_path);
return info.directory;
} catch (e) {
if (e.message.split(':')[1].trim() == '-2') {
return false;
}
throw new Error(e.message);
}
},
list: async (remote_path, page_reader_cb) =>
ops.list_directory(conn, remote_path, page_reader_cb),
remove: async (remote_path) => ops.remove_directory(conn, remote_path),
snapshot: async (remote_path) => {
return ops.snapshot_directory(conn, remote_path);
},
},
file: {
create_or_open: async (remote_path) =>
new file(
conn,
await ops.create_or_open_file(conn, remote_path),
remote_path
),
download: async (
remote_path,
local_path,
progress_cb,
overwrite,
resume
) =>
ops.download_file(
conn,
remote_path,
local_path,
progress_cb,
overwrite,
resume
),
exists: async (remote_path) => {
try {
const info = await ops.get_file_attributes2(conn, remote_path);
return !info.directory;
} catch (e) {
if (e.message.split(':')[1].trim() == '-2') {
return false;
}
throw new Error(e.message);
}
},
open: async (remote_path) =>
new file(conn, await ops.open_file(conn, remote_path), remote_path),
remove: async (remote_path) => ops.remove_file(conn, remote_path),
upload: async (local_path, remote_path, progress_cb, overwrite, resume) =>
ops.upload_file(
conn,
local_path,
remote_path,
progress_cb,
overwrite,
resume
),
},
get_drive_information: async () => ops.get_drive_information(conn),
};
};
export const create_pool = async (pool_size, host_or_ip, port, password) => {
if (pool_size <= 1) {
return connect(host_or_ip, port, password);
}
return new connection_pool(pool_size, host_or_ip, port, password);
};
import file from './io/file';
import connection from './networking/connection';
import connection_pool from './networking/connection_pool';
import * as ops from './ops';
export * as byte_order from './utils/byte_order';
export { getCustomEncryption, setCustomEncryption } from './utils/constants';
export { default as packet } from './networking/packet';
export const connect = async (host_or_ip, port, password) => {
const conn = new connection(host_or_ip, port, password);
await conn.connect();
return conn;
};
export const create_api = (conn) => {
return {
directory: {
create: async (remote_path) => ops.create_directory(conn, remote_path),
exists: async (remote_path) => {
try {
const info = await ops.get_file_attributes2(conn, remote_path);
return info.directory;
} catch (e) {
if (e.message.split(':')[1].trim() == '-2') {
return false;
}
throw new Error(e.message);
}
},
list: async (remote_path, page_reader_cb) =>
ops.list_directory(conn, remote_path, page_reader_cb),
remove: async (remote_path) => ops.remove_directory(conn, remote_path),
snapshot: async (remote_path) => {
return ops.snapshot_directory(conn, remote_path);
},
},
file: {
create_or_open: async (remote_path) =>
new file(
conn,
await ops.create_or_open_file(conn, remote_path),
remote_path
),
download: async (
remote_path,
local_path,
progress_cb,
overwrite,
resume
) =>
ops.download_file(
conn,
remote_path,
local_path,
progress_cb,
overwrite,
resume
),
exists: async (remote_path) => {
try {
const info = await ops.get_file_attributes2(conn, remote_path);
return !info.directory;
} catch (e) {
if (e.message.split(':')[1].trim() == '-2') {
return false;
}
throw new Error(e.message);
}
},
open: async (remote_path) =>
new file(conn, await ops.open_file(conn, remote_path), remote_path),
remove: async (remote_path) => ops.remove_file(conn, remote_path),
upload: async (local_path, remote_path, progress_cb, overwrite, resume) =>
ops.upload_file(
conn,
local_path,
remote_path,
progress_cb,
overwrite,
resume
),
},
get_drive_information: async () => ops.get_drive_information(conn),
};
};
export const create_pool = async (pool_size, host_or_ip, port, password) => {
if (pool_size <= 1) {
return connect(host_or_ip, port, password);
}
return new connection_pool(pool_size, host_or_ip, port, password);
};

View File

@@ -1,108 +1,108 @@
import * as ops from '../ops';
let next_thread_id = 1;
export default class file {
constructor(conn, handle, remote_path) {
this.conn = conn;
this.handle = handle || null;
this.remote_path = remote_path;
this.thread_id = next_thread_id++;
}
conn;
handle = null;
thread_id;
remote_path;
async close() {
if (this.handle !== null) {
const result = await ops.close_file(
this.conn,
this.remote_path,
this.handle,
this.thread_id
);
if (result === 0) {
this.handle = null;
}
return result;
}
return 0;
}
async get_size() {
if (this.handle === null) {
return Promise.reject(new Error("'get_size()' failed: invalid handle"));
}
const attrs = await ops.get_file_attributes(
this.conn,
this.handle,
this.remote_path,
this.thread_id
);
return attrs.size;
}
async read(offset, length) {
if (this.handle === null) {
return Promise.reject(new Error("'read()' failed: invalid handle"));
}
return ops.read_file(
this.conn,
this.handle,
this.remote_path,
offset,
length,
this.thread_id
);
}
async truncate(length) {
if (this.handle === null) {
return Promise.reject(new Error("'truncate()' failed: invalid handle"));
}
return ops.truncate_file(
this.conn,
this.handle,
this.remote_path,
length,
this.thread_id
);
}
async write(offset, buffer) {
if (this.handle === null) {
return Promise.reject(new Error("'write()' failed: invalid handle"));
}
return ops.write_file(
this.conn,
this.handle,
this.remote_path,
offset,
buffer,
this.thread_id
);
}
async write_base64(offset, base64_string) {
if (this.handle === null) {
return Promise.reject(
new Error("'write_base64()' failed: invalid handle")
);
}
return ops.write_base64_file(
this.conn,
this.handle,
this.remote_path,
offset,
base64_string,
this.thread_id
);
}
}
import * as ops from '../ops';
let next_thread_id = 1;
export default class file {
constructor(conn, handle, remote_path) {
this.conn = conn;
this.handle = handle || null;
this.remote_path = remote_path;
this.thread_id = next_thread_id++;
}
conn;
handle = null;
thread_id;
remote_path;
async close() {
if (this.handle !== null) {
const result = await ops.close_file(
this.conn,
this.remote_path,
this.handle,
this.thread_id
);
if (result === 0) {
this.handle = null;
}
return result;
}
return 0;
}
async get_size() {
if (this.handle === null) {
return Promise.reject(new Error("'get_size()' failed: invalid handle"));
}
const attrs = await ops.get_file_attributes(
this.conn,
this.handle,
this.remote_path,
this.thread_id
);
return attrs.size;
}
async read(offset, length) {
if (this.handle === null) {
return Promise.reject(new Error("'read()' failed: invalid handle"));
}
return ops.read_file(
this.conn,
this.handle,
this.remote_path,
offset,
length,
this.thread_id
);
}
async truncate(length) {
if (this.handle === null) {
return Promise.reject(new Error("'truncate()' failed: invalid handle"));
}
return ops.truncate_file(
this.conn,
this.handle,
this.remote_path,
length,
this.thread_id
);
}
async write(offset, buffer) {
if (this.handle === null) {
return Promise.reject(new Error("'write()' failed: invalid handle"));
}
return ops.write_file(
this.conn,
this.handle,
this.remote_path,
offset,
buffer,
this.thread_id
);
}
async write_base64(offset, base64_string) {
if (this.handle === null) {
return Promise.reject(
new Error("'write_base64()' failed: invalid handle")
);
}
return ops.write_base64_file(
this.conn,
this.handle,
this.remote_path,
offset,
base64_string,
this.thread_id
);
}
}

View File

@@ -1,172 +1,177 @@
import Socket from 'net';
import * as constants from '../utils/constants';
import packet from './packet';
export default class connection {
constructor(host_or_ip, port, password, socket) {
this.host_or_ip = host_or_ip;
this.port = port;
this.password = password;
if (socket) {
this.socket = socket;
this.connected = true;
this.setup_socket();
}
}
connected = false;
host_or_ip = '';
password = '';
port = 20000;
reject;
resolve;
socket;
cleanup_handlers() {
this.reject = null;
this.resolve = null;
}
async connect() {
if (!this.socket) {
try {
await new Promise((resolve, reject) => {
this.socket = Socket.createConnection(
this.port,
this.host_or_ip,
(err) => {
if (err) {
console.log(err);
return reject(err);
}
return resolve();
}
);
});
} catch (err) {
return Promise.reject(new Error(`'connect()' failed: ${err}`));
}
this.connected = true;
this.setup_socket();
}
}
setup_socket() {
let buffer;
const cleanup = () => {
this.cleanup_handlers();
buffer = null;
};
if (this.socket._socket) {
this.socket._socket.setNoDelay(true);
this.socket._socket.setKeepAlive(true);
} else {
this.socket.setNoDelay(true);
this.socket.setKeepAlive(true);
}
this.socket.on('data', (chunk) => {
buffer = buffer ? Buffer.concat([buffer, chunk]) : chunk;
if (buffer.length > 4) {
const size = buffer.readUInt32BE(0);
if (buffer.length >= size + 4) {
const packet_data = buffer.slice(4, 4 + size);
if (this.resolve) {
const complete = () => {
const reject = this.reject;
const resolve = this.resolve;
cleanup();
return {
reject,
resolve,
};
};
const response = new packet(this.password);
response.buffer = new Uint8Array(packet_data);
response
.decrypt()
.then(() => {
const { resolve } = complete();
if (resolve) {
resolve(response);
}
})
.catch((e) => {
console.log(e);
const { reject } = complete();
if (reject) {
reject(e);
}
});
}
}
}
});
this.socket.on('error', (e) => {
if (this.reject) {
const reject = this.reject;
cleanup();
this.connected = false;
console.log(e);
if (reject) {
reject(e);
}
}
});
this.socket.on('close', () => {
if (this.reject) {
const reject = this.reject;
cleanup();
this.connected = false;
console.log('socket closed');
if (reject) {
reject(new Error('socket closed'));
}
}
});
}
async disconnect() {
try {
if (this.socket) {
this.socket.destroy();
this.socket = null;
this.cleanup_handlers();
this.connected = false;
}
} catch (e) {
console.log(e);
}
}
async send(method_name, packet, optional_thread_id) {
packet.token = this.password;
packet.encode_top_utf8(method_name);
packet.encode_top_ui64(optional_thread_id || 1);
packet.encode_top_utf8(constants.instance_id);
packet.encode_top_ui32(0); // Service flags
packet.encode_top_utf8(constants.get_version());
await packet.encrypt();
packet.encode_top_ui32(packet.buffer.length);
return new Promise((resolve, reject) => {
this.reject = reject;
this.resolve = resolve;
this.socket.write(Buffer.from(packet.buffer), null, (err) => {
if (err) {
this.cleanup_handlers();
reject(err);
}
});
});
}
}
import Socket from 'net';
import * as constants from '../utils/constants';
import packet from './packet';
export default class connection {
constructor(host_or_ip, port, password, socket) {
this.host_or_ip = host_or_ip;
this.port = port;
this.password = password;
if (socket) {
this.socket = socket;
this.connected = true;
this.setup_socket();
}
}
connected = false;
host_or_ip = '';
nonce = '';
password = '';
port = 20000;
reject;
resolve;
socket;
cleanup_handlers() {
this.reject = null;
this.resolve = null;
}
async connect() {
if (!this.socket) {
try {
await new Promise((resolve, reject) => {
this.socket = Socket.createConnection(
this.port,
this.host_or_ip,
(err) => {
if (err) {
console.log(err);
return reject(err);
}
this.reject = reject;
this.resolve = resolve;
}
);
});
} catch (err) {
return Promise.reject(new Error(`'connect()' failed: ${err}`));
}
this.connected = true;
this.setup_socket();
}
}
setup_socket() {
let buffer;
const cleanup = () => {
this.cleanup_handlers();
buffer = null;
};
if (this.socket._socket) {
this.socket._socket.setNoDelay(true);
this.socket._socket.setKeepAlive(true);
} else {
this.socket.setNoDelay(true);
this.socket.setKeepAlive(true);
}
this.socket.on('data', (chunk) => {
buffer = buffer ? Buffer.concat([buffer, chunk]) : chunk;
if (buffer.length > 4) {
const size = buffer.readUInt32BE(0);
if (buffer.length >= size + 4) {
const packet_data = buffer.slice(4, 4 + size);
if (this.resolve) {
const complete = () => {
const reject = this.reject;
const resolve = this.resolve;
cleanup();
return {
reject,
resolve,
};
};
const response = new packet(this.password);
response.buffer = new Uint8Array(packet_data);
response
.decrypt()
.then(() => {
this.nonce = response.decode_utf8();
const { resolve } = complete();
if (resolve) {
resolve(response);
}
})
.catch((e) => {
console.log(e);
const { reject } = complete();
if (reject) {
reject(e);
}
});
}
}
}
});
this.socket.on('error', (e) => {
if (this.reject) {
const reject = this.reject;
cleanup();
this.connected = false;
console.log(e);
if (reject) {
reject(e);
}
}
});
this.socket.on('close', () => {
if (this.reject) {
const reject = this.reject;
cleanup();
this.connected = false;
console.log('socket closed');
if (reject) {
reject(new Error('socket closed'));
}
}
});
}
async disconnect() {
try {
if (this.socket) {
this.socket.destroy();
this.socket = null;
this.cleanup_handlers();
this.connected = false;
}
} catch (e) {
console.log(e);
}
}
async send(method_name, packet, optional_thread_id) {
packet.token = this.password;
packet.encode_top_utf8(method_name);
packet.encode_top_ui64(optional_thread_id || 1);
packet.encode_top_utf8(constants.instance_id);
packet.encode_top_ui32(0); // Service flags
packet.encode_top_utf8(constants.get_version());
packet.encode_top_utf8(nonce);
await packet.encrypt();
packet.encode_top_ui32(packet.buffer.length);
return new Promise((resolve, reject) => {
this.reject = reject;
this.resolve = resolve;
this.socket.write(Buffer.from(packet.buffer), null, (err) => {
if (err) {
this.cleanup_handlers();
reject(err);
}
});
});
}
}

View File

@@ -1,69 +1,69 @@
import Pool from 'socket-pool';
import connection from './connection';
export default class connection_pool {
constructor(pool_size, host_or_ip, port, password) {
this.host_or_ip = host_or_ip;
this.port = port;
this.password = password;
if (pool_size > 1) {
this.pool = new Pool({
connect: { host: host_or_ip, port: port },
connectTimeout: 5000,
pool: { max: pool_size, min: 2 },
});
} else {
throw new Error("'pool_size' must be > 1");
}
}
host_or_ip = '';
next_thread_id = 1;
password = '';
port = 20000;
pool;
shutdown = false;
async disconnect() {
await this.pool._pool.drain();
await this.pool._pool.clear();
this.pool = null;
this.shutdown = true;
}
async send(method_name, packet, optional_thread_id) {
try {
const socket = await this.pool.acquire();
if (!socket.thread_id) {
socket.thread_id = this.next_thread_id++;
}
const cleanup = () => {
try {
socket.release();
} catch (err) {
console.log(`'release()' failed: ${err}`);
}
};
try {
const result = await new connection(
this.host_or_ip,
this.port,
this.password,
socket
).send(method_name, packet, optional_thread_id || socket.thread_id);
cleanup();
return result;
} catch (err) {
cleanup();
return Promise.reject(
new Error(`'send(${method_name})' failed: ${err}`)
);
}
} catch (err) {
return Promise.reject(new Error(`'acquire()' socket failed: ${err}`));
}
}
}
import Pool from 'socket-pool';
import connection from './connection';
export default class connection_pool {
constructor(pool_size, host_or_ip, port, password) {
this.host_or_ip = host_or_ip;
this.port = port;
this.password = password;
if (pool_size > 1) {
this.pool = new Pool({
connect: { host: host_or_ip, port: port },
connectTimeout: 5000,
pool: { max: pool_size, min: 2 },
});
} else {
throw new Error("'pool_size' must be > 1");
}
}
host_or_ip = '';
next_thread_id = 1;
password = '';
port = 20000;
pool;
shutdown = false;
async disconnect() {
await this.pool._pool.drain();
await this.pool._pool.clear();
this.pool = null;
this.shutdown = true;
}
async send(method_name, packet, optional_thread_id) {
try {
const socket = await this.pool.acquire();
if (!socket.thread_id) {
socket.thread_id = this.next_thread_id++;
}
const cleanup = () => {
try {
socket.release();
} catch (err) {
console.log(`'release()' failed: ${err}`);
}
};
try {
const result = await new connection(
this.host_or_ip,
this.port,
this.password,
socket
).send(method_name, packet, optional_thread_id || socket.thread_id);
cleanup();
return result;
} catch (err) {
cleanup();
return Promise.reject(
new Error(`'send(${method_name})' failed: ${err}`)
);
}
} catch (err) {
return Promise.reject(new Error(`'acquire()' socket failed: ${err}`));
}
}
}

View File

@@ -1,330 +1,330 @@
import { randomBytes } from 'crypto';
import { Int64BE, Uint64BE } from 'int64-buffer';
import crypto from 'crypto';
import { TextEncoder } from 'text-encoding';
import { getCustomEncryption } from '../utils/constants';
import {
be_ui8_array_to_i16,
be_ui8_array_to_i32,
be_ui8_array_to_ui16,
be_ui8_array_to_ui32,
i16_to_be_ui8_array,
i32_to_be_ui8_array,
i8_to_ui8_array,
ui16_to_be_ui8_array,
ui32_to_be_ui8_array,
ui8_array_to_i8,
ui8_array_to_ui8,
ui8_to_ui8_array,
} from '../utils/byte_order';
import { XChaCha20Poly1305 } from '@stablelib/xchacha20poly1305';
export default class packet {
constructor(token) {
this.token = token;
}
buffer = new Uint8Array(0);
decode_offset = 0;
token;
append_buffer = (buffer) => {
if (!(buffer instanceof Uint8Array)) {
throw new Error('Buffer must be of type Uint8Array');
}
this.buffer = this.buffer
? new Uint8Array([...this.buffer, ...buffer])
: buffer;
};
clear = () => {
this.buffer = null;
this.decode_offset = 0;
};
decode_buffer = (length) => {
if (!this.buffer) {
throw new Error('Invalid buffer');
}
const ret = this.buffer.slice(
this.decode_offset,
this.decode_offset + length
);
this.decode_offset += length;
return Buffer.from(ret);
};
decode_stat = () => {
const mode = this.decode_ui16();
const nlink = this.decode_ui16();
const uid = this.decode_ui32();
const gid = this.decode_ui32();
const atime = this.decode_ui64();
const mtime = this.decode_ui64();
const ctime = this.decode_ui64();
const birth_time = this.decode_ui64();
const size = this.decode_ui64();
const blocks = this.decode_ui64();
const blksize = this.decode_ui32();
const flags = this.decode_ui32();
const directory = !!this.decode_ui8();
return {
mode,
nlink,
uid,
gid,
atime,
mtime,
ctime,
birth_time,
size,
blocks,
blksize,
flags,
directory,
};
};
decode_utf8 = () => {
if (!this.buffer) {
throw new Error('Invalid buffer');
}
const startIndex = this.decode_offset;
const endIndex = this.buffer.indexOf(0, startIndex);
if (endIndex >= 0) {
let ret = '';
for (let i = startIndex; i < endIndex; i++) {
ret += String.fromCharCode(this.buffer[i]);
}
this.decode_offset = endIndex + 1;
return ret;
}
throw new Error('String not found in buffer');
};
decode_i8 = () => {
return ui8_array_to_i8(this.buffer, this.decode_offset++);
};
decode_ui8 = () => {
return ui8_array_to_ui8(this.buffer, this.decode_offset++);
};
decode_i16 = () => {
const ret = be_ui8_array_to_i16(this.buffer, this.decode_offset);
this.decode_offset += 2;
return ret;
};
decode_ui16 = () => {
const ret = be_ui8_array_to_ui16(this.buffer, this.decode_offset);
this.decode_offset += 2;
return ret;
};
decode_i32 = () => {
const ret = be_ui8_array_to_i32(this.buffer, this.decode_offset);
this.decode_offset += 4;
return ret;
};
decode_ui32 = () => {
const ret = be_ui8_array_to_ui32(this.buffer, this.decode_offset);
this.decode_offset += 4;
return ret;
};
decode_i64 = () => {
const ret = new Int64BE(
this.buffer.slice(this.decode_offset, this.decode_offset + 8)
);
this.decode_offset += 8;
return ret.toString(10);
};
decode_ui64 = () => {
const ret = new Uint64BE(
this.buffer.slice(this.decode_offset, this.decode_offset + 8)
);
this.decode_offset += 8;
return ret.toString(10);
};
decrypt = async () => {
try {
let hash = crypto.createHash('sha256');
hash = hash.update(new TextEncoder().encode(this.token));
const key = Uint8Array.from(hash.digest());
const nonce = this.buffer.slice(0, 24);
const mac = this.buffer.slice(24, 16 + 24);
const customEncryption = getCustomEncryption();
if (customEncryption) {
this.buffer = Buffer.from(
await customEncryption.decrypt(
Buffer.from(key).toString('base64'),
Buffer.from(nonce).toString('base64'),
Buffer.from(mac).toString('base64'),
Buffer.from(this.buffer.slice(40)).toString('base64')
),
'base64'
);
} else {
const aad = ui32_to_be_ui8_array(this.buffer.length);
this.buffer = new Uint8Array([
...this.buffer.slice(nonce.length + mac.length),
...this.buffer.slice(nonce.length, nonce.length + mac.length),
]);
const result = new XChaCha20Poly1305(key).open(nonce, this.buffer, aad);
if (!result) {
throw new Error('decryption failed');
}
this.buffer = Buffer.from(result);
}
this.buffer = new Uint8Array(this.buffer);
return this.buffer;
} catch (e) {
return Promise.reject(e);
}
};
encode_buffer = (buffer) => {
this.append_buffer(new Uint8Array(buffer));
};
encode_i8 = (num) => {
this.append_buffer(i8_to_ui8_array(num));
};
encode_top_i8 = (num) => {
this.push_buffer(i8_to_ui8_array(num));
};
encode_u8 = (num) => {
this.append_buffer(ui8_to_ui8_array(num));
};
encode_top_u8 = (num) => {
this.push_buffer(ui8_to_ui8_array(num));
};
encode_i16 = (num) => {
this.append_buffer(i16_to_be_ui8_array(num));
};
encode_top_i16 = (num) => {
this.push_buffer(i16_to_be_ui8_array(num));
};
encode_ui16 = (num) => {
this.append_buffer(ui16_to_be_ui8_array(num));
};
encode_top_ui16 = (num) => {
this.push_buffer(ui16_to_be_ui8_array(num));
};
encode_i32 = (num) => {
this.append_buffer(i32_to_be_ui8_array(num));
};
encode_top_i32 = (num) => {
this.push_buffer(i32_to_be_ui8_array(num));
};
encode_ui32 = (num) => {
this.append_buffer(ui32_to_be_ui8_array(num));
};
encode_top_ui32 = (num) => {
this.push_buffer(ui32_to_be_ui8_array(num));
};
encode_i64 = (num) => {
this.append_buffer(new Uint8Array(new Int64BE(num).toArray()));
};
encode_top_i64 = (num) => {
this.push_buffer(new Uint8Array(new Int64BE(num).toArray()));
};
encode_ui64 = (num) => {
this.append_buffer(new Uint8Array(new Uint64BE(num).toArray()));
};
encode_top_ui64 = (num) => {
this.push_buffer(new Uint8Array(new Uint64BE(num).toArray()));
};
encode_utf8 = (str) => {
if (!(typeof str === 'string' || str instanceof String)) {
throw new Error('Value must be of type string');
}
const buffer = new Uint8Array([...new TextEncoder().encode(str), 0]);
this.append_buffer(buffer);
};
encode_top_utf8 = (str) => {
if (!(typeof str === 'string' || str instanceof String)) {
throw new Error('Value must be of type string');
}
const buffer = new Uint8Array([...new TextEncoder().encode(str), 0]);
this.push_buffer(buffer);
};
encrypt = async (nonce) => {
try {
let hash = crypto.createHash('sha256');
hash = hash.update(new TextEncoder().encode(this.token));
const key = Uint8Array.from(hash.digest());
if (!nonce) {
nonce = Uint8Array.from(randomBytes(24));
}
const customEncryption = getCustomEncryption();
if (customEncryption) {
this.buffer = new Uint8Array(
Buffer.from(
await customEncryption.encrypt(
Buffer.from(key).toString('base64'),
Buffer.from(nonce).toString('base64'),
Buffer.from(this.buffer).toString('base64')
),
'base64'
)
);
} else {
const aad = ui32_to_be_ui8_array(this.buffer.length + 40);
this.buffer = new XChaCha20Poly1305(key).seal(nonce, this.buffer, aad);
this.buffer = new Uint8Array([
...this.buffer.slice(this.buffer.length - 16),
...this.buffer.slice(0, this.buffer.length - 16),
]);
this.push_buffer(nonce);
}
return this.buffer;
} catch (e) {
return Promise.reject(e);
}
};
push_buffer = (buffer) => {
if (!(buffer instanceof Uint8Array)) {
throw new Error('Buffer must be of type Uint8Array');
}
this.buffer = this.buffer
? new Uint8Array([...buffer, ...this.buffer])
: buffer;
};
}
import { randomBytes } from 'crypto';
import { Int64BE, Uint64BE } from 'int64-buffer';
import crypto from 'crypto';
import { TextEncoder } from 'text-encoding';
import { getCustomEncryption } from '../utils/constants';
import {
be_ui8_array_to_i16,
be_ui8_array_to_i32,
be_ui8_array_to_ui16,
be_ui8_array_to_ui32,
i16_to_be_ui8_array,
i32_to_be_ui8_array,
i8_to_ui8_array,
ui16_to_be_ui8_array,
ui32_to_be_ui8_array,
ui8_array_to_i8,
ui8_array_to_ui8,
ui8_to_ui8_array,
} from '../utils/byte_order';
import { XChaCha20Poly1305 } from '@stablelib/xchacha20poly1305';
export default class packet {
constructor(token) {
this.token = token;
}
buffer = new Uint8Array(0);
decode_offset = 0;
token;
append_buffer = (buffer) => {
if (!(buffer instanceof Uint8Array)) {
throw new Error('Buffer must be of type Uint8Array');
}
this.buffer = this.buffer
? new Uint8Array([...this.buffer, ...buffer])
: buffer;
};
clear = () => {
this.buffer = null;
this.decode_offset = 0;
};
decode_buffer = (length) => {
if (!this.buffer) {
throw new Error('Invalid buffer');
}
const ret = this.buffer.slice(
this.decode_offset,
this.decode_offset + length
);
this.decode_offset += length;
return Buffer.from(ret);
};
decode_stat = () => {
const mode = this.decode_ui16();
const nlink = this.decode_ui16();
const uid = this.decode_ui32();
const gid = this.decode_ui32();
const atime = this.decode_ui64();
const mtime = this.decode_ui64();
const ctime = this.decode_ui64();
const birth_time = this.decode_ui64();
const size = this.decode_ui64();
const blocks = this.decode_ui64();
const blksize = this.decode_ui32();
const flags = this.decode_ui32();
const directory = !!this.decode_ui8();
return {
mode,
nlink,
uid,
gid,
atime,
mtime,
ctime,
birth_time,
size,
blocks,
blksize,
flags,
directory,
};
};
decode_utf8 = () => {
if (!this.buffer) {
throw new Error('Invalid buffer');
}
const startIndex = this.decode_offset;
const endIndex = this.buffer.indexOf(0, startIndex);
if (endIndex >= 0) {
let ret = '';
for (let i = startIndex; i < endIndex; i++) {
ret += String.fromCharCode(this.buffer[i]);
}
this.decode_offset = endIndex + 1;
return ret;
}
throw new Error('String not found in buffer');
};
decode_i8 = () => {
return ui8_array_to_i8(this.buffer, this.decode_offset++);
};
decode_ui8 = () => {
return ui8_array_to_ui8(this.buffer, this.decode_offset++);
};
decode_i16 = () => {
const ret = be_ui8_array_to_i16(this.buffer, this.decode_offset);
this.decode_offset += 2;
return ret;
};
decode_ui16 = () => {
const ret = be_ui8_array_to_ui16(this.buffer, this.decode_offset);
this.decode_offset += 2;
return ret;
};
decode_i32 = () => {
const ret = be_ui8_array_to_i32(this.buffer, this.decode_offset);
this.decode_offset += 4;
return ret;
};
decode_ui32 = () => {
const ret = be_ui8_array_to_ui32(this.buffer, this.decode_offset);
this.decode_offset += 4;
return ret;
};
decode_i64 = () => {
const ret = new Int64BE(
this.buffer.slice(this.decode_offset, this.decode_offset + 8)
);
this.decode_offset += 8;
return ret.toString(10);
};
decode_ui64 = () => {
const ret = new Uint64BE(
this.buffer.slice(this.decode_offset, this.decode_offset + 8)
);
this.decode_offset += 8;
return ret.toString(10);
};
decrypt = async () => {
try {
let hash = crypto.createHash('sha256');
hash = hash.update(new TextEncoder().encode(this.token));
const key = Uint8Array.from(hash.digest());
const nonce = this.buffer.slice(0, 24);
const mac = this.buffer.slice(24, 16 + 24);
const customEncryption = getCustomEncryption();
if (customEncryption) {
this.buffer = Buffer.from(
await customEncryption.decrypt(
Buffer.from(key).toString('base64'),
Buffer.from(nonce).toString('base64'),
Buffer.from(mac).toString('base64'),
Buffer.from(this.buffer.slice(40)).toString('base64')
),
'base64'
);
} else {
const aad = ui32_to_be_ui8_array(this.buffer.length);
this.buffer = new Uint8Array([
...this.buffer.slice(nonce.length + mac.length),
...this.buffer.slice(nonce.length, nonce.length + mac.length),
]);
const result = new XChaCha20Poly1305(key).open(nonce, this.buffer, aad);
if (!result) {
throw new Error('decryption failed');
}
this.buffer = Buffer.from(result);
}
this.buffer = new Uint8Array(this.buffer);
return this.buffer;
} catch (e) {
return Promise.reject(e);
}
};
encode_buffer = (buffer) => {
this.append_buffer(new Uint8Array(buffer));
};
encode_i8 = (num) => {
this.append_buffer(i8_to_ui8_array(num));
};
encode_top_i8 = (num) => {
this.push_buffer(i8_to_ui8_array(num));
};
encode_u8 = (num) => {
this.append_buffer(ui8_to_ui8_array(num));
};
encode_top_u8 = (num) => {
this.push_buffer(ui8_to_ui8_array(num));
};
encode_i16 = (num) => {
this.append_buffer(i16_to_be_ui8_array(num));
};
encode_top_i16 = (num) => {
this.push_buffer(i16_to_be_ui8_array(num));
};
encode_ui16 = (num) => {
this.append_buffer(ui16_to_be_ui8_array(num));
};
encode_top_ui16 = (num) => {
this.push_buffer(ui16_to_be_ui8_array(num));
};
encode_i32 = (num) => {
this.append_buffer(i32_to_be_ui8_array(num));
};
encode_top_i32 = (num) => {
this.push_buffer(i32_to_be_ui8_array(num));
};
encode_ui32 = (num) => {
this.append_buffer(ui32_to_be_ui8_array(num));
};
encode_top_ui32 = (num) => {
this.push_buffer(ui32_to_be_ui8_array(num));
};
encode_i64 = (num) => {
this.append_buffer(new Uint8Array(new Int64BE(num).toArray()));
};
encode_top_i64 = (num) => {
this.push_buffer(new Uint8Array(new Int64BE(num).toArray()));
};
encode_ui64 = (num) => {
this.append_buffer(new Uint8Array(new Uint64BE(num).toArray()));
};
encode_top_ui64 = (num) => {
this.push_buffer(new Uint8Array(new Uint64BE(num).toArray()));
};
encode_utf8 = (str) => {
if (!(typeof str === 'string' || str instanceof String)) {
throw new Error('Value must be of type string');
}
const buffer = new Uint8Array([...new TextEncoder().encode(str), 0]);
this.append_buffer(buffer);
};
encode_top_utf8 = (str) => {
if (!(typeof str === 'string' || str instanceof String)) {
throw new Error('Value must be of type string');
}
const buffer = new Uint8Array([...new TextEncoder().encode(str), 0]);
this.push_buffer(buffer);
};
encrypt = async (nonce) => {
try {
let hash = crypto.createHash('sha256');
hash = hash.update(new TextEncoder().encode(this.token));
const key = Uint8Array.from(hash.digest());
if (!nonce) {
nonce = Uint8Array.from(randomBytes(24));
}
const customEncryption = getCustomEncryption();
if (customEncryption) {
this.buffer = new Uint8Array(
Buffer.from(
await customEncryption.encrypt(
Buffer.from(key).toString('base64'),
Buffer.from(nonce).toString('base64'),
Buffer.from(this.buffer).toString('base64')
),
'base64'
)
);
} else {
const aad = ui32_to_be_ui8_array(this.buffer.length + 40);
this.buffer = new XChaCha20Poly1305(key).seal(nonce, this.buffer, aad);
this.buffer = new Uint8Array([
...this.buffer.slice(this.buffer.length - 16),
...this.buffer.slice(0, this.buffer.length - 16),
]);
this.push_buffer(nonce);
}
return this.buffer;
} catch (e) {
return Promise.reject(e);
}
};
push_buffer = (buffer) => {
if (!(buffer instanceof Uint8Array)) {
throw new Error('Buffer must be of type Uint8Array');
}
this.buffer = this.buffer
? new Uint8Array([...buffer, ...this.buffer])
: buffer;
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,112 +1,112 @@
export const is_big_endian_system =
new Uint8Array(new Uint32Array([0x12345678]).buffer)[0] === 0x12;
export const is_little_endian_system =
new Uint8Array(new Uint32Array([0x12345678]).buffer)[0] === 0x78;
export const i8_to_ui8_array = (num) => {
if (typeof num === 'string' || num instanceof String) {
num = parseInt(num, 10);
}
const buffer = Buffer.alloc(1);
buffer.writeInt8(num);
return new Uint8Array(buffer);
};
export const ui8_array_to_i8 = (ar, offset) => {
const buffer = Buffer.alloc(1);
buffer[0] = ar[offset];
return buffer.readInt8(0);
};
export const ui8_to_ui8_array = (num) => {
if (typeof num === 'string' || num instanceof String) {
num = parseInt(num, 10);
}
const buffer = Buffer.alloc(1);
buffer.writeUInt8(num);
return new Uint8Array(buffer);
};
export const ui8_array_to_ui8 = (ar, offset) => {
const buffer = Buffer.alloc(1);
buffer[0] = ar[offset];
return buffer.readUInt8(0);
};
export const i16_to_be_ui8_array = (num) => {
if (typeof num === 'string' || num instanceof String) {
num = parseInt(num, 10);
}
const buffer = Buffer.alloc(2);
buffer.writeInt16BE(num);
return new Uint8Array(buffer);
};
export const be_ui8_array_to_i16 = (ar, offset) => {
const buffer = Buffer.alloc(2);
for (let i = offset; i < buffer.length + offset; i++) {
buffer[i - offset] = ar[i];
}
return buffer.readInt16BE(0);
};
export const ui16_to_be_ui8_array = (num) => {
if (typeof num === 'string' || num instanceof String) {
num = parseInt(num, 10);
}
const buffer = Buffer.alloc(2);
buffer.writeUInt16BE(num);
return new Uint8Array(buffer);
};
export const be_ui8_array_to_ui16 = (ar, offset) => {
const buffer = Buffer.alloc(2);
for (let i = offset; i < buffer.length + offset; i++) {
buffer[i - offset] = ar[i];
}
return buffer.readUInt16BE(0);
};
export const i32_to_be_ui8_array = (num) => {
if (typeof num === 'string' || num instanceof String) {
num = parseInt(num, 10);
}
const buffer = Buffer.alloc(4);
buffer.writeInt32BE(num);
return new Uint8Array(buffer);
};
export const be_ui8_array_to_i32 = (ar, offset) => {
const buffer = Buffer.alloc(4);
for (let i = offset; i < buffer.length + offset; i++) {
buffer[i - offset] = ar[i];
}
return buffer.readInt32BE(0);
};
export const ui32_to_be_ui8_array = (num) => {
if (typeof num === 'string' || num instanceof String) {
num = parseInt(num, 10);
}
const buffer = Buffer.alloc(4);
buffer.writeUInt32BE(num);
return new Uint8Array(buffer);
};
export const be_ui8_array_to_ui32 = (ar, offset) => {
const buffer = Buffer.alloc(4);
for (let i = offset; i < buffer.length + offset; i++) {
buffer[i - offset] = ar[i];
}
return buffer.readUInt32BE(0);
};
export const is_big_endian_system =
new Uint8Array(new Uint32Array([0x12345678]).buffer)[0] === 0x12;
export const is_little_endian_system =
new Uint8Array(new Uint32Array([0x12345678]).buffer)[0] === 0x78;
export const i8_to_ui8_array = (num) => {
if (typeof num === 'string' || num instanceof String) {
num = parseInt(num, 10);
}
const buffer = Buffer.alloc(1);
buffer.writeInt8(num);
return new Uint8Array(buffer);
};
export const ui8_array_to_i8 = (ar, offset) => {
const buffer = Buffer.alloc(1);
buffer[0] = ar[offset];
return buffer.readInt8(0);
};
export const ui8_to_ui8_array = (num) => {
if (typeof num === 'string' || num instanceof String) {
num = parseInt(num, 10);
}
const buffer = Buffer.alloc(1);
buffer.writeUInt8(num);
return new Uint8Array(buffer);
};
export const ui8_array_to_ui8 = (ar, offset) => {
const buffer = Buffer.alloc(1);
buffer[0] = ar[offset];
return buffer.readUInt8(0);
};
export const i16_to_be_ui8_array = (num) => {
if (typeof num === 'string' || num instanceof String) {
num = parseInt(num, 10);
}
const buffer = Buffer.alloc(2);
buffer.writeInt16BE(num);
return new Uint8Array(buffer);
};
export const be_ui8_array_to_i16 = (ar, offset) => {
const buffer = Buffer.alloc(2);
for (let i = offset; i < buffer.length + offset; i++) {
buffer[i - offset] = ar[i];
}
return buffer.readInt16BE(0);
};
export const ui16_to_be_ui8_array = (num) => {
if (typeof num === 'string' || num instanceof String) {
num = parseInt(num, 10);
}
const buffer = Buffer.alloc(2);
buffer.writeUInt16BE(num);
return new Uint8Array(buffer);
};
export const be_ui8_array_to_ui16 = (ar, offset) => {
const buffer = Buffer.alloc(2);
for (let i = offset; i < buffer.length + offset; i++) {
buffer[i - offset] = ar[i];
}
return buffer.readUInt16BE(0);
};
export const i32_to_be_ui8_array = (num) => {
if (typeof num === 'string' || num instanceof String) {
num = parseInt(num, 10);
}
const buffer = Buffer.alloc(4);
buffer.writeInt32BE(num);
return new Uint8Array(buffer);
};
export const be_ui8_array_to_i32 = (ar, offset) => {
const buffer = Buffer.alloc(4);
for (let i = offset; i < buffer.length + offset; i++) {
buffer[i - offset] = ar[i];
}
return buffer.readInt32BE(0);
};
export const ui32_to_be_ui8_array = (num) => {
if (typeof num === 'string' || num instanceof String) {
num = parseInt(num, 10);
}
const buffer = Buffer.alloc(4);
buffer.writeUInt32BE(num);
return new Uint8Array(buffer);
};
export const be_ui8_array_to_ui32 = (ar, offset) => {
const buffer = Buffer.alloc(4);
for (let i = offset; i < buffer.length + offset; i++) {
buffer[i - offset] = ar[i];
}
return buffer.readUInt32BE(0);
};

View File

@@ -1,16 +1,16 @@
import { v4 as uuidv4 } from 'uuid';
import _package_json from '../../package.json';
let customEncryption;
export const getCustomEncryption = () => {
return customEncryption;
};
export const setCustomEncryption = (ce) => {
customEncryption = ce;
};
export const instance_id = uuidv4();
export const package_json = _package_json;
export const get_version = () => _package_json.version;
import { v4 as uuidv4 } from 'uuid';
import _package_json from '../../package.json';
let customEncryption;
export const getCustomEncryption = () => {
return customEncryption;
};
export const setCustomEncryption = (ce) => {
customEncryption = ce;
};
export const instance_id = uuidv4();
export const package_json = _package_json;
export const get_version = () => _package_json.version;