feat(upload): Add relevant headers and emit file size

Co-authored-by: yonatan.bendahan@gmail.com <yonatan.bendahan@gmail.com>
pull/39/head
FabianLars 3 years ago
parent 27b73413e9
commit 2c439f5a42
No known key found for this signature in database
GPG Key ID: 3B12BC1DEBF61125

1
Cargo.lock generated

@ -4261,6 +4261,7 @@ dependencies = [
"thiserror",
"tokio",
"tokio-util",
"url",
]
[[package]]

@ -13,8 +13,9 @@ serde_json.workspace = true
tauri.workspace = true
log.workspace = true
thiserror.workspace = true
tokio = { version = "1.17", features = [ "fs" ] }
tokio = { version = "1", features = [ "fs" ] }
tokio-util = { version = "0.7", features = [ "codec" ] }
reqwest = { version = "0.11", features = [ "json", "stream" ] }
futures = "0.3"
read-progress-stream = "1.0.0"
read-progress-stream = "1"
url = "2"

@ -1,3 +1,18 @@
type ProgressHandler = (progress: number, total: number) => void;
export default function upload(url: string, filePath: string, progressHandler?: ProgressHandler, headers?: Map<string, string>): Promise<void>;
interface BaseHandlerData {
id: number;
}
interface ProgressHandlerData extends BaseHandlerData {
progress: number;
total: number;
}
interface SizeHandlerData extends BaseHandlerData {
size: number;
}
interface ResponseData {
text: string;
status: number;
}
type ProgressHandler = (data: ProgressHandlerData) => unknown;
type SizeHandler = (data: SizeHandlerData) => unknown;
export default function upload(url: string, filePath: string, progressHandler?: ProgressHandler, fileSizeHandler?: SizeHandler, headers?: Record<string, string>): Promise<ResponseData>;
export {};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -1,32 +1,41 @@
import { invoke } from '@tauri-apps/api/tauri';
import { appWindow } from '@tauri-apps/api/window';
var UploadEvent;
(function (UploadEvent) {
UploadEvent["progress"] = "upload://progress";
UploadEvent["fileSize"] = "upload://file-size";
})(UploadEvent || (UploadEvent = {}));
const handlers = new Map();
let listening = false;
async function listenToUploadEventIfNeeded() {
if (listening) {
return await Promise.resolve();
const listeningMap = new Map();
const getIdForEvent = (event, id) => `${event}-${id}`;
async function listenToEventIfNeeded(event) {
if (listeningMap.get(event)) {
return;
}
return await appWindow
.listen("upload://progress", ({ payload }) => {
const handler = handlers.get(payload.id);
if (handler != null) {
handler(payload.progress, payload.total);
return appWindow.listen(event, ({ payload }) => {
const eventId = getIdForEvent(event, payload.id);
const handler = handlers.get(eventId);
if (typeof handler === 'function') {
handler(payload);
}
})
.then(() => {
listening = true;
});
}
async function upload(url, filePath, progressHandler, headers) {
async function upload(url, filePath, progressHandler, fileSizeHandler, headers) {
const ids = new Uint32Array(1);
window.crypto.getRandomValues(ids);
const id = ids[0];
if (progressHandler != null) {
handlers.set(id, progressHandler);
if (progressHandler) {
const eventId = getIdForEvent(UploadEvent.progress, id);
handlers.set(eventId, progressHandler);
}
await listenToUploadEventIfNeeded();
await invoke("plugin:upload|upload", {
if (fileSizeHandler) {
const eventId = getIdForEvent(UploadEvent.fileSize, id);
handlers.set(eventId, fileSizeHandler);
}
await listenToEventIfNeeded(UploadEvent.progress);
await listenToEventIfNeeded(UploadEvent.fileSize);
return await invoke('plugin:upload|upload', {
id,
url,
filePath,

@ -1 +1 @@
{"version":3,"file":"index.mjs","sources":["../index.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAUA,MAAM,QAAQ,GAAiC,IAAI,GAAG,EAAE,CAAC;AACzD,IAAI,SAAS,GAAG,KAAK,CAAC;AAEtB,eAAe,2BAA2B,GAAA;AACxC,IAAA,IAAI,SAAS,EAAE;AACb,QAAA,OAAO,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;AAChC,KAAA;AACD,IAAA,OAAO,MAAM,SAAS;SACnB,MAAM,CAAkB,mBAAmB,EAAE,CAAC,EAAE,OAAO,EAAE,KAAI;QAC5D,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACzC,IAAI,OAAO,IAAI,IAAI,EAAE;YACnB,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;AAC1C,SAAA;AACH,KAAC,CAAC;SACD,IAAI,CAAC,MAAK;QACT,SAAS,GAAG,IAAI,CAAC;AACnB,KAAC,CAAC,CAAC;AACP,CAAC;AAEc,eAAe,MAAM,CAClC,GAAW,EACX,QAAgB,EAChB,eAAiC,EACjC,OAA6B,EAAA;AAE7B,IAAA,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC;AAC/B,IAAA,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;AACnC,IAAA,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IAElB,IAAI,eAAe,IAAI,IAAI,EAAE;AAC3B,QAAA,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,eAAe,CAAC,CAAC;AACnC,KAAA;IAED,MAAM,2BAA2B,EAAE,CAAC;IAEpC,MAAM,MAAM,CAAC,sBAAsB,EAAE;QACnC,EAAE;QACF,GAAG;QACH,QAAQ;AACR,QAAA,OAAO,EAAE,OAAO,KAAA,IAAA,IAAP,OAAO,KAAP,KAAA,CAAA,GAAA,OAAO,GAAI,EAAE;AACvB,KAAA,CAAC,CAAC;AACL;;;;"}
{"version":3,"file":"index.mjs","sources":["../index.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAqBA,IAAK,WAGJ,CAAA;AAHD,CAAA,UAAK,WAAW,EAAA;AACZ,IAAA,WAAA,CAAA,UAAA,CAAA,GAAA,mBAA8B,CAAA;AAC9B,IAAA,WAAA,CAAA,UAAA,CAAA,GAAA,oBAA+B,CAAA;AACnC,CAAC,EAHI,WAAW,KAAX,WAAW,GAGf,EAAA,CAAA,CAAA,CAAA;AAMD,MAAM,QAAQ,GAAgD,IAAI,GAAG,EAAE,CAAC;AACxE,MAAM,YAAY,GAA8B,IAAI,GAAG,EAAE,CAAC;AAE1D,MAAM,aAAa,GAAG,CAAC,KAAkB,EAAE,EAAU,KAAc,CAAG,EAAA,KAAK,CAAI,CAAA,EAAA,EAAE,EAAE,CAAC;AAEpF,eAAe,qBAAqB,CAAC,KAAkB,EAAA;AACnD,IAAA,IAAI,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;QACzB,OAAO;AACV,KAAA;IACD,OAAO,SAAS,CAAC,MAAM,CAAwC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,KAAI;QAClF,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACtC,QAAA,IAAI,OAAO,OAAO,KAAK,UAAU,EAAE;YAC/B,OAAO,CAAC,OAAO,CAAC,CAAC;AACpB,SAAA;AACL,KAAC,CAAC,CAAC;AACP,CAAC;AAEc,eAAe,MAAM,CAAC,GAAW,EAAE,QAAgB,EAAE,eAAiC,EAAE,eAA6B,EAAE,OAAgC,EAAA;AAClK,IAAA,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC;AAC/B,IAAA,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;AACnC,IAAA,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;AAElB,IAAA,IAAI,eAAe,EAAE;QACjB,MAAM,OAAO,GAAG,aAAa,CAAC,WAAW,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AACxD,QAAA,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;AAC1C,KAAA;AAED,IAAA,IAAI,eAAe,EAAE;QACjB,MAAM,OAAO,GAAG,aAAa,CAAC,WAAW,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AACxD,QAAA,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;AAC1C,KAAA;AAED,IAAA,MAAM,qBAAqB,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;AAClD,IAAA,MAAM,qBAAqB,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;AAElD,IAAA,OAAO,MAAM,MAAM,CAAe,sBAAsB,EAAE;QACtD,EAAE;QACF,GAAG;QACH,QAAQ;AACR,QAAA,OAAO,EAAE,OAAO,KAAA,IAAA,IAAP,OAAO,KAAP,KAAA,CAAA,GAAA,OAAO,GAAI,EAAE;AACzB,KAAA,CAAC,CAAC;AACP;;;;"}

@ -1,49 +1,70 @@
import { invoke } from "@tauri-apps/api/tauri";
import { appWindow } from "@tauri-apps/api/window";
import { invoke } from '@tauri-apps/api/tauri';
import { appWindow } from '@tauri-apps/api/window';
interface ProgressPayload {
interface BaseHandlerData {
id: number;
}
interface ProgressHandlerData extends BaseHandlerData {
progress: number;
total: number;
}
type ProgressHandler = (progress: number, total: number) => void;
const handlers: Map<number, ProgressHandler> = new Map();
let listening = false;
interface SizeHandlerData extends BaseHandlerData {
size: number;
}
interface ResponseData {
text: string;
status: number;
}
enum UploadEvent {
progress = 'upload://progress',
fileSize = 'upload://file-size',
}
type EventId = `${UploadEvent}-${number}`;
type ProgressHandler = (data: ProgressHandlerData) => unknown;
type SizeHandler = (data: SizeHandlerData) => unknown;
const handlers: Map<EventId, ProgressHandler | SizeHandler> = new Map();
const listeningMap: Map<UploadEvent, boolean> = new Map();
async function listenToUploadEventIfNeeded(): Promise<void> {
if (listening) {
return await Promise.resolve();
const getIdForEvent = (event: UploadEvent, id: number): EventId => `${event}-${id}`;
async function listenToEventIfNeeded(event: UploadEvent) {
if (listeningMap.get(event)) {
return;
}
return await appWindow
.listen<ProgressPayload>("upload://progress", ({ payload }) => {
const handler = handlers.get(payload.id);
if (handler != null) {
handler(payload.progress, payload.total);
return appWindow.listen<SizeHandlerData & ProgressHandlerData>(event, ({ payload }) => {
const eventId = getIdForEvent(event, payload.id);
const handler = handlers.get(eventId);
if (typeof handler === 'function') {
handler(payload);
}
})
.then(() => {
listening = true;
});
}
export default async function upload(
url: string,
filePath: string,
progressHandler?: ProgressHandler,
headers?: Map<string, string>
): Promise<void> {
export default async function upload(url: string, filePath: string, progressHandler?: ProgressHandler, fileSizeHandler?: SizeHandler, headers?: Record<string, string>) {
const ids = new Uint32Array(1);
window.crypto.getRandomValues(ids);
const id = ids[0];
if (progressHandler != null) {
handlers.set(id, progressHandler);
if (progressHandler) {
const eventId = getIdForEvent(UploadEvent.progress, id);
handlers.set(eventId, progressHandler);
}
if (fileSizeHandler) {
const eventId = getIdForEvent(UploadEvent.fileSize, id);
handlers.set(eventId, fileSizeHandler);
}
await listenToUploadEventIfNeeded();
await listenToEventIfNeeded(UploadEvent.progress);
await listenToEventIfNeeded(UploadEvent.fileSize);
await invoke("plugin:upload|upload", {
return await invoke<ResponseData>('plugin:upload|upload', {
id,
url,
filePath,

@ -38,6 +38,18 @@ struct ProgressPayload {
total: u64,
}
#[derive(Clone, Serialize)]
struct FileSizePayload {
id: u32,
size: u64,
}
#[derive(Clone, Serialize)]
struct ResponseData {
text: String,
status: u16,
}
#[command]
async fn upload<R: Runtime>(
window: Window<R>,
@ -45,15 +57,33 @@ async fn upload<R: Runtime>(
url: &str,
file_path: &str,
headers: HashMap<String, String>,
) -> Result<serde_json::Value> {
) -> Result<ResponseData> {
// Read the file
let parsed_url = url::Url::parse(url).unwrap();
let file = File::open(file_path).await?;
let file_metadata = file.metadata().await?;
let file_size = file_metadata.len();
let _ = window.emit(
"upload://file-size",
FileSizePayload {
size: file_size,
id,
},
);
// Create the request and attach the file to the body
let client = reqwest::Client::new();
let mut request = client.post(url).body(file_to_body(id, window, file));
let mut request = client.put(url).body(file_to_body(id, window, file));
request = request.header("Content-Length", file_size);
request = request.header("User-Agent", "Tauri/1.0");
request = request.header("Accept-Encoding", "gzip, deflate, br");
request = request.header("Accept", "*/*");
request = request.header("Connection", "keep-alive");
let host = parsed_url.host().unwrap();
request = request.header("Host", host.to_string());
// Loop trought the headers keys and values
// Loop trough the headers keys and values
// and add them to the request object.
for (key, value) in headers {
request = request.header(&key, value);
@ -61,7 +91,9 @@ async fn upload<R: Runtime>(
let response = request.send().await?;
response.json().await.map_err(Into::into)
let status = response.status().as_u16();
let text = response.text().await?;
Ok(ResponseData { text, status })
}
fn file_to_body<R: Runtime>(id: u32, window: Window<R>, file: File) -> reqwest::Body {

Loading…
Cancel
Save