Merged 1.3.1_branch into master

This commit is contained in:
2021-06-02 00:24:38 -05:00
8 changed files with 129 additions and 11 deletions

8
CHANGELOG.md Normal file
View File

@@ -0,0 +1,8 @@
# Changelog
## 1.3.1-r3
- Added directory/file exists
- Fix unit tests
## 1.3.1-r2
- Initial release

View File

@@ -56,6 +56,7 @@ also be set to a strong, random password.
```javascript
import * as rep from "@blockstorage/repertory-js";
//const rep = require("@blockstorage/repertory-js");
// Repertory host settings
@@ -78,6 +79,9 @@ const conn = await rep.create_pool(8, MY_HOST_OR_IP, MY_PORT, MY_TOKEN);
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 //
@@ -94,6 +98,9 @@ const api = rep.create_api(conn);
// *********** 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++) {
@@ -126,6 +133,9 @@ await api.directory.remove('/test')
// *********** File Operations *********** //
//------------------------------------------------------------------------------------------------//
// Check if file exists
const exists = await api.file.exists('/my_file.txt')
// Delete a file
await api.file.delete('/my_file.txt')

View File

@@ -1,6 +1,6 @@
{
"name": "@blockstorage/repertory-js",
"version": "1.3.1-r2",
"version": "1.3.1-r3",
"description": "A Node.js module for interfacing with Repertory's remote mount API",
"author": "scott.e.graves@protonmail.com",
"license": "MIT",

View File

@@ -1,4 +1,4 @@
import {get_version, instance_id, package_json} from '../utils/constants';
import { get_version, instance_id, package_json } from '../utils/constants';
import * as uuid from 'uuid';
test(`can read 'package.json'`, () => {
@@ -14,7 +14,7 @@ test(`'instance_id' is valid`, () => {
test(`'version' can be read from 'package.json'`, () => {
console.log(get_version());
expect(get_version()).toBe('1.3.1-r1');
expect(get_version()).toBe('1.3.1-r3');
});
test(`'version' can be overridden by environment variable`, () => {

View File

@@ -102,6 +102,8 @@ test('can create and remove a directory using api', async () => {
);
const api = repertory.create_api(conn);
expect(await api.directory.create('/repertory_js')).toEqual(0);
expect(await api.directory.exists('/repertory_js')).toEqual(true);
expect(await api.file.exists('/repertory_js')).toEqual(false);
expect(await api.directory.remove('/repertory_js')).toEqual(0);
await conn.disconnect();
@@ -278,6 +280,8 @@ test('can upload and download a file using api', async () => {
await calculate_sha256('repertory_test.dat')
);
expect(await api.directory.exists('/repertory_test.dat')).toEqual(false);
expect(await api.file.exists('/repertory_test.dat')).toEqual(true);
expect(await api.file.delete('/repertory_test.dat')).toEqual(0);
fs.unlinkSync('repertory_test.dat');
@@ -518,3 +522,27 @@ test('can resume upload using api', async () => {
await conn.disconnect();
}, 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 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 api = repertory.create_api(conn);
expect(await api.file.exists('/cow')).toEqual(false);
await conn.disconnect();
});

View File

@@ -13,6 +13,17 @@ 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),
@@ -43,6 +54,17 @@ export const create_api = (conn) => {
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),
upload: async (local_path, remote_path, progress_cb, overwrite, resume) =>

View File

@@ -38,6 +38,7 @@ export default class connection {
this.host_or_ip,
(err) => {
if (err) {
console.log(err);
return reject(err);
}
return resolve();
@@ -67,20 +68,32 @@ export default class connection {
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);
}
});
}
}
@@ -94,8 +107,11 @@ export default class connection {
cleanup();
this.connected = false;
console.log(e);
if (reject) {
reject(e);
}
}
});
this.socket.on('close', () => {
@@ -105,8 +121,11 @@ export default class connection {
cleanup();
this.connected = false;
console.log('socket closed');
if (reject) {
reject(new Error('socket closed'));
}
}
});
}

View File

@@ -312,6 +312,37 @@ export const get_file_attributes = async (
}
};
export const get_file_attributes2 = async (
conn,
remote_path,
optional_thread_id
) => {
try {
const request = new packet();
request.encode_utf8(remote_path);
request.encode_ui32(0);
request.encode_ui32(0);
const response = await conn.send(
'::RemoteFUSEGetattr',
request,
optional_thread_id
);
response.decode_ui32(); // Service flags
const result = response.decode_i32();
if (result === 0) {
return response.decode_stat();
}
return Promise.reject(
new Error(`'get_file_attributes2' failed: ${result}`)
);
} catch (err) {
return Promise.reject(new Error(`'get_file_attributes2' failed: ${err}`));
}
};
export const list_directory = async (conn, remote_path, page_reader_cb) => {
const dir_snapshot = await _snapshot_directory(conn, remote_path);
try {