package main import ( "database/sql" "encoding/json" "fmt" "log" "net/http" "os" "path/filepath" _ "github.com/mattn/go-sqlite3" "gopkg.in/yaml.v2" ) type Config struct { Server struct { Port string `yaml:"port"` } `yaml:"server"` Database struct { Path string `yaml:"path"` } `yaml:"database"` } type Site struct { ID int `json:"id"` Name string `json:"name"` URL string `json:"url"` Icon string `json:"icon,omitempty"` Category string `json:"category"` } var db *sql.DB func main() { // 加载配置 config, err := loadConfig("config/config.yaml") if err != nil { log.Fatalf("Error loading config: %v", err) } // 初始化数据库 err = initDB(config.Database.Path) if err != nil { log.Fatal(err) } defer db.Close() // 设置路由 http.HandleFunc("/api/sites", sitesHandler) http.HandleFunc("/api/add", addSiteHandler) http.HandleFunc("/api/delete", deleteSiteHandler) // 静态文件服务 fs := http.FileServer(http.Dir("../frontend")) http.Handle("/", fs) // 启动服务器 log.Printf("Starting server on :%s", config.Server.Port) log.Fatal(http.ListenAndServe(":"+config.Server.Port, nil)) } func loadConfig(path string) (*Config, error) { config := &Config{} file, err := os.Open(path) if err != nil { return nil, err } defer file.Close() d := yaml.NewDecoder(file) if err := d.Decode(&config); err != nil { return nil, err } return config, nil } func initDB(dbPath string) error { var err error // 确保数据库目录存在 os.MkdirAll(filepath.Dir(dbPath), 0755) db, err = sql.Open("sqlite3", dbPath) if err != nil { return err } // 创建表 _, err = db.Exec(`CREATE TABLE IF NOT EXISTS sites ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, url TEXT NOT NULL, icon TEXT, category TEXT NOT NULL )`) return err } func sitesHandler(w http.ResponseWriter, r *http.Request) { switch r.Method { case "GET": getSites(w, r) default: http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) } } func getSites(w http.ResponseWriter, r *http.Request) { rows, err := db.Query("SELECT id, name, url, icon, category FROM sites") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } defer rows.Close() var sites []Site for rows.Next() { var s Site if err := rows.Scan(&s.ID, &s.Name, &s.URL, &s.Icon, &s.Category); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } sites = append(sites, s) } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(sites) } func addSiteHandler(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } var s Site if err := json.NewDecoder(r.Body).Decode(&s); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } // 验证数据 if s.Name == "" || s.URL == "" || s.Category == "" { http.Error(w, "Name, URL and Category are required", http.StatusBadRequest) return } // 插入数据库 res, err := db.Exec("INSERT INTO sites (name, url, icon, category) VALUES (?, ?, ?, ?)", s.Name, s.URL, s.Icon, s.Category) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } id, _ := res.LastInsertId() s.ID = int(id) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(s) } func deleteSiteHandler(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } var request struct { ID int `json:"id"` } if err := json.NewDecoder(r.Body).Decode(&request); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } _, err := db.Exec("DELETE FROM sites WHERE id = ?", request.ID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) fmt.Fprint(w, `{"status": "success"}`) }