Sync engine (#298)

Fixes #261
This commit is contained in:
Zef Hemel
2023-01-13 15:41:29 +01:00
committed by GitHub
parent de6f531e91
commit a56e14bff1
51 changed files with 1033 additions and 1418 deletions
+63 -24
View File
@@ -3,33 +3,51 @@ import { Plug } from "../../plugos/plug.ts";
import { FileData, FileEncoding, SpacePrimitives } from "./space_primitives.ts";
import {
base64DecodeDataUrl,
base64Encode,
base64EncodedDataUrl,
} from "../../plugos/asset_bundle/base64.ts";
import { mime } from "../../plugos/deps.ts";
export class HttpSpacePrimitives implements SpacePrimitives {
fsUrl: string;
private fsUrl: string;
private plugUrl: string;
constructor(url: string) {
constructor(
url: string,
readonly user?: string,
readonly password?: string,
readonly base64Put?: boolean,
) {
this.fsUrl = url + "/fs";
this.plugUrl = url + "/plug";
}
private async authenticatedFetch(
url: string,
options: any,
options: Record<string, any>,
): Promise<Response> {
if (this.user && this.password) {
// Explicitly set an auth cookie
if (!options.headers) {
options.headers = {};
}
options.headers["cookie"] = `auth=${
btoa(`${this.user}:${this.password}`)
}`;
}
const result = await fetch(url, options);
if (result.status === 401) {
if (result.status === 401 || result.redirected) {
// Invalid credentials, reloading the browser should trigger authentication
location.reload();
if (typeof location !== "undefined") {
location.reload();
}
throw Error("Unauthorized");
}
return result;
}
public async fetchFileList(): Promise<FileMeta[]> {
async fetchFileList(): Promise<FileMeta[]> {
const req = await this.authenticatedFetch(this.fsUrl, {
method: "GET",
});
@@ -41,9 +59,12 @@ export class HttpSpacePrimitives implements SpacePrimitives {
name: string,
encoding: FileEncoding,
): Promise<{ data: FileData; meta: FileMeta }> {
const res = await this.authenticatedFetch(`${this.fsUrl}/${name}`, {
method: "GET",
});
const res = await this.authenticatedFetch(
`${this.fsUrl}/${encodeURI(name)}`,
{
method: "GET",
},
);
if (res.status === 404) {
throw new Error(`Page not found`);
}
@@ -52,7 +73,6 @@ export class HttpSpacePrimitives implements SpacePrimitives {
case "arraybuffer":
{
data = await res.arrayBuffer();
// data = await abBlob.arrayBuffer();
}
break;
case "dataurl":
@@ -63,7 +83,7 @@ export class HttpSpacePrimitives implements SpacePrimitives {
);
}
break;
case "string":
case "utf8":
data = await res.text();
break;
}
@@ -82,37 +102,56 @@ export class HttpSpacePrimitives implements SpacePrimitives {
switch (encoding) {
case "arraybuffer":
case "string":
// actually we want an Uint8Array
body = data instanceof ArrayBuffer ? new Uint8Array(data) : data;
break;
case "utf8":
body = data;
break;
case "dataurl":
data = base64DecodeDataUrl(data as string);
break;
}
const res = await this.authenticatedFetch(`${this.fsUrl}/${name}`, {
method: "PUT",
headers: {
"Content-type": "application/octet-stream",
const headers: Record<string, string> = {
"Content-Type": "application/octet-stream",
};
if (this.base64Put) {
headers["X-Content-Base64"] = "true";
headers["Content-Type"] = "text/plain";
body = base64Encode(body);
}
const res = await this.authenticatedFetch(
`${this.fsUrl}/${encodeURI(name)}`,
{
method: "PUT",
headers,
body,
},
body,
});
);
const newMeta = this.responseToMeta(name, res);
return newMeta;
}
async deleteFile(name: string): Promise<void> {
const req = await this.authenticatedFetch(`${this.fsUrl}/${name}`, {
method: "DELETE",
});
const req = await this.authenticatedFetch(
`${this.fsUrl}/${encodeURI(name)}`,
{
method: "DELETE",
},
);
if (req.status !== 200) {
throw Error(`Failed to delete file: ${req.statusText}`);
}
}
async getFileMeta(name: string): Promise<FileMeta> {
const res = await this.authenticatedFetch(`${this.fsUrl}/${name}`, {
method: "OPTIONS",
});
const res = await this.authenticatedFetch(
`${this.fsUrl}/${encodeURI(name)}`,
{
method: "OPTIONS",
},
);
if (res.status === 404) {
throw new Error(`File not found`);
}