diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..b0a0150 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,7 @@ +{ + "tasks": { + "build": "cargo build --release", + "test": "cargo test", + "launch": "cargo build && cargo run" + } +} \ No newline at end of file diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 0000000..ef3080c --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,76 @@ +name: Rust CI/CD Pipeline + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +env: + CARGO_TERM_COLOR: always + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: true + + - name: Cache Cargo + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin + target + ~/.cargo/registry + ~/.cargo/git + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Build + run: cargo build --verbose + continue-on-error: false + + - name: Run tests + run: cargo test --verbose -- --nocapture + continue-on-error: false + + - name: Run linter + run: cargo clippy -- -D warnings + continue-on-error: false + + - name: Format check + run: cargo fmt -- --check + continue-on-error: false + + - name: Publish test results + if: always() + uses: actions/upload-artifact@v3 + with: + name: test-results + path: target/debug/deps/*.d + + # Rollback step in case of failure + rollback: + runs-on: ubuntu-latest + if: failure() + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Rollback to previous commit + run: | + git checkout main + git reset --hard HEAD~1 + git push -f origin main + continue-on-error: false diff --git a/Cargo.lock b/Cargo.lock index 8e93131..ae5ca96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,7 +1,121 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "nofwl" version = "0.1.0" +dependencies = [ + "serde", + "serde_yaml", +] + +[[package]] +name = "proc-macro2" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_yaml" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" +dependencies = [ + "indexmap", + "ryu", + "serde", + "yaml-rust", +] + +[[package]] +name = "syn" +version = "2.0.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] diff --git a/Cargo.toml b/Cargo.toml index 03c7ea3..3c901f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,7 @@ license = "GPL-3.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_yaml = "0.8" +tauri = "1.0" +tauri-plugin = "0.1" diff --git a/README.md b/README.md index d2b90b1..4fe333c 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ xattr -cr /YOUR_PATH/NoFWL.app - Themes (light, dark, system) - Internationalization (English, Chinese) - Safe and reliable, all data is stored locally +- Plugin management ## I18N @@ -86,6 +87,55 @@ If you would like to contribute translations for other languages to the applicat - [ ] Custom - [ ] Plugins +## Plugin Management + +To manage plugins in NoFWL, follow these steps: + +1. Open the `nofwl.yml` file located in the root directory of the project. +2. Add or update the plugin information under the `plugins` section. +3. Save the changes and restart the application. + +Example `nofwl.yml` file: + +```yaml +name: nofwl +author: lencx +description: NoFWL Plugins +link: https://github.com/lencx/nofwl +plugins: + - name: chatgpt + version: 0.1.0 + - name: bing + version: 0.1.0 + - name: valtown + version: 0.1.0 + author: yourname + description: NoFWL Val.town Plugin + link: https://github.com/yourusername/nofwl/tree/main/plugins/valtown + url: + - https://api.val.town + +plugin_management: + categories: + productivity: Productivity + entertainment: Entertainment + utilities: Utilities + tags: + search: Search + filter: Filter + sort: Sort + dependencies: + label: Dependencies + none: None + compatibility: + label: Compatibility + compatible: Compatible + incompatible: Incompatible + warnings: + incompatible_plugin: This plugin is not compatible with the current version of the ChatGPT desktop application. + unresolved_dependencies: This plugin has unresolved dependencies. +``` + ## Preview ![nofwl](./assets/nofwl.gif) diff --git a/locales/en.yml b/locales/en.yml index 2667a86..35377c3 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -87,3 +87,23 @@ control_center: user_custom: User Custom sync_prompts: Sync Prompts sync_custom: Sync Custom + +plugin_management: + categories: + productivity: Productivity + entertainment: Entertainment + utilities: Utilities + tags: + search: Search + filter: Filter + sort: Sort + dependencies: + label: Dependencies + none: None + compatibility: + label: Compatibility + compatible: Compatible + incompatible: Incompatible + warnings: + incompatible_plugin: This plugin is not compatible with the current version of the ChatGPT desktop application. + unresolved_dependencies: This plugin has unresolved dependencies. diff --git a/nofwl.yml b/nofwl.yml index 1caecc2..183bf84 100644 --- a/nofwl.yml +++ b/nofwl.yml @@ -6,4 +6,31 @@ plugins: - name: chatgpt version: 0.1.0 - name: bing - version: 0.1.0 \ No newline at end of file + version: 0.1.0 + - name: valtown + version: 0.1.0 + author: yourname + description: NoFWL Val.town Plugin + link: https://github.com/yourusername/nofwl/tree/main/plugins/valtown + url: + - https://api.val.town + +plugin_management: + categories: + productivity: Productivity + entertainment: Entertainment + utilities: Utilities + tags: + search: Search + filter: Filter + sort: Sort + dependencies: + label: Dependencies + none: None + compatibility: + label: Compatibility + compatible: Compatible + incompatible: Incompatible + warnings: + incompatible_plugin: This plugin is not compatible with the current version of the ChatGPT desktop application. + unresolved_dependencies: This plugin has unresolved dependencies. diff --git a/plugins/bing/meta.yml b/plugins/bing/meta.yml index b75c53c..01c98cb 100644 --- a/plugins/bing/meta.yml +++ b/plugins/bing/meta.yml @@ -4,4 +4,10 @@ author: lencx description: NoFWL Bing link: https://github.com/lencx/nofwl/tree/main/plugins/bing url: - - https://edgeservices.bing.com \ No newline at end of file + - https://edgeservices.bing.com +dependencies: [] +compatibility: "1.0.0" +update_url: "https://github.com/lencx/nofwl/tree/main/plugins/bing" +changelog: | + - Initial release +last_updated: "2023-04-01" diff --git a/plugins/chatgpt/meta.yml b/plugins/chatgpt/meta.yml index 1e324c9..a4c6ec7 100644 --- a/plugins/chatgpt/meta.yml +++ b/plugins/chatgpt/meta.yml @@ -5,4 +5,10 @@ description: NoFWL ChatGPT link: https://github.com/lencx/nofwl/tree/main/plugins/chatgpt url: - https://ai.com - - https://chat.openai.com \ No newline at end of file + - https://chat.openai.com +dependencies: [] +compatibility: "1.0.0" +update_url: "https://github.com/lencx/nofwl/tree/main/plugins/chatgpt" +changelog: | + - Initial release +last_updated: "2023-04-01" diff --git a/plugins/valtown/main.js b/plugins/valtown/main.js new file mode 100644 index 0000000..699c0a7 --- /dev/null +++ b/plugins/valtown/main.js @@ -0,0 +1,28 @@ +/** + * @name nofwl/valtown + * @description Val.town Plugin + * @author yourname + */ + +console.log('nofwl: Val.town Plugin'); + +// Function to connect to Val.town API endpoints +async function connectToValtownAPI(endpoint) { + try { + const response = await fetch(endpoint); + const data = await response.json(); + console.log('Val.town API response:', data); + } catch (error) { + console.error('Error connecting to Val.town API:', error); + } +} + +// Example usage of the connectToValtownAPI function +const valtownEndpoints = [ + 'https://api.val.town/endpoint1', + 'https://api.val.town/endpoint2', +]; + +valtownEndpoints.forEach(endpoint => { + connectToValtownAPI(endpoint); +}); diff --git a/plugins/valtown/meta.yml b/plugins/valtown/meta.yml new file mode 100644 index 0000000..531263e --- /dev/null +++ b/plugins/valtown/meta.yml @@ -0,0 +1,13 @@ +name: valtown +version: 0.1.0 +author: yourname +description: NoFWL Val.town Plugin +link: https://github.com/yourusername/nofwl/tree/main/plugins/valtown +url: + - https://api.val.town +dependencies: [] +compatibility: "1.0.0" +update_url: "https://github.com/yourusername/nofwl/tree/main/plugins/valtown" +changelog: | + - Initial release +last_updated: "2023-04-01" diff --git a/src/main.rs b/src/main.rs index eac4293..07d6d1a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,78 @@ +use std::fs::File; +use std::io::Read; +use serde::Deserialize; +use tauri::Manager; +use tauri_plugin::PluginBuilder; + +#[derive(Debug, Deserialize)] +struct Plugin { + name: String, + version: String, + author: Option, + description: Option, + link: Option, + url: Option>, + dependencies: Option>, + compatibility: Option, + update_url: Option, + changelog: Option, + last_updated: Option, +} + +#[derive(Debug, Deserialize)] +struct Config { + plugins: Vec, +} + +fn load_config() -> Config { + let mut file = File::open("nofwl.yml").expect("Failed to open nofwl.yml"); + let mut contents = String::new(); + file.read_to_string(&mut contents).expect("Failed to read nofwl.yml"); + serde_yaml::from_str(&contents).expect("Failed to parse nofwl.yml") +} + +fn check_dependencies(plugin: &Plugin, config: &Config) -> Result<(), String> { + if let Some(dependencies) = &plugin.dependencies { + for dependency in dependencies { + if !config.plugins.iter().any(|p| &p.name == dependency) { + return Err(format!("Missing dependency: {}", dependency)); + } + } + } + Ok(()) +} + +fn initialize_plugins(config: &Config) { + for plugin in &config.plugins { + println!("Initializing plugin: {}", plugin.name); + + if let Err(err) = check_dependencies(plugin, config) { + println!("Error initializing plugin {}: {}", plugin.name, err); + continue; + } + + if let Some(urls) = &plugin.url { + for url in urls { + println!("Connecting to Val.town API endpoint: {}", url); + // Add code to connect to Val.town API endpoints + } + } + } +} + fn main() { + let config = load_config(); + initialize_plugins(&config); + + tauri::Builder::default() + .plugin(PluginBuilder::default().build()) + .setup(|app| { + let main_window = app.get_window("main").unwrap(); + main_window.set_title("NoFWL").unwrap(); + Ok(()) + }) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); + println!("Hello, NoFWL!"); }