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
191 lines
5.0 KiB
Dart
191 lines
5.0 KiB
Dart
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);
|
|
}
|
|
}
|