Skip to content

Commit

Permalink
feat: add/edit plugins from UI
Browse files Browse the repository at this point in the history
  • Loading branch information
lideming committed Jun 7, 2023
1 parent 5195d50 commit da57dcd
Show file tree
Hide file tree
Showing 6 changed files with 224 additions and 27 deletions.
30 changes: 15 additions & 15 deletions src/API/UserStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,24 @@ export type UserStoreValueType = "json" | "text" | "raw";
class UserStore {
async get<T = any>(
key: string,
type?: "json"
type?: "json",
): Promise<null | ({ value: T } & UserStoreFields)>;
async get(
key: string,
type: "text"
type: "text",
): Promise<null | ({ value: string } & UserStoreFields)>;
async get(
key: string,
type: "raw"
type: "raw",
): Promise<null | ({ value: ArrayBuffer } & UserStoreFields)>;
async get(
key: string,
type: UserStoreValueType
type: UserStoreValueType,
): Promise<null | ({ value: any } & UserStoreFields)>;

async get(
key: string,
type: UserStoreValueType = "json"
type: UserStoreValueType = "json",
): Promise<null | ({ value: any } & UserStoreFields)> {
var resp = await api._fetch(`${api.baseUrl}my/store/${key}`, {
headers: api.getHeaders(),
Expand All @@ -42,7 +42,7 @@ class UserStore {
throw new Error("unknown type");
}
const fields = new URLSearchParams(
resp.headers.get("x-mcloud-store-fields")!
resp.headers.get("x-mcloud-store-fields")!,
);
const visibility = +fields.get("visibility")!;
const revision = +fields.get("revision")!;
Expand All @@ -51,16 +51,21 @@ class UserStore {

async set(
key: string,
data: { value: any } & Partial<UserStoreFields>
data: { value: any } & Partial<UserStoreFields>,
type?: UserStoreValueType,
): Promise<void> {
let { value } = data;
if (
!type &&
!(
value instanceof ArrayBuffer ||
value instanceof TypedArray ||
value instanceof Blob
)
) {
type = "json";
}
if (type === "json") {
value = JSON.stringify(value);
}
const headers = api.getHeaders();
Expand All @@ -82,12 +87,7 @@ class UserStore {

async delete(
key: string,
data: { value: any } & Partial<UserStoreFields>
): Promise<void> {
let { value } = data;
if (!(value instanceof ArrayBuffer || value instanceof Blob)) {
value = JSON.stringify(value);
}
var resp = await api._fetch(`${api.baseUrl}my/store/${key}`, {
method: "DELETE",
headers: api.getHeaders(),
Expand Down Expand Up @@ -131,17 +131,17 @@ export class UserStoreItem<T = any> extends Ref<T> implements UserStoreFields {

put() {
if (this._putPending) return this._putPending;
let pendingTask;
let pendingTask: Promise<void>;
pendingTask = (async () => {
if (this._putInProgress) {
this._putPending = pendingTask;
this._putPending = pendingTask!;
try {
await this._putInProgress;
} catch (error) {}
this._putPending = null;
}
const putTask = (this._putInProgress = (async () => {
await userStore.set(this.key, this);
await userStore.set(this.key, this, this.type);
this.revision++;
this._putInProgress = null;
})());
Expand Down
8 changes: 8 additions & 0 deletions src/I18n/i18n-data.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,14 @@
["This project is based on {0}.", "此项目基于 {0}。", "このプロジェクトは {0} に基づいています。"],
["open-sourced", "开源", "オープンソース"],
["Recent changes:", "最近更改:", "最近の変更:"],
["Plugins", "插件"],
["Add plugin by URL", "添加插件 URL"],
["Add", "添加"],
["Add plugin by code", "添加插件代码"],
["Enable", "启用"],
["Disable", "禁用"],
["Edit plugin code", "编辑插件代码"],
["Plugin code", "插件代码"],
["Music Cloud", "Music Cloud", "Music Cloud"]
],
[
Expand Down
22 changes: 22 additions & 0 deletions src/Infra/nanoid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
let bytes: Uint8Array | null = null;

export function nanoid(size = 21) {
let id = "";
if (!bytes || bytes.length != size) {
bytes = new Uint8Array(size);
}
crypto.getRandomValues(bytes);
while (size--) {
let byte = bytes[size] & 63;
if (byte < 36) {
id += byte.toString(36);
} else if (byte < 62) {
id += (byte - 26).toString(36).toUpperCase();
} else if (byte < 63) {
id += "_";
} else {
id += "-";
}
}
return id;
}
61 changes: 52 additions & 9 deletions src/Plugins/plugins.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { buildDOM, Semaphore } from "@yuuza/webfx";
import { UserStoreItem } from "../API/UserStore";
import { user, userStore } from "../main";
import { nanoid } from "../Infra/nanoid";

export interface PluginInfo {
name: string;
Expand Down Expand Up @@ -71,24 +72,36 @@ export const plugins = new (class Plugins {
plugins: value.plugins.filter((x) => x.url != url),
};
});
const { type, key } = this.parsePluginURL(url);
if (type === "user-store") {
await this.deletePluginCode(key);
}
}

async toggleUserPlugin(url: string, enabled: boolean) {
await this.userPluginList.concurrencyAwareUpdate((value) => {
return {
...value,
plugins: value.plugins.map((x) =>
x.url == url ? { ...x, enabled } : x
),
plugins: value.plugins.map((x) => x.url == url ? { ...x, enabled } : x),
};
});
}

async loadPlugin(url: string) {
parsePluginURL(url: string) {
if (url.startsWith("user-store:")) {
return await this.loadPluginFromUserStore(
url.substring("user-store:".length)
);
return {
type: "user-store" as const,
key: url.substring("user-store:".length),
};
} else {
return { type: "url" as const, url };
}
}

async loadPlugin(url: string) {
const { type, key } = this.parsePluginURL(url);
if (type === "user-store") {
return await this.loadPluginFromUserStore(key);
} else {
return await this.loadPluginFromURL(url);
}
Expand Down Expand Up @@ -132,7 +145,7 @@ export const plugins = new (class Plugins {
onload: () => {
afterLoadResolve();
},
})
}),
);

await afterLoadPromise;
Expand All @@ -146,8 +159,38 @@ export const plugins = new (class Plugins {
return info;
}

getUserStorePluginKey(key: string) {
return "plugins." + key;
}

getPluginCodeItem(key: string) {
return new UserStoreItem({
key: this.getUserStorePluginKey(key),
type: "text",
});
}

async setPluginCode(key: string, code: string) {
await userStore.set(
this.getUserStorePluginKey(key),
{ value: code },
"text",
);
}

async addPluginCode(code: string) {
const key = nanoid();
await this.setPluginCode(key, code);
await this.addUserPlugin("user-store:" + key);
}

async deletePluginCode(key: string) {
await userStore.delete(this.getUserStorePluginKey(key));
}

// Load "user-store:" script
async loadPluginFromUserStore(key: string) {
key = this.getUserStorePluginKey(key);
const keyValue = await userStore.get(key, "text");
if (!keyValue) throw new Error("userStore key not found: " + key);

Expand Down Expand Up @@ -184,7 +227,7 @@ export const plugins = new (class Plugins {
if (!this._currentRegisterCallback) {
throw new Error(
"Currently no plugin loading task (registerPlugin must be" +
" call during the script execution, usually in top level)."
" call during the script execution, usually in top level).",
);
}
this._currentRegisterCallback(info);
Expand Down
Loading

0 comments on commit da57dcd

Please sign in to comment.