mirror of
https://github.com/rubickCenter/rubick
synced 2026-02-26 00:42:21 +08:00
✨ API 部分迁移完成
This commit is contained in:
@@ -40,9 +40,23 @@ global.LOCAL_PLUGINS = {
|
||||
});
|
||||
if (!has) {
|
||||
global.LOCAL_PLUGINS.PLUGINS.unshift(plugin);
|
||||
fs.writeFileSync(configPath, JSON.stringify(global.LOCAL_PLUGINS.PLUGINS));
|
||||
fs.writeFileSync(
|
||||
configPath,
|
||||
JSON.stringify(global.LOCAL_PLUGINS.PLUGINS)
|
||||
);
|
||||
}
|
||||
},
|
||||
updatePlugin(plugin) {
|
||||
global.LOCAL_PLUGINS.PLUGINS = global.LOCAL_PLUGINS.PLUGINS.map(
|
||||
(origin) => {
|
||||
if (origin.name === plugin.name) {
|
||||
return plugin;
|
||||
}
|
||||
return origin;
|
||||
}
|
||||
);
|
||||
fs.writeFileSync(configPath, JSON.stringify(global.LOCAL_PLUGINS.PLUGINS));
|
||||
},
|
||||
async deletePlugin(plugin) {
|
||||
await pluginInstance.uninstall([plugin.name]);
|
||||
global.LOCAL_PLUGINS.PLUGINS = global.LOCAL_PLUGINS.PLUGINS.filter((p) => plugin.name !== p.name);
|
||||
|
||||
3
src/core/@types/index.d.ts
vendored
3
src/core/@types/index.d.ts
vendored
@@ -11,4 +11,7 @@ declare module "@ts-type/package-dts/package-json" {
|
||||
IDependency
|
||||
};
|
||||
};
|
||||
|
||||
declare module "pouchdb";
|
||||
|
||||
declare module "*.types";
|
||||
|
||||
170
src/core/db/index.ts
Normal file
170
src/core/db/index.ts
Normal file
@@ -0,0 +1,170 @@
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import PouchDB from "pouchdb";
|
||||
|
||||
import { DBError, Doc, DocRes } from "./types";
|
||||
|
||||
export default class {
|
||||
readonly docMaxByteLength;
|
||||
readonly docAttachmentMaxByteLength;
|
||||
public dbpath;
|
||||
public defaultDbName;
|
||||
public pouchDB: any;
|
||||
|
||||
constructor(dbPath: string) {
|
||||
this.docMaxByteLength = 2 * 1024 * 1024; // 2M
|
||||
this.docAttachmentMaxByteLength = 20 * 1024 * 1024; // 20M
|
||||
this.dbpath = dbPath;
|
||||
this.defaultDbName = path.join(dbPath, "default");
|
||||
}
|
||||
|
||||
init(): void {
|
||||
fs.existsSync(this.dbpath) || fs.mkdirSync(this.dbpath);
|
||||
this.pouchDB = new PouchDB(this.defaultDbName, { auto_compaction: true });
|
||||
}
|
||||
|
||||
getDocId(name: string, id: string): string {
|
||||
return name + "/" + id;
|
||||
}
|
||||
|
||||
replaceDocId(name: string, id: string): string {
|
||||
return id.replace(name + "/", "");
|
||||
}
|
||||
|
||||
errorInfo(name: string, message: string): DBError {
|
||||
return { error: true, name, message };
|
||||
}
|
||||
|
||||
private checkDocSize(doc: Doc<any>) {
|
||||
if (Buffer.byteLength(JSON.stringify(doc)) > this.docMaxByteLength) {
|
||||
return this.errorInfo(
|
||||
"exception",
|
||||
`doc max size ${this.docMaxByteLength / 1024 / 1024} M`
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async put(
|
||||
name: string,
|
||||
doc: Doc<any>,
|
||||
strict = true
|
||||
): Promise<DBError | DocRes> {
|
||||
if (strict) {
|
||||
const err = this.checkDocSize(doc);
|
||||
if (err) return err;
|
||||
}
|
||||
doc._id = this.getDocId(name, doc._id);
|
||||
try {
|
||||
const result: DocRes = await this.pouchDB.put(doc);
|
||||
doc._id = result.id = this.replaceDocId(name, result.id);
|
||||
return result;
|
||||
} catch (e: any) {
|
||||
doc._id = this.replaceDocId(name, doc._id);
|
||||
return { id: doc._id, name: e.name, error: !0, message: e.message };
|
||||
}
|
||||
}
|
||||
|
||||
async get(name: string, id: string): Promise<DocRes | null> {
|
||||
try {
|
||||
const result: DocRes = await this.pouchDB.get(this.getDocId(name, id));
|
||||
result._id = this.replaceDocId(name, result._id);
|
||||
return result;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async remove(name: string, doc: Doc<any> | string) {
|
||||
try {
|
||||
let target;
|
||||
if ("object" == typeof doc) {
|
||||
target = doc;
|
||||
if (!target._id || "string" !== typeof target._id) {
|
||||
return this.errorInfo("exception", "doc _id error");
|
||||
}
|
||||
target._id = this.getDocId(name, target._id);
|
||||
} else {
|
||||
if ("string" !== typeof doc) {
|
||||
return this.errorInfo("exception", "param error");
|
||||
}
|
||||
target = await this.pouchDB.get(this.getDocId(name, doc));
|
||||
}
|
||||
const result: DocRes = await this.pouchDB.remove(target);
|
||||
target._id = result.id = this.replaceDocId(name, result.id);
|
||||
return result;
|
||||
} catch (e: any) {
|
||||
if ("object" === typeof doc) {
|
||||
doc._id = this.replaceDocId(name, doc._id);
|
||||
}
|
||||
return this.errorInfo(e.name, e.message);
|
||||
}
|
||||
}
|
||||
|
||||
async bulkDocs(name: string, docs: Array<Doc<any>>): Promise<DBError | Array<DocRes>> {
|
||||
let result;
|
||||
try {
|
||||
if (!Array.isArray(docs)) return this.errorInfo("exception", "not array");
|
||||
if (docs.find((e) => !e._id))
|
||||
return this.errorInfo("exception", "doc not _id field");
|
||||
if (new Set(docs.map((e) => e._id)).size !== docs.length)
|
||||
return this.errorInfo("exception", "_id value exists as");
|
||||
for (const doc of docs) {
|
||||
const err = this.checkDocSize(doc);
|
||||
if (err) return err;
|
||||
doc._id = this.getDocId(name, doc._id)
|
||||
}
|
||||
result = await this.pouchDB.bulkDocs(docs);
|
||||
result = result.map((res: any) => {
|
||||
res.id = this.replaceDocId(name, res.id);
|
||||
return res.error
|
||||
? {
|
||||
id: res.id,
|
||||
name: res.name,
|
||||
error: true,
|
||||
message: res.message
|
||||
}
|
||||
: res;
|
||||
});
|
||||
docs.forEach((doc) => {
|
||||
doc._id = this.replaceDocId(name, doc._id)
|
||||
});
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async allDocs(name: string, key: string | Array<string>): Promise<DBError | Array<DocRes>> {
|
||||
const config: any = { include_docs: true };
|
||||
if (key) {
|
||||
if ("string" == typeof key) {
|
||||
config.startkey = this.getDocId(name, key);
|
||||
config.endkey = config.startkey + "";
|
||||
} else {
|
||||
if (!Array.isArray(key))
|
||||
return this.errorInfo(
|
||||
"exception",
|
||||
"param only key(string) or keys(Array[string])"
|
||||
);
|
||||
config.keys = key.map((key) => this.getDocId(name, key));
|
||||
}
|
||||
} else {
|
||||
config.startkey = this.getDocId(name, "");
|
||||
config.endkey = config.startkey + "";
|
||||
}
|
||||
const result: Array<any> = [];
|
||||
try {
|
||||
(await this.pouchDB.allDocs(config)).rows.forEach((res: any) => {
|
||||
if (!res.error && res.doc) {
|
||||
res.doc._id = this.replaceDocId(name, res.doc._id);
|
||||
result.push(res.doc);
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
36
src/core/db/types.ts
Normal file
36
src/core/db/types.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
type RevisionId = string;
|
||||
|
||||
// todo 附件和索引
|
||||
export interface Doc<T> {
|
||||
_id: string;
|
||||
data: T;
|
||||
_rev?: RevisionId;
|
||||
_attachments?: any;
|
||||
}
|
||||
|
||||
export interface DocRes {
|
||||
id: string;
|
||||
ok: boolean;
|
||||
rev: RevisionId;
|
||||
_id: string;
|
||||
}
|
||||
|
||||
export interface DBError {
|
||||
/**
|
||||
* HTTP Status Code during HTTP or HTTP-like operations
|
||||
*/
|
||||
status?: number | undefined;
|
||||
name?: string | undefined;
|
||||
message?: string | undefined;
|
||||
reason?: string | undefined;
|
||||
error?: string | boolean | undefined;
|
||||
id?: string | undefined;
|
||||
rev?: RevisionId | undefined;
|
||||
}
|
||||
|
||||
export interface AllDocsOptions {
|
||||
include_docs?: boolean;
|
||||
startkey?: string;
|
||||
endkey?: string;
|
||||
keys?: string[];
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
import appSearch from "@/core/app-search";
|
||||
import PluginHandler from "@/core/plugin-handler";
|
||||
import LocalDb from "@/core/db";
|
||||
|
||||
export {
|
||||
appSearch,
|
||||
PluginHandler,
|
||||
LocalDb,
|
||||
};
|
||||
|
||||
@@ -12,9 +12,10 @@ export default () => {
|
||||
};
|
||||
|
||||
const createView = (plugin, window: BrowserWindow) => {
|
||||
const preload = commonConst.dev()
|
||||
? path.resolve(__static, `../feature/public/preload.js`)
|
||||
: path.resolve(plugin.indexPath, `../`, plugin.preload);
|
||||
const preload =
|
||||
commonConst.dev() && plugin.name === "rubick-system-feature"
|
||||
? path.resolve(__static, `../feature/public/preload.js`)
|
||||
: path.resolve(plugin.indexPath.replace("file:", ""), `../`, plugin.preload);
|
||||
|
||||
const ses = session.fromPartition("<" + plugin.name + ">");
|
||||
ses.setPreloads([`${__static}/preload.js`]);
|
||||
@@ -54,6 +55,7 @@ export default () => {
|
||||
const getView = () => view;
|
||||
|
||||
const executeHooks = (hook, data) => {
|
||||
if (!view) return;
|
||||
const evalJs = `if(window.rubick && window.rubick.hooks && typeof window.rubick.hooks.on${hook} === 'function' ) {
|
||||
try {
|
||||
window.rubick.hooks.on${hook}(${data ? JSON.stringify(data) : ""});
|
||||
|
||||
@@ -1,20 +1,30 @@
|
||||
import { BrowserWindow, ipcMain, dialog, webContents } from "electron";
|
||||
import {
|
||||
BrowserWindow,
|
||||
ipcMain,
|
||||
dialog,
|
||||
app,
|
||||
Notification,
|
||||
nativeImage,
|
||||
clipboard,
|
||||
} from "electron";
|
||||
import { runner } from "../browsers";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import { LocalDb } from "@/core";
|
||||
import plist from "plist";
|
||||
|
||||
const runnerInstance = runner();
|
||||
const dbInstance = new LocalDb(app.getPath("userData"));
|
||||
|
||||
function getWorkWebContentsBySender(sender, mainWindow) {
|
||||
const window = BrowserWindow.fromWebContents(sender);
|
||||
console.log(window);
|
||||
|
||||
if (!window) return null;
|
||||
return window.webContents;
|
||||
}
|
||||
dbInstance.init();
|
||||
|
||||
const API: any = {
|
||||
currentPlugin: null,
|
||||
DBKEY: "RUBICK_DB_DEFAULT",
|
||||
openPlugin({ plugin }, window) {
|
||||
runnerInstance.removeView(window);
|
||||
runnerInstance.init(plugin, window);
|
||||
API.currentPlugin = plugin;
|
||||
},
|
||||
removePlugin(e, window) {
|
||||
runnerInstance.removeView(window);
|
||||
@@ -42,6 +52,103 @@ const API: any = {
|
||||
sendSubInputChangeEvent({ data }) {
|
||||
runnerInstance.executeHooks("SubInputChange", data);
|
||||
},
|
||||
removeSubInput(e, window) {
|
||||
window.webContents.executeJavaScript(`window.removeSubInput()`);
|
||||
},
|
||||
setSubInputValue({ data }, window) {
|
||||
window.webContents.executeJavaScript(
|
||||
`window.setSubInputValue(${JSON.stringify({
|
||||
value: data.text,
|
||||
})})`
|
||||
);
|
||||
},
|
||||
getPath({ data }) {
|
||||
return app.getPath(data.name);
|
||||
},
|
||||
showNotification({ data: { body } }) {
|
||||
if (!Notification.isSupported()) return;
|
||||
"string" != typeof body && (body = String(body));
|
||||
const plugin = API.currentPlugin;
|
||||
if (!plugin) return;
|
||||
const notify = new Notification({
|
||||
title: plugin.pluginName,
|
||||
body,
|
||||
icon: plugin.logo,
|
||||
});
|
||||
notify.show();
|
||||
},
|
||||
copyImage: ({ data }) => {
|
||||
const image = nativeImage.createFromDataURL(data.img);
|
||||
clipboard.writeImage(image);
|
||||
},
|
||||
copyText({ data }) {
|
||||
clipboard.writeText(String(data.text));
|
||||
return true;
|
||||
},
|
||||
copyFile: ({ data }) => {
|
||||
if (data.file && fs.existsSync(data.file)) {
|
||||
clipboard.writeBuffer(
|
||||
"NSFilenamesPboardType",
|
||||
Buffer.from(plist.build([data.file]))
|
||||
);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
dbPut({ data }) {
|
||||
return dbInstance.put(API.DBKEY, data.data);
|
||||
},
|
||||
dbGet({ data }) {
|
||||
return dbInstance.get(API.DBKEY, data.id);
|
||||
},
|
||||
dbRemove({ data }) {
|
||||
return dbInstance.remove(API.DBKEY, data.doc);
|
||||
},
|
||||
dbBulkDocs({ data }) {
|
||||
return dbInstance.bulkDocs(API.DBKEY, data.docs);
|
||||
},
|
||||
dbAllDocs({ data }) {
|
||||
return dbInstance.bulkDocs(API.DBKEY, data.key);
|
||||
},
|
||||
getFeatures() {
|
||||
return API.currentPlugin.features;
|
||||
},
|
||||
setFeature({ data }, window) {
|
||||
API.currentPlugin = {
|
||||
...API.currentPlugin,
|
||||
features: (() => {
|
||||
let has = false;
|
||||
API.currentPlugin.features.some((feature) => {
|
||||
has = feature.code === data.feature.code;
|
||||
return has;
|
||||
});
|
||||
if (!has) {
|
||||
return [...API.currentPlugin.features, data.feature];
|
||||
}
|
||||
return API.currentPlugin.features;
|
||||
})(),
|
||||
};
|
||||
window.webContents.executeJavaScript(
|
||||
`window.updatePlugin(${JSON.stringify({
|
||||
currentPlugin: API.currentPlugin,
|
||||
})})`
|
||||
);
|
||||
return true;
|
||||
},
|
||||
removeFeature({ data }, window) {
|
||||
API.currentPlugin = {
|
||||
...API.currentPlugin,
|
||||
features: API.currentPlugin.features.filter(
|
||||
(feature) => feature.code !== data.code
|
||||
),
|
||||
};
|
||||
window.webContents.executeJavaScript(
|
||||
`window.updatePlugin(${JSON.stringify({
|
||||
currentPlugin: API.currentPlugin,
|
||||
})})`
|
||||
);
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
export default (mainWindow: BrowserWindow) => {
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { watch, ref, nextTick, toRaw } from "vue";
|
||||
import { ipcRenderer } from "electron";
|
||||
import { ipcRenderer, remote } from "electron";
|
||||
import Result from "./components/result.vue";
|
||||
import Search from "./components/search.vue";
|
||||
import getWindowHeight from "../common/utils/getWindowHeight";
|
||||
@@ -51,6 +51,7 @@ getPluginInfo({
|
||||
pluginPath: `${__static}/feature/package.json`,
|
||||
}).then((res) => {
|
||||
menuPluginInfo.value = res;
|
||||
remote.getGlobal("LOCAL_PLUGINS").addPlugin(res);
|
||||
});
|
||||
|
||||
watch([searchValue], () => {
|
||||
|
||||
@@ -80,6 +80,10 @@ const createPluginManager = (): any => {
|
||||
const removePlugin = (plugin: any) => {
|
||||
// todo
|
||||
};
|
||||
window.updatePlugin = ({ currentPlugin }: any) => {
|
||||
state.currentPlugin = currentPlugin;
|
||||
remote.getGlobal("LOCAL_PLUGINS").updatePlugin(currentPlugin);
|
||||
};
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { reactive, toRefs } from "vue";
|
||||
import {ipcRenderer} from "electron";
|
||||
import { ipcRenderer, remote } from "electron";
|
||||
|
||||
const searchManager = () => {
|
||||
const state = reactive({
|
||||
@@ -24,6 +24,12 @@ const searchManager = () => {
|
||||
window.setSubInput = ({ placeholder }: { placeholder: string }) => {
|
||||
state.placeholder = placeholder;
|
||||
};
|
||||
window.removeSubInput = () => {
|
||||
state.placeholder = "";
|
||||
};
|
||||
window.setSubInputValue = ({ value }: { value: string }) => {
|
||||
state.searchValue = value;
|
||||
};
|
||||
|
||||
return {
|
||||
...toRefs(state),
|
||||
|
||||
3
src/renderer/shims-vue.d.ts
vendored
3
src/renderer/shims-vue.d.ts
vendored
@@ -15,4 +15,7 @@ declare module 'lodash.throttle'
|
||||
|
||||
interface Window {
|
||||
setSubInput: ({ placeholder }: { placeholder: string }) => void;
|
||||
setSubInputValue: ({ value }: { value: string }) => void;
|
||||
removeSubInput: () => void;
|
||||
updatePlugin: (plugin: any) => void;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user