From 6e6d04998cfd55d026a486a3913df2f7213b81af Mon Sep 17 00:00:00 2001
From: Exidex <16986685+Exidex@users.noreply.github.com>
Date: Wed, 27 Mar 2024 19:41:39 +0100
Subject: [PATCH] Implement bundled plugins
---
Cargo.lock | 23 +++
bundled_plugins/applications/.gitignore | 2 +
bundled_plugins/applications/gauntlet.toml | 13 ++
bundled_plugins/applications/package.json | 17 +++
bundled_plugins/applications/src/default.ts | 38 +++++
bundled_plugins/applications/tsconfig.json | 12 ++
bundled_plugins/calculator/.gitignore | 2 +
bundled_plugins/calculator/gauntlet.toml | 11 ++
bundled_plugins/calculator/package.json | 17 +++
bundled_plugins/calculator/src/default.tsx | 25 ++++
bundled_plugins/calculator/tsconfig.json | 12 ++
js/build/src/main.ts | 19 +--
package-lock.json | 141 ++++++++++++++++++
package.json | 1 +
rust/client/Cargo.toml | 4 +-
rust/common/Cargo.toml | 2 +-
rust/component_model/Cargo.toml | 2 +-
rust/management_client/Cargo.toml | 2 +-
rust/server/Cargo.toml | 3 +-
rust/server/db_migrations/6_plugin_type.sql | 2 +
rust/server/src/lib.rs | 11 +-
rust/server/src/plugins/config_reader.rs | 13 +-
rust/server/src/plugins/data_db_repository.rs | 34 ++++-
rust/server/src/plugins/loader.rs | 42 +++++-
rust/server/src/plugins/mod.rs | 19 +++
25 files changed, 426 insertions(+), 41 deletions(-)
create mode 100644 bundled_plugins/applications/.gitignore
create mode 100644 bundled_plugins/applications/gauntlet.toml
create mode 100644 bundled_plugins/applications/package.json
create mode 100644 bundled_plugins/applications/src/default.ts
create mode 100644 bundled_plugins/applications/tsconfig.json
create mode 100644 bundled_plugins/calculator/.gitignore
create mode 100644 bundled_plugins/calculator/gauntlet.toml
create mode 100644 bundled_plugins/calculator/package.json
create mode 100644 bundled_plugins/calculator/src/default.tsx
create mode 100644 bundled_plugins/calculator/tsconfig.json
create mode 100644 rust/server/db_migrations/6_plugin_type.sql
diff --git a/Cargo.lock b/Cargo.lock
index fca7751..00f8dd8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -231,6 +231,9 @@ name = "anyhow"
version = "1.0.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
+dependencies = [
+ "backtrace",
+]
[[package]]
name = "approx"
@@ -4448,6 +4451,25 @@ dependencies = [
"hashbrown 0.12.3",
]
+[[package]]
+name = "include_dir"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18762faeff7122e89e0857b02f7ce6fcc0d101d5e9ad2ad7846cc01d61b7f19e"
+dependencies = [
+ "include_dir_macros",
+]
+
+[[package]]
+name = "include_dir_macros"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f"
+dependencies = [
+ "proc-macro2 1.0.78",
+ "quote 1.0.35",
+]
+
[[package]]
name = "indexmap"
version = "1.9.3"
@@ -7116,6 +7138,7 @@ dependencies = [
"deno_runtime",
"directories",
"gix",
+ "include_dir",
"once_cell",
"regex",
"serde",
diff --git a/bundled_plugins/applications/.gitignore b/bundled_plugins/applications/.gitignore
new file mode 100644
index 0000000..de4d1f0
--- /dev/null
+++ b/bundled_plugins/applications/.gitignore
@@ -0,0 +1,2 @@
+dist
+node_modules
diff --git a/bundled_plugins/applications/gauntlet.toml b/bundled_plugins/applications/gauntlet.toml
new file mode 100644
index 0000000..92fdade
--- /dev/null
+++ b/bundled_plugins/applications/gauntlet.toml
@@ -0,0 +1,13 @@
+[gauntlet]
+name = 'Bundled - Applications'
+description = ''
+
+[[entrypoint]]
+id = 'default'
+name = 'Default'
+path = 'src/default.ts'
+type = 'command-generator'
+description = ''
+
+[[supported_system]]
+os = 'linux'
diff --git a/bundled_plugins/applications/package.json b/bundled_plugins/applications/package.json
new file mode 100644
index 0000000..c29b270
--- /dev/null
+++ b/bundled_plugins/applications/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "@project-gauntlet/bundled-plugin-application",
+ "private": true,
+ "scripts": {
+ "build": "gauntlet build",
+ "dev": "gauntlet dev"
+ },
+ "dependencies": {
+ "@project-gauntlet/api": "file:../../js/api"
+ },
+ "devDependencies": {
+ "@types/react": "^18.2.14",
+ "@project-gauntlet/deno": "file:../../js/deno",
+ "@project-gauntlet/tools": "0.3.0",
+ "typescript": "^5.3.3"
+ }
+}
diff --git a/bundled_plugins/applications/src/default.ts b/bundled_plugins/applications/src/default.ts
new file mode 100644
index 0000000..0a5f494
--- /dev/null
+++ b/bundled_plugins/applications/src/default.ts
@@ -0,0 +1,38 @@
+interface GeneratedCommand { // TODO Add this type to api
+ id: string
+ name: string
+ fn: () => void
+}
+
+export default function Default(): GeneratedCommand[] {
+ return [
+ {
+ id: 'generated-test-1',
+ name: 'Application 1',
+ fn: () => {
+ console.log('opening application 1')
+ }
+ },
+ {
+ id: 'generated-test-2',
+ name: 'Application 2',
+ fn: () => {
+ console.log('opening application 2')
+ }
+ },
+ {
+ id: 'generated-test-3',
+ name: 'Application 3',
+ fn: () => {
+ console.log('opening application 3')
+ }
+ },
+ {
+ id: 'generated-test-4',
+ name: 'Application 4',
+ fn: () => {
+ console.log('opening application 4')
+ }
+ }
+ ]
+}
diff --git a/bundled_plugins/applications/tsconfig.json b/bundled_plugins/applications/tsconfig.json
new file mode 100644
index 0000000..cbe7961
--- /dev/null
+++ b/bundled_plugins/applications/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "compilerOptions": {
+ "strict": true,
+ "module": "ES2022",
+ "esModuleInterop": true,
+ "target": "ES2022",
+ "moduleResolution": "bundler",
+ "jsx": "react-jsx",
+ "types": ["@project-gauntlet/deno"]
+ },
+ "lib": ["ES2020"]
+}
\ No newline at end of file
diff --git a/bundled_plugins/calculator/.gitignore b/bundled_plugins/calculator/.gitignore
new file mode 100644
index 0000000..de4d1f0
--- /dev/null
+++ b/bundled_plugins/calculator/.gitignore
@@ -0,0 +1,2 @@
+dist
+node_modules
diff --git a/bundled_plugins/calculator/gauntlet.toml b/bundled_plugins/calculator/gauntlet.toml
new file mode 100644
index 0000000..7d300a9
--- /dev/null
+++ b/bundled_plugins/calculator/gauntlet.toml
@@ -0,0 +1,11 @@
+[gauntlet]
+name = 'Bundled - Calculator'
+description = ''
+
+[[entrypoint]]
+id = 'default'
+name = 'Default'
+path = 'src/default.tsx'
+type = 'inline-view'
+description = ''
+
diff --git a/bundled_plugins/calculator/package.json b/bundled_plugins/calculator/package.json
new file mode 100644
index 0000000..926e6fa
--- /dev/null
+++ b/bundled_plugins/calculator/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "@project-gauntlet/bundled-plugin-calculator",
+ "private": true,
+ "scripts": {
+ "build": "gauntlet build",
+ "dev": "gauntlet dev"
+ },
+ "dependencies": {
+ "@project-gauntlet/api": "file:../../js/api"
+ },
+ "devDependencies": {
+ "@types/react": "^18.2.14",
+ "@project-gauntlet/deno": "file:../../js/deno",
+ "@project-gauntlet/tools": "0.3.0",
+ "typescript": "^5.3.3"
+ }
+}
diff --git a/bundled_plugins/calculator/src/default.tsx b/bundled_plugins/calculator/src/default.tsx
new file mode 100644
index 0000000..29b3d58
--- /dev/null
+++ b/bundled_plugins/calculator/src/default.tsx
@@ -0,0 +1,25 @@
+import { Content, Inline } from "@project-gauntlet/api/components";
+import { ReactNode } from "react";
+
+export default function Default(props: { text: string }): ReactNode | undefined {
+ const text = props.text;
+ if (!text.startsWith("inline")) {
+ return undefined
+ }
+
+ return (
+
+
+
+ Testing inline view left {text}
+
+
+
+
+
+ Testing inline view right
+
+
+
+ )
+}
diff --git a/bundled_plugins/calculator/tsconfig.json b/bundled_plugins/calculator/tsconfig.json
new file mode 100644
index 0000000..cbe7961
--- /dev/null
+++ b/bundled_plugins/calculator/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "compilerOptions": {
+ "strict": true,
+ "module": "ES2022",
+ "esModuleInterop": true,
+ "target": "ES2022",
+ "moduleResolution": "bundler",
+ "jsx": "react-jsx",
+ "types": ["@project-gauntlet/deno"]
+ },
+ "lib": ["ES2020"]
+}
\ No newline at end of file
diff --git a/js/build/src/main.ts b/js/build/src/main.ts
index c9b3e9f..b8cd8ad 100644
--- a/js/build/src/main.ts
+++ b/js/build/src/main.ts
@@ -25,26 +25,15 @@ program.command('build')
await program.parseAsync(process.argv);
function build(projectRoot: string, check: boolean) {
- console.log("Building @project-gauntlet/api-build...")
- execSync('npm run build --workspace @project-gauntlet/api-build', { stdio: "inherit", cwd: projectRoot});
- console.log("Building @project-gauntlet/api...")
- execSync('npm run build --workspace @project-gauntlet/api', { stdio: "inherit", cwd: projectRoot});
- console.log("Building @project-gauntlet/deno...")
- execSync('npm run build --workspace @project-gauntlet/deno', { stdio: "inherit", cwd: projectRoot });
- console.log("Building @project-gauntlet/react...")
- execSync('npm run build --workspace @project-gauntlet/react', { stdio: "inherit", cwd: projectRoot });
-
- console.log("Building @project-gauntlet/react-renderer...")
- execSync('npm run build --workspace @project-gauntlet/react-renderer', { stdio: "inherit", cwd: projectRoot });
- console.log("Building @project-gauntlet/core...")
- execSync('npm run build --workspace @project-gauntlet/core', { stdio: "inherit", cwd: projectRoot });
+ console.log("Building js...")
+ execSync('npm run build', { stdio: "inherit", cwd: projectRoot});
if (check) {
- console.log("Check application...")
+ console.log("Checking rust...")
execSync('cargo check', { stdio: "inherit", cwd: projectRoot });
}
- console.log("Building application...")
+ console.log("Building rust...")
execSync('cargo build --release', { stdio: "inherit", cwd: projectRoot });
}
diff --git a/package-lock.json b/package-lock.json
index 26b992a..69dc8ae 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6,6 +6,7 @@
"": {
"name": "project-gauntlet",
"workspaces": [
+ "bundled_plugins/*",
"js/typings",
"js/build",
"js/api_build",
@@ -16,6 +17,28 @@
"js/react_renderer"
]
},
+ "bundled_plugins/applications": {
+ "dependencies": {
+ "@project-gauntlet/api": "file:../../js/api"
+ },
+ "devDependencies": {
+ "@project-gauntlet/deno": "file:../../js/deno",
+ "@project-gauntlet/tools": "0.3.0",
+ "@types/react": "^18.2.14",
+ "typescript": "^5.3.3"
+ }
+ },
+ "bundled_plugins/calculator": {
+ "dependencies": {
+ "@project-gauntlet/api": "file:../../js/api"
+ },
+ "devDependencies": {
+ "@project-gauntlet/deno": "file:../../js/deno",
+ "@project-gauntlet/tools": "0.3.0",
+ "@types/react": "^18.2.14",
+ "typescript": "^5.3.3"
+ }
+ },
"js/api": {
"name": "@project-gauntlet/api",
"version": "0.1.0",
@@ -106,6 +129,27 @@
"js/typings": {
"name": "@project-gauntlet/typings"
},
+ "node_modules/@dbus-types/dbus": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/@dbus-types/dbus/-/dbus-0.0.4.tgz",
+ "integrity": "sha512-KRD48WayYXEmFfVyR4zrCpZ5tviBSU2NXddMOQ4AW1zPfLtEkg7gvVvZUL1/DlThUoFwMC+RRR+EK0yGtZq3Jw==",
+ "dev": true
+ },
+ "node_modules/@homebridge/long": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/@homebridge/long/-/long-5.2.1.tgz",
+ "integrity": "sha512-i5Df8R63XNPCn+Nj1OgAoRdw9e+jHUQb3CNUbvJneI2iu3j4+OtzQj+5PA1Ce+747NR1SPqZSvyvD483dOT3AA==",
+ "dev": true
+ },
+ "node_modules/@homebridge/put": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/@homebridge/put/-/put-0.0.8.tgz",
+ "integrity": "sha512-mwxLHHqKebOmOSU0tsPEWQSBHGApPhuaqtNpCe7U+AMdsduweANiu64E9SXXUtdpyTjsOpgSMLhD1+kbLHD2gA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.3.0"
+ }
+ },
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.4.15",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
@@ -460,6 +504,14 @@
"resolved": "js/build",
"link": true
},
+ "node_modules/@project-gauntlet/bundled-plugin-application": {
+ "resolved": "bundled_plugins/applications",
+ "link": true
+ },
+ "node_modules/@project-gauntlet/bundled-plugin-calculator": {
+ "resolved": "bundled_plugins/calculator",
+ "link": true
+ },
"node_modules/@project-gauntlet/core": {
"resolved": "js/core",
"link": true
@@ -476,6 +528,28 @@
"resolved": "js/react_renderer",
"link": true
},
+ "node_modules/@project-gauntlet/tools": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@project-gauntlet/tools/-/tools-0.3.0.tgz",
+ "integrity": "sha512-1meJKEWRAF5oVf3322aurxNRY3htPHeyWkPXAzGMo5MD+ZYpklCxP5MwJnWE1aWZmfAaIkr21tpDjZeuYjch+A==",
+ "dev": true,
+ "dependencies": {
+ "@rollup/plugin-commonjs": "^25.0.7",
+ "@rollup/plugin-node-resolve": "^15.2.3",
+ "@rollup/plugin-typescript": "^11.1.5",
+ "chalk": "^5.3.0",
+ "commander": "^11.1.0",
+ "dbus-ts": "^0.0.7",
+ "rollup": "^4.3.0",
+ "simple-git": "^3.22.0",
+ "toml": "^3.0.0",
+ "tslib": "^2.6.2",
+ "zod": "^3.22.4"
+ },
+ "bin": {
+ "gauntlet": "bin/main.js"
+ }
+ },
"node_modules/@project-gauntlet/typings": {
"resolved": "js/typings",
"link": true
@@ -897,6 +971,18 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/chalk": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
+ "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
+ "dev": true,
+ "engines": {
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
"node_modules/clean-stack": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
@@ -925,6 +1011,18 @@
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
"dev": true
},
+ "node_modules/dbus-ts": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/dbus-ts/-/dbus-ts-0.0.7.tgz",
+ "integrity": "sha512-2Iig5znVcrIMSAgTxy5DcUm2mIkgbFGP01YUSxSakkzQzrx+OH24LMIiopDAEWS8LR6V3/eVywO72us438eX0Q==",
+ "dev": true,
+ "dependencies": {
+ "@dbus-types/dbus": "^0.0.4",
+ "@homebridge/long": "^5.2.1",
+ "@homebridge/put": "^0.0.8",
+ "xml2js": "^0.4.23"
+ }
+ },
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -1363,6 +1461,12 @@
}
]
},
+ "node_modules/sax": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz",
+ "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==",
+ "dev": true
+ },
"node_modules/scheduler": {
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
@@ -1422,6 +1526,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/toml": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz",
+ "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==",
+ "dev": true
+ },
"node_modules/tslib": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
@@ -1465,10 +1575,41 @@
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
+ "node_modules/xml2js": {
+ "version": "0.4.23",
+ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz",
+ "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==",
+ "dev": true,
+ "dependencies": {
+ "sax": ">=0.6.0",
+ "xmlbuilder": "~11.0.0"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/xmlbuilder": {
+ "version": "11.0.1",
+ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
+ "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
+ "dev": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+ },
+ "node_modules/zod": {
+ "version": "3.22.4",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz",
+ "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
}
}
}
diff --git a/package.json b/package.json
index 6babe36..0a515f9 100644
--- a/package.json
+++ b/package.json
@@ -5,6 +5,7 @@
"build": "npm run build --workspaces --if-present"
},
"workspaces": [
+ "bundled_plugins/*",
"js/typings",
"js/build",
"js/api_build",
diff --git a/rust/client/Cargo.toml b/rust/client/Cargo.toml
index 7af68ef..7859431 100644
--- a/rust/client/Cargo.toml
+++ b/rust/client/Cargo.toml
@@ -4,7 +4,7 @@ edition = "2021"
[dependencies]
tokio = "1.28.1"
-anyhow = "1"
+anyhow = { version = "1", features = ["backtrace"] }
thiserror = "1"
#iced = { version = "0.12.0", features = ["tokio", "lazy", "advanced"] }
iced = { git = "https://github.com/project-gauntlet/iced.git", branch = "gauntlet", features = ["tokio", "lazy", "advanced", "multi-window", "image"] }
@@ -20,5 +20,5 @@ itertools = "0.12.1"
[build-dependencies]
component_model = { path = "../component_model" }
-anyhow = "1"
+anyhow = { version = "1", features = ["backtrace"] }
convert_case = "0.6.0"
diff --git a/rust/common/Cargo.toml b/rust/common/Cargo.toml
index ddd8752..78f5a28 100644
--- a/rust/common/Cargo.toml
+++ b/rust/common/Cargo.toml
@@ -4,7 +4,7 @@ edition = "2021"
[dependencies]
gix = { version = "0.52.0", features = ["blocking-http-transport-curl"] }
-anyhow = "1.0.75"
+anyhow = { version = "1", features = ["backtrace"] }
tonic = "0.11.0"
prost = "0.12.3"
diff --git a/rust/component_model/Cargo.toml b/rust/component_model/Cargo.toml
index 6025235..e2e675f 100644
--- a/rust/component_model/Cargo.toml
+++ b/rust/component_model/Cargo.toml
@@ -5,5 +5,5 @@ edition = "2021"
[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0" }
-anyhow = "1.0.75"
+anyhow = { version = "1", features = ["backtrace"] }
indexmap = { version = "2.1.0", features = ["serde"] }
diff --git a/rust/management_client/Cargo.toml b/rust/management_client/Cargo.toml
index 3815340..11e22ee 100644
--- a/rust/management_client/Cargo.toml
+++ b/rust/management_client/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2021"
[dependencies]
tokio = "1.28.1"
clap = { version = "4.3.22", features = ["derive"] }
-anyhow = "1.0.75"
+anyhow = { version = "1", features = ["backtrace"] }
thiserror = "1.0.48"
#iced = { version = "0.12.0", features = ["tokio", "lazy", "advanced"] }
iced = { git = "https://github.com/project-gauntlet/iced.git", branch = "gauntlet", features = ["tokio", "lazy", "advanced"] }
diff --git a/rust/server/Cargo.toml b/rust/server/Cargo.toml
index c63eb6f..fe4f9c6 100644
--- a/rust/server/Cargo.toml
+++ b/rust/server/Cargo.toml
@@ -15,7 +15,7 @@ once_cell = "1.18.0"
gix = { version = "0.52.0", features = ["blocking-http-transport-curl"] }
tempfile = "3"
async-stream = "0.3.5"
-anyhow = "1.0.75"
+anyhow = { version = "1", features = ["backtrace"] }
thiserror = "1.0.48"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
@@ -26,6 +26,7 @@ component_model = { path = "../component_model" }
tonic = "0.11.0"
client = { path = "../client" }
walkdir = "2.4.0"
+include_dir = "0.7.3"
[features]
dev = []
diff --git a/rust/server/db_migrations/6_plugin_type.sql b/rust/server/db_migrations/6_plugin_type.sql
new file mode 100644
index 0000000..96bb8b7
--- /dev/null
+++ b/rust/server/db_migrations/6_plugin_type.sql
@@ -0,0 +1,2 @@
+ALTER TABLE plugin DROP COLUMN from_config;
+ALTER TABLE plugin ADD COLUMN type TEXT NOT NULL DEFAULT ('normal');
diff --git a/rust/server/src/lib.rs b/rust/server/src/lib.rs
index 0bbc16b..1503b56 100644
--- a/rust/server/src/lib.rs
+++ b/rust/server/src/lib.rs
@@ -32,16 +32,17 @@ async fn run_server() -> anyhow::Result<()> {
let search_index = SearchIndex::create_index()?;
let mut application_manager = ApplicationManager::create(search_index.clone()).await?;
+ if let Err(err) = application_manager.load_builtin_plugins().await {
+ tracing::error!("error loading bundled plugin(s): {:?}", err);
+ }
+
if cfg!(feature = "dev") {
let plugin_path = concat!(env!("CARGO_MANIFEST_DIR"), "/../../dev_plugin/dist").to_owned();
let plugin_path = std::fs::canonicalize(plugin_path).expect("valid path");
let plugin_path = plugin_path.to_str().expect("valid utf8");
- let result = application_manager.save_local_plugin(plugin_path)
- .await;
-
- if let Err(err) = result {
- tracing::error!("error loading dev plugin: {}", err);
+ if let Err(err) = application_manager.save_local_plugin(plugin_path).await {
+ tracing::error!("error loading dev plugin: {:?}", err);
}
}
diff --git a/rust/server/src/plugins/config_reader.rs b/rust/server/src/plugins/config_reader.rs
index 987f48a..7a2928f 100644
--- a/rust/server/src/plugins/config_reader.rs
+++ b/rust/server/src/plugins/config_reader.rs
@@ -1,5 +1,4 @@
use serde::Deserialize;
-use tracing::{error, info};
use crate::dirs::Dirs;
use crate::plugins::data_db_repository::{DataDbRepository, DbWritePendingPlugin};
@@ -42,17 +41,15 @@ impl ConfigReader {
match config_content {
Ok(config_content) => {
- match toml::from_str(&config_content) {
- Ok(config) => config,
- Err(err) => {
- error!("Unable to parse config, error: {error}", error = err.message());
+ toml::from_str(&config_content)
+ .unwrap_or_else(|err| {
+ tracing::error!("Unable to parse config, error: {:?}", err);
ApplicationConfig::default()
- }
- }
+ })
}
Err(_) => {
- info!("No config found, using default configuration");
+ tracing::info!("No config found, using default configuration");
ApplicationConfig::default()
}
diff --git a/rust/server/src/plugins/data_db_repository.rs b/rust/server/src/plugins/data_db_repository.rs
index 8559aa7..ddb6f2a 100644
--- a/rust/server/src/plugins/data_db_repository.rs
+++ b/rust/server/src/plugins/data_db_repository.rs
@@ -30,7 +30,8 @@ pub struct DbReadPlugin {
pub code: DbCode,
#[sqlx(json)]
pub permissions: DbPluginPermissions,
- pub from_config: bool,
+ #[sqlx(rename = "type")]
+ pub plugin_type: String,
#[sqlx(json)]
pub preferences: HashMap,
#[sqlx(json)]
@@ -70,7 +71,7 @@ pub struct DbWritePlugin {
pub entrypoints: Vec,
pub asset_data: Vec,
pub permissions: DbPluginPermissions,
- pub from_config: bool,
+ pub plugin_type: String,
pub preferences: HashMap,
pub preferences_user_data: HashMap,
}
@@ -99,6 +100,13 @@ pub enum DbPluginEntrypointType {
CommandGenerator,
}
+#[derive(Debug, Clone)]
+pub enum DbPluginType {
+ Normal,
+ Config,
+ Bundled,
+}
+
#[derive(Debug, Deserialize, Serialize)]
pub struct DbPluginPermissions {
pub environment: Vec,
@@ -524,10 +532,10 @@ impl DataDbRepository {
.bind(plugin.enabled)
.bind(Json(plugin.code))
.bind(Json(plugin.permissions))
- .bind(false)
.bind(Json(plugin.preferences))
.bind(Json(plugin.preferences_user_data))
.bind(plugin.description)
+ .bind(plugin.plugin_type)
.execute(&mut *tx)
.await?;
@@ -580,6 +588,24 @@ pub fn db_entrypoint_from_str(value: &str) -> DbPluginEntrypointType {
"view" => DbPluginEntrypointType::View,
"inline-view" => DbPluginEntrypointType::InlineView,
"command-generator" => DbPluginEntrypointType::CommandGenerator,
- _ => panic!("index contains illegal entrypoint_type: {}", value)
+ _ => panic!("illegal entrypoint_type: {}", value)
+ }
+}
+
+
+pub fn db_plugin_type_to_str(value: DbPluginType) -> &'static str {
+ match value {
+ DbPluginType::Normal => "normal",
+ DbPluginType::Config => "config",
+ DbPluginType::Bundled => "bundled"
+ }
+}
+
+pub fn db_plugin_type_from_str(value: &str) -> DbPluginType {
+ match value {
+ "normal" => DbPluginType::Normal,
+ "config" => DbPluginType::Config,
+ "bundled" => DbPluginType::Bundled,
+ _ => panic!("illegal plugin_type: {}", value)
}
}
diff --git a/rust/server/src/plugins/loader.rs b/rust/server/src/plugins/loader.rs
index 0786d77..b277c52 100644
--- a/rust/server/src/plugins/loader.rs
+++ b/rust/server/src/plugins/loader.rs
@@ -2,17 +2,19 @@ use std::cell::RefCell;
use std::collections::HashMap;
use std::ffi::OsStr;
use std::fs::DirEntry;
+use std::io::{Error, ErrorKind};
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::thread;
use anyhow::{anyhow, Context};
+use include_dir::Dir;
use serde::{Deserialize, Serialize};
use walkdir::WalkDir;
use common::model::{DownloadStatus, PluginId};
-use crate::plugins::data_db_repository::{DataDbRepository, db_entrypoint_to_str, DbCode, DbPluginAction, DbPluginActionShortcutKind, DbPluginEntrypointType, DbPluginPermissions, DbPluginPreference, DbPluginPreferenceUserData, DbPreferenceEnumValue, DbWritePlugin, DbWritePluginAssetData, DbWritePluginEntrypoint};
+use crate::plugins::data_db_repository::{DataDbRepository, db_entrypoint_to_str, db_plugin_type_to_str, DbCode, DbPluginAction, DbPluginActionShortcutKind, DbPluginEntrypointType, DbPluginPermissions, DbPluginPreference, DbPluginPreferenceUserData, DbPluginType, DbPreferenceEnumValue, DbWritePlugin, DbWritePluginAssetData, DbWritePluginEntrypoint};
use crate::plugins::download_status::DownloadStatusHolder;
use crate::plugins::js::asset_data;
@@ -57,7 +59,7 @@ impl PluginLoader {
entrypoints: plugin_data.entrypoints,
asset_data: plugin_data.asset_data,
permissions: plugin_data.permissions,
- from_config: false,
+ plugin_type: db_plugin_type_to_str(DbPluginType::Normal).to_owned(),
preferences: plugin_data.preferences,
preferences_user_data: HashMap::new(),
}).await?;
@@ -96,7 +98,37 @@ impl PluginLoader {
entrypoints: plugin_data.entrypoints,
asset_data: plugin_data.asset_data,
permissions: plugin_data.permissions,
- from_config: false,
+ plugin_type: db_plugin_type_to_str(DbPluginType::Normal).to_owned(),
+ preferences: plugin_data.preferences,
+ preferences_user_data: HashMap::new()
+ }).await?;
+
+ Ok(plugin_id)
+ }
+
+ pub async fn save_builtin_plugin(&self, id: &str, dir: &Dir<'_>) -> anyhow::Result {
+ let plugin_id = PluginId::from_string(format!("builtin://{id}"));
+ let temp_dir = tempfile::tempdir()?;
+
+ dir.extract(&temp_dir)?;
+
+ let plugin_data = PluginLoader::read_plugin_dir(temp_dir.path(), plugin_id.clone())
+ .await
+ .context("Unable to read plugin directory")?;
+
+ // TODO instead of overwrite just update the code and assets
+ self.db_repository.remove_plugin(&plugin_data.id).await?;
+
+ self.db_repository.save_plugin(DbWritePlugin {
+ id: plugin_data.id,
+ name: plugin_data.name,
+ description: plugin_data.description,
+ enabled: true,
+ code: plugin_data.code,
+ entrypoints: plugin_data.entrypoints,
+ asset_data: plugin_data.asset_data,
+ permissions: plugin_data.permissions,
+ plugin_type: db_plugin_type_to_str(DbPluginType::Bundled).to_owned(),
preferences: plugin_data.preferences,
preferences_user_data: HashMap::new()
}).await?;
@@ -162,6 +194,10 @@ impl PluginLoader {
let asset_data = WalkDir::new(&assets)
.into_iter()
.collect::>>()
+ .or_else(|err| match err.io_error() {
+ Some(err) if matches!(err.kind(), ErrorKind::NotFound) => Ok(vec![]),
+ _ => Err(err),
+ })
.context("Unable to get list of plugin asset data files")?
.into_iter()
.filter(|dir_entry| dir_entry.file_type().is_file())
diff --git a/rust/server/src/plugins/mod.rs b/rust/server/src/plugins/mod.rs
index cc7bbf2..f3d7ddd 100644
--- a/rust/server/src/plugins/mod.rs
+++ b/rust/server/src/plugins/mod.rs
@@ -1,4 +1,5 @@
use std::collections::HashMap;
+use include_dir::{Dir, include_dir};
use common::model::{DownloadStatus, EntrypointId, PluginId, PropertyValue};
use common::rpc::{plugin_preference_user_data_from_npb, plugin_preference_user_data_to_npb, rpc_ui_property_value, RpcEntrypoint, RpcEntrypointTypeSettings, RpcEnumValue, RpcNoProtoBufPluginPreferenceUserData, RpcPlugin, RpcPluginPreference, RpcPluginPreferenceUserData, RpcPluginPreferenceValueType, RpcUiPropertyValue};
@@ -19,6 +20,12 @@ mod loader;
mod run_status;
mod download_status;
+
+static BUILTIN_PLUGINS: [(&str, Dir); 2] = [
+ ("applications", include_dir!("$CARGO_MANIFEST_DIR/../../bundled_plugins/applications/dist")),
+ ("calculator", include_dir!("$CARGO_MANIFEST_DIR/../../bundled_plugins/calculator/dist")),
+];
+
pub struct ApplicationManager {
config_reader: ConfigReader,
search_index: SearchIndex,
@@ -69,6 +76,18 @@ impl ApplicationManager {
Ok(())
}
+ pub async fn load_builtin_plugins(&self) -> anyhow::Result<()> {
+ for (id, dir) in &BUILTIN_PLUGINS {
+ tracing::info!(target = "plugin", "Saving builtin plugin with id: {:?}", id);
+
+ let plugin_id = self.plugin_downloader.save_builtin_plugin(id, dir).await?;
+
+ self.reload_plugin(plugin_id).await?;
+ }
+
+ Ok(())
+ }
+
pub async fn plugins(&self) -> anyhow::Result> {
let result = self.db_repository
.list_plugins_and_entrypoints()