package main import ( "encoding/json" "fmt" "net/http" "os" "slices" "time" "github.com/caarlos0/env/v11" "github.com/gin-gonic/gin" ) func ping(c *gin.Context) { c.String(http.StatusOK, "Pong!") } func authMiddleware(appConfig *AppConfig) gin.HandlerFunc { return func(ctx *gin.Context) { if appConfig.Secret != "" { if ctx.Request.Header.Get("PQM_AUTH") != appConfig.Secret { ctx.Abort() ctx.String(http.StatusForbidden, "拜拜") return } } ctx.Next() } } type AppConfig struct { Secret string `env:"PQM_SECRET"` DataPath string `env:"PQM_DATA_PATH" envDefault:"data.json"` } type PMemo struct { Content string `json:"content"` CreatedDate time.Time `json:"created_date"` } type PMemoFilter struct { Till time.Time `json:"till"` } type AppData struct { Memos []PMemo `json:"memos"` } func SaveData(appConfig *AppConfig, data *AppData) error { dat, err := json.Marshal(data) if err != nil { return err } err = os.WriteFile(appConfig.DataPath, dat, os.FileMode(0o666)) if err != nil { return err } return nil } func LoadData(appConfig *AppConfig) AppData { var appData AppData dat, err := os.ReadFile(appConfig.DataPath) if err != nil { appData = AppData{Memos: []PMemo{}} SaveData(appConfig, &appData) return appData } err = json.Unmarshal(dat, &appData) if err != nil { appData = AppData{Memos: []PMemo{}} } return appData } func main() { var config AppConfig err := env.Parse(&config) if err != nil { fmt.Println("读取环境变量出错啦!") panic(err) } appData := LoadData(&config) r := gin.Default() r.Use(authMiddleware(&config)) r.GET("/", func(ctx *gin.Context) { ping(ctx) }) r.GET("/all", func(ctx *gin.Context) { ctx.AsciiJSON(http.StatusOK, appData) }) r.PUT("/create", func(ctx *gin.Context) { var content string if err := ctx.BindPlain(&content); err != nil { ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } memo := PMemo{ Content: content, CreatedDate: time.Now(), } appData.Memos = append(appData.Memos, memo) if err := SaveData(&config, &appData); err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } ctx.JSON(http.StatusOK, gin.H{"error": "ok", "data": memo}) }) r.DELETE("/all", func(ctx *gin.Context) { appData.Memos = []PMemo{} if err := SaveData(&config, &appData); err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } ctx.JSON(http.StatusOK, gin.H{"error": "ok"}) }) r.POST("/filtered", func(ctx *gin.Context) { var filter PMemoFilter if err := ctx.BindJSON(&filter); err != nil { ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } memos := slices.Collect(func(yield func(PMemo) bool) { for _, memo := range appData.Memos { if filter.Till.After(memo.CreatedDate) { if !yield(memo) { return } } } }) ctx.JSON(http.StatusOK, gin.H{"error": "ok", "data": gin.H{"memos": memos}}) }) r.DELETE("/filtered", func(ctx *gin.Context) { var filter PMemoFilter if err := ctx.BindJSON(&filter); err != nil { ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } appData.Memos = slices.Collect(func(yield func(PMemo) bool) { for _, memo := range appData.Memos { if !filter.Till.After(memo.CreatedDate) { if !yield(memo) { return } } } }) if err := SaveData(&config, &appData); err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } ctx.JSON(http.StatusOK, gin.H{"error": "ok", "data": appData}) }) r.Run() }