diff --git a/.cspell/words.txt b/.cspell/words.txt new file mode 100644 index 0000000..b27e5c8 --- /dev/null +++ b/.cspell/words.txt @@ -0,0 +1,7 @@ +alloc +blockstorage +fuse_fgetattr +fuse_getattr +stablelib +uuidv4 +xchacha20poly1305 \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..e0c82b6 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +fixup text eol=lf diff --git a/.nvimrc b/.nvimrc index 8417e95..9eced6d 100644 --- a/.nvimrc +++ b/.nvimrc @@ -1,3 +1,2 @@ -set path+=.,src/** -let &makeprg="npm run build" - +set path+=.,src/** +let &makeprg="npm run build" diff --git a/CHANGELOG.md b/CHANGELOG.md index 49c1588..46ed94d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,22 @@ # Changelog +## 2.0.0-r1 + +- Integrated `repertory` v2.0 changes +- Removed connection pool + ## 1.4.0-r1 -- Switched packet encryption to XChaCha20-Poly1305 -- Allow external XChaCha20-Poly1305 encryption/decryption + +- 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 diff --git a/LICENSE.md b/LICENSE.md index 11998c7..959f791 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ # `repertory-js` MIT License -### Copyright <2021> +### Copyright <2021-2025> 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, diff --git a/README.md b/README.md index 299bec4..3eb640f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # About -`repertory-js` is a Node.js module for interfacing with `repertory's` remote mount API. +`repertory-js` is a Node.js module for interfacing with `repertory's` remote +mount API. ## Installing @@ -10,43 +11,44 @@ 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. +A Repertory mount must be active with the `RemoteMount.Enable` setting enabled. +`RemoteMount.EncryptionToken` 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" + repertory.exe -set RemoteMount.Enable true + repertory.exe -set RemoteMount.EncryptionToken 'my password' [Optional - change listening port] - repertory.exe -set RemoteMount.RemotePort 20202 + repertory.exe -set RemoteMount.ApiPort 20202 ``` ### Enabling Sia Remote Mount API on *NIX Systems ```shell ./repertory -unmount - ./repertory -set RemoteMount.EnableRemoteMount true - ./repertory -set RemoteMount.RemoteToken "my password" + ./repertory -set RemoteMount.Enable true + ./repertory -set RemoteMount.EncryptionToken 'my password' [Optional - change listening port] - ./repertory -set RemoteMount.RemotePort 20202 + ./repertory -set RemoteMount.ApiPort 20202 ``` -### Skynet and ScPrime Mounts +### S3 Mounts -* For Skynet mounts, add `-sk` argument to all commands listed above. -* For ScPrime mounts, add `-sp` argument to all commands listed above. +* For S3 mounts, add `-s3` and `--name ''` 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` +* 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 @@ -58,7 +60,7 @@ import * as rep from "@blockstorage/repertory-js"; // Repertory host settings const MY_HOST_OR_IP = 'localhost'; const MY_PORT = 20000; -const MY_TOKEN = 'password'; +const MY_PASSWORD = 'password'; // Progress callback for uploads / downloads const progress_cb = (local_path, remote_path, progress, completed) => { @@ -66,33 +68,29 @@ const progress_cb = (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); -*/ +//****************************************************************************// +// Step 1. Create a connection // +//****************************************************************************// +const conn = await rep.connect(MY_HOST_OR_IP, MY_PORT, MY_PASSWORD); /* Disconnect when complete await conn.disconnect(); */ -//************************************************************************************************// -// Step 2. Create an 'api' instance using the connection pool / connection // -//************************************************************************************************// +//****************************************************************************// +// Step 2. Create an 'api' instance using the connection // +//****************************************************************************// const api = rep.create_api(conn); -//************************************************************************************************// -// Step 3. Use 'api' // -//************************************************************************************************// +//****************************************************************************// +// Step 3. Use 'api' // +//****************************************************************************// -//------------------------------------------------------------------------------------------------// -// *********** Directory Operations *********** // -//------------------------------------------------------------------------------------------------// +//----------------------------------------------------------------------------// +// *********** Directory Operations *********** // +//----------------------------------------------------------------------------// // Check if directory exists const exists = await api.directory.exists('/my_directory'); @@ -125,9 +123,9 @@ await api.directory.create('/test'); await api.directory.remove('/test') -//------------------------------------------------------------------------------------------------// -// *********** File Operations *********** // -//------------------------------------------------------------------------------------------------// +//----------------------------------------------------------------------------// +// *********** File Operations *********** // +//----------------------------------------------------------------------------// // Check if file exists const exists = await api.file.exists('/my_file.txt') @@ -154,9 +152,9 @@ await api.file.upload('C:\\my_file.txt', '/my_file.txt', progress_cb, true); await api.file.upload('C:\\my_file.txt', '/my_file.txt', progress_cb, false, true); -//------------------------------------------------------------------------------------------------// -// *********** Low-Level File Operations *********** // -//------------------------------------------------------------------------------------------------// +//----------------------------------------------------------------------------// +// *********** Low-Level File Operations *********** // +//----------------------------------------------------------------------------// // Create or open a remote file { diff --git a/cspell.json b/cspell.json new file mode 100644 index 0000000..cba22db --- /dev/null +++ b/cspell.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://raw.githubusercontent.com/streetsidesoftware/cspell/main/cspell.schema.json", + "version": "0.2", + "dictionaries": ["workspace-words", "user-words"], + "dictionaryDefinitions": [{ + "name": "workspace-words", + "path": "./.cspell/words.txt", + "addWords": true + }, + { + "name": "user-words", + "path": "C:\\.desktop\\.cspell\\user_words.txt", + "addWords": true + } + ] +} \ No newline at end of file diff --git a/fixup b/fixup index 6e77047..f0289ed 100755 --- a/fixup +++ b/fixup @@ -1,11 +1,11 @@ -cat <dist/cjs/package.json -{ - "type": "commonjs" -} -EOF - -cat <dist/mjs/package.json -{ - "type": "module" -} -EOF +cat <dist/cjs/package.json +{ + "type": "commonjs" +} +EOF + +cat <dist/mjs/package.json +{ + "type": "module" +} +EOF diff --git a/package.json b/package.json index 9fbb5b0..73ea0cf 100644 --- a/package.json +++ b/package.json @@ -37,15 +37,16 @@ ], "scripts": { "build": "rollup -c && ./fixup", + "build_win": "rollup -c && mingw64 ./fixup", "test": "jest", "prepublish": "rollup -c --silent && ./fixup" }, "dependencies": { "@stablelib/xchacha20poly1305": "^1.0.1", - "int64-buffer": "^1.0.0", - "socket-pool": "^1.2.3", + "blake2b": "^2.1.4", + "int64-buffer": "^1.1.0", "text-encoding": "^0.7.0", - "uuid": "^8.3.2" + "uuid": "^11.0.5" }, "devDependencies": { "@babel/core": "^7.14.3", diff --git a/src/__tests__/connection_pool.test.js b/src/__tests__/connection_pool.test.js deleted file mode 100644 index 450d139..0000000 --- a/src/__tests__/connection_pool.test.js +++ /dev/null @@ -1,59 +0,0 @@ -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); -}); diff --git a/src/__tests__/constants.test.js b/src/__tests__/constants.test.js index e8aa872..512eec5 100644 --- a/src/__tests__/constants.test.js +++ b/src/__tests__/constants.test.js @@ -14,5 +14,5 @@ test(`'instance_id' is valid`, () => { test(`'version' can be read from 'package.json'`, () => { console.log(get_version()); - expect(get_version()).toBe('1.4.0-r1'); + expect(get_version()).toBe('2.0.0-r1'); }); diff --git a/src/__tests__/repertory.test.js b/src/__tests__/repertory.test.js index 16b90a4..729e8a1 100644 --- a/src/__tests__/repertory.test.js +++ b/src/__tests__/repertory.test.js @@ -1,10 +1,9 @@ -import crypto from 'crypto'; +import blake2b from 'blake2b'; import fs from 'fs'; import { Uint64BE } from 'int64-buffer'; import * as repertory from '../index.js'; import connection from '../networking/connection'; -import connection_pool from '../networking/connection_pool'; const TEST_HOST = process.env.TEST_HOST || 'localhost'; const TEST_PASSWORD = process.env.TEST_PASSWORD || ''; @@ -12,10 +11,12 @@ const TEST_PORT = process.env.TEST_PORT || 20000; const calculate_sha256 = (path) => { return new Promise((resolve, reject) => { - const hash = crypto.createHash('sha256'); + const hash = blake2b(32); fs.createReadStream(path) - .on('data', (data) => hash.update(data)) + .on('data', (data) => { + return hash.update(new Uint8Array(data)); + }) .on('error', (err) => reject(err)) .on('end', () => { const h = hash.digest('hex'); @@ -35,56 +36,16 @@ const test_connection = (conn, should_be_connected) => { }; test('can create a connection to repertory api', async () => { + console.log('TEST_PASSWORD', TEST_PASSWORD); const conn = await repertory.connect(TEST_HOST, TEST_PORT, TEST_PASSWORD); test_connection(conn, true); - - await conn.disconnect(); -}); - -test('create_pool returns a connection if pool size is <=1', async () => { - for (let i = 0; i < 2; i++) { - const conn = await repertory.create_pool( - i, - TEST_HOST, - TEST_PORT, - TEST_PASSWORD - ); - expect(conn).toBeInstanceOf(connection); - test_connection(conn, true); - - await conn.disconnect(); - } -}); - -test('can create a connection pool', async () => { - const conn = await repertory.create_pool( - 2, - TEST_HOST, - TEST_PORT, - TEST_PASSWORD - ); - console.log(conn); - expect(conn).toBeInstanceOf(connection_pool); - expect(conn.host_or_ip).toEqual(TEST_HOST); - expect(conn.port).toEqual(TEST_PORT); - expect(conn.password).toEqual(TEST_PASSWORD); - expect(conn.shutdown).toEqual(false); - expect(conn.pool._pool.max).toEqual(2); - expect(conn.pool._pool.min).toEqual(2); - await conn.disconnect(); }); test('can get drive information using api', async () => { - const conn = await repertory.create_pool( - 2, - TEST_HOST, - TEST_PORT, - TEST_PASSWORD - ); + const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD); const api = repertory.create_api(conn); const di = await api.get_drive_information(); - console.log(di); expect(di.free).toBeDefined(); expect(di.total).toBeDefined(); @@ -94,12 +55,7 @@ test('can get drive information using api', async () => { }); test('can create and remove a directory using api', async () => { - const conn = await repertory.create_pool( - 2, - TEST_HOST, - TEST_PORT, - TEST_PASSWORD - ); + const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD); const api = repertory.create_api(conn); expect(await api.directory.create('/repertory_js')).toEqual(0); expect(await api.directory.exists('/repertory_js')).toEqual(true); @@ -110,12 +66,7 @@ test('can create and remove a directory using api', async () => { }); test('can get directory list and snapshot using api', async () => { - const conn = await repertory.create_pool( - 2, - TEST_HOST, - TEST_PORT, - TEST_PASSWORD - ); + const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD); const api = repertory.create_api(conn); const test_results = async (remote_path, page_count, get_page) => { @@ -127,10 +78,11 @@ test('can get directory list and snapshot using api', async () => { console.log(items); expect(items.length).toBeGreaterThanOrEqual(2); - expect(items[0].directory).toBeTruthy(); - expect(items[0].path).toEqual('.'); - expect(items[1].directory).toBeTruthy(); - expect(items[1].path).toEqual('..'); + expect(items[0].Directory).toBeTruthy(); + expect(items[0].ApiPath).toEqual('.'); + + expect(items[1].Directory).toBeTruthy(); + expect(items[1].ApiPath).toEqual('..'); } }; @@ -153,12 +105,7 @@ test('can get directory list and snapshot using api', async () => { }); test('can create, close and remove a file using api', async () => { - const conn = await repertory.create_pool( - 2, - TEST_HOST, - TEST_PORT, - TEST_PASSWORD - ); + const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD); const api = repertory.create_api(conn); const f = await api.file.create_or_open('/repertory_file.dat'); console.log(f); @@ -175,12 +122,7 @@ test('can create, close and remove a file using api', async () => { }); test('can open, close and remove a file using api', async () => { - const conn = await repertory.create_pool( - 2, - TEST_HOST, - TEST_PORT, - TEST_PASSWORD - ); + const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD); const api = repertory.create_api(conn); let f = await api.file.create_or_open('/repertory_file.dat'); expect(await f.close()).toEqual(0); @@ -200,12 +142,7 @@ test('can open, close and remove a file using api', async () => { }); test('can write to and read from a file using api', async () => { - const conn = await repertory.create_pool( - 2, - TEST_HOST, - TEST_PORT, - TEST_PASSWORD - ); + const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD); const api = repertory.create_api(conn); const f = await api.file.create_or_open('/repertory_file.dat'); @@ -227,12 +164,7 @@ test('can write to and read from a file using api', async () => { }); test('can truncate a file using api', async () => { - const conn = await repertory.create_pool( - 2, - TEST_HOST, - TEST_PORT, - TEST_PASSWORD - ); + const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD); const api = repertory.create_api(conn); const f = await api.file.create_or_open('/repertory_file.dat'); @@ -253,12 +185,7 @@ test('can upload and download a file using api', async () => { fs.unlinkSync('repertory_test.dat'); } catch {} - const conn = await repertory.create_pool( - 2, - TEST_HOST, - TEST_PORT, - TEST_PASSWORD - ); + const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD); const api = repertory.create_api(conn); expect( await api.file.upload('test.dat', '/repertory_test.dat', (l, r, p, c) => { @@ -289,12 +216,7 @@ test('can upload and download a file using api', async () => { }, 60000); test('can download and overwrite a file using api', async () => { - const conn = await repertory.create_pool( - 2, - TEST_HOST, - TEST_PORT, - TEST_PASSWORD - ); + const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD); const api = repertory.create_api(conn); expect( await api.file.upload('test.dat', '/repertory_test.dat', (l, r, p, c) => { @@ -330,12 +252,7 @@ test('can download and overwrite a file using api', async () => { }, 60000); test('download fails if overwrite is false using api', async () => { - const conn = await repertory.create_pool( - 2, - TEST_HOST, - TEST_PORT, - TEST_PASSWORD - ); + const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD); const api = repertory.create_api(conn); expect( await api.file.upload('test.dat', '/repertory_test.dat', (l, r, p, c) => { @@ -371,12 +288,7 @@ test('download fails if overwrite is false using api', async () => { }, 60000); test('can upload and overwrite a file using api', async () => { - const conn = await repertory.create_pool( - 2, - TEST_HOST, - TEST_PORT, - TEST_PASSWORD - ); + const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD); const api = repertory.create_api(conn); expect( await api.file.upload('test.dat', '/repertory_test.dat', (l, r, p, c) => { @@ -401,12 +313,7 @@ test('can upload and overwrite a file using api', async () => { }, 60000); test('upload fails if overwrite is false using api', async () => { - const conn = await repertory.create_pool( - 2, - TEST_HOST, - TEST_PORT, - TEST_PASSWORD - ); + const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD); const api = repertory.create_api(conn); expect( await api.file.upload('test.dat', '/repertory_test.dat', (l, r, p, c) => { @@ -431,12 +338,7 @@ test('upload fails if overwrite is false using api', async () => { }, 60000); test('can resume download using api', async () => { - const conn = await repertory.create_pool( - 2, - TEST_HOST, - TEST_PORT, - TEST_PASSWORD - ); + const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD); const api = repertory.create_api(conn); expect( await api.file.upload('test.dat', '/repertory_test.dat', (l, r, p, c) => { @@ -474,12 +376,7 @@ test('can resume download using api', async () => { }, 60000); test('can resume upload using api', async () => { - const conn = await repertory.create_pool( - 2, - TEST_HOST, - TEST_PORT, - TEST_PASSWORD - ); + const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD); const api = repertory.create_api(conn); const fd = fs.openSync('test.dat', 'r'); @@ -524,24 +421,14 @@ test('can resume upload using api', async () => { }, 60000); test('exists returns false if directory is not found', async () => { - const conn = await repertory.create_pool( - 2, - TEST_HOST, - TEST_PORT, - TEST_PASSWORD - ); + const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD); const api = repertory.create_api(conn); expect(await api.directory.exists('/cow')).toEqual(false); await conn.disconnect(); }); test('exists returns false if file is not found', async () => { - const conn = await repertory.create_pool( - 2, - TEST_HOST, - TEST_PORT, - TEST_PASSWORD - ); + const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD); const api = repertory.create_api(conn); expect(await api.file.exists('/cow')).toEqual(false); await conn.disconnect(); diff --git a/src/index.js b/src/index.js index ec9d35d..07077cf 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,5 @@ 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'; @@ -9,7 +8,13 @@ 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(); + try { + await conn.connect(); + } catch (e) { + await conn.disconnect(); + throw e; + } + return conn; }; @@ -85,10 +90,6 @@ export const create_api = (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); +export const create = async (host_or_ip, port, password) => { + return connect(host_or_ip, port, password); }; diff --git a/src/networking/connection.js b/src/networking/connection.js index e7bc239..e85f8ed 100644 --- a/src/networking/connection.js +++ b/src/networking/connection.js @@ -39,21 +39,21 @@ export default class connection { this.host_or_ip, (err) => { if (err) { - console.log(err); + console.error(err); return reject(err); } this.reject = reject; this.resolve = resolve; + + this.connected = true; + this.setup_socket(); } ); }); } catch (err) { return Promise.reject(new Error(`'connect()' failed: ${err}`)); } - - this.connected = true; - this.setup_socket(); } } @@ -88,6 +88,7 @@ export default class connection { }; }; + this.buffer = null; const response = new packet(this.password); response.buffer = new Uint8Array(packet_data); response @@ -100,7 +101,7 @@ export default class connection { } }) .catch((e) => { - console.log(e); + console.error(e); const { reject } = complete(); if (reject) { reject(e); @@ -118,7 +119,7 @@ export default class connection { cleanup(); this.connected = false; - console.log(e); + console.error(e); if (reject) { reject(e); } @@ -132,7 +133,7 @@ export default class connection { cleanup(); this.connected = false; - console.log('socket closed'); + console.warn('socket closed'); if (reject) { reject(new Error('socket closed')); } @@ -149,7 +150,7 @@ export default class connection { this.connected = false; } } catch (e) { - console.log(e); + console.error(e); } } @@ -160,7 +161,7 @@ export default class connection { 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); + packet.encode_top_utf8(this.nonce); await packet.encrypt(); packet.encode_top_ui32(packet.buffer.length); return new Promise((resolve, reject) => { diff --git a/src/networking/connection_pool.js b/src/networking/connection_pool.js deleted file mode 100644 index e958f44..0000000 --- a/src/networking/connection_pool.js +++ /dev/null @@ -1,69 +0,0 @@ -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}`)); - } - } -} diff --git a/src/networking/packet.js b/src/networking/packet.js index 8b8c77b..40dceeb 100644 --- a/src/networking/packet.js +++ b/src/networking/packet.js @@ -1,6 +1,6 @@ import { randomBytes } from 'crypto'; import { Int64BE, Uint64BE } from 'int64-buffer'; -import crypto from 'crypto'; +import blake2b from 'blake2b'; import { TextEncoder } from 'text-encoding'; import { getCustomEncryption } from '../utils/constants'; import { @@ -156,7 +156,7 @@ export default class packet { decrypt = async () => { try { - let hash = crypto.createHash('sha256'); + let hash = blake2b(32); hash = hash.update(new TextEncoder().encode(this.token)); const key = Uint8Array.from(hash.digest()); @@ -282,7 +282,7 @@ export default class packet { encrypt = async (nonce) => { try { - let hash = crypto.createHash('sha256'); + let hash = blake2b(32); hash = hash.update(new TextEncoder().encode(this.token)); const key = Uint8Array.from(hash.digest()); diff --git a/src/ops/index.js b/src/ops/index.js index 51f855b..dc388b3 100644 --- a/src/ops/index.js +++ b/src/ops/index.js @@ -3,6 +3,7 @@ import { Uint64BE } from 'int64-buffer'; import file from '../io/file'; import packet from '../networking/packet'; +import { RW_BUFFER_SIZE } from '../utils/constants'; const _snapshot_directory = async (conn, remote_path) => { try { @@ -167,14 +168,14 @@ export const download_file = async ( try { await src.close(); } catch (err) { - console.log(err); + console.error(err); } try { if (fd !== undefined) { fs.closeSync(fd); } } catch (err) { - console.log(err); + console.error(err); } }; @@ -218,7 +219,7 @@ export const download_file = async ( let remain = src_size - offset; while (remain > 0) { - const to_write = remain >= 65536 ? 65536 : remain; + const to_write = remain >= RW_BUFFER_SIZE ? RW_BUFFER_SIZE : remain; const buffer = await src.read(offset, to_write); const written = fs.writeSync(dst_fd, buffer, 0, to_write, offset); if (written > 0) { @@ -466,14 +467,14 @@ export const upload_file = async ( try { fs.closeSync(src_fd); } catch (err) { - console.log(err); + console.error(err); } try { if (f) { await f.close(); } } catch (err) { - console.log(err); + console.error(err); } }; try { @@ -531,7 +532,7 @@ export const upload_file = async ( } let remain = src_st.size - offset; - const default_buffer = Buffer.alloc(65536 * 2); + const default_buffer = Buffer.alloc(RW_BUFFER_SIZE); while (remain > 0) { const to_write = remain >= default_buffer.length ? default_buffer.length : remain; diff --git a/src/utils/constants.js b/src/utils/constants.js index d1e15ca..0447efb 100644 --- a/src/utils/constants.js +++ b/src/utils/constants.js @@ -14,3 +14,4 @@ export const setCustomEncryption = (ce) => { export const instance_id = uuidv4(); export const package_json = _package_json; export const get_version = () => _package_json.version; +export const RW_BUFFER_SIZE = 1024 * 1024;