186 lines
6.1 KiB
TypeScript
186 lines
6.1 KiB
TypeScript
|
/// <reference path="../imports/imports_shared.d.ts" />
|
||
|
|
||
|
|
||
|
window["require_setup"](module);
|
||
|
import * as native from "teaclient_connection";
|
||
|
import * as path from "path";
|
||
|
|
||
|
namespace _transfer {
|
||
|
class NativeFileDownload implements transfer.DownloadTransfer {
|
||
|
readonly key: transfer.DownloadKey;
|
||
|
private _handle: native.ft.NativeFileTransfer;
|
||
|
private _buffer: Uint8Array;
|
||
|
|
||
|
private _result: Promise<void>;
|
||
|
private _response: Response;
|
||
|
|
||
|
private _result_success: () => any;
|
||
|
private _result_error: (error: any) => any;
|
||
|
|
||
|
constructor(key: transfer.DownloadKey) {
|
||
|
this.key = key;
|
||
|
this._buffer = new Uint8Array(key.total_size);
|
||
|
this._handle = native.ft.spawn_connection({
|
||
|
client_transfer_id: key.client_transfer_id,
|
||
|
server_transfer_id: key.server_transfer_id,
|
||
|
|
||
|
remote_address: key.peer.hosts[0],
|
||
|
remote_port: key.peer.port,
|
||
|
|
||
|
transfer_key: key.key,
|
||
|
|
||
|
object: native.ft.download_transfer_object_from_buffer(this._buffer.buffer)
|
||
|
});
|
||
|
}
|
||
|
|
||
|
get_key(): transfer.DownloadKey {
|
||
|
return this.key;
|
||
|
}
|
||
|
|
||
|
async request_file(): Promise<Response> {
|
||
|
if(this._response)
|
||
|
return this._response;
|
||
|
|
||
|
try {
|
||
|
await (this._result || this._start_transfer());
|
||
|
} catch(error) {
|
||
|
throw error;
|
||
|
}
|
||
|
|
||
|
if(this._response)
|
||
|
return this._response;
|
||
|
|
||
|
const buffer = this._buffer.buffer.slice(this._buffer.byteOffset, this._buffer.byteOffset + Math.min(64, this._buffer.byteLength));
|
||
|
|
||
|
/* may another task has been stepped by and already set the response */
|
||
|
return this._response || (this._response = new Response(this._buffer, {
|
||
|
status: 200,
|
||
|
statusText: "success",
|
||
|
headers: {
|
||
|
"X-media-bytes": base64_encode_ab(buffer)
|
||
|
|
||
|
}
|
||
|
}));
|
||
|
}
|
||
|
|
||
|
_start_transfer() : Promise<void> {
|
||
|
return this._result = new Promise((resolve, reject) => {
|
||
|
this._result_error = (error) => {
|
||
|
this._result_error = undefined;
|
||
|
this._result_success = undefined;
|
||
|
reject(error);
|
||
|
};
|
||
|
this._result_success = () => {
|
||
|
this._result_error = undefined;
|
||
|
this._result_success = undefined;
|
||
|
resolve();
|
||
|
};
|
||
|
|
||
|
this._handle.callback_failed = this._result_error;
|
||
|
this._handle.callback_finished = aborted => {
|
||
|
if(aborted)
|
||
|
this._result_error("aborted");
|
||
|
else
|
||
|
this._result_success();
|
||
|
};
|
||
|
|
||
|
this._handle.start();
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class NativeFileUpload implements transfer.UploadTransfer {
|
||
|
readonly transfer_key: transfer.UploadKey;
|
||
|
private _handle: native.ft.NativeFileTransfer;
|
||
|
|
||
|
private _result: Promise<void>;
|
||
|
|
||
|
private _result_success: () => any;
|
||
|
private _result_error: (error: any) => any;
|
||
|
|
||
|
constructor(key: transfer.UploadKey) {
|
||
|
this.transfer_key = key;
|
||
|
}
|
||
|
|
||
|
async put_data(data: BlobPart | File) : Promise<void> {
|
||
|
if(this._result) {
|
||
|
await this._result;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
let buffer: native.ft.FileTransferSource;
|
||
|
|
||
|
if(data instanceof File) {
|
||
|
if(data.size != this.transfer_key.total_size)
|
||
|
throw "invalid size";
|
||
|
|
||
|
buffer = native.ft.upload_transfer_object_from_file(path.dirname(data.path), data.name);
|
||
|
} else if(typeof(data) === "string") {
|
||
|
if(data.length != this.transfer_key.total_size)
|
||
|
throw "invalid size";
|
||
|
|
||
|
buffer = native.ft.upload_transfer_object_from_buffer(str2ab8(data));
|
||
|
} else {
|
||
|
let buf = <BufferSource>data;
|
||
|
if(buf.byteLength != this.transfer_key.total_size)
|
||
|
throw "invalid size";
|
||
|
|
||
|
if(ArrayBuffer.isView(buf))
|
||
|
buf = buf.buffer.slice(buf.byteOffset);
|
||
|
|
||
|
buffer = native.ft.upload_transfer_object_from_buffer(buf);
|
||
|
}
|
||
|
|
||
|
this._handle = native.ft.spawn_connection({
|
||
|
client_transfer_id: this.transfer_key.client_transfer_id,
|
||
|
server_transfer_id: this.transfer_key.server_transfer_id,
|
||
|
|
||
|
remote_address: this.transfer_key.peer.hosts[0],
|
||
|
remote_port: this.transfer_key.peer.port,
|
||
|
|
||
|
transfer_key: this.transfer_key.key,
|
||
|
|
||
|
object: buffer
|
||
|
});
|
||
|
|
||
|
await (this._result = new Promise((resolve, reject) => {
|
||
|
this._result_error = (error) => {
|
||
|
this._result_error = undefined;
|
||
|
this._result_success = undefined;
|
||
|
reject(error);
|
||
|
};
|
||
|
this._result_success = () => {
|
||
|
this._result_error = undefined;
|
||
|
this._result_success = undefined;
|
||
|
resolve();
|
||
|
};
|
||
|
|
||
|
this._handle.callback_failed = this._result_error;
|
||
|
this._handle.callback_finished = aborted => {
|
||
|
if(aborted)
|
||
|
this._result_error("aborted");
|
||
|
else
|
||
|
this._result_success();
|
||
|
};
|
||
|
|
||
|
this._handle.start();
|
||
|
}));
|
||
|
}
|
||
|
|
||
|
get_key(): transfer.UploadKey {
|
||
|
return this.transfer_key;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
export function spawn_download_transfer(key: transfer.DownloadKey) : transfer.DownloadTransfer {
|
||
|
return new NativeFileDownload(key);
|
||
|
}
|
||
|
|
||
|
|
||
|
export function spawn_upload_transfer(key: transfer.UploadKey) : transfer.UploadTransfer {
|
||
|
return new NativeFileUpload(key);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Object.assign(window["transfer"] || (window["transfer"] = {} as any), _transfer);
|