import formidable from 'formidable'; import { ClientUtils } from '../ClientUtils'; import { Utils } from '../Utils'; import { Upload } from '../server/SharedMediaTypes'; /** * Networking is repsonsible for connecting the client to the server. Networking * mainly provides methods that the client can use to begin the process of * interacting with the server, such as fetching or uploading files. */ export namespace Networking { export async function FetchFromServer(relativeRoute: string) { return (await fetch(relativeRoute)).text(); } export function PostToServer(relativeRoute: string, body?: unknown) { return fetch(ClientUtils.prepend(relativeRoute), { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: body ? JSON.stringify(body) : undefined, }).then(response => { if (response.ok) return response.json() as object; return response.text().then(text => ({ error: '' + response.status + ':' + response.statusText + '-' + text })); }); } /** * FileGuidPair attaches a guid to a file that is being uploaded, * allowing the client to track the upload progress. * * When files are dragged to the canvas, the overWriteDoc's ID is * used as the guid. Otherwise, a new guid is generated. */ export interface FileGuidPair { file: File | Blob; guid?: string; } /** * Handles uploading basic file types to server and makes the API call to "/uploadFormData" endpoint * with the mapping of guid to files as parameters. * * @param fileguidpairs the files and corresponding guids to be uploaded to the server * @param browndash whether the endpoint should be invoked on the browndash server * @returns the response as a json from the server */ export async function UploadFilesToServer(fileguidpairs: FileGuidPair | FileGuidPair[], browndash?: boolean): Promise[]> { const formData = new FormData(); if (Array.isArray(fileguidpairs)) { if (!fileguidpairs.length) { return []; } const maxFileSize = 50000000; if (fileguidpairs.some(f => f.file.size > maxFileSize)) { return new Promise[]>(res => res([{ source: { newFilename: '', mimetype: '' } as formidable.File, result: new Error(`max file size (${maxFileSize / 1000000}MB) exceeded`) }])); } formData.set('fileguids', fileguidpairs.map(pair => pair.guid).join(';')); formData.set('filesize', fileguidpairs.reduce((sum, pair) => sum + pair.file.size, 0).toString()); // If the fileguidpair has a guid to use (From the overwriteDoc) use that guid. Otherwise, generate a new guid. fileguidpairs.forEach(fileguidpair => formData.append(fileguidpair.guid ?? Utils.GenerateGuid(), fileguidpair.file)); } else { // Handle the case where fileguidpairs is a single file. const guids = fileguidpairs.guid ?? Utils.GenerateGuid(); formData.set('fileguids', guids); formData.set('filesize', fileguidpairs.file.size.toString()); formData.append(guids, fileguidpairs.file); } const parameters = { method: 'POST', body: formData, }; const endpoint = browndash ? '[insert endpoint allowing local => browndash]' : '/uploadFormData'; const response = await fetch(endpoint, parameters); return response.json().then((json: Upload.FileResponse[]) => json.map(fileresponse => { if ('message' in fileresponse.result) fileresponse.result = new Error(fileresponse.result.message); return fileresponse; }) ); } export async function UploadYoutubeToServer(videoId: string, overwriteId?: string): Promise[]> { const parameters = { method: 'POST', body: JSON.stringify({ videoId, overwriteId }), json: true, }; const response = await fetch('/uploadYoutubeVideo', parameters); return response.json(); } export async function QueryYoutubeProgress(videoId: string): Promise<{ progress: string }> { const parameters = { method: 'POST', body: JSON.stringify({ videoId }), json: true, }; const response = await fetch('/queryYoutubeProgress', parameters); return response.json(); } }