Skip to content

Commit d272e3e

Browse files
Merge branch 'dev' into dev
2 parents dfdb401 + 7f5b1e1 commit d272e3e

40 files changed

Lines changed: 3634 additions & 1159 deletions

Cargo.lock

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/plugin_api.md

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# 插件 API 文档
2+
3+
本文档列出了所有提供给前端插件的 API 接口,方便前端开发者直接查看和使用。
4+
5+
## 目录
6+
7+
- [Element API](#element-api)
8+
- [Server API](#server-api)
9+
- [Console API](#console-api)
10+
- [FileSystem API](#filesystem-api)
11+
12+
## Element API
13+
14+
| 方法名 | 参数 | 返回值 | 描述 |
15+
| ------------------------------------------ | ---------------------------------------------------------------------- | -------------------------------- | ------------------------ |
16+
| `sl.element.get_text(selector)` | `selector: string` - CSS 选择器 | `string``nil` - 元素文本内容 | 获取指定元素的文本内容 |
17+
| `sl.element.get_value(selector)` | `selector: string` - CSS 选择器 | `string``nil` - 元素值 | 获取指定元素的值 |
18+
| `sl.element.get_attribute(selector, attr)` | `selector: string` - CSS 选择器<br>`attr: string` - 属性名 | `string``nil` - 属性值 | 获取指定元素的指定属性值 |
19+
| `sl.element.get_attributes(selector)` | `selector: string` - CSS 选择器 | `object``nil` - 元素所有属性 | 获取指定元素的所有属性 |
20+
| `sl.element.click(selector)` | `selector: string` - CSS 选择器 | `boolean` - 操作是否成功 | 点击指定元素 |
21+
| `sl.element.set_value(selector, value)` | `selector: string` - CSS 选择器<br>`value: string` - 要设置的值 | `boolean` - 操作是否成功 | 设置指定元素的值 |
22+
| `sl.element.check(selector, checked)` | `selector: string` - CSS 选择器<br>`checked: boolean` - 是否选中 | `boolean` - 操作是否成功 | 检查或取消检查指定元素 |
23+
| `sl.element.select(selector, value)` | `selector: string` - CSS 选择器<br>`value: string` - 要选择的值 | `boolean` - 操作是否成功 | 选择指定元素的选项 |
24+
| `sl.element.focus(selector)` | `selector: string` - CSS 选择器 | `boolean` - 操作是否成功 | 聚焦指定元素 |
25+
| `sl.element.blur(selector)` | `selector: string` - CSS 选择器 | `boolean` - 操作是否成功 | 使指定元素失焦 |
26+
| `sl.element.on_change(selector, callback)` | `selector: string` - CSS 选择器<br>`callback: function` - 变化回调函数 | `function` - 清理函数 | 监听指定元素的变化 |
27+
28+
## Server API
29+
30+
| 方法名 | 参数 | 返回值 | 描述 |
31+
| --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | -------------------------------- | -------------------------- |
32+
| `sl.server.list()` || `table` - 服务器列表 | 获取所有服务器列表 |
33+
| `sl.server.get_path(server_id)` | `server_id: string` - 服务器 ID | `string` - 服务器路径 | 获取指定服务器的路径 |
34+
| `sl.server.read_file(server_id, relative_path)` | `server_id: string` - 服务器 ID<br>`relative_path: string` - 相对路径 | `string` - 文件内容 | 读取服务器文件内容 |
35+
| `sl.server.write_file(server_id, relative_path, content)` | `server_id: string` - 服务器 ID<br>`relative_path: string` - 相对路径<br>`content: string` - 文件内容 | `boolean` - 操作是否成功 | 写入服务器文件 |
36+
| `sl.server.list_dir(server_id, relative_path)` | `server_id: string` - 服务器 ID<br>`relative_path: string` - 相对路径 | `table` - 目录内容列表 | 列出服务器目录内容 |
37+
| `sl.server.exists(server_id, relative_path)` | `server_id: string` - 服务器 ID<br>`relative_path: string` - 相对路径 | `boolean` - 文件是否存在 | 检查服务器文件是否存在 |
38+
| `sl.server.logs.get(server_id, count)` | `server_id: string` - 服务器 ID<br>`count: number` - 日志行数 (可选,默认 100) | `table` - 日志列表 | 获取指定服务器的日志 |
39+
| `sl.server.logs.getAll(count)` | `count: number` - 日志行数 (可选,默认 100) | `table` - 所有运行中服务器的日志 | 获取所有运行中服务器的日志 |
40+
41+
## Console API
42+
43+
| 方法名 | 参数 | 返回值 | 描述 |
44+
| --------------------------------------- | ------------------------------------------------------------------------------ | ----------------------------------- | -------------------- |
45+
| `sl.console.send(server_id, command)` | `server_id: string` - 服务器 ID<br>`command: string` - 命令内容 | `boolean` - 发送是否成功 | 发送命令到指定服务器 |
46+
| `sl.console.get_logs(server_id, count)` | `server_id: string` - 服务器 ID<br>`count: number` - 日志行数 (可选,默认 100) | `table` - 包含content字段的日志列表 | 获取指定服务器的日志 |
47+
| `sl.console.get_status(server_id)` | `server_id: string` - 服务器 ID | `string` - 服务器状态 | 获取指定服务器的状态 |
48+
49+
## 权限说明
50+
51+
- `sl.element` 相关 API:需要 `ui` 权限
52+
- `sl.server` 相关 API:需要 `server` 权限
53+
- `sl.console` 相关 API:需要 `console` 权限
54+
- `sl.fs` 相关 API:需要 `fs.data``fs.server``fs.global` 权限
55+
- `fs.data`:只能访问插件数据目录
56+
- `fs.server`:只能访问服务器目录
57+
- `fs.global`:可以访问全局目录
58+
59+
## FileSystem API
60+
61+
| 方法名 | 参数 | 返回值 | 描述 |
62+
| ---------------------------------- | ---------------------------------------------------------- | --------------------------------- | -------------------- |
63+
| `sl.fs.read(path)` | `path: string` - 文件路径 | `string` - 文件内容 | 读取文件内容 |
64+
| `sl.fs.read_binary(path)` | `path: string` - 文件路径 | `string` - Base64编码的二进制内容 | 读取二进制文件内容 |
65+
| `sl.fs.write(path, content)` | `path: string` - 文件路径<br>`content: string` - 文件内容 | `nil` | 写入文件内容 |
66+
| `sl.fs.exists(path)` | `path: string` - 文件路径 | `boolean` - 文件是否存在 | 检查文件是否存在 |
67+
| `sl.fs.list(path)` | `path: string` - 目录路径 | `table` - 文件名列表 | 列出目录内容 |
68+
| `sl.fs.mkdir(path)` | `path: string` - 目录路径 | `nil` | 创建目录(递归) |
69+
| `sl.fs.remove(path)` | `path: string` - 文件或目录路径 | `nil` | 删除文件或目录 |
70+
| `sl.fs.info(path)` | `path: string` - 文件或目录路径 | `table` - 文件信息 | 获取文件信息 |
71+
| `sl.fs.copy(src, dst)` | `src: string` - 源路径<br>`dst: string` - 目标路径 | `nil` | 复制文件或目录 |
72+
| `sl.fs.move(src, dst)` | `src: string` - 源路径<br>`dst: string` - 目标路径 | `nil` | 移动文件或目录 |
73+
| `sl.fs.rename(old_path, new_path)` | `old_path: string` - 旧路径<br>`new_path: string` - 新路径 | `nil` | 重命名文件或目录 |
74+
| `sl.fs.get_path(scope)` | `scope: string` - 作用域 (`data`, `server`, `global`) | `string` - 路径 | 获取指定作用域的路径 |
75+
76+
## 示例
77+
78+
### 发送命令到服务器
79+
80+
```lua
81+
local success = sl.console.send("server1", "say Hello from plugin!")
82+
if success then
83+
print("Command sent successfully")
84+
else
85+
print("Failed to send command")
86+
end
87+
```
88+
89+
### 获取服务器状态
90+
91+
```lua
92+
local status = sl.console.get_status("server1")
93+
print("Server status: " .. status)
94+
```
95+
96+
### 文件系统操作
97+
98+
```lua
99+
-- 读取文件
100+
local content = sl.fs.read("config.txt")
101+
print("File content: " .. content)
102+
103+
-- 写入文件
104+
sl.fs.write("output.txt", "Hello, world!")
105+
106+
-- 检查文件是否存在
107+
local exists = sl.fs.exists("config.txt")
108+
print("File exists: " .. tostring(exists))
109+
110+
-- 列出目录内容
111+
local files = sl.fs.list("")
112+
for i, file in ipairs(files) do
113+
print("File " .. i .. ": " .. file)
114+
end
115+
```

src-tauri/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ image = { version = "0.25", default-features = false, features = [
6262
] }
6363
url = "2.5"
6464
rusqlite = { version = "0.32", features = ["bundled"] }
65+
ipnet = "2.10"
66+
chrono = "0.4"
67+
lazy_static = "1.4"
6568
nasm-rs = "0.3.1"
6669
shlex = "1.3.0"
6770

src-tauri/build.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
use nasm_rs::compile_library_args;
2-
use std::env;
3-
use std::path::Path;
4-
51
fn main() {
62
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
73
{
@@ -12,6 +8,10 @@ fn main() {
128

139
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
1410
fn load_asm() {
11+
use nasm_rs::compile_library_args;
12+
use std::env;
13+
use std::path::Path;
14+
1515
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
1616
let asm_path =
1717
Path::new(&manifest_dir).join("src/assemblies/panic_report/getregs/x64_linux.asm");

src-tauri/src/commands/logging.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use crate::services::global;
2+
use crate::utils::logger::{LogEntry, GLOBAL_LOG_COLLECTOR};
3+
use tauri::command;
4+
5+
#[command]
6+
pub fn get_logs(limit: Option<usize>) -> Vec<LogEntry> {
7+
GLOBAL_LOG_COLLECTOR.get_logs(limit)
8+
}
9+
10+
#[command]
11+
pub fn clear_logs() {
12+
GLOBAL_LOG_COLLECTOR.clear();
13+
}
14+
15+
#[command]
16+
pub fn check_developer_mode() -> bool {
17+
global::settings_manager().get().developer_mode
18+
}

src-tauri/src/commands/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
pub mod config;
22
pub mod downloader;
33
pub mod java;
4+
pub mod logging;
45
pub mod mcs_plugin;
56
pub mod player;
67
pub mod plugin;

src-tauri/src/commands/plugin.rs

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,3 +860,147 @@ pub fn get_plugin_sidebar_snapshot() -> Vec<BufferedSidebarEvent> {
860860
pub fn get_plugin_context_menu_snapshot() -> Vec<BufferedContextMenuEvent> {
861861
crate::plugins::api::take_context_menu_snapshot()
862862
}
863+
864+
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
865+
pub struct PermissionInfo {
866+
pub id: String,
867+
pub name: String,
868+
pub description: String,
869+
pub risk_level: String,
870+
pub category: String,
871+
}
872+
873+
#[tauri::command]
874+
pub fn get_permission_list() -> Vec<PermissionInfo> {
875+
vec![
876+
PermissionInfo {
877+
id: "log".to_string(),
878+
name: "Logging".to_string(),
879+
description: "Allow plugin to write logs".to_string(),
880+
risk_level: "low".to_string(),
881+
category: "system".to_string(),
882+
},
883+
PermissionInfo {
884+
id: "fs".to_string(),
885+
name: "File System (Legacy)".to_string(),
886+
description: "Allow plugin to read/write files in plugin data directory (deprecated, use fs.data)".to_string(),
887+
risk_level: "low".to_string(),
888+
category: "filesystem".to_string(),
889+
},
890+
PermissionInfo {
891+
id: "fs.data".to_string(),
892+
name: "File System - Data".to_string(),
893+
description: "Allow plugin to read/write files in its private data directory".to_string(),
894+
risk_level: "low".to_string(),
895+
category: "filesystem".to_string(),
896+
},
897+
PermissionInfo {
898+
id: "fs.server".to_string(),
899+
name: "File System - Server".to_string(),
900+
description: "Allow plugin to read/write files in server configuration directory".to_string(),
901+
risk_level: "medium".to_string(),
902+
category: "filesystem".to_string(),
903+
},
904+
PermissionInfo {
905+
id: "fs.global".to_string(),
906+
name: "File System - Global".to_string(),
907+
description: "Allow plugin to read/write files in global application directory".to_string(),
908+
risk_level: "high".to_string(),
909+
category: "filesystem".to_string(),
910+
},
911+
PermissionInfo {
912+
id: "http".to_string(),
913+
name: "HTTP Requests".to_string(),
914+
description: "Allow plugin to make HTTP requests to external servers".to_string(),
915+
risk_level: "medium".to_string(),
916+
category: "network".to_string(),
917+
},
918+
PermissionInfo {
919+
id: "i18n".to_string(),
920+
name: "Internationalization".to_string(),
921+
description: "Allow plugin to access and modify locale settings".to_string(),
922+
risk_level: "low".to_string(),
923+
category: "system".to_string(),
924+
},
925+
PermissionInfo {
926+
id: "process".to_string(),
927+
name: "Process Control".to_string(),
928+
description: "Allow plugin to start and manage system processes".to_string(),
929+
risk_level: "high".to_string(),
930+
category: "system".to_string(),
931+
},
932+
PermissionInfo {
933+
id: "server".to_string(),
934+
name: "Server Control".to_string(),
935+
description: "Allow plugin to control Minecraft servers".to_string(),
936+
risk_level: "medium".to_string(),
937+
category: "server".to_string(),
938+
},
939+
PermissionInfo {
940+
id: "storage".to_string(),
941+
name: "Storage".to_string(),
942+
description: "Allow plugin to store persistent data".to_string(),
943+
risk_level: "low".to_string(),
944+
category: "storage".to_string(),
945+
},
946+
PermissionInfo {
947+
id: "ui".to_string(),
948+
name: "UI Components".to_string(),
949+
description: "Allow plugin to create and manage UI components".to_string(),
950+
risk_level: "low".to_string(),
951+
category: "ui".to_string(),
952+
},
953+
PermissionInfo {
954+
id: "system".to_string(),
955+
name: "System Information".to_string(),
956+
description: "Allow plugin to access system information".to_string(),
957+
risk_level: "medium".to_string(),
958+
category: "system".to_string(),
959+
},
960+
PermissionInfo {
961+
id: "console".to_string(),
962+
name: "Console Access".to_string(),
963+
description: "Allow plugin to access and control the console".to_string(),
964+
risk_level: "medium".to_string(),
965+
category: "system".to_string(),
966+
},
967+
PermissionInfo {
968+
id: "element".to_string(),
969+
name: "DOM Elements".to_string(),
970+
description: "Allow plugin to create and manipulate DOM elements".to_string(),
971+
risk_level: "low".to_string(),
972+
category: "ui".to_string(),
973+
},
974+
PermissionInfo {
975+
id: "api".to_string(),
976+
name: "Plugin API".to_string(),
977+
description: "Allow plugin to call other plugins' APIs".to_string(),
978+
risk_level: "medium".to_string(),
979+
category: "api".to_string(),
980+
},
981+
]
982+
}
983+
984+
// 获取插件已申请的权限列表
985+
#[tauri::command]
986+
pub fn get_plugin_permissions(
987+
plugin_id: String,
988+
manager: tauri::State<'_, Arc<Mutex<PluginManager>>>,
989+
) -> Result<Vec<PermissionInfo>, String> {
990+
validate_plugin_id(&plugin_id)?;
991+
let mgr = manager.lock().unwrap_or_else(|e| e.into_inner());
992+
let plugin_list = mgr.get_plugin_list();
993+
994+
let plugin = plugin_list
995+
.iter()
996+
.find(|p| p.manifest.id == plugin_id)
997+
.ok_or_else(|| format!("Plugin '{}' not found", plugin_id))?;
998+
999+
let all_permissions = get_permission_list();
1000+
let plugin_permissions: Vec<PermissionInfo> = all_permissions
1001+
.into_iter()
1002+
.filter(|p| plugin.manifest.permissions.contains(&p.id))
1003+
.collect();
1004+
1005+
Ok(plugin_permissions)
1006+
}

src-tauri/src/commands/settings.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::models::settings::{AppSettings, PartialSettings};
22
use crate::services::global;
33
use font_kit::source::SystemSource;
4+
use serde::Deserialize;
45
use std::collections::HashSet;
56

67
#[derive(serde::Serialize)]
@@ -9,6 +10,12 @@ pub struct UpdateSettingsResult {
910
pub changed_groups: Vec<String>,
1011
}
1112

13+
#[derive(serde::Serialize, Deserialize)]
14+
pub struct PluginCommands {
15+
pub allowed: Vec<String>,
16+
pub blocked: Vec<String>,
17+
}
18+
1219
#[tauri::command]
1320
pub fn get_settings() -> AppSettings {
1421
global::settings_manager().get()
@@ -80,3 +87,30 @@ pub fn get_system_fonts() -> Result<Vec<String>, String> {
8087

8188
Ok(sorted_fonts)
8289
}
90+
91+
#[tauri::command]
92+
pub fn get_plugin_commands() -> PluginCommands {
93+
let settings = global::settings_manager().get();
94+
PluginCommands {
95+
allowed: settings.plugin_allowed_commands,
96+
blocked: settings.plugin_blocked_commands,
97+
}
98+
}
99+
100+
#[tauri::command]
101+
pub fn update_plugin_commands(commands: PluginCommands) -> Result<UpdateSettingsResult, String> {
102+
let partial = PartialSettings {
103+
plugin_allowed_commands: Some(commands.allowed),
104+
plugin_blocked_commands: Some(commands.blocked),
105+
..Default::default()
106+
};
107+
let result = global::settings_manager().update_partial(partial)?;
108+
Ok(UpdateSettingsResult {
109+
settings: result.settings,
110+
changed_groups: result
111+
.changed_groups
112+
.into_iter()
113+
.map(|g| format!("{:?}", g))
114+
.collect(),
115+
})
116+
}

0 commit comments

Comments
 (0)