2.0.0-r1 #2
7
.cspell/words.txt
Normal file
7
.cspell/words.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
alloc
|
||||||
|
blockstorage
|
||||||
|
fuse_fgetattr
|
||||||
|
fuse_getattr
|
||||||
|
stablelib
|
||||||
|
uuidv4
|
||||||
|
xchacha20poly1305
|
||||||
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
fixup text eol=lf
|
||||||
5
.nvimrc
5
.nvimrc
@@ -1,3 +1,2 @@
|
|||||||
set path+=.,src/**
|
set path+=.,src/**
|
||||||
let &makeprg="npm run build"
|
let &makeprg="npm run build"
|
||||||
|
|
||||||
|
|||||||
12
CHANGELOG.md
12
CHANGELOG.md
@@ -1,14 +1,22 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2.0.0-r1
|
||||||
|
|
||||||
|
- Integrated `repertory` v2.0 changes
|
||||||
|
- Removed connection pool
|
||||||
|
|
||||||
## 1.4.0-r1
|
## 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
|
- Support writing base64 string data
|
||||||
- Renamed 'delete/delete_file' to 'remove/remove_file'
|
- Renamed 'delete/delete_file' to 'remove/remove_file'
|
||||||
|
|
||||||
## 1.3.1-r3
|
## 1.3.1-r3
|
||||||
|
|
||||||
- Added directory/file exists
|
- Added directory/file exists
|
||||||
- Fix unit tests
|
- Fix unit tests
|
||||||
|
|
||||||
## 1.3.1-r2
|
## 1.3.1-r2
|
||||||
|
|
||||||
- Initial release
|
- Initial release
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# `repertory-js` MIT License
|
# `repertory-js` MIT License
|
||||||
|
|
||||||
### Copyright <2021> <scott.e.graves@protonmail.com>
|
### Copyright <2021-2025> <scott.e.graves@protonmail.com>
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
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,
|
associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||||
|
|||||||
80
README.md
80
README.md
@@ -1,6 +1,7 @@
|
|||||||
# About
|
# 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
|
## Installing
|
||||||
|
|
||||||
@@ -10,43 +11,44 @@ npm i @blockstorage/repertory-js
|
|||||||
|
|
||||||
## Repertory Configuration
|
## Repertory Configuration
|
||||||
|
|
||||||
A Repertory mount must be active with the `EnableRemoteMount` setting enabled. `RemoteToken` should
|
A Repertory mount must be active with the `RemoteMount.Enable` setting enabled.
|
||||||
also be set to a strong, random password.
|
`RemoteMount.EncryptionToken` should also be set to a strong, random password.
|
||||||
|
|
||||||
### Enabling Sia Remote Mount API on Windows Systems
|
### Enabling Sia Remote Mount API on Windows Systems
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
repertory.exe -unmount
|
repertory.exe -unmount
|
||||||
repertory.exe -set RemoteMount.EnableRemoteMount true
|
repertory.exe -set RemoteMount.Enable true
|
||||||
repertory.exe -set RemoteMount.RemoteToken "my password"
|
repertory.exe -set RemoteMount.EncryptionToken 'my password'
|
||||||
|
|
||||||
[Optional - change listening port]
|
[Optional - change listening port]
|
||||||
repertory.exe -set RemoteMount.RemotePort 20202
|
repertory.exe -set RemoteMount.ApiPort 20202
|
||||||
```
|
```
|
||||||
|
|
||||||
### Enabling Sia Remote Mount API on *NIX Systems
|
### Enabling Sia Remote Mount API on *NIX Systems
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
./repertory -unmount
|
./repertory -unmount
|
||||||
./repertory -set RemoteMount.EnableRemoteMount true
|
./repertory -set RemoteMount.Enable true
|
||||||
./repertory -set RemoteMount.RemoteToken "my password"
|
./repertory -set RemoteMount.EncryptionToken 'my password'
|
||||||
|
|
||||||
[Optional - change listening port]
|
[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 S3 mounts, add `-s3` and `--name '<my config name>'` argument to all
|
||||||
* For ScPrime mounts, add `-sp` argument to all commands listed above.
|
commands listed above.
|
||||||
|
|
||||||
## Module Environment Variables
|
## Module Environment Variables
|
||||||
|
|
||||||
* To successfully complete unit tests, a `repertory` mount supporting remote mount needs to be
|
* To successfully complete unit tests, a `repertory` mount supporting remote
|
||||||
active. Set the following environment variables prior to running tests:
|
mount needs to be active. Set the following environment variables prior to
|
||||||
* `TEST_HOST`
|
running tests:
|
||||||
* `TEST_PASSWORD`
|
* `TEST_HOST`
|
||||||
* `TEST_PORT`
|
* `TEST_PASSWORD`
|
||||||
|
* `TEST_PORT`
|
||||||
|
|
||||||
## Example API Usage
|
## Example API Usage
|
||||||
|
|
||||||
@@ -58,7 +60,7 @@ import * as rep from "@blockstorage/repertory-js";
|
|||||||
// Repertory host settings
|
// Repertory host settings
|
||||||
const MY_HOST_OR_IP = 'localhost';
|
const MY_HOST_OR_IP = 'localhost';
|
||||||
const MY_PORT = 20000;
|
const MY_PORT = 20000;
|
||||||
const MY_TOKEN = 'password';
|
const MY_PASSWORD = 'password';
|
||||||
|
|
||||||
// Progress callback for uploads / downloads
|
// Progress callback for uploads / downloads
|
||||||
const progress_cb = (local_path, remote_path, progress, completed) => {
|
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) //
|
// Step 1. Create a connection //
|
||||||
//************************************************************************************************//
|
//****************************************************************************//
|
||||||
|
const conn = await rep.connect(MY_HOST_OR_IP, MY_PORT, MY_PASSWORD);
|
||||||
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
|
/* Disconnect when complete
|
||||||
await conn.disconnect();
|
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);
|
const api = rep.create_api(conn);
|
||||||
|
|
||||||
|
|
||||||
//************************************************************************************************//
|
//****************************************************************************//
|
||||||
// Step 3. Use 'api' //
|
// Step 3. Use 'api' //
|
||||||
//************************************************************************************************//
|
//****************************************************************************//
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------//
|
//----------------------------------------------------------------------------//
|
||||||
// *********** Directory Operations *********** //
|
// *********** Directory Operations *********** //
|
||||||
//------------------------------------------------------------------------------------------------//
|
//----------------------------------------------------------------------------//
|
||||||
|
|
||||||
// Check if directory exists
|
// Check if directory exists
|
||||||
const exists = await api.directory.exists('/my_directory');
|
const exists = await api.directory.exists('/my_directory');
|
||||||
@@ -125,9 +123,9 @@ await api.directory.create('/test');
|
|||||||
await api.directory.remove('/test')
|
await api.directory.remove('/test')
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------//
|
//----------------------------------------------------------------------------//
|
||||||
// *********** File Operations *********** //
|
// *********** File Operations *********** //
|
||||||
//------------------------------------------------------------------------------------------------//
|
//----------------------------------------------------------------------------//
|
||||||
|
|
||||||
// Check if file exists
|
// Check if file exists
|
||||||
const exists = await api.file.exists('/my_file.txt')
|
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);
|
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
|
// Create or open a remote file
|
||||||
{
|
{
|
||||||
|
|||||||
16
cspell.json
Normal file
16
cspell.json
Normal file
@@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
22
fixup
22
fixup
@@ -1,11 +1,11 @@
|
|||||||
cat <<EOF >dist/cjs/package.json
|
cat <<EOF >dist/cjs/package.json
|
||||||
{
|
{
|
||||||
"type": "commonjs"
|
"type": "commonjs"
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
cat <<EOF >dist/mjs/package.json
|
cat <<EOF >dist/mjs/package.json
|
||||||
{
|
{
|
||||||
"type": "module"
|
"type": "module"
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|||||||
@@ -37,15 +37,16 @@
|
|||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "rollup -c && ./fixup",
|
"build": "rollup -c && ./fixup",
|
||||||
|
"build_win": "rollup -c && mingw64 ./fixup",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"prepublish": "rollup -c --silent && ./fixup"
|
"prepublish": "rollup -c --silent && ./fixup"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@stablelib/xchacha20poly1305": "^1.0.1",
|
"@stablelib/xchacha20poly1305": "^1.0.1",
|
||||||
"int64-buffer": "^1.0.0",
|
"blake2b": "^2.1.4",
|
||||||
"socket-pool": "^1.2.3",
|
"int64-buffer": "^1.1.0",
|
||||||
"text-encoding": "^0.7.0",
|
"text-encoding": "^0.7.0",
|
||||||
"uuid": "^8.3.2"
|
"uuid": "^11.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.14.3",
|
"@babel/core": "^7.14.3",
|
||||||
|
|||||||
@@ -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);
|
|
||||||
});
|
|
||||||
@@ -14,5 +14,5 @@ test(`'instance_id' is valid`, () => {
|
|||||||
|
|
||||||
test(`'version' can be read from 'package.json'`, () => {
|
test(`'version' can be read from 'package.json'`, () => {
|
||||||
console.log(get_version());
|
console.log(get_version());
|
||||||
expect(get_version()).toBe('1.4.0-r1');
|
expect(get_version()).toBe('2.0.0-r1');
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import crypto from 'crypto';
|
import blake2b from 'blake2b';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { Uint64BE } from 'int64-buffer';
|
import { Uint64BE } from 'int64-buffer';
|
||||||
|
|
||||||
import * as repertory from '../index.js';
|
import * as repertory from '../index.js';
|
||||||
import connection from '../networking/connection';
|
import connection from '../networking/connection';
|
||||||
import connection_pool from '../networking/connection_pool';
|
|
||||||
|
|
||||||
const TEST_HOST = process.env.TEST_HOST || 'localhost';
|
const TEST_HOST = process.env.TEST_HOST || 'localhost';
|
||||||
const TEST_PASSWORD = process.env.TEST_PASSWORD || '';
|
const TEST_PASSWORD = process.env.TEST_PASSWORD || '';
|
||||||
@@ -12,10 +11,12 @@ const TEST_PORT = process.env.TEST_PORT || 20000;
|
|||||||
|
|
||||||
const calculate_sha256 = (path) => {
|
const calculate_sha256 = (path) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const hash = crypto.createHash('sha256');
|
const hash = blake2b(32);
|
||||||
|
|
||||||
fs.createReadStream(path)
|
fs.createReadStream(path)
|
||||||
.on('data', (data) => hash.update(data))
|
.on('data', (data) => {
|
||||||
|
return hash.update(new Uint8Array(data));
|
||||||
|
})
|
||||||
.on('error', (err) => reject(err))
|
.on('error', (err) => reject(err))
|
||||||
.on('end', () => {
|
.on('end', () => {
|
||||||
const h = hash.digest('hex');
|
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 () => {
|
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);
|
const conn = await repertory.connect(TEST_HOST, TEST_PORT, TEST_PASSWORD);
|
||||||
test_connection(conn, true);
|
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();
|
await conn.disconnect();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('can get drive information using api', async () => {
|
test('can get drive information using api', async () => {
|
||||||
const conn = await repertory.create_pool(
|
const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD);
|
||||||
2,
|
|
||||||
TEST_HOST,
|
|
||||||
TEST_PORT,
|
|
||||||
TEST_PASSWORD
|
|
||||||
);
|
|
||||||
const api = repertory.create_api(conn);
|
const api = repertory.create_api(conn);
|
||||||
const di = await api.get_drive_information();
|
const di = await api.get_drive_information();
|
||||||
console.log(di);
|
|
||||||
|
|
||||||
expect(di.free).toBeDefined();
|
expect(di.free).toBeDefined();
|
||||||
expect(di.total).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 () => {
|
test('can create and remove a directory using api', async () => {
|
||||||
const conn = await repertory.create_pool(
|
const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD);
|
||||||
2,
|
|
||||||
TEST_HOST,
|
|
||||||
TEST_PORT,
|
|
||||||
TEST_PASSWORD
|
|
||||||
);
|
|
||||||
const api = repertory.create_api(conn);
|
const api = repertory.create_api(conn);
|
||||||
expect(await api.directory.create('/repertory_js')).toEqual(0);
|
expect(await api.directory.create('/repertory_js')).toEqual(0);
|
||||||
expect(await api.directory.exists('/repertory_js')).toEqual(true);
|
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 () => {
|
test('can get directory list and snapshot using api', async () => {
|
||||||
const conn = await repertory.create_pool(
|
const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD);
|
||||||
2,
|
|
||||||
TEST_HOST,
|
|
||||||
TEST_PORT,
|
|
||||||
TEST_PASSWORD
|
|
||||||
);
|
|
||||||
const api = repertory.create_api(conn);
|
const api = repertory.create_api(conn);
|
||||||
|
|
||||||
const test_results = async (remote_path, page_count, get_page) => {
|
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);
|
console.log(items);
|
||||||
|
|
||||||
expect(items.length).toBeGreaterThanOrEqual(2);
|
expect(items.length).toBeGreaterThanOrEqual(2);
|
||||||
expect(items[0].directory).toBeTruthy();
|
expect(items[0].Directory).toBeTruthy();
|
||||||
expect(items[0].path).toEqual('.');
|
expect(items[0].ApiPath).toEqual('.');
|
||||||
expect(items[1].directory).toBeTruthy();
|
|
||||||
expect(items[1].path).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 () => {
|
test('can create, close and remove a file using api', async () => {
|
||||||
const conn = await repertory.create_pool(
|
const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD);
|
||||||
2,
|
|
||||||
TEST_HOST,
|
|
||||||
TEST_PORT,
|
|
||||||
TEST_PASSWORD
|
|
||||||
);
|
|
||||||
const api = repertory.create_api(conn);
|
const api = repertory.create_api(conn);
|
||||||
const f = await api.file.create_or_open('/repertory_file.dat');
|
const f = await api.file.create_or_open('/repertory_file.dat');
|
||||||
console.log(f);
|
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 () => {
|
test('can open, close and remove a file using api', async () => {
|
||||||
const conn = await repertory.create_pool(
|
const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD);
|
||||||
2,
|
|
||||||
TEST_HOST,
|
|
||||||
TEST_PORT,
|
|
||||||
TEST_PASSWORD
|
|
||||||
);
|
|
||||||
const api = repertory.create_api(conn);
|
const api = repertory.create_api(conn);
|
||||||
let f = await api.file.create_or_open('/repertory_file.dat');
|
let f = await api.file.create_or_open('/repertory_file.dat');
|
||||||
expect(await f.close()).toEqual(0);
|
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 () => {
|
test('can write to and read from a file using api', async () => {
|
||||||
const conn = await repertory.create_pool(
|
const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD);
|
||||||
2,
|
|
||||||
TEST_HOST,
|
|
||||||
TEST_PORT,
|
|
||||||
TEST_PASSWORD
|
|
||||||
);
|
|
||||||
const api = repertory.create_api(conn);
|
const api = repertory.create_api(conn);
|
||||||
const f = await api.file.create_or_open('/repertory_file.dat');
|
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 () => {
|
test('can truncate a file using api', async () => {
|
||||||
const conn = await repertory.create_pool(
|
const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD);
|
||||||
2,
|
|
||||||
TEST_HOST,
|
|
||||||
TEST_PORT,
|
|
||||||
TEST_PASSWORD
|
|
||||||
);
|
|
||||||
const api = repertory.create_api(conn);
|
const api = repertory.create_api(conn);
|
||||||
const f = await api.file.create_or_open('/repertory_file.dat');
|
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');
|
fs.unlinkSync('repertory_test.dat');
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|
||||||
const conn = await repertory.create_pool(
|
const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD);
|
||||||
2,
|
|
||||||
TEST_HOST,
|
|
||||||
TEST_PORT,
|
|
||||||
TEST_PASSWORD
|
|
||||||
);
|
|
||||||
const api = repertory.create_api(conn);
|
const api = repertory.create_api(conn);
|
||||||
expect(
|
expect(
|
||||||
await api.file.upload('test.dat', '/repertory_test.dat', (l, r, p, c) => {
|
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);
|
}, 60000);
|
||||||
|
|
||||||
test('can download and overwrite a file using api', async () => {
|
test('can download and overwrite a file using api', async () => {
|
||||||
const conn = await repertory.create_pool(
|
const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD);
|
||||||
2,
|
|
||||||
TEST_HOST,
|
|
||||||
TEST_PORT,
|
|
||||||
TEST_PASSWORD
|
|
||||||
);
|
|
||||||
const api = repertory.create_api(conn);
|
const api = repertory.create_api(conn);
|
||||||
expect(
|
expect(
|
||||||
await api.file.upload('test.dat', '/repertory_test.dat', (l, r, p, c) => {
|
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);
|
}, 60000);
|
||||||
|
|
||||||
test('download fails if overwrite is false using api', async () => {
|
test('download fails if overwrite is false using api', async () => {
|
||||||
const conn = await repertory.create_pool(
|
const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD);
|
||||||
2,
|
|
||||||
TEST_HOST,
|
|
||||||
TEST_PORT,
|
|
||||||
TEST_PASSWORD
|
|
||||||
);
|
|
||||||
const api = repertory.create_api(conn);
|
const api = repertory.create_api(conn);
|
||||||
expect(
|
expect(
|
||||||
await api.file.upload('test.dat', '/repertory_test.dat', (l, r, p, c) => {
|
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);
|
}, 60000);
|
||||||
|
|
||||||
test('can upload and overwrite a file using api', async () => {
|
test('can upload and overwrite a file using api', async () => {
|
||||||
const conn = await repertory.create_pool(
|
const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD);
|
||||||
2,
|
|
||||||
TEST_HOST,
|
|
||||||
TEST_PORT,
|
|
||||||
TEST_PASSWORD
|
|
||||||
);
|
|
||||||
const api = repertory.create_api(conn);
|
const api = repertory.create_api(conn);
|
||||||
expect(
|
expect(
|
||||||
await api.file.upload('test.dat', '/repertory_test.dat', (l, r, p, c) => {
|
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);
|
}, 60000);
|
||||||
|
|
||||||
test('upload fails if overwrite is false using api', async () => {
|
test('upload fails if overwrite is false using api', async () => {
|
||||||
const conn = await repertory.create_pool(
|
const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD);
|
||||||
2,
|
|
||||||
TEST_HOST,
|
|
||||||
TEST_PORT,
|
|
||||||
TEST_PASSWORD
|
|
||||||
);
|
|
||||||
const api = repertory.create_api(conn);
|
const api = repertory.create_api(conn);
|
||||||
expect(
|
expect(
|
||||||
await api.file.upload('test.dat', '/repertory_test.dat', (l, r, p, c) => {
|
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);
|
}, 60000);
|
||||||
|
|
||||||
test('can resume download using api', async () => {
|
test('can resume download using api', async () => {
|
||||||
const conn = await repertory.create_pool(
|
const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD);
|
||||||
2,
|
|
||||||
TEST_HOST,
|
|
||||||
TEST_PORT,
|
|
||||||
TEST_PASSWORD
|
|
||||||
);
|
|
||||||
const api = repertory.create_api(conn);
|
const api = repertory.create_api(conn);
|
||||||
expect(
|
expect(
|
||||||
await api.file.upload('test.dat', '/repertory_test.dat', (l, r, p, c) => {
|
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);
|
}, 60000);
|
||||||
|
|
||||||
test('can resume upload using api', async () => {
|
test('can resume upload using api', async () => {
|
||||||
const conn = await repertory.create_pool(
|
const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD);
|
||||||
2,
|
|
||||||
TEST_HOST,
|
|
||||||
TEST_PORT,
|
|
||||||
TEST_PASSWORD
|
|
||||||
);
|
|
||||||
const api = repertory.create_api(conn);
|
const api = repertory.create_api(conn);
|
||||||
|
|
||||||
const fd = fs.openSync('test.dat', 'r');
|
const fd = fs.openSync('test.dat', 'r');
|
||||||
@@ -524,24 +421,14 @@ test('can resume upload using api', async () => {
|
|||||||
}, 60000);
|
}, 60000);
|
||||||
|
|
||||||
test('exists returns false if directory is not found', async () => {
|
test('exists returns false if directory is not found', async () => {
|
||||||
const conn = await repertory.create_pool(
|
const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD);
|
||||||
2,
|
|
||||||
TEST_HOST,
|
|
||||||
TEST_PORT,
|
|
||||||
TEST_PASSWORD
|
|
||||||
);
|
|
||||||
const api = repertory.create_api(conn);
|
const api = repertory.create_api(conn);
|
||||||
expect(await api.directory.exists('/cow')).toEqual(false);
|
expect(await api.directory.exists('/cow')).toEqual(false);
|
||||||
await conn.disconnect();
|
await conn.disconnect();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('exists returns false if file is not found', async () => {
|
test('exists returns false if file is not found', async () => {
|
||||||
const conn = await repertory.create_pool(
|
const conn = await repertory.create(TEST_HOST, TEST_PORT, TEST_PASSWORD);
|
||||||
2,
|
|
||||||
TEST_HOST,
|
|
||||||
TEST_PORT,
|
|
||||||
TEST_PASSWORD
|
|
||||||
);
|
|
||||||
const api = repertory.create_api(conn);
|
const api = repertory.create_api(conn);
|
||||||
expect(await api.file.exists('/cow')).toEqual(false);
|
expect(await api.file.exists('/cow')).toEqual(false);
|
||||||
await conn.disconnect();
|
await conn.disconnect();
|
||||||
|
|||||||
17
src/index.js
17
src/index.js
@@ -1,6 +1,5 @@
|
|||||||
import file from './io/file';
|
import file from './io/file';
|
||||||
import connection from './networking/connection';
|
import connection from './networking/connection';
|
||||||
import connection_pool from './networking/connection_pool';
|
|
||||||
import * as ops from './ops';
|
import * as ops from './ops';
|
||||||
|
|
||||||
export * as byte_order from './utils/byte_order';
|
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) => {
|
export const connect = async (host_or_ip, port, password) => {
|
||||||
const conn = new connection(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;
|
return conn;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -85,10 +90,6 @@ export const create_api = (conn) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const create_pool = async (pool_size, host_or_ip, port, password) => {
|
export const create = async (host_or_ip, port, password) => {
|
||||||
if (pool_size <= 1) {
|
return connect(host_or_ip, port, password);
|
||||||
return connect(host_or_ip, port, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new connection_pool(pool_size, host_or_ip, port, password);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -39,21 +39,21 @@ export default class connection {
|
|||||||
this.host_or_ip,
|
this.host_or_ip,
|
||||||
(err) => {
|
(err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
return reject(err);
|
return reject(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.reject = reject;
|
this.reject = reject;
|
||||||
this.resolve = resolve;
|
this.resolve = resolve;
|
||||||
|
|
||||||
|
this.connected = true;
|
||||||
|
this.setup_socket();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return Promise.reject(new Error(`'connect()' failed: ${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);
|
const response = new packet(this.password);
|
||||||
response.buffer = new Uint8Array(packet_data);
|
response.buffer = new Uint8Array(packet_data);
|
||||||
response
|
response
|
||||||
@@ -100,7 +101,7 @@ export default class connection {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.log(e);
|
console.error(e);
|
||||||
const { reject } = complete();
|
const { reject } = complete();
|
||||||
if (reject) {
|
if (reject) {
|
||||||
reject(e);
|
reject(e);
|
||||||
@@ -118,7 +119,7 @@ export default class connection {
|
|||||||
cleanup();
|
cleanup();
|
||||||
|
|
||||||
this.connected = false;
|
this.connected = false;
|
||||||
console.log(e);
|
console.error(e);
|
||||||
if (reject) {
|
if (reject) {
|
||||||
reject(e);
|
reject(e);
|
||||||
}
|
}
|
||||||
@@ -132,7 +133,7 @@ export default class connection {
|
|||||||
cleanup();
|
cleanup();
|
||||||
|
|
||||||
this.connected = false;
|
this.connected = false;
|
||||||
console.log('socket closed');
|
console.warn('socket closed');
|
||||||
if (reject) {
|
if (reject) {
|
||||||
reject(new Error('socket closed'));
|
reject(new Error('socket closed'));
|
||||||
}
|
}
|
||||||
@@ -149,7 +150,7 @@ export default class connection {
|
|||||||
this.connected = false;
|
this.connected = false;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} 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_utf8(constants.instance_id);
|
||||||
packet.encode_top_ui32(0); // Service flags
|
packet.encode_top_ui32(0); // Service flags
|
||||||
packet.encode_top_utf8(constants.get_version());
|
packet.encode_top_utf8(constants.get_version());
|
||||||
packet.encode_top_utf8(nonce);
|
packet.encode_top_utf8(this.nonce);
|
||||||
await packet.encrypt();
|
await packet.encrypt();
|
||||||
packet.encode_top_ui32(packet.buffer.length);
|
packet.encode_top_ui32(packet.buffer.length);
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
|||||||
@@ -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}`));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { randomBytes } from 'crypto';
|
import { randomBytes } from 'crypto';
|
||||||
import { Int64BE, Uint64BE } from 'int64-buffer';
|
import { Int64BE, Uint64BE } from 'int64-buffer';
|
||||||
import crypto from 'crypto';
|
import blake2b from 'blake2b';
|
||||||
import { TextEncoder } from 'text-encoding';
|
import { TextEncoder } from 'text-encoding';
|
||||||
import { getCustomEncryption } from '../utils/constants';
|
import { getCustomEncryption } from '../utils/constants';
|
||||||
import {
|
import {
|
||||||
@@ -156,7 +156,7 @@ export default class packet {
|
|||||||
|
|
||||||
decrypt = async () => {
|
decrypt = async () => {
|
||||||
try {
|
try {
|
||||||
let hash = crypto.createHash('sha256');
|
let hash = blake2b(32);
|
||||||
hash = hash.update(new TextEncoder().encode(this.token));
|
hash = hash.update(new TextEncoder().encode(this.token));
|
||||||
|
|
||||||
const key = Uint8Array.from(hash.digest());
|
const key = Uint8Array.from(hash.digest());
|
||||||
@@ -282,7 +282,7 @@ export default class packet {
|
|||||||
|
|
||||||
encrypt = async (nonce) => {
|
encrypt = async (nonce) => {
|
||||||
try {
|
try {
|
||||||
let hash = crypto.createHash('sha256');
|
let hash = blake2b(32);
|
||||||
hash = hash.update(new TextEncoder().encode(this.token));
|
hash = hash.update(new TextEncoder().encode(this.token));
|
||||||
|
|
||||||
const key = Uint8Array.from(hash.digest());
|
const key = Uint8Array.from(hash.digest());
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Uint64BE } from 'int64-buffer';
|
|||||||
|
|
||||||
import file from '../io/file';
|
import file from '../io/file';
|
||||||
import packet from '../networking/packet';
|
import packet from '../networking/packet';
|
||||||
|
import { RW_BUFFER_SIZE } from '../utils/constants';
|
||||||
|
|
||||||
const _snapshot_directory = async (conn, remote_path) => {
|
const _snapshot_directory = async (conn, remote_path) => {
|
||||||
try {
|
try {
|
||||||
@@ -167,14 +168,14 @@ export const download_file = async (
|
|||||||
try {
|
try {
|
||||||
await src.close();
|
await src.close();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (fd !== undefined) {
|
if (fd !== undefined) {
|
||||||
fs.closeSync(fd);
|
fs.closeSync(fd);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -218,7 +219,7 @@ export const download_file = async (
|
|||||||
|
|
||||||
let remain = src_size - offset;
|
let remain = src_size - offset;
|
||||||
while (remain > 0) {
|
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 buffer = await src.read(offset, to_write);
|
||||||
const written = fs.writeSync(dst_fd, buffer, 0, to_write, offset);
|
const written = fs.writeSync(dst_fd, buffer, 0, to_write, offset);
|
||||||
if (written > 0) {
|
if (written > 0) {
|
||||||
@@ -466,14 +467,14 @@ export const upload_file = async (
|
|||||||
try {
|
try {
|
||||||
fs.closeSync(src_fd);
|
fs.closeSync(src_fd);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (f) {
|
if (f) {
|
||||||
await f.close();
|
await f.close();
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
@@ -531,7 +532,7 @@ export const upload_file = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
let remain = src_st.size - offset;
|
let remain = src_st.size - offset;
|
||||||
const default_buffer = Buffer.alloc(65536 * 2);
|
const default_buffer = Buffer.alloc(RW_BUFFER_SIZE);
|
||||||
while (remain > 0) {
|
while (remain > 0) {
|
||||||
const to_write =
|
const to_write =
|
||||||
remain >= default_buffer.length ? default_buffer.length : remain;
|
remain >= default_buffer.length ? default_buffer.length : remain;
|
||||||
|
|||||||
@@ -14,3 +14,4 @@ export const setCustomEncryption = (ce) => {
|
|||||||
export const instance_id = uuidv4();
|
export const instance_id = uuidv4();
|
||||||
export const package_json = _package_json;
|
export const package_json = _package_json;
|
||||||
export const get_version = () => _package_json.version;
|
export const get_version = () => _package_json.version;
|
||||||
|
export const RW_BUFFER_SIZE = 1024 * 1024;
|
||||||
|
|||||||
Reference in New Issue
Block a user