Add Opencode (opencode.ai) integration via SSH tunnel
Features: - Opencode AI chat interface - SSH tunnel for secure API communication - Auto-install Opencode on remote servers - API key management with server-side storage - Session history and management - Integration with flutter_server_box server list
This commit is contained in:
190
lib/data/store/opencode_store.dart
Normal file
190
lib/data/store/opencode_store.dart
Normal file
@@ -0,0 +1,190 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:fl_lib/fl_lib.dart';
|
||||
import 'package:server_box/data/model/opencode/models.dart';
|
||||
|
||||
/// Opencode 会话存储
|
||||
class OpencodeSessionStore {
|
||||
static const _boxName = 'opencode_sessions';
|
||||
late final Box<String> _box;
|
||||
|
||||
static final OpencodeSessionStore _instance = OpencodeSessionStore._internal();
|
||||
factory OpencodeSessionStore() => _instance;
|
||||
OpencodeSessionStore._internal();
|
||||
|
||||
Future<void> init() async {
|
||||
_box = await Hive.openBox<String>(_boxName);
|
||||
}
|
||||
|
||||
Future<void> saveSession(OpencodeSession session) async {
|
||||
final key = 'session_${session.id}';
|
||||
await _box.put(key, jsonEncode(session.toJson()));
|
||||
await _updateSessionList(session.id, add: true);
|
||||
}
|
||||
|
||||
OpencodeSession? getSession(String sessionId) {
|
||||
final key = 'session_$sessionId';
|
||||
final data = _box.get(key);
|
||||
if (data == null) return null;
|
||||
|
||||
try {
|
||||
final json = jsonDecode(data) as Map<String, dynamic>;
|
||||
return OpencodeSession.fromJson(json);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteSession(String sessionId) async {
|
||||
final key = 'session_$sessionId';
|
||||
await _box.delete(key);
|
||||
await _updateSessionList(sessionId, add: false);
|
||||
}
|
||||
|
||||
List<OpencodeSession> getAllSessions() {
|
||||
final sessionIds = _box.get('session_list')?.split(',') ?? [];
|
||||
final sessions = <OpencodeSession>[];
|
||||
|
||||
for (final id in sessionIds) {
|
||||
if (id.isEmpty) continue;
|
||||
final session = getSession(id);
|
||||
if (session != null) {
|
||||
sessions.add(session);
|
||||
}
|
||||
}
|
||||
|
||||
sessions.sort((a, b) => b.updatedAt.compareTo(a.updatedAt));
|
||||
return sessions;
|
||||
}
|
||||
|
||||
List<OpencodeSession> getSessionsByServer(String serverId) {
|
||||
return getAllSessions()
|
||||
.where((s) => s.serverId == serverId)
|
||||
.toList();
|
||||
}
|
||||
|
||||
Future<void> _updateSessionList(String sessionId, {required bool add}) async {
|
||||
final listStr = _box.get('session_list') ?? '';
|
||||
final list = listStr.split(',').where((s) => s.isNotEmpty).toList();
|
||||
|
||||
if (add) {
|
||||
if (!list.contains(sessionId)) {
|
||||
list.add(sessionId);
|
||||
}
|
||||
} else {
|
||||
list.remove(sessionId);
|
||||
}
|
||||
|
||||
await _box.put('session_list', list.join(','));
|
||||
}
|
||||
|
||||
Future<void> updateSessionMessages(OpencodeSession session) async {
|
||||
await saveSession(session);
|
||||
}
|
||||
|
||||
Future<void> clearAllSessions() async {
|
||||
await _box.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// Opencode 服务器配置存储
|
||||
class OpencodeConfigStore {
|
||||
static const _boxName = 'opencode_configs';
|
||||
late final Box<String> _box;
|
||||
|
||||
static final OpencodeConfigStore _instance = OpencodeConfigStore._internal();
|
||||
factory OpencodeConfigStore() => _instance;
|
||||
OpencodeConfigStore._internal();
|
||||
|
||||
Future<void> init() async {
|
||||
_box = await Hive.openBox<String>(_boxName);
|
||||
}
|
||||
|
||||
Future<void> saveConfig(OpencodeServerConfig config) async {
|
||||
final key = 'config_${config.serverId}';
|
||||
await _box.put(key, jsonEncode(config.toJson()));
|
||||
}
|
||||
|
||||
OpencodeServerConfig getConfig(String serverId) {
|
||||
final key = 'config_$serverId';
|
||||
final data = _box.get(key);
|
||||
|
||||
if (data == null) {
|
||||
return OpencodeServerConfig(serverId: serverId);
|
||||
}
|
||||
|
||||
try {
|
||||
final json = jsonDecode(data) as Map<String, dynamic>;
|
||||
return OpencodeServerConfig.fromJson(json);
|
||||
} catch (e) {
|
||||
return OpencodeServerConfig(serverId: serverId);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> deleteConfig(String serverId) async {
|
||||
final key = 'config_$serverId';
|
||||
await _box.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
/// Opencode API 密钥存储
|
||||
class OpencodeKeyStore {
|
||||
static const _boxName = 'opencode_keys';
|
||||
late final Box<String> _box;
|
||||
|
||||
static final OpencodeKeyStore _instance = OpencodeKeyStore._internal();
|
||||
factory OpencodeKeyStore() => _instance;
|
||||
OpencodeKeyStore._internal();
|
||||
|
||||
Future<void> init() async {
|
||||
_box = await Hive.openBox<String>(_boxName);
|
||||
}
|
||||
|
||||
/// 保存服务器 API 密钥
|
||||
Future<void> saveServerKey(String serverId, {
|
||||
required String apiKey,
|
||||
String? description,
|
||||
}) async {
|
||||
final key = 'key_$serverId';
|
||||
final data = jsonEncode({
|
||||
'server_id': serverId,
|
||||
'api_key': apiKey, // 注意:这里存储明文密钥
|
||||
'description': description,
|
||||
'updated_at': DateTime.now().toIso8601String(),
|
||||
});
|
||||
await _box.put(key, data);
|
||||
}
|
||||
|
||||
/// 获取服务器密钥
|
||||
String? getServerKey(String serverId) {
|
||||
final key = 'key_$serverId';
|
||||
final data = _box.get(key);
|
||||
if (data == null) return null;
|
||||
|
||||
try {
|
||||
final json = jsonDecode(data) as Map<String, dynamic>;
|
||||
return json['api_key'] as String?;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// 获取服务器密钥信息
|
||||
Map<String, dynamic>? getServerKeyInfo(String serverId) {
|
||||
final key = 'key_$serverId';
|
||||
final data = _box.get(key);
|
||||
if (data == null) return null;
|
||||
|
||||
try {
|
||||
return jsonDecode(data) as Map<String, dynamic>;
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// 删除服务器密钥
|
||||
Future<void> deleteServerKey(String serverId) async {
|
||||
final key = 'key_$serverId';
|
||||
await _box.delete(key);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user