added directory snapshot

This commit is contained in:
2021-03-09 16:05:24 -06:00
parent b553984808
commit e783d490a7
4 changed files with 354 additions and 295 deletions

View File

@@ -102,6 +102,19 @@ await api.directory.list('/', async (remote_path, page_count, get_page) => {
} }
}); });
// 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 // Create new directory
await api.directory.create('/test'); await api.directory.create('/test');

View File

@@ -91,12 +91,12 @@ test('can create and remove a directory using api', async () => {
await conn.disconnect(); await conn.disconnect();
}); });
test('can get directory list using api', async () => { test('can get directory list and snapshot using api', async () => {
const conn = const conn =
await repertory.create_pool(2, TEST_HOST, TEST_PORT, TEST_PASSWORD); await repertory.create_pool(2, TEST_HOST, TEST_PORT, TEST_PASSWORD);
const api = repertory.create_api(conn); const api = repertory.create_api(conn);
await api.directory.list('/', async (remote_path, page_count, get_page) => {
console.log(remote_path, page_count, get_page); const test_results = async (remote_path, page_count, get_page) => {
expect(remote_path).toEqual('/'); expect(remote_path).toEqual('/');
expect(page_count).toBeGreaterThanOrEqual(1); expect(page_count).toBeGreaterThanOrEqual(1);
expect(get_page).toBeInstanceOf(Function); expect(get_page).toBeInstanceOf(Function);
@@ -110,8 +110,23 @@ test('can get directory list using api', async () => {
expect(items[1].directory).toBeTruthy(); expect(items[1].directory).toBeTruthy();
expect(items[1].path).toEqual('..'); expect(items[1].path).toEqual('..');
} }
};
await api.directory.list('/', async (remote_path, page_count, get_page) => {
console.log(remote_path, page_count, get_page);
await test_results(remote_path, page_count, get_page);
}); });
const snap = await api.directory.snapshot('/');
try {
console.log(snap.remote_path, snap.page_count, snap.get_page);
await test_results(snap.remote_path, snap.page_count, snap.get_page);
} catch (err) {
console.log(err);
} finally {
await snap.release();
}
await conn.disconnect(); await conn.disconnect();
}); });

View File

@@ -12,10 +12,13 @@ export const connect = async (host_or_ip, port, password) => {
export const create_api = conn => { export const create_api = conn => {
return { return {
directory : { directory : {
create: async remote_path => ops.create_directory(conn, remote_path),
list: async (remote_path, page_reader_cb) => list: async (remote_path, page_reader_cb) =>
ops.list_directory(conn, remote_path, page_reader_cb), ops.list_directory(conn, remote_path, page_reader_cb),
create : async remote_path => ops.create_directory(conn, remote_path),
remove: async remote_path => ops.remove_directory(conn, remote_path), remove: async remote_path => ops.remove_directory(conn, remote_path),
snapshot: async remote_path => {
return ops.snapshot_directory(conn, remote_path);
},
}, },
file : { file : {
create_or_open : async remote_path => new file( create_or_open : async remote_path => new file(

View File

@@ -4,6 +4,69 @@ 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';
const _snapshot_directory = async (conn, remote_path) => {
try {
const request = new packet();
request.encode_utf8(remote_path);
const response =
await conn.send('::RemoteJSONCreateDirectorySnapshot', request);
response.decode_ui32(); // Service flags
const result = response.decode_i32();
if (result === 0) {
const data = JSON.parse(response.decode_utf8());
let released = false;
const release = async () => {
if (!released) {
released = true;
const request = new packet();
request.encode_ui64(data.handle);
await conn.send('::RemoteJSONReleaseDirectorySnapshot', request);
}
};
try {
const get_page = async page => {
try {
const request = new packet();
request.encode_utf8(remote_path);
request.encode_ui64(data.handle);
request.encode_ui32(page);
const response =
await conn.send('::RemoteJSONReadDirectorySnapshot', request);
response.decode_ui32(); // Service flags
const result = response.decode_i32();
if (result === 0 || result === -120) {
const data = JSON.parse(response.decode_utf8());
return data.directory_list;
}
} catch (err) {
await release();
return Promise.reject(new Error(`'get_page' failed: ${err}`));
}
return [];
};
return {
get_page,
page_count: data.page_count,
release,
remote_path,
};
} catch (err) {
await release();
return Promise.reject(new Error(`'snapshot_directory' failed: ${err}`));
}
}
} catch (err) {
return Promise.reject(new Error(`'snapshot_directory' failed: ${err}`));
}
};
export const close_file = export const close_file =
async (conn, remote_path, handle, optional_thread_id) => { async (conn, remote_path, handle, optional_thread_id) => {
try { try {
@@ -209,50 +272,13 @@ export const get_file_attributes =
}; };
export const list_directory = async (conn, remote_path, page_reader_cb) => { export const list_directory = async (conn, remote_path, page_reader_cb) => {
const dir_snapshot = await _snapshot_directory(conn, remote_path);
try { try {
const request = new packet(); await page_reader_cb(dir_snapshot.remote_path, dir_snapshot.page_count, dir_snapshot.get_page);
request.encode_utf8(remote_path); await dir_snapshot.release();
const response =
await conn.send('::RemoteJSONCreateDirectorySnapshot', request);
response.decode_ui32(); // Service flags
const result = response.decode_i32();
if (result === 0) {
const data = JSON.parse(response.decode_utf8());
const cleanup = async () => {
const request = new packet();
request.encode_ui64(data.handle);
await conn.send('::RemoteJSONReleaseDirectorySnapshot', request);
};
try {
const get_page = async page => {
const request = new packet();
request.encode_utf8(remote_path);
request.encode_ui64(data.handle);
request.encode_ui32(page);
const response =
await conn.send('::RemoteJSONReadDirectorySnapshot', request);
response.decode_ui32(); // Service flags
const result = response.decode_i32();
if (result === 0 || result === -120) {
const data = JSON.parse(response.decode_utf8());
return data.directory_list;
}
return [];
};
await page_reader_cb(remote_path, data.page_count, get_page);
await cleanup();
} catch (err) { } catch (err) {
await cleanup(); await dir_snapshot.release();
return Promise.reject(new Error(`'list_directory' failed: ${err}`)); return Promise.reject(`'list_directory' failed: ${err}`);
}
}
} catch (err) {
return Promise.reject(new Error(`'list_directory' failed: ${err}`));
} }
}; };
@@ -313,6 +339,8 @@ export const remove_directory = async (conn, remote_path) => {
} }
}; };
export const snapshot_directory = _snapshot_directory;
export const truncate_file = export const truncate_file =
async (conn, handle, remote_path, length, optional_thread_id) => { async (conn, handle, remote_path, length, optional_thread_id) => {
try { try {
@@ -387,7 +415,7 @@ export const upload_file =
new file(conn, await open_file(conn, remote_path), remote_path); new file(conn, await open_file(conn, remote_path), remote_path);
await cleanup(f); await cleanup(f);
return Promise.reject( return Promise.reject(
new Error("'upload_file' failed: file exists")); new Error('\'upload_file\' failed: file exists'));
} catch (err) { } catch (err) {
await create_dest(); await create_dest();
} }