mirror of
https://github.com/Kori1c/ecs-controller.git
synced 2026-05-07 22:27:22 +08:00
249 lines
11 KiB
PHP
249 lines
11 KiB
PHP
<?php
|
|
|
|
class ConfigManager
|
|
{
|
|
private $db;
|
|
private $configCache = [];
|
|
private $accountsCache = [];
|
|
|
|
public function __construct(Database $db)
|
|
{
|
|
$this->db = $db->getPdo();
|
|
$this->load();
|
|
}
|
|
|
|
public function load()
|
|
{
|
|
$stmt = $this->db->query("SELECT key, value FROM settings");
|
|
while ($row = $stmt->fetch()) {
|
|
$this->configCache[$row['key']] = $row['value'];
|
|
}
|
|
|
|
$stmt = $this->db->query("SELECT * FROM accounts ORDER BY id ASC");
|
|
$this->accountsCache = $stmt->fetchAll();
|
|
}
|
|
|
|
public function get($key, $default = null)
|
|
{
|
|
return $this->configCache[$key] ?? $default;
|
|
}
|
|
|
|
public function getAllSettings()
|
|
{
|
|
return $this->configCache;
|
|
}
|
|
|
|
public function getAccounts()
|
|
{
|
|
return $this->accountsCache;
|
|
}
|
|
|
|
public function getAccountById($id)
|
|
{
|
|
foreach ($this->accountsCache as $acc) {
|
|
if ($acc['id'] == $id)
|
|
return $acc;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public function isInitialized()
|
|
{
|
|
return !empty($this->configCache['admin_password']);
|
|
}
|
|
|
|
private function saveSetting($key, $value)
|
|
{
|
|
$stmt = $this->db->prepare("INSERT OR REPLACE INTO settings (key, value) VALUES (?, ?)");
|
|
$stmt->execute([$key, $value]);
|
|
$this->configCache[$key] = $value;
|
|
}
|
|
|
|
// --- 新增:心跳时间管理 ---
|
|
|
|
public function updateLastRunTime($time)
|
|
{
|
|
$this->saveSetting('last_monitor_run', $time);
|
|
}
|
|
|
|
public function getLastRunTime()
|
|
{
|
|
return (int) ($this->configCache['last_monitor_run'] ?? 0);
|
|
}
|
|
|
|
// ------------------------
|
|
|
|
public function updateConfig($data)
|
|
{
|
|
try {
|
|
$this->db->beginTransaction();
|
|
|
|
// 1. 保存全局设置
|
|
$this->saveSetting('admin_password', $data['admin_password']);
|
|
$this->saveSetting('traffic_threshold', $data['traffic_threshold']);
|
|
$this->saveSetting('enable_schedule_email', $data['enable_schedule_email'] ? '1' : '0');
|
|
$this->saveSetting('shutdown_mode', $data['shutdown_mode']);
|
|
$this->saveSetting('threshold_action', $data['threshold_action']);
|
|
$this->saveSetting('keep_alive', isset($data['keep_alive']) && $data['keep_alive'] ? '1' : '0');
|
|
$this->saveSetting('api_interval', $data['api_interval'] ?? 600);
|
|
|
|
if (isset($data['Notification'])) {
|
|
// Email
|
|
$this->saveSetting('notify_email_enabled', isset($data['Notification']['email_enabled']) && $data['Notification']['email_enabled'] ? '1' : '0');
|
|
$this->saveSetting('notify_email', $data['Notification']['email'] ?? '');
|
|
$this->saveSetting('notify_host', $data['Notification']['host'] ?? '');
|
|
$this->saveSetting('notify_port', $data['Notification']['port'] ?? 465);
|
|
$this->saveSetting('notify_username', $data['Notification']['username'] ?? '');
|
|
$this->saveSetting('notify_password', $data['Notification']['password'] ?? '');
|
|
$this->saveSetting('notify_secure', $data['Notification']['secure'] ?? 'ssl');
|
|
|
|
// Telegram
|
|
if (isset($data['Notification']['telegram'])) {
|
|
$tg = $data['Notification']['telegram'];
|
|
$this->saveSetting('notify_tg_enabled', isset($tg['enabled']) && $tg['enabled'] ? '1' : '0');
|
|
$this->saveSetting('notify_tg_token', $tg['token'] ?? '');
|
|
$this->saveSetting('notify_tg_chat_id', $tg['chat_id'] ?? '');
|
|
$this->saveSetting('notify_tg_proxy_type', $tg['proxy_type'] ?? 'none');
|
|
$this->saveSetting('notify_tg_proxy_url', $tg['proxy_url'] ?? '');
|
|
$this->saveSetting('notify_tg_proxy_ip', $tg['proxy_ip'] ?? '');
|
|
$this->saveSetting('notify_tg_proxy_port', $tg['proxy_port'] ?? '');
|
|
$this->saveSetting('notify_tg_proxy_user', $tg['proxy_user'] ?? '');
|
|
$this->saveSetting('notify_tg_proxy_pass', $tg['proxy_pass'] ?? '');
|
|
}
|
|
|
|
// Webhook
|
|
if (isset($data['Notification']['webhook'])) {
|
|
$wh = $data['Notification']['webhook'];
|
|
$this->saveSetting('notify_wh_enabled', isset($wh['enabled']) && $wh['enabled'] ? '1' : '0');
|
|
$this->saveSetting('notify_wh_url', $wh['url'] ?? '');
|
|
$this->saveSetting('notify_wh_method', $wh['method'] ?? 'GET');
|
|
$this->saveSetting('notify_wh_request_type', $wh['request_type'] ?? 'JSON');
|
|
$this->saveSetting('notify_wh_headers', $wh['headers'] ?? '');
|
|
$this->saveSetting('notify_wh_body', $wh['body'] ?? '');
|
|
}
|
|
}
|
|
|
|
// 2. 账号增量同步
|
|
$newAccounts = $data['Accounts'] ?? [];
|
|
$stmt = $this->db->query("SELECT id, access_key_id, region_id, instance_id FROM accounts");
|
|
$existingMap = [];
|
|
while ($row = $stmt->fetch()) {
|
|
// Use composite key for deduplication: AK + Region + InstanceID
|
|
$compositeKey = $row['access_key_id'] . '|' . $row['region_id'] . '|' . ($row['instance_id'] ?? '');
|
|
$existingMap[$compositeKey] = $row['id'];
|
|
}
|
|
|
|
$keptIds = [];
|
|
$insertStmt = $this->db->prepare("INSERT INTO accounts (access_key_id, access_key_secret, region_id, instance_id, max_traffic, schedule_enabled, start_time, stop_time, remark, traffic_used, instance_status, updated_at, last_keep_alive_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 0, 'Unknown', 0, 0)");
|
|
$updateStmt = $this->db->prepare("UPDATE accounts SET access_key_secret = ?, region_id = ?, instance_id = ?, max_traffic = ?, schedule_enabled = ?, start_time = ?, stop_time = ?, remark = ? WHERE id = ?");
|
|
|
|
foreach ($newAccounts as $acc) {
|
|
$key = $acc['AccessKeyId'];
|
|
$region = $acc['regionId'];
|
|
$instance = $acc['instanceId'] ?? '';
|
|
$compositeKey = $key . '|' . $region . '|' . $instance;
|
|
|
|
$params = [
|
|
$acc['AccessKeySecret'],
|
|
$region,
|
|
$instance,
|
|
$acc['maxTraffic'],
|
|
($acc['schedule']['enabled'] ?? false) ? 1 : 0,
|
|
$acc['schedule']['startTime'] ?? '',
|
|
$acc['schedule']['stopTime'] ?? '',
|
|
$acc['remark'] ?? ''
|
|
];
|
|
|
|
if (isset($existingMap[$compositeKey])) {
|
|
$id = $existingMap[$compositeKey];
|
|
$params[] = $id;
|
|
$updateStmt->execute($params);
|
|
$keptIds[] = $id;
|
|
} else {
|
|
$insertParams = [$key];
|
|
array_push($insertParams, ...$params);
|
|
$insertStmt->execute($insertParams);
|
|
// For new inserts, we need to track the ID to avoid deleting it if user sends duplicate valid entries in one request?
|
|
// But assume frontend sends unique list. If not, this logic might add duplicates.
|
|
// Ideally we should track inserted IDs too but here we just rely on existingMap keys.
|
|
// Actually, if we just inserted, we can't easily get the ID back without lastInsertId but we don't strictly need it for the delete logic below if we assume input list is unique.
|
|
// However, to be safe against deleting effectively "new" accounts just added, let's just trust input list defines the "desired state".
|
|
// Wait, $idsToDelete is calculated from existingMap vs keptIds. If it's a new insert, it wasn't in existingMap, so it won't be in idsToDelete anyway.
|
|
}
|
|
}
|
|
|
|
// 3. 删除移除的账号
|
|
$idsToDelete = array_diff(array_values($existingMap), $keptIds);
|
|
if (!empty($idsToDelete)) {
|
|
$placeholders = implode(',', array_fill(0, count($idsToDelete), '?'));
|
|
$deleteStmt = $this->db->prepare("DELETE FROM accounts WHERE id IN ($placeholders)");
|
|
$deleteStmt->execute(array_values($idsToDelete));
|
|
}
|
|
|
|
$this->db->commit();
|
|
|
|
// 4. 重排 ID
|
|
$this->reorderIds();
|
|
|
|
// 5. 刷新缓存
|
|
$this->load();
|
|
return true;
|
|
} catch (Exception $e) {
|
|
if ($this->db->inTransaction())
|
|
$this->db->rollBack();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private function reorderIds()
|
|
{
|
|
try {
|
|
$this->db->beginTransaction();
|
|
$stmt = $this->db->query("SELECT * FROM accounts ORDER BY id ASC");
|
|
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
if (!empty($rows)) {
|
|
$this->db->exec("DELETE FROM accounts");
|
|
$this->db->exec("DELETE FROM sqlite_sequence WHERE name='accounts'");
|
|
|
|
$insertStmt = $this->db->prepare("INSERT INTO accounts (id, access_key_id, access_key_secret, region_id, instance_id, max_traffic, schedule_enabled, start_time, stop_time, remark, traffic_used, instance_status, updated_at, last_keep_alive_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
|
|
|
$newId = 1;
|
|
foreach ($rows as $row) {
|
|
$insertStmt->execute([
|
|
$newId++,
|
|
$row['access_key_id'],
|
|
$row['access_key_secret'],
|
|
$row['region_id'],
|
|
$row['instance_id'],
|
|
$row['max_traffic'],
|
|
$row['schedule_enabled'],
|
|
$row['start_time'],
|
|
$row['stop_time'],
|
|
$row['remark'] ?? '',
|
|
$row['traffic_used'],
|
|
$row['instance_status'],
|
|
$row['updated_at'],
|
|
$row['last_keep_alive_at']
|
|
]);
|
|
}
|
|
}
|
|
$this->db->commit();
|
|
} catch (Exception $e) {
|
|
if ($this->db->inTransaction())
|
|
$this->db->rollBack();
|
|
}
|
|
}
|
|
|
|
public function updateAccountStatus($id, $traffic, $status, $updatedAt)
|
|
{
|
|
$stmt = $this->db->prepare("UPDATE accounts SET traffic_used = ?, instance_status = ?, updated_at = ? WHERE id = ?");
|
|
return $stmt->execute([$traffic, $status, $updatedAt, $id]);
|
|
}
|
|
|
|
public function updateLastKeepAlive($id, $time)
|
|
{
|
|
$stmt = $this->db->prepare("UPDATE accounts SET last_keep_alive_at = ? WHERE id = ?");
|
|
return $stmt->execute([$time, $id]);
|
|
}
|
|
} |