Add complete French (fr) and Chinese (zh) translations for all documentation: - Root files: README, CHANGELOG, SECURITY, BETA-RELEASE - docs/: All 16 core documentation files - DOCS/: All 19 deep-dive documents including embedded/ and archive/ - package/secubox/: All 123+ package READMEs - Misc: secubox-tools/, scripts/, EXAMPLES/, config-backups/, streamlit-apps/ Total: 346 translation files created Each file includes language switcher links for easy navigation between English, French, and Chinese versions. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
835 lines
22 KiB
Markdown
835 lines
22 KiB
Markdown
# SecuBox 管理控制中心 - 使用示例
|
||
|
||
> **语言:** [English](../../docs/admin-control-center/EXAMPLES.md) | [Francais](../../docs-fr/admin-control-center/EXAMPLES.md) | 中文
|
||
|
||
状态管理和组件注册表操作的完整示例。
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
1. [CLI 示例](#cli-示例)
|
||
- [状态管理](#状态管理-cli)
|
||
- [组件注册表](#组件注册表-cli)
|
||
- [常见工作流](#常见工作流-cli)
|
||
2. [Shell 脚本示例](#shell-脚本示例)
|
||
3. [JavaScript 前端示例](#javascript-前端示例)
|
||
4. [集成示例](#集成示例)
|
||
|
||
---
|
||
|
||
## CLI 示例
|
||
|
||
### 状态管理 CLI
|
||
|
||
#### 基本状态操作
|
||
|
||
```bash
|
||
# 获取组件的当前状态
|
||
secubox-state get luci-app-auth-guardian
|
||
|
||
# 设置组件状态
|
||
secubox-state set luci-app-auth-guardian starting user_request
|
||
|
||
# 查看状态历史
|
||
secubox-state history luci-app-auth-guardian 20
|
||
|
||
# 列出所有运行中的组件
|
||
secubox-state list --state=running
|
||
|
||
# 列出所有应用
|
||
secubox-state list --type=app
|
||
|
||
# 验证状态一致性
|
||
secubox-state validate luci-app-auth-guardian
|
||
|
||
# 将状态数据库与系统同步
|
||
secubox-state sync
|
||
```
|
||
|
||
#### 错误处理
|
||
|
||
```bash
|
||
# 清除错误状态
|
||
secubox-state clear-error luci-app-vpn-client
|
||
|
||
# 清除错误后检查组件
|
||
secubox-state get luci-app-vpn-client
|
||
```
|
||
|
||
#### 冻结/解冻组件
|
||
|
||
```bash
|
||
# 冻结关键组件
|
||
secubox-state freeze luci-app-firewall system_critical
|
||
|
||
# 检查冻结状态
|
||
secubox-state get luci-app-firewall
|
||
|
||
# 解冻(转换回激活状态)
|
||
secubox-state set luci-app-firewall active admin_unfreeze
|
||
```
|
||
|
||
### 组件注册表 CLI
|
||
|
||
#### 组件注册
|
||
|
||
```bash
|
||
# 注册新的应用组件
|
||
secubox-component register my-custom-app app '{
|
||
"name": "My Custom App",
|
||
"packages": ["my-custom-app", "dependency-pkg"],
|
||
"capabilities": ["custom-feature"],
|
||
"dependencies": {
|
||
"required": ["luci-base"],
|
||
"optional": []
|
||
},
|
||
"managed_services": ["my-service"]
|
||
}'
|
||
|
||
# 注册模块
|
||
secubox-component register my-module module '{
|
||
"name": "My Module",
|
||
"packages": ["my-module-pkg"]
|
||
}'
|
||
|
||
# 注册小部件
|
||
secubox-component register my-widget widget '{
|
||
"name": "My Dashboard Widget",
|
||
"packages": ["luci-app-widget-provider"]
|
||
}'
|
||
```
|
||
|
||
#### 组件查询
|
||
|
||
```bash
|
||
# 获取组件详情
|
||
secubox-component get luci-app-auth-guardian
|
||
|
||
# 列出所有应用
|
||
secubox-component list --type=app
|
||
|
||
# 列出所有运行中的组件
|
||
secubox-component list --state=running
|
||
|
||
# 列出配置文件中的组件
|
||
secubox-component list --profile=home-security
|
||
|
||
# 显示依赖树
|
||
secubox-component tree luci-app-auth-guardian
|
||
|
||
# 显示反向依赖
|
||
secubox-component affected luci-base
|
||
```
|
||
|
||
#### 组件管理
|
||
|
||
```bash
|
||
# 更新组件设置
|
||
secubox-component set-setting luci-app-auth-guardian enabled true
|
||
|
||
# 注销组件
|
||
secubox-component unregister my-old-app
|
||
```
|
||
|
||
### 常见工作流 CLI
|
||
|
||
#### 安装应用(完整工作流)
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
|
||
APP_ID="luci-app-vpn-client"
|
||
|
||
# 1. 检查组件是否已注册
|
||
if ! secubox-component get "$APP_ID" > /dev/null 2>&1; then
|
||
echo "Component not registered, syncing registry..."
|
||
secubox-sync-registry apps
|
||
fi
|
||
|
||
# 2. 设置状态为 installing
|
||
secubox-state set "$APP_ID" installing user_install
|
||
|
||
# 3. 执行实际安装(这将由 secubox-appstore 完成)
|
||
# opkg install luci-app-vpn-client
|
||
|
||
# 4. 成功后设置为 installed
|
||
secubox-state set "$APP_ID" installed install_success
|
||
|
||
# 5. 配置应用
|
||
secubox-state set "$APP_ID" configuring user_config
|
||
|
||
# 6. 标记为 configured
|
||
secubox-state set "$APP_ID" configured config_complete
|
||
|
||
# 7. 激活
|
||
secubox-state set "$APP_ID" activating user_activate
|
||
secubox-state set "$APP_ID" active activation_complete
|
||
|
||
# 8. 启动服务
|
||
secubox-state set "$APP_ID" starting user_start
|
||
|
||
# 9. 标记为 running
|
||
secubox-state set "$APP_ID" running start_success
|
||
```
|
||
|
||
#### 批量状态更改
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
|
||
# 停止所有运行中的应用
|
||
for app_id in $(secubox-state list --state=running --type=app | jq -r '.[].id'); do
|
||
echo "Stopping $app_id..."
|
||
secubox-state set "$app_id" stopping bulk_shutdown
|
||
secubox-state set "$app_id" stopped shutdown_complete
|
||
done
|
||
```
|
||
|
||
#### 健康检查脚本
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
|
||
echo "=== SecuBox Component Health Check ==="
|
||
echo
|
||
|
||
# 获取所有组件
|
||
components=$(secubox-component list)
|
||
|
||
# 按状态统计
|
||
echo "Component Distribution:"
|
||
echo " Running: $(echo "$components" | jq '[.[] | select(.current_state=="running")] | length')"
|
||
echo " Stopped: $(echo "$components" | jq '[.[] | select(.current_state=="stopped")] | length')"
|
||
echo " Error: $(echo "$components" | jq '[.[] | select(.current_state=="error")] | length')"
|
||
echo " Frozen: $(echo "$components" | jq '[.[] | select(.current_state=="frozen")] | length')"
|
||
echo " Disabled: $(echo "$components" | jq '[.[] | select(.current_state=="disabled")] | length')"
|
||
echo
|
||
|
||
# 显示错误组件
|
||
error_count=$(echo "$components" | jq '[.[] | select(.current_state=="error")] | length')
|
||
if [ "$error_count" -gt 0 ]; then
|
||
echo "Components in ERROR state:"
|
||
echo "$components" | jq -r '.[] | select(.current_state=="error") | " - \(.name) (\(.id))"'
|
||
echo
|
||
fi
|
||
|
||
# 显示冻结组件
|
||
frozen_count=$(echo "$components" | jq '[.[] | select(.current_state=="frozen")] | length')
|
||
if [ "$frozen_count" -gt 0 ]; then
|
||
echo "Components in FROZEN state:"
|
||
echo "$components" | jq -r '.[] | select(.current_state=="frozen") | " - \(.name) (\(.id))"'
|
||
echo
|
||
fi
|
||
|
||
# 验证所有组件状态
|
||
echo "Validating component states..."
|
||
invalid_count=0
|
||
for comp_id in $(echo "$components" | jq -r '.[].id'); do
|
||
if ! secubox-state validate "$comp_id" > /dev/null 2>&1; then
|
||
echo " ⚠ Invalid state: $comp_id"
|
||
invalid_count=$((invalid_count + 1))
|
||
fi
|
||
done
|
||
|
||
if [ "$invalid_count" -eq 0 ]; then
|
||
echo " ✓ All component states are valid"
|
||
else
|
||
echo " ✗ Found $invalid_count invalid states"
|
||
fi
|
||
```
|
||
|
||
---
|
||
|
||
## Shell 脚本示例
|
||
|
||
### 示例:启动时自动启动所有应用
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# /etc/init.d/secubox-autostart
|
||
|
||
START=99
|
||
STOP=10
|
||
|
||
start() {
|
||
echo "Starting SecuBox components..."
|
||
|
||
# 获取所有活动组件
|
||
components=$(secubox-component list --state=active --type=app)
|
||
|
||
for app_id in $(echo "$components" | jq -r '.[].id'); do
|
||
# 检查是否启用 auto_start
|
||
auto_start=$(secubox-component get "$app_id" | jq -r '.settings.auto_start // false')
|
||
|
||
if [ "$auto_start" = "true" ]; then
|
||
echo " Starting $app_id..."
|
||
secubox-state set "$app_id" starting boot_autostart
|
||
|
||
# 启动管理的服务
|
||
services=$(secubox-component get "$app_id" | jq -r '.managed_services[]')
|
||
for service in $services; do
|
||
/etc/init.d/"$service" start
|
||
done
|
||
|
||
secubox-state set "$app_id" running start_success
|
||
fi
|
||
done
|
||
}
|
||
|
||
stop() {
|
||
echo "Stopping SecuBox components..."
|
||
|
||
# 获取所有运行中的组件
|
||
components=$(secubox-state list --state=running --type=app)
|
||
|
||
for app_id in $(echo "$components" | jq -r '.[].id'); do
|
||
echo " Stopping $app_id..."
|
||
secubox-state set "$app_id" stopping shutdown
|
||
|
||
# 停止管理的服务
|
||
services=$(secubox-component get "$app_id" | jq -r '.managed_services[]')
|
||
for service in $services; do
|
||
/etc/init.d/"$service" stop
|
||
done
|
||
|
||
secubox-state set "$app_id" stopped stop_success
|
||
done
|
||
}
|
||
```
|
||
|
||
### 示例:组件依赖解析器
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
|
||
resolve_dependencies() {
|
||
local component_id="$1"
|
||
local resolved=()
|
||
local seen=()
|
||
|
||
resolve_recursive() {
|
||
local comp_id="$1"
|
||
|
||
# 检查是否已处理过(循环依赖)
|
||
for s in "${seen[@]}"; do
|
||
if [ "$s" = "$comp_id" ]; then
|
||
echo "Error: Circular dependency detected: $comp_id" >&2
|
||
return 1
|
||
fi
|
||
done
|
||
|
||
seen+=("$comp_id")
|
||
|
||
# 获取必需的依赖
|
||
local deps=$(secubox-component get "$comp_id" | jq -r '.dependencies.required[]')
|
||
|
||
for dep in $deps; do
|
||
resolve_recursive "$dep"
|
||
done
|
||
|
||
# 添加到已解析列表
|
||
resolved+=("$comp_id")
|
||
}
|
||
|
||
resolve_recursive "$component_id"
|
||
|
||
# 按安装顺序打印
|
||
printf '%s\n' "${resolved[@]}"
|
||
}
|
||
|
||
# 使用
|
||
echo "Install order for luci-app-auth-guardian:"
|
||
resolve_dependencies "luci-app-auth-guardian"
|
||
```
|
||
|
||
### 示例:状态转换监控器
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
|
||
watch_state_transitions() {
|
||
local component_id="$1"
|
||
local last_state=""
|
||
|
||
echo "Watching state transitions for: $component_id"
|
||
echo "Press Ctrl+C to stop"
|
||
echo
|
||
|
||
while true; do
|
||
current_state=$(secubox-state get "$component_id" | jq -r '.current_state')
|
||
|
||
if [ "$current_state" != "$last_state" ]; then
|
||
timestamp=$(date "+%Y-%m-%d %H:%M:%S")
|
||
echo "[$timestamp] State changed: $last_state -> $current_state"
|
||
last_state="$current_state"
|
||
fi
|
||
|
||
sleep 1
|
||
done
|
||
}
|
||
|
||
# 使用
|
||
watch_state_transitions "luci-app-vpn-client"
|
||
```
|
||
|
||
---
|
||
|
||
## JavaScript 前端示例
|
||
|
||
### 示例:组件仪表盘
|
||
|
||
```javascript
|
||
'use strict';
|
||
'require view';
|
||
'require secubox-admin.api as api';
|
||
'require secubox-admin.components.StateIndicator as StateIndicator';
|
||
|
||
return view.extend({
|
||
load: function() {
|
||
return api.getAllComponentsWithStates({ type: 'app' });
|
||
},
|
||
|
||
render: function(components) {
|
||
var container = E('div', { 'class': 'component-dashboard' });
|
||
|
||
components.forEach(function(comp) {
|
||
var card = E('div', {
|
||
'class': 'component-card',
|
||
'style': 'padding: 1rem; margin-bottom: 1rem; border: 1px solid #e5e7eb; border-radius: 0.5rem;'
|
||
});
|
||
|
||
// 组件名称
|
||
var name = E('h3', {}, comp.name);
|
||
card.appendChild(name);
|
||
|
||
// 状态指示器
|
||
var state = comp.state_info ? comp.state_info.current_state : 'unknown';
|
||
var stateIndicator = StateIndicator.render(state, {
|
||
showIcon: true,
|
||
showLabel: true
|
||
});
|
||
card.appendChild(stateIndicator);
|
||
|
||
// 操作按钮
|
||
var actions = E('div', { 'style': 'margin-top: 1rem; display: flex; gap: 0.5rem;' });
|
||
|
||
if (state === 'stopped') {
|
||
var startBtn = E('button', {
|
||
'class': 'btn cbi-button-action',
|
||
'click': function() {
|
||
api.setComponentState(comp.id, 'starting', 'user_action')
|
||
.then(function() {
|
||
location.reload();
|
||
});
|
||
}
|
||
}, 'Start');
|
||
actions.appendChild(startBtn);
|
||
} else if (state === 'running') {
|
||
var stopBtn = E('button', {
|
||
'class': 'btn cbi-button-negative',
|
||
'click': function() {
|
||
api.setComponentState(comp.id, 'stopping', 'user_action')
|
||
.then(function() {
|
||
location.reload();
|
||
});
|
||
}
|
||
}, 'Stop');
|
||
actions.appendChild(stopBtn);
|
||
}
|
||
|
||
card.appendChild(actions);
|
||
container.appendChild(card);
|
||
});
|
||
|
||
return container;
|
||
}
|
||
});
|
||
```
|
||
|
||
### 示例:状态转换处理器
|
||
|
||
```javascript
|
||
function handleStateTransition(componentId, newState) {
|
||
// 显示加载指示器
|
||
ui.showModal(_('Changing State'), [
|
||
E('p', { 'class': 'spinning' }, _('Updating component state...'))
|
||
]);
|
||
|
||
// 验证转换
|
||
return api.getComponentState(componentId).then(function(stateInfo) {
|
||
var currentState = stateInfo.current_state;
|
||
|
||
if (!stateUtils.canTransition(currentState, newState)) {
|
||
ui.hideModal();
|
||
ui.addNotification(null,
|
||
E('p', _('Invalid state transition: %s -> %s').format(currentState, newState)),
|
||
'error'
|
||
);
|
||
return Promise.reject('Invalid transition');
|
||
}
|
||
|
||
// 执行转换
|
||
return api.setComponentState(componentId, newState, 'user_action');
|
||
}).then(function(result) {
|
||
ui.hideModal();
|
||
|
||
if (result.success) {
|
||
ui.addNotification(null,
|
||
E('p', _('State changed successfully')),
|
||
'success'
|
||
);
|
||
|
||
// 重新加载组件数据
|
||
return api.getComponentWithState(componentId);
|
||
} else {
|
||
throw new Error(result.message || 'State change failed');
|
||
}
|
||
}).catch(function(error) {
|
||
ui.hideModal();
|
||
ui.addNotification(null,
|
||
E('p', _('Error: %s').format(error.message || error)),
|
||
'error'
|
||
);
|
||
});
|
||
}
|
||
|
||
// 使用
|
||
handleStateTransition('luci-app-vpn-client', 'starting');
|
||
```
|
||
|
||
### 示例:实时状态监控器
|
||
|
||
```javascript
|
||
var StateMonitor = baseclass.extend({
|
||
__init__: function(componentId) {
|
||
this.componentId = componentId;
|
||
this.pollInterval = 2000; // 2 秒
|
||
this.callbacks = [];
|
||
},
|
||
|
||
start: function() {
|
||
var self = this;
|
||
this.lastState = null;
|
||
|
||
this.pollId = poll.add(function() {
|
||
return api.getComponentState(self.componentId).then(function(stateInfo) {
|
||
var currentState = stateInfo.current_state;
|
||
|
||
if (currentState !== self.lastState) {
|
||
self.notifyChange(self.lastState, currentState, stateInfo);
|
||
self.lastState = currentState;
|
||
}
|
||
});
|
||
}, this.pollInterval / 1000);
|
||
},
|
||
|
||
stop: function() {
|
||
if (this.pollId) {
|
||
poll.remove(this.pollId);
|
||
this.pollId = null;
|
||
}
|
||
},
|
||
|
||
onChange: function(callback) {
|
||
this.callbacks.push(callback);
|
||
},
|
||
|
||
notifyChange: function(oldState, newState, stateInfo) {
|
||
this.callbacks.forEach(function(callback) {
|
||
callback(oldState, newState, stateInfo);
|
||
});
|
||
}
|
||
});
|
||
|
||
// 使用
|
||
var monitor = new StateMonitor('luci-app-vpn-client');
|
||
|
||
monitor.onChange(function(oldState, newState, stateInfo) {
|
||
console.log('State changed:', oldState, '->', newState);
|
||
|
||
// 更新界面
|
||
var indicator = document.getElementById('state-indicator');
|
||
if (indicator) {
|
||
var newIndicator = StateIndicator.render(newState);
|
||
indicator.replaceWith(newIndicator);
|
||
}
|
||
});
|
||
|
||
monitor.start();
|
||
```
|
||
|
||
### 示例:批量操作
|
||
|
||
```javascript
|
||
function bulkStartComponents(componentIds) {
|
||
ui.showModal(_('Starting Components'), [
|
||
E('p', {}, _('Starting %d components...').format(componentIds.length)),
|
||
E('div', { 'id': 'bulk-progress' })
|
||
]);
|
||
|
||
var progressDiv = document.getElementById('bulk-progress');
|
||
var completed = 0;
|
||
var failed = 0;
|
||
|
||
// 并行启动所有组件
|
||
return api.bulkSetComponentState(componentIds, 'starting', 'bulk_start')
|
||
.then(function(results) {
|
||
results.forEach(function(result, index) {
|
||
var componentId = componentIds[index];
|
||
|
||
if (result.success) {
|
||
completed++;
|
||
progressDiv.appendChild(
|
||
E('div', { 'style': 'color: #10b981;' },
|
||
'✓ ' + componentId
|
||
)
|
||
);
|
||
} else {
|
||
failed++;
|
||
progressDiv.appendChild(
|
||
E('div', { 'style': 'color: #ef4444;' },
|
||
'✗ ' + componentId + ': ' + (result.error || 'Unknown error')
|
||
)
|
||
);
|
||
}
|
||
});
|
||
|
||
setTimeout(function() {
|
||
ui.hideModal();
|
||
|
||
var message = _('Completed: %d, Failed: %d').format(completed, failed);
|
||
ui.addNotification(null, E('p', message),
|
||
failed > 0 ? 'warning' : 'success'
|
||
);
|
||
}, 2000);
|
||
});
|
||
}
|
||
|
||
// 使用
|
||
var appsToStart = ['luci-app-vpn-client', 'luci-app-firewall', 'luci-app-ddns'];
|
||
bulkStartComponents(appsToStart);
|
||
```
|
||
|
||
---
|
||
|
||
## 集成示例
|
||
|
||
### 示例:具有状态感知的 LuCI 表单
|
||
|
||
```javascript
|
||
var form = new form.Map('myapp', _('My Application'));
|
||
|
||
var section = form.section(form.TypedSection, 'config');
|
||
|
||
// 向 section 添加状态指示器
|
||
section.load = function() {
|
||
var self = this;
|
||
|
||
return Promise.all([
|
||
form.TypedSection.prototype.load.call(this),
|
||
api.getComponentState('my-app')
|
||
]).then(function(results) {
|
||
var stateInfo = results[1];
|
||
|
||
// 将状态信息添加到 section 标题
|
||
var stateIndicator = StateIndicator.render(stateInfo.current_state);
|
||
var titleNode = self.titleFn ? document.querySelector('.cbi-section-node h3') : null;
|
||
if (titleNode) {
|
||
titleNode.appendChild(document.createTextNode(' '));
|
||
titleNode.appendChild(stateIndicator);
|
||
}
|
||
|
||
return results[0];
|
||
});
|
||
};
|
||
|
||
// 添加状态感知选项
|
||
var stateOption = section.option(form.DummyValue, '_state', _('Service State'));
|
||
stateOption.cfgvalue = function() {
|
||
return api.getComponentState('my-app').then(function(stateInfo) {
|
||
return StateIndicator.render(stateInfo.current_state);
|
||
});
|
||
};
|
||
|
||
// 添加控制按钮
|
||
var controlOption = section.option(form.Button, '_control', _('Service Control'));
|
||
controlOption.inputtitle = _('Start');
|
||
controlOption.onclick = function() {
|
||
return handleStateTransition('my-app', 'starting');
|
||
};
|
||
```
|
||
|
||
### 示例:WebSocket 状态更新
|
||
|
||
```javascript
|
||
// 注意:需要后端 WebSocket 支持
|
||
|
||
var StateWebSocket = baseclass.extend({
|
||
__init__: function(url) {
|
||
this.url = url || 'ws://localhost:8080/state-updates';
|
||
this.ws = null;
|
||
this.callbacks = {};
|
||
},
|
||
|
||
connect: function() {
|
||
var self = this;
|
||
|
||
this.ws = new WebSocket(this.url);
|
||
|
||
this.ws.onopen = function() {
|
||
console.log('State WebSocket connected');
|
||
};
|
||
|
||
this.ws.onmessage = function(event) {
|
||
var data = JSON.parse(event.data);
|
||
|
||
if (data.type === 'state_change') {
|
||
self.handleStateChange(data);
|
||
}
|
||
};
|
||
|
||
this.ws.onerror = function(error) {
|
||
console.error('WebSocket error:', error);
|
||
};
|
||
|
||
this.ws.onclose = function() {
|
||
console.log('WebSocket closed, reconnecting...');
|
||
setTimeout(function() {
|
||
self.connect();
|
||
}, 5000);
|
||
};
|
||
},
|
||
|
||
subscribe: function(componentId, callback) {
|
||
if (!this.callbacks[componentId]) {
|
||
this.callbacks[componentId] = [];
|
||
}
|
||
this.callbacks[componentId].push(callback);
|
||
|
||
// 发送订阅消息
|
||
this.send({
|
||
type: 'subscribe',
|
||
component_id: componentId
|
||
});
|
||
},
|
||
|
||
handleStateChange: function(data) {
|
||
var componentId = data.component_id;
|
||
var callbacks = this.callbacks[componentId] || [];
|
||
|
||
callbacks.forEach(function(callback) {
|
||
callback(data.old_state, data.new_state, data.state_info);
|
||
});
|
||
},
|
||
|
||
send: function(data) {
|
||
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
||
this.ws.send(JSON.stringify(data));
|
||
}
|
||
}
|
||
});
|
||
|
||
// 使用
|
||
var ws = new StateWebSocket();
|
||
ws.connect();
|
||
|
||
ws.subscribe('luci-app-vpn-client', function(oldState, newState, stateInfo) {
|
||
console.log('Real-time update:', oldState, '->', newState);
|
||
// 立即更新界面
|
||
});
|
||
```
|
||
|
||
---
|
||
|
||
## 测试示例
|
||
|
||
### 示例:状态转换单元测试
|
||
|
||
```javascript
|
||
describe('State Transitions', function() {
|
||
it('should allow valid transitions', function() {
|
||
expect(stateUtils.canTransition('stopped', 'starting')).toBe(true);
|
||
expect(stateUtils.canTransition('starting', 'running')).toBe(true);
|
||
expect(stateUtils.canTransition('running', 'stopping')).toBe(true);
|
||
});
|
||
|
||
it('should reject invalid transitions', function() {
|
||
expect(stateUtils.canTransition('stopped', 'running')).toBe(false);
|
||
expect(stateUtils.canTransition('available', 'running')).toBe(false);
|
||
});
|
||
|
||
it('should handle error transitions', function() {
|
||
expect(stateUtils.canTransition('installing', 'error')).toBe(true);
|
||
expect(stateUtils.canTransition('error', 'available')).toBe(true);
|
||
});
|
||
});
|
||
```
|
||
|
||
### 示例:集成测试
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
|
||
test_component_lifecycle() {
|
||
local app_id="test-app"
|
||
|
||
echo "Testing component lifecycle for: $app_id"
|
||
|
||
# 1. 注册组件
|
||
echo " 1. Registering component..."
|
||
secubox-component register "$app_id" app '{"name":"Test App","packages":["test-pkg"]}'
|
||
|
||
# 2. 初始化状态
|
||
echo " 2. Initializing state..."
|
||
secubox-state set "$app_id" available init
|
||
|
||
# 3. 安装
|
||
echo " 3. Installing..."
|
||
secubox-state set "$app_id" installing test
|
||
secubox-state set "$app_id" installed test
|
||
|
||
# 4. 激活
|
||
echo " 4. Activating..."
|
||
secubox-state set "$app_id" configuring test
|
||
secubox-state set "$app_id" configured test
|
||
secubox-state set "$app_id" activating test
|
||
secubox-state set "$app_id" active test
|
||
|
||
# 5. 启动
|
||
echo " 5. Starting..."
|
||
secubox-state set "$app_id" starting test
|
||
secubox-state set "$app_id" running test
|
||
|
||
# 6. 停止
|
||
echo " 6. Stopping..."
|
||
secubox-state set "$app_id" stopping test
|
||
secubox-state set "$app_id" stopped test
|
||
|
||
# 7. 卸载
|
||
echo " 7. Uninstalling..."
|
||
secubox-state set "$app_id" uninstalling test
|
||
secubox-state set "$app_id" available test
|
||
|
||
# 8. 清理
|
||
echo " 8. Cleaning up..."
|
||
secubox-component unregister "$app_id"
|
||
|
||
echo "✓ Lifecycle test completed successfully"
|
||
}
|
||
|
||
test_component_lifecycle
|
||
```
|
||
|
||
---
|
||
|
||
**另请参阅:**
|
||
- [API 参考](API-REFERENCE.md)
|
||
- [状态管理指南](STATE-MANAGEMENT.md)
|
||
- [组件系统指南](COMPONENT-SYSTEM.md)
|
||
|
||
---
|
||
|
||
**版本:** 1.0
|
||
**最后更新:** 2026-01-05
|