db.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. package database
  2. import (
  3. "database/sql"
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. "time"
  8. _ "modernc.org/sqlite"
  9. )
  10. // DB 数据库实例
  11. type DB struct {
  12. *sql.DB
  13. }
  14. // FTPUser FTP用户
  15. type FTPUser struct {
  16. ID int64 `json:"id"`
  17. Username string `json:"username"`
  18. Password string `json:"password,omitempty"`
  19. HomeDir string `json:"home_dir"`
  20. Permissions string `json:"permissions"` // "read", "write", "read,write", "admin"
  21. QuotaSize int64 `json:"quota_size"` // 字节, 0 = 无限制
  22. QuotaFiles int `json:"quota_files"` // 文件数, 0 = 无限制
  23. UploadRate int `json:"upload_rate"` // KB/s, 0 = 无限制
  24. DownloadRate int `json:"download_rate"` // KB/s, 0 = 无限制
  25. Enabled bool `json:"enabled"`
  26. CreatedAt string `json:"created_at"`
  27. UpdatedAt string `json:"updated_at"`
  28. }
  29. // FTPLog FTP操作日志
  30. type FTPLog struct {
  31. ID int64 `json:"id"`
  32. Username string `json:"username"`
  33. IP string `json:"ip"`
  34. Action string `json:"action"`
  35. FilePath string `json:"file_path"`
  36. FileSize int64 `json:"file_size"`
  37. Status string `json:"status"`
  38. CreatedAt string `json:"created_at"`
  39. }
  40. // OnlineUser 在线用户
  41. type OnlineUser struct {
  42. ID int `json:"id"`
  43. Username string `json:"username"`
  44. IP string `json:"ip"`
  45. LoginTime time.Time `json:"login_time"`
  46. LastActivity time.Time `json:"last_activity"`
  47. CurrentDir string `json:"current_dir"`
  48. }
  49. // IPAccessRule IP访问规则
  50. type IPAccessRule struct {
  51. ID int64 `json:"id"`
  52. IP string `json:"ip"` // 支持单IP (192.168.1.1)、CIDR (192.168.1.0/24)、IP范围 (192.168.1.1-192.168.1.100)
  53. Type string `json:"type"` // "whitelist" 或 "blacklist"
  54. Note string `json:"note"` // 备注说明
  55. Enabled bool `json:"enabled"`
  56. CreatedAt string `json:"created_at"`
  57. }
  58. // Open 打开数据库
  59. func Open(dbPath string) (*DB, error) {
  60. dir := filepath.Dir(dbPath)
  61. if err := os.MkdirAll(dir, 0755); err != nil {
  62. return nil, fmt.Errorf("创建数据库目录失败: %w", err)
  63. }
  64. db, err := sql.Open("sqlite", dbPath+"?_journal_mode=WAL&_busy_timeout=5000")
  65. if err != nil {
  66. return nil, fmt.Errorf("打开数据库失败: %w", err)
  67. }
  68. if err := db.Ping(); err != nil {
  69. return nil, fmt.Errorf("连接数据库失败: %w", err)
  70. }
  71. d := &DB{db}
  72. if err := d.initTables(); err != nil {
  73. return nil, err
  74. }
  75. return d, nil
  76. }
  77. // initTables 初始化数据表
  78. func (db *DB) initTables() error {
  79. schema := `
  80. CREATE TABLE IF NOT EXISTS ftp_users (
  81. id INTEGER PRIMARY KEY AUTOINCREMENT,
  82. username TEXT NOT NULL UNIQUE,
  83. password TEXT NOT NULL,
  84. home_dir TEXT NOT NULL,
  85. permissions TEXT DEFAULT 'read',
  86. quota_size INTEGER DEFAULT 0,
  87. quota_files INTEGER DEFAULT 0,
  88. upload_rate INTEGER DEFAULT 0,
  89. download_rate INTEGER DEFAULT 0,
  90. enabled INTEGER DEFAULT 1,
  91. created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
  92. updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
  93. );
  94. CREATE TABLE IF NOT EXISTS ftp_logs (
  95. id INTEGER PRIMARY KEY AUTOINCREMENT,
  96. username TEXT DEFAULT '',
  97. ip TEXT DEFAULT '',
  98. action TEXT NOT NULL,
  99. file_path TEXT DEFAULT '',
  100. file_size INTEGER DEFAULT 0,
  101. status TEXT DEFAULT 'success',
  102. created_at DATETIME DEFAULT CURRENT_TIMESTAMP
  103. );
  104. CREATE INDEX IF NOT EXISTS idx_logs_username ON ftp_logs(username);
  105. CREATE INDEX IF NOT EXISTS idx_logs_created ON ftp_logs(created_at);
  106. CREATE INDEX IF NOT EXISTS idx_logs_action ON ftp_logs(action);
  107. CREATE TABLE IF NOT EXISTS system_stats (
  108. id INTEGER PRIMARY KEY AUTOINCREMENT,
  109. total_uploads INTEGER DEFAULT 0,
  110. total_downloads INTEGER DEFAULT 0,
  111. total_upload_bytes INTEGER DEFAULT 0,
  112. total_download_bytes INTEGER DEFAULT 0,
  113. updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
  114. );
  115. CREATE TABLE IF NOT EXISTS ip_access_rules (
  116. id INTEGER PRIMARY KEY AUTOINCREMENT,
  117. ip TEXT NOT NULL,
  118. type TEXT NOT NULL DEFAULT 'blacklist',
  119. note TEXT DEFAULT '',
  120. enabled INTEGER DEFAULT 1,
  121. created_at DATETIME DEFAULT CURRENT_TIMESTAMP
  122. );
  123. CREATE INDEX IF NOT EXISTS idx_ip_rules_type ON ip_access_rules(type);
  124. CREATE INDEX IF NOT EXISTS idx_ip_rules_enabled ON ip_access_rules(enabled);
  125. `
  126. _, err := db.Exec(schema)
  127. return err
  128. }
  129. // --- FTP用户 CRUD ---
  130. // CreateUser 创建FTP用户
  131. func (db *DB) CreateUser(user *FTPUser) error {
  132. now := time.Now().Format("2006-01-02 15:04:05")
  133. result, err := db.Exec(`
  134. INSERT INTO ftp_users (username, password, home_dir, permissions, quota_size, quota_files,
  135. upload_rate, download_rate, enabled, created_at, updated_at)
  136. VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
  137. user.Username, user.Password, user.HomeDir, user.Permissions,
  138. user.QuotaSize, user.QuotaFiles, user.UploadRate, user.DownloadRate,
  139. user.Enabled, now, now)
  140. if err != nil {
  141. return fmt.Errorf("创建用户失败: %w", err)
  142. }
  143. user.ID, _ = result.LastInsertId()
  144. user.CreatedAt = now
  145. user.UpdatedAt = now
  146. return nil
  147. }
  148. // GetUser 获取用户
  149. func (db *DB) GetUser(username string) (*FTPUser, error) {
  150. user := &FTPUser{}
  151. var enabled int
  152. err := db.QueryRow(`
  153. SELECT id, username, password, home_dir, permissions, quota_size, quota_files,
  154. upload_rate, download_rate, enabled, created_at, updated_at
  155. FROM ftp_users WHERE username = ?`, username,
  156. ).Scan(&user.ID, &user.Username, &user.Password, &user.HomeDir, &user.Permissions,
  157. &user.QuotaSize, &user.QuotaFiles, &user.UploadRate, &user.DownloadRate,
  158. &enabled, &user.CreatedAt, &user.UpdatedAt)
  159. if err == sql.ErrNoRows {
  160. return nil, nil
  161. }
  162. if err != nil {
  163. return nil, err
  164. }
  165. user.Enabled = enabled == 1
  166. return user, nil
  167. }
  168. // ListUsers 列出所有用户
  169. func (db *DB) ListUsers() ([]FTPUser, error) {
  170. rows, err := db.Query(`
  171. SELECT id, username, password, home_dir, permissions, quota_size, quota_files,
  172. upload_rate, download_rate, enabled, created_at, updated_at
  173. FROM ftp_users ORDER BY id`)
  174. if err != nil {
  175. return nil, err
  176. }
  177. defer rows.Close()
  178. var users []FTPUser
  179. for rows.Next() {
  180. var user FTPUser
  181. var enabled int
  182. err := rows.Scan(&user.ID, &user.Username, &user.Password, &user.HomeDir, &user.Permissions,
  183. &user.QuotaSize, &user.QuotaFiles, &user.UploadRate, &user.DownloadRate,
  184. &enabled, &user.CreatedAt, &user.UpdatedAt)
  185. if err != nil {
  186. return nil, err
  187. }
  188. user.Enabled = enabled == 1
  189. users = append(users, user)
  190. }
  191. return users, nil
  192. }
  193. // UpdateUser 更新用户
  194. func (db *DB) UpdateUser(user *FTPUser) error {
  195. now := time.Now().Format("2006-01-02 15:04:05")
  196. _, err := db.Exec(`
  197. UPDATE ftp_users SET home_dir=?, permissions=?, quota_size=?, quota_files=?,
  198. upload_rate=?, download_rate=?, enabled=?, updated_at=?
  199. WHERE username=?`,
  200. user.HomeDir, user.Permissions, user.QuotaSize, user.QuotaFiles,
  201. user.UploadRate, user.DownloadRate, user.Enabled, now, user.Username)
  202. return err
  203. }
  204. // UpdateUserPassword 更新用户密码
  205. func (db *DB) UpdateUserPassword(username, password string) error {
  206. now := time.Now().Format("2006-01-02 15:04:05")
  207. _, err := db.Exec(`UPDATE ftp_users SET password=?, updated_at=? WHERE username=?`,
  208. password, now, username)
  209. return err
  210. }
  211. // DeleteUser 删除用户
  212. func (db *DB) DeleteUser(username string) error {
  213. _, err := db.Exec(`DELETE FROM ftp_users WHERE username=?`, username)
  214. return err
  215. }
  216. // --- 日志 ---
  217. // AddLog 添加操作日志
  218. func (db *DB) AddLog(log *FTPLog) error {
  219. now := time.Now().Format("2006-01-02 15:04:05")
  220. result, err := db.Exec(`
  221. INSERT INTO ftp_logs (username, ip, action, file_path, file_size, status, created_at)
  222. VALUES (?, ?, ?, ?, ?, ?, ?)`,
  223. log.Username, log.IP, log.Action, log.FilePath, log.FileSize, log.Status, now)
  224. if err != nil {
  225. return err
  226. }
  227. log.ID, _ = result.LastInsertId()
  228. log.CreatedAt = now
  229. return nil
  230. }
  231. // QueryLogs 查询日志
  232. func (db *DB) QueryLogs(username, action string, page, pageSize int) ([]FTPLog, int, error) {
  233. where := "WHERE 1=1"
  234. args := []interface{}{}
  235. if username != "" {
  236. where += " AND username LIKE ?"
  237. args = append(args, "%"+username+"%")
  238. }
  239. if action != "" {
  240. where += " AND action = ?"
  241. args = append(args, action)
  242. }
  243. // 获取总数
  244. var total int
  245. countSQL := fmt.Sprintf("SELECT COUNT(*) FROM ftp_logs %s", where)
  246. err := db.QueryRow(countSQL, args...).Scan(&total)
  247. if err != nil {
  248. return nil, 0, err
  249. }
  250. // 分页查询
  251. offset := (page - 1) * pageSize
  252. querySQL := fmt.Sprintf(`
  253. SELECT id, username, ip, action, file_path, file_size, status, created_at
  254. FROM ftp_logs %s ORDER BY id DESC LIMIT ? OFFSET ?`, where)
  255. queryArgs := append(args, pageSize, offset)
  256. rows, err := db.Query(querySQL, queryArgs...)
  257. if err != nil {
  258. return nil, 0, err
  259. }
  260. defer rows.Close()
  261. var logs []FTPLog
  262. for rows.Next() {
  263. var log FTPLog
  264. err := rows.Scan(&log.ID, &log.Username, &log.IP, &log.Action, &log.FilePath,
  265. &log.FileSize, &log.Status, &log.CreatedAt)
  266. if err != nil {
  267. return nil, 0, err
  268. }
  269. logs = append(logs, log)
  270. }
  271. return logs, total, nil
  272. }
  273. // GetLogStats 获取日志统计
  274. func (db *DB) GetLogStats() (map[string]interface{}, error) {
  275. stats := make(map[string]interface{})
  276. var totalUsers int
  277. db.QueryRow("SELECT COUNT(*) FROM ftp_users").Scan(&totalUsers)
  278. stats["total_users"] = totalUsers
  279. var enabledUsers int
  280. db.QueryRow("SELECT COUNT(*) FROM ftp_users WHERE enabled=1").Scan(&enabledUsers)
  281. stats["enabled_users"] = enabledUsers
  282. var todayLogins int
  283. db.QueryRow("SELECT COUNT(DISTINCT username) FROM ftp_logs WHERE action='login' AND created_at >= date('now')").Scan(&todayLogins)
  284. stats["today_logins"] = todayLogins
  285. var todayUploads int
  286. db.QueryRow("SELECT COUNT(*) FROM ftp_logs WHERE action='upload' AND created_at >= date('now')").Scan(&todayUploads)
  287. stats["today_uploads"] = todayUploads
  288. var todayDownloads int
  289. db.QueryRow("SELECT COUNT(*) FROM ftp_logs WHERE action='download' AND created_at >= date('now')").Scan(&todayDownloads)
  290. stats["today_downloads"] = todayDownloads
  291. var totalUploadBytes int64
  292. db.QueryRow("SELECT COALESCE(SUM(file_size),0) FROM ftp_logs WHERE action='upload'").Scan(&totalUploadBytes)
  293. stats["total_upload_bytes"] = totalUploadBytes
  294. var totalDownloadBytes int64
  295. db.QueryRow("SELECT COALESCE(SUM(file_size),0) FROM ftp_logs WHERE action='download'").Scan(&totalDownloadBytes)
  296. stats["total_download_bytes"] = totalDownloadBytes
  297. return stats, nil
  298. }
  299. // CleanOldLogs 清理旧日志(保留最近N天)
  300. func (db *DB) CleanOldLogs(days int) (int64, error) {
  301. result, err := db.Exec(`DELETE FROM ftp_logs WHERE created_at < datetime('now', ?||' days')`,
  302. fmt.Sprintf("-%d", days))
  303. if err != nil {
  304. return 0, err
  305. }
  306. return result.RowsAffected()
  307. }
  308. // --- IP访问规则 CRUD ---
  309. // CreateIPRule 创建IP规则
  310. func (db *DB) CreateIPRule(rule *IPAccessRule) error {
  311. now := time.Now().Format("2006-01-02 15:04:05")
  312. result, err := db.Exec(`
  313. INSERT INTO ip_access_rules (ip, type, note, enabled, created_at)
  314. VALUES (?, ?, ?, ?, ?)`,
  315. rule.IP, rule.Type, rule.Note, rule.Enabled, now)
  316. if err != nil {
  317. return fmt.Errorf("创建IP规则失败: %w", err)
  318. }
  319. rule.ID, _ = result.LastInsertId()
  320. rule.CreatedAt = now
  321. return nil
  322. }
  323. // ListIPRules 列出所有IP规则
  324. func (db *DB) ListIPRules(ruleType string) ([]IPAccessRule, error) {
  325. var rows *sql.Rows
  326. var err error
  327. if ruleType != "" {
  328. rows, err = db.Query(`SELECT id, ip, type, note, enabled, created_at
  329. FROM ip_access_rules WHERE type=? ORDER BY id`, ruleType)
  330. } else {
  331. rows, err = db.Query(`SELECT id, ip, type, note, enabled, created_at
  332. FROM ip_access_rules ORDER BY id`)
  333. }
  334. if err != nil {
  335. return nil, err
  336. }
  337. defer rows.Close()
  338. var rules []IPAccessRule
  339. for rows.Next() {
  340. var rule IPAccessRule
  341. var enabled int
  342. if err := rows.Scan(&rule.ID, &rule.IP, &rule.Type, &rule.Note, &enabled, &rule.CreatedAt); err != nil {
  343. return nil, err
  344. }
  345. rule.Enabled = enabled == 1
  346. rules = append(rules, rule)
  347. }
  348. return rules, nil
  349. }
  350. // DeleteIPRule 删除IP规则
  351. func (db *DB) DeleteIPRule(id int64) error {
  352. _, err := db.Exec(`DELETE FROM ip_access_rules WHERE id=?`, id)
  353. return err
  354. }
  355. // UpdateIPRule 更新IP规则
  356. func (db *DB) UpdateIPRule(rule *IPAccessRule) error {
  357. _, err := db.Exec(`UPDATE ip_access_rules SET ip=?, type=?, note=?, enabled=? WHERE id=?`,
  358. rule.IP, rule.Type, rule.Note, rule.Enabled, rule.ID)
  359. return err
  360. }
  361. // GetEnabledIPRules 获取所有启用的IP规则
  362. func (db *DB) GetEnabledIPRules() ([]IPAccessRule, error) {
  363. rows, err := db.Query(`SELECT id, ip, type, note, enabled, created_at
  364. FROM ip_access_rules WHERE enabled=1 ORDER BY id`)
  365. if err != nil {
  366. return nil, err
  367. }
  368. defer rows.Close()
  369. var rules []IPAccessRule
  370. for rows.Next() {
  371. var rule IPAccessRule
  372. var enabled int
  373. if err := rows.Scan(&rule.ID, &rule.IP, &rule.Type, &rule.Note, &enabled, &rule.CreatedAt); err != nil {
  374. return nil, err
  375. }
  376. rule.Enabled = enabled == 1
  377. rules = append(rules, rule)
  378. }
  379. return rules, nil
  380. }