diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6004d56..7f07d5f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,7 +33,7 @@ jobs: uses: docker/build-push-action@v3 with: context: . - file: ./build/package/eiblog.Dockerfile + file: ./build/package/eiblog/Dockerfile platforms: linux/amd64,linux/arm64,linux/arm/v7 push: true tags: | @@ -44,7 +44,7 @@ jobs: uses: docker/build-push-action@v3 with: context: . - file: ./build/package/backup.Dockerfile + file: ./build/package/backup/Dockerfile platforms: linux/amd64,linux/arm64,linux/arm/v7 push: true tags: | diff --git a/.gitignore b/.gitignore index f8c5a88..7d66ea0 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,6 @@ *.DS_Store *.tar.gz *.db -backend # Test binary, built with `go test -c` *.test @@ -18,5 +17,7 @@ backend # Dependency directories (remove the comment below to include it) # vendor/ bin -assets/*.* +assets/*.xml +assets/*.txt db.sqlite +cmd/*/backend \ No newline at end of file diff --git a/Makefile b/Makefile index 3b47979..a8da9a2 100644 --- a/Makefile +++ b/Makefile @@ -22,10 +22,6 @@ backup: dist: @scripts/dist_tar.sh $(tag) -# clean -clean: - @rm -rf bin && rm -f *.tar.gz && rm -f backend - # protoc protoc: @cd pkg/proto && make protoc diff --git a/build/package/backup.Dockerfile b/build/package/backup/Dockerfile similarity index 100% rename from build/package/backup.Dockerfile rename to build/package/backup/Dockerfile diff --git a/build/package/eiblog.Dockerfile b/build/package/eiblog/Dockerfile similarity index 100% rename from build/package/eiblog.Dockerfile rename to build/package/eiblog/Dockerfile diff --git a/cmd/backup/config/config.go b/cmd/backup/config/config.go new file mode 100644 index 0000000..cdfcef5 --- /dev/null +++ b/cmd/backup/config/config.go @@ -0,0 +1,67 @@ +package config + +import ( + "os" + "path/filepath" + "strings" + + "github.com/eiblog/eiblog/pkg/config" + + "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" +) + +// Config config +type Config struct { + config.APIMode + + Database config.Database // 数据库配置 + BackupTo string // 备份到, default: qiniu + Interval string // 备份周期, default: 7d + Validity int // 备份保留时间, default: 60 + Qiniu config.Qiniu // 七牛OSS配置 +} + +// Conf 配置 +var Conf Config + +// load config file +func init() { + // run mode + mode := config.RunMode(os.Getenv("RUN_MODE")) + if !mode.IsRunMode() { + panic("config: unsupported env RUN_MODE" + mode) + } + logrus.Infof("Run mode:%s", mode) + + // 加载配置文件 + dir, err := config.WalkWorkDir() + if err != nil { + panic(err) + } + + path := filepath.Join(dir, "etc", "app.yml") + data, err := os.ReadFile(path) + if err != nil { + panic(err) + } + err = yaml.Unmarshal(data, &Conf) + if err != nil { + panic(err) + } + Conf.RunMode = mode + + // read env + readDatabaseEnv() +} + +func readDatabaseEnv() { + key := strings.ToUpper(Conf.Name) + "_DB_DRIVER" + if d := os.Getenv(key); d != "" { + Conf.Database.Driver = d + } + key = strings.ToUpper(Conf.Name) + "_DB_SOURCE" + if s := os.Getenv(key); s != "" { + Conf.Database.Source = s + } +} diff --git a/cmd/backup/docs/docs.go b/cmd/backup/docs/docs.go new file mode 100644 index 0000000..fd6361b --- /dev/null +++ b/cmd/backup/docs/docs.go @@ -0,0 +1,60 @@ +// Package docs Code generated by swaggo/swag. DO NOT EDIT +package docs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/ping": { + "get": { + "description": "ping", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ping" + ], + "summary": "ping", + "responses": { + "200": { + "description": "it's ok", + "schema": { + "type": "string" + } + } + } + } + } + } +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "1.0", + Host: "", + BasePath: "", + Schemes: []string{}, + Title: "backup API", + Description: "This is a backup server.", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/cmd/backup/docs/swagger.json b/cmd/backup/docs/swagger.json new file mode 100644 index 0000000..473c233 --- /dev/null +++ b/cmd/backup/docs/swagger.json @@ -0,0 +1,34 @@ +{ + "swagger": "2.0", + "info": { + "description": "This is a backup server.", + "title": "backup API", + "contact": {}, + "version": "1.0" + }, + "paths": { + "/ping": { + "get": { + "description": "ping", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "ping" + ], + "summary": "ping", + "responses": { + "200": { + "description": "it's ok", + "schema": { + "type": "string" + } + } + } + } + } + } +} \ No newline at end of file diff --git a/cmd/backup/docs/swagger.yaml b/cmd/backup/docs/swagger.yaml new file mode 100644 index 0000000..d502eda --- /dev/null +++ b/cmd/backup/docs/swagger.yaml @@ -0,0 +1,22 @@ +info: + contact: {} + description: This is a backup server. + title: backup API + version: "1.0" +paths: + /ping: + get: + consumes: + - application/json + description: ping + produces: + - application/json + responses: + "200": + description: it's ok + schema: + type: string + summary: ping + tags: + - ping +swagger: "2.0" diff --git a/cmd/backup/etc/app.yml b/cmd/backup/etc/app.yml new file mode 100644 index 0000000..8a6a098 --- /dev/null +++ b/cmd/backup/etc/app.yml @@ -0,0 +1,14 @@ +apimode: + name: cmd-backup + listen: 0.0.0.0:9000 +database: # 数据库配置 + driver: sqlite + source: ./db.sqlite +backupto: qiniu # 备份到, default: qiniu +interval: 7d # 备份周期, default: 7d +validity: 60 # 备份保留时间, default: 60 +qiniu: # 七牛OSS + bucket: eiblog + domain: st.deepzz.com + accesskey: MB6AXl_Sj_mmFsL-Lt59Dml2Vmy2o8XMmiCbbSeC + secretkey: BIrMy0fsZ0_SHNceNXk3eDuo7WmVYzj2-zrmd5Tf diff --git a/cmd/backup/handler/internal/internal.go b/cmd/backup/handler/internal/internal.go new file mode 100644 index 0000000..6a74518 --- /dev/null +++ b/cmd/backup/handler/internal/internal.go @@ -0,0 +1,17 @@ +package internal + +import ( + "github.com/eiblog/eiblog/cmd/backup/config" + "github.com/eiblog/eiblog/pkg/third/qiniu" +) + +// QiniuClient 七牛客户端 +var QiniuClient *qiniu.QiniuClient + +func init() { + var err error + QiniuClient, err = qiniu.NewQiniuClient(config.Conf.Qiniu) + if err != nil { + panic(err) + } +} diff --git a/pkg/core/backup/ping/ping.go b/cmd/backup/handler/ping/ping.go similarity index 64% rename from pkg/core/backup/ping/ping.go rename to cmd/backup/handler/ping/ping.go index f35ca3c..7c637f4 100644 --- a/pkg/core/backup/ping/ping.go +++ b/cmd/backup/handler/ping/ping.go @@ -1,4 +1,3 @@ -// Package ping provides ... package ping import ( @@ -13,6 +12,13 @@ func RegisterRoutes(group gin.IRoutes) { } // handlePing ping +// @Summary ping +// @Description ping +// @Tags ping +// @Accept json +// @Produce json +// @Success 200 {string} string "it's ok" +// @Router /ping [get] func handlePing(c *gin.Context) { c.String(http.StatusOK, "it's ok") } diff --git a/pkg/core/eiblog/swag/swag.go b/cmd/backup/handler/swag/swag.go similarity index 76% rename from pkg/core/eiblog/swag/swag.go rename to cmd/backup/handler/swag/swag.go index 4c3a516..3c63870 100644 --- a/pkg/core/eiblog/swag/swag.go +++ b/cmd/backup/handler/swag/swag.go @@ -1,8 +1,7 @@ -// Package swag provides ... package swag import ( - _ "github.com/eiblog/eiblog/pkg/core/eiblog/docs" // docs + _ "github.com/eiblog/eiblog/cmd/eiblog/docs" // docs "github.com/gin-gonic/gin" swaggerFiles "github.com/swaggo/files" diff --git a/pkg/core/backup/timer/qiniu/qiniu.go b/cmd/backup/handler/timer/qiniu/qiniu.go similarity index 70% rename from pkg/core/backup/timer/qiniu/qiniu.go rename to cmd/backup/handler/timer/qiniu/qiniu.go index f2b8e65..39d9ba7 100644 --- a/pkg/core/backup/timer/qiniu/qiniu.go +++ b/cmd/backup/handler/timer/qiniu/qiniu.go @@ -1,4 +1,3 @@ -// Package qiniu provides ... package qiniu import ( @@ -11,16 +10,17 @@ import ( "path/filepath" "time" - "github.com/eiblog/eiblog/pkg/cache/store" - "github.com/eiblog/eiblog/pkg/config" - "github.com/eiblog/eiblog/pkg/internal" + "github.com/eiblog/eiblog/cmd/backup/config" + "github.com/eiblog/eiblog/cmd/backup/handler/internal" + "github.com/eiblog/eiblog/pkg/connector/db" + "github.com/eiblog/eiblog/pkg/third/qiniu" ) -// Storage qiniu storage -type Storage struct{} +// BackupRestorer qiniu backup restorer +type BackupRestorer struct{} -// BackupData implements timer.Storage -func (s Storage) BackupData(now time.Time) error { +// Backup implements timer.BackupRestorer +func (s BackupRestorer) Backup(now time.Time) error { switch config.Conf.Database.Driver { case "mongodb": return backupFromMongoDB(now) @@ -30,8 +30,8 @@ func (s Storage) BackupData(now time.Time) error { } } -// RestoreData implements timer.Storage -func (s Storage) RestoreData() error { +// Restore implements timer.BackupRestorer +func (s BackupRestorer) Restore() error { switch config.Conf.Database.Driver { case "mongodb": return restoreToMongoDB() @@ -74,37 +74,31 @@ func backupFromMongoDB(now time.Time) error { if err != nil { return err } - uploadParams := internal.UploadParams{ + uploadParams := qiniu.UploadParams{ Name: filepath.Join("blog", name), // blog/eiblog-xx.tar.gz Size: s.Size(), Data: f, NoCompletePath: true, - - Conf: config.Conf.BackupApp.Qiniu, } - _, err = internal.QiniuUpload(uploadParams) + _, err = internal.QiniuClient.Upload(uploadParams) if err != nil { return err } // after days delete - deleteParams := internal.DeleteParams{ + deleteParams := qiniu.DeleteParams{ Name: filepath.Join("blog", name), // blog/eiblog-xx.tar.gz - Days: config.Conf.BackupApp.Validity, + Days: config.Conf.Validity, NoCompletePath: true, - - Conf: config.Conf.BackupApp.Qiniu, } - return internal.QiniuDelete(deleteParams) + return internal.QiniuClient.Delete(deleteParams) } func restoreToMongoDB() error { // backup file - params := internal.ContentParams{ + params := qiniu.ContentParams{ Prefix: "blog/", - - Conf: config.Conf.BackupApp.Qiniu, } - raw, err := internal.QiniuContent(params) + raw, err := internal.QiniuClient.Content(params) if err != nil { return err } @@ -118,17 +112,16 @@ func restoreToMongoDB() error { ctx, cancel := context.WithTimeout(context.Background(), time.Minute*20) defer cancel() // drop database - store, err := store.NewStore(config.Conf.Database.Driver, - config.Conf.Database.Source) + mdb, err := db.NewMDB(config.Conf.Database) if err != nil { return err } - err = store.DropDatabase(ctx) + err = mdb.Drop(ctx) if err != nil { return err } // unarchive - arg := fmt.Sprintf("tar xzf /tmp/eiblog.tar.gz -C /tmp") + arg := "tar xzf /tmp/eiblog.tar.gz -C /tmp" cmd := exec.CommandContext(ctx, "sh", "-c", arg) err = cmd.Run() if err != nil { diff --git a/pkg/core/backup/timer/timer.go b/cmd/backup/handler/timer/timer.go similarity index 60% rename from pkg/core/backup/timer/timer.go rename to cmd/backup/handler/timer/timer.go index d3a434b..56dd401 100644 --- a/pkg/core/backup/timer/timer.go +++ b/cmd/backup/handler/timer/timer.go @@ -1,4 +1,3 @@ -// Package timer provides ... package timer import ( @@ -6,41 +5,48 @@ import ( "strconv" "time" - "github.com/eiblog/eiblog/pkg/config" - "github.com/eiblog/eiblog/pkg/core/backup/timer/qiniu" + "github.com/eiblog/eiblog/cmd/backup/config" + "github.com/eiblog/eiblog/cmd/backup/handler/timer/qiniu" "github.com/sirupsen/logrus" ) +// BackupRestorer 备份恢复器 +type BackupRestorer interface { + Backup(now time.Time) error + Restore() error +} + // Start to backup with ticker func Start(restore bool) (err error) { - var storage Storage + var storage BackupRestorer + // backup instance - switch config.Conf.BackupApp.BackupTo { + switch config.Conf.BackupTo { case "qiniu": - storage = qiniu.Storage{} + storage = qiniu.BackupRestorer{} default: return errors.New("timer: unknown backup to driver: " + - config.Conf.BackupApp.BackupTo) + config.Conf.BackupTo) } if restore { - err = storage.RestoreData() + err = storage.Restore() if err != nil { return err } - logrus.Info("timer: RestoreData success") + logrus.Info("timer: Restore success") } // parse duration - interval, err := ParseDuration(config.Conf.BackupApp.Interval) + interval, err := ParseDuration(config.Conf.Interval) if err != nil { return err } t := time.NewTicker(interval) for now := range t.C { - err = storage.BackupData(now) + err = storage.Backup(now) if err != nil { - logrus.Error("timer: Start.BackupData: ", now.Format(time.RFC3339), err) + logrus.Error("timer: Start.Backup: ", now.Format(time.RFC3339), err) } } return nil @@ -63,12 +69,5 @@ func ParseDuration(d string) (time.Duration, error) { } return time.Duration(di) * time.Hour * 24, nil } - return 0, errors.New("timer: unsupported duration:" + d) } - -// Storage backup backend -type Storage interface { - BackupData(now time.Time) error - RestoreData() error -} diff --git a/cmd/backup/main.go b/cmd/backup/main.go index 055ccf3..a462cc9 100644 --- a/cmd/backup/main.go +++ b/cmd/backup/main.go @@ -3,16 +3,20 @@ package main import ( "flag" - "fmt" - "github.com/eiblog/eiblog/pkg/config" - "github.com/eiblog/eiblog/pkg/core/backup/ping" - "github.com/eiblog/eiblog/pkg/core/backup/swag" - "github.com/eiblog/eiblog/pkg/core/backup/timer" + "github.com/eiblog/eiblog/cmd/backup/config" + "github.com/eiblog/eiblog/cmd/backup/handler/ping" + "github.com/eiblog/eiblog/cmd/backup/handler/swag" + "github.com/eiblog/eiblog/cmd/backup/handler/timer" "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" ) +// @title backup API +// @version 1.0 +// @description This is a backup server. + var restore bool func init() { @@ -20,15 +24,15 @@ func init() { } func main() { - fmt.Println("Hi, it's App " + config.Conf.BackupApp.Name) - flag.Parse() + logrus.Info("Hi, it's App " + config.Conf.Name) + flag.Parse() endRun := make(chan error, 1) runCommand(restore, endRun) runHTTPServer(endRun) - fmt.Println(<-endRun) + logrus.Fatal(<-endRun) } func runCommand(restore bool, endRun chan error) { @@ -38,11 +42,7 @@ func runCommand(restore bool, endRun chan error) { } func runHTTPServer(endRun chan error) { - if !config.Conf.BackupApp.EnableHTTP { - return - } - - if config.Conf.RunMode == config.ModeProd { + if config.Conf.RunMode.IsReleaseMode() { gin.SetMode(gin.ReleaseMode) } e := gin.Default() @@ -54,9 +54,8 @@ func runHTTPServer(endRun chan error) { ping.RegisterRoutes(e) // start - address := fmt.Sprintf(":%d", config.Conf.BackupApp.HTTPPort) go func() { - endRun <- e.Run(address) + endRun <- e.Run(config.Conf.Listen) }() - fmt.Println("HTTP server running on: " + address) + logrus.Info("HTTP server running on: " + config.Conf.Listen) } diff --git a/cmd/eiblog/config/config.go b/cmd/eiblog/config/config.go new file mode 100644 index 0000000..ed31f76 --- /dev/null +++ b/cmd/eiblog/config/config.go @@ -0,0 +1,82 @@ +package config + +import ( + "os" + "path/filepath" + "strings" + + "github.com/eiblog/eiblog/pkg/config" + + "github.com/sirupsen/logrus" + "gopkg.in/yaml.v3" +) + +var ( + // Conf 配置 + Conf Config + // WorkDir 工作目录 + WorkDir string +) + +// Config config +type Config struct { + config.APIMode + // 静态资源版本, 每次更改了 js/css 都需要提高该值 + StaticVersion int + // 数据库配置 + Database config.Database + // 热词, 手动指定, 用于搜索 + HotWords []string + // Elasticsearch 配置 + ESHost string + + General config.General + Disqus config.Disqus + Google config.Google + Qiniu config.Qiniu + Twitter config.Twitter + FeedRPC config.FeedRPC + Account config.Account +} + +// init 初始化配置 +func init() { + // run mode + mode := config.RunMode(os.Getenv("RUN_MODE")) + if !mode.IsRunMode() { + panic("config: unsupported env RUN_MODE" + mode) + } + logrus.Infof("Run mode:%s", mode) + + // 加载配置文件 + var err error + WorkDir, err = config.WalkWorkDir() + if err != nil { + panic(err) + } + + path := filepath.Join(WorkDir, "etc", "app.yml") + data, err := os.ReadFile(path) + if err != nil { + panic(err) + } + err = yaml.Unmarshal(data, &Conf) + if err != nil { + panic(err) + } + Conf.RunMode = mode + + // 读取环境变量配置 + readDatabaseEnv() +} + +func readDatabaseEnv() { + key := strings.ToUpper(Conf.Name) + "_DB_DRIVER" + if d := os.Getenv(key); d != "" { + Conf.Database.Driver = d + } + key = strings.ToUpper(Conf.Name) + "_DB_SOURCE" + if s := os.Getenv(key); s != "" { + Conf.Database.Source = s + } +} diff --git a/cmd/eiblog/docs/docs.go b/cmd/eiblog/docs/docs.go new file mode 100644 index 0000000..6676994 --- /dev/null +++ b/cmd/eiblog/docs/docs.go @@ -0,0 +1,36 @@ +// Package docs Code generated by swaggo/swag. DO NOT EDIT +package docs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": {} +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "", + Host: "", + BasePath: "", + Schemes: []string{}, + Title: "", + Description: "", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/cmd/eiblog/docs/swagger.json b/cmd/eiblog/docs/swagger.json new file mode 100644 index 0000000..ec416cd --- /dev/null +++ b/cmd/eiblog/docs/swagger.json @@ -0,0 +1,7 @@ +{ + "swagger": "2.0", + "info": { + "contact": {} + }, + "paths": {} +} \ No newline at end of file diff --git a/cmd/eiblog/docs/swagger.yaml b/cmd/eiblog/docs/swagger.yaml new file mode 100644 index 0000000..b64379c --- /dev/null +++ b/cmd/eiblog/docs/swagger.yaml @@ -0,0 +1,4 @@ +info: + contact: {} +paths: {} +swagger: "2.0" diff --git a/cmd/eiblog/etc/app.yml b/cmd/eiblog/etc/app.yml new file mode 100644 index 0000000..2bd7ae6 --- /dev/null +++ b/cmd/eiblog/etc/app.yml @@ -0,0 +1,49 @@ +apimode: + name: cmd-eiblog + listen: 0.0.0.0:9000 + host: example.com +database: # 数据库配置 + driver: sqlite + source: ./db.sqlite +hotwords: # 热搜词 + - docker + - mongodb + - curl + - dns +staticversion: 1 +eshost: # http://elasticsearch:9200 +general: # 常规配置 + pagenum: 10 # 首页展示文章数量 + pagesize: 20 # 管理界面 + descprefix: "Desc:" # 文章描述前缀 + identifier: # 截取预览标识 + length: 400 # 自动截取预览, 字符数 + timezone: Asia/Shanghai # 时区 +disqus: # 评论相关 + shortname: xxxxxx + publickey: wdSgxRm9rdGAlLKFcFdToBe3GT4SibmV7Y8EjJQ0r4GWXeKtxpopMAeIeoI2dTEg + accesstoken: 50023908f39f4607957e909b495326af +google: # 谷歌分析 + url: https://www.google-analytics.com/g/collect + tid: G-xxxxxxxxxx + v: "2" + adsense: +qiniu: # 七牛OSS + bucket: eiblog + domain: st.deepzz.com + accesskey: MB6AXl_Sj_mmFsL-Lt59Dml2Vmy2o8XMmiCbbSeC + secretkey: BIrMy0fsZ0_SHNceNXk3eDuo7WmVYzj2-zrmd5Tf +twitter: # twitter card + card: summary + site: deepzz02 + image: st.deepzz.com/static/img/avatar.jpg + address: twitter.com/deepzz02 +feedrpc: # rss ping + feedrurl: https://deepzz.superfeedr.com/ + pingrpc: + - http://ping.baidu.com/ping/RPC2 + - http://rpc.pingomatic.com/ +# 数据初始化操作,可到博客后台修改 +account: + username: deepzz # *后台登录用户名 + password: deepzz # *登录明文密码 diff --git a/pkg/core/eiblog/admin/admin.go b/cmd/eiblog/handler/admin/admin.go similarity index 81% rename from pkg/core/eiblog/admin/admin.go rename to cmd/eiblog/handler/admin/admin.go index 4fda88f..76bb42e 100644 --- a/pkg/core/eiblog/admin/admin.go +++ b/cmd/eiblog/handler/admin/admin.go @@ -1,4 +1,3 @@ -// Package admin provides ... package admin import ( @@ -10,11 +9,10 @@ import ( "strings" "time" - "github.com/eiblog/eiblog/pkg/cache" - "github.com/eiblog/eiblog/pkg/config" - "github.com/eiblog/eiblog/pkg/core/eiblog" - "github.com/eiblog/eiblog/pkg/internal" + "github.com/eiblog/eiblog/cmd/eiblog/handler/internal" + "github.com/eiblog/eiblog/pkg/middleware" "github.com/eiblog/eiblog/pkg/model" + "github.com/eiblog/eiblog/pkg/third/qiniu" "github.com/eiblog/eiblog/tools" "github.com/gin-gonic/gin" @@ -60,20 +58,20 @@ func handleAcctLogin(c *gin.Context) { c.Redirect(http.StatusFound, "/admin/login") return } - if cache.Ei.Account.Username != user || - cache.Ei.Account.Password != tools.EncryptPasswd(user, pwd) { + if internal.Ei.Account.Username != user || + internal.Ei.Account.Password != tools.EncryptPasswd(user, pwd) { logrus.Warnf("账号或密码错误 %s, %s", user, pwd) c.Redirect(http.StatusFound, "/admin/login") return } // 登录成功 - eiblog.SetLogin(c, user) + middleware.SetLogin(c, user) - cache.Ei.Account.LoginIP = c.ClientIP() - cache.Ei.Account.LoginAt = time.Now() - cache.Ei.UpdateAccount(context.Background(), user, map[string]interface{}{ - "login_ip": cache.Ei.Account.LoginIP, - "login_at": cache.Ei.Account.LoginAt, + internal.Ei.Account.LoginIP = c.ClientIP() + internal.Ei.Account.LoginAt = time.Now() + internal.Ei.UpdateAccount(context.Background(), user, map[string]interface{}{ + "login_ip": internal.Ei.Account.LoginIP, + "login_at": internal.Ei.Account.LoginAt, }) c.Redirect(http.StatusFound, "/admin/profile") } @@ -91,7 +89,7 @@ func handleAPIBlogger(c *gin.Context) { return } - err := cache.Ei.UpdateBlogger(context.Background(), map[string]interface{}{ + err := internal.Ei.UpdateBlogger(context.Background(), map[string]interface{}{ "blog_name": bn, "b_title": bt, "bei_an": ba, @@ -104,14 +102,14 @@ func handleAPIBlogger(c *gin.Context) { responseNotice(c, NoticeNotice, err.Error(), "") return } - cache.Ei.Blogger.BlogName = bn - cache.Ei.Blogger.BTitle = bt - cache.Ei.Blogger.BeiAn = ba - cache.Ei.Blogger.SubTitle = st - cache.Ei.Blogger.SeriesSay = ss - cache.Ei.Blogger.ArchivesSay = as - cache.PagesCh <- cache.PageSeries - cache.PagesCh <- cache.PageArchive + internal.Ei.Blogger.BlogName = bn + internal.Ei.Blogger.BTitle = bt + internal.Ei.Blogger.BeiAn = ba + internal.Ei.Blogger.SubTitle = st + internal.Ei.Blogger.SeriesSay = ss + internal.Ei.Blogger.ArchivesSay = as + internal.PagesCh <- internal.PageSeries + internal.PagesCh <- internal.PageArchive responseNotice(c, NoticeSuccess, "更新成功", "") } @@ -126,7 +124,7 @@ func handleAPIAccount(c *gin.Context) { return } - err := cache.Ei.UpdateAccount(context.Background(), cache.Ei.Account.Username, + err := internal.Ei.UpdateAccount(context.Background(), internal.Ei.Account.Username, map[string]interface{}{ "email": e, "phone_n": pn, @@ -137,9 +135,9 @@ func handleAPIAccount(c *gin.Context) { responseNotice(c, NoticeNotice, err.Error(), "") return } - cache.Ei.Account.Email = e - cache.Ei.Account.PhoneN = pn - cache.Ei.Account.Address = ad + internal.Ei.Account.Email = e + internal.Ei.Account.PhoneN = pn + internal.Ei.Account.Address = ad responseNotice(c, NoticeSuccess, "更新成功", "") } @@ -156,13 +154,13 @@ func handleAPIPassword(c *gin.Context) { responseNotice(c, NoticeNotice, "密码格式错误", "") return } - if cache.Ei.Account.Password != tools.EncryptPasswd(cache.Ei.Account.Username, od) { + if internal.Ei.Account.Password != tools.EncryptPasswd(internal.Ei.Account.Username, od) { responseNotice(c, NoticeNotice, "原始密码不正确", "") return } - newPwd := tools.EncryptPasswd(cache.Ei.Account.Username, nw) + newPwd := tools.EncryptPasswd(internal.Ei.Account.Username, nw) - err := cache.Ei.UpdateAccount(context.Background(), cache.Ei.Account.Username, + err := internal.Ei.UpdateAccount(context.Background(), internal.Ei.Account.Username, map[string]interface{}{ "password": newPwd, }) @@ -171,7 +169,7 @@ func handleAPIPassword(c *gin.Context) { responseNotice(c, NoticeNotice, err.Error(), "") return } - cache.Ei.Account.Password = newPwd + internal.Ei.Account.Password = newPwd responseNotice(c, NoticeSuccess, "更新成功", "") } @@ -183,7 +181,7 @@ func handleDraftDelete(c *gin.Context) { responseNotice(c, NoticeNotice, "参数错误", "") return } - err = cache.Ei.RemoveArticle(context.Background(), id) + err = internal.Ei.RemoveArticle(context.Background(), id) if err != nil { logrus.Error("handleDraftDelete.RemoveArticle: ", err) responseNotice(c, NoticeNotice, "删除失败", "") @@ -198,11 +196,11 @@ func handleAPIPostDelete(c *gin.Context) { var ids []int for _, v := range c.PostFormArray("cid[]") { id, err := strconv.Atoi(v) - if err != nil || id < config.Conf.EiBlogApp.General.StartID { + if err != nil || id < internal.ArticleStartID { responseNotice(c, NoticeNotice, "参数错误", "") return } - err = cache.Ei.DelArticle(id) + err = internal.Ei.DelArticle(id) if err != nil { logrus.Error("handleAPIPostDelete.DelArticle: ", err) @@ -212,7 +210,7 @@ func handleAPIPostDelete(c *gin.Context) { ids = append(ids, id) } // elasticsearch - err := internal.ElasticDelIndex(ids) + err := internal.ESClient.ElasticDelIndex(ids) if err != nil { logrus.Error("handleAPIPostDelete.ElasticDelIndex: ", err) } @@ -271,7 +269,7 @@ func handleAPIPostCreate(c *gin.Context) { Content: text, Slug: slug, IsDraft: do != "publish", - Author: cache.Ei.Account.Username, + Author: internal.Ei.Account.Username, SerieID: serieid, Tags: tags, CreatedAt: date, @@ -279,7 +277,7 @@ func handleAPIPostCreate(c *gin.Context) { cid, err = strconv.Atoi(c.PostForm("cid")) // 新文章 if err != nil || cid < 1 { - err = cache.Ei.AddArticle(article) + err = internal.Ei.AddArticle(article) if err != nil { logrus.Error("handleAPIPostCreate.AddArticle: ", err) return @@ -289,20 +287,20 @@ func handleAPIPostCreate(c *gin.Context) { if !article.IsDraft { // disqus - internal.ThreadCreate(article, cache.Ei.Blogger.BTitle) + internal.DisqusClient.ThreadCreate(article, internal.Ei.Blogger.BTitle) // 异步执行,快 go func() { // elastic - internal.ElasticAddIndex(article) + internal.ESClient.ElasticAddIndex(article) // rss - internal.PingFunc(cache.Ei.Blogger.BTitle, slug) + internal.Pinger.PingFunc(internal.Ei.Blogger.BTitle, slug) }() } return } // 旧文章 article.ID = cid - artc, _ := cache.Ei.FindArticleByID(article.ID) // cache + artc, _ := internal.Ei.FindArticleByID(article.ID) // cache if artc != nil { article.IsDraft = false article.Count = artc.Count @@ -312,7 +310,7 @@ func handleAPIPostCreate(c *gin.Context) { article.UpdatedAt = time.Now() } // 数据库更新 - err = cache.Ei.UpdateArticle(context.Background(), article.ID, map[string]interface{}{ + err = internal.Ei.UpdateArticle(context.Background(), article.ID, map[string]interface{}{ "title": article.Title, "content": article.Content, "serie_id": article.SerieID, @@ -326,17 +324,17 @@ func handleAPIPostCreate(c *gin.Context) { return } if !article.IsDraft { - cache.Ei.RepArticle(artc, article) + internal.Ei.RepArticle(artc, article) // disqus if artc == nil { - internal.ThreadCreate(article, cache.Ei.Blogger.BTitle) + internal.DisqusClient.ThreadCreate(article, internal.Ei.Blogger.BTitle) } // 异步执行,快 go func() { // elastic - internal.ElasticAddIndex(article) + internal.ESClient.ElasticAddIndex(article) // rss - internal.PingFunc(cache.Ei.Blogger.BTitle, slug) + internal.Pinger.PingFunc(internal.Ei.Blogger.BTitle, slug) }() } } @@ -349,7 +347,7 @@ func handleAPISerieDelete(c *gin.Context) { responseNotice(c, NoticeNotice, err.Error(), "") return } - err = cache.Ei.DelSerie(id) + err = internal.Ei.DelSerie(id) if err != nil { responseNotice(c, NoticeNotice, err.Error(), "") return @@ -376,7 +374,7 @@ func handleAPISerieCreate(c *gin.Context) { mid, err := strconv.Atoi(c.PostForm("mid")) if err == nil && mid > 0 { var serie *model.Serie - for _, v := range cache.Ei.Series { + for _, v := range internal.Ei.Series { if v.ID == mid { serie = v break @@ -386,7 +384,7 @@ func handleAPISerieCreate(c *gin.Context) { responseNotice(c, NoticeNotice, "专题不存在", "") return } - err = cache.Ei.UpdateSerie(context.Background(), mid, map[string]interface{}{ + err = internal.Ei.UpdateSerie(context.Background(), mid, map[string]interface{}{ "slug": slug, "name": name, "desc": desc, @@ -399,9 +397,9 @@ func handleAPISerieCreate(c *gin.Context) { serie.Slug = slug serie.Name = name serie.Desc = desc - cache.PagesCh <- cache.PageSeries + internal.PagesCh <- internal.PageSeries } else { - err = cache.Ei.AddSerie(&model.Serie{ + err = internal.Ei.AddSerie(&model.Serie{ Slug: slug, Name: name, Desc: desc, @@ -424,7 +422,7 @@ func handleAPITrashDelete(c *gin.Context) { responseNotice(c, NoticeNotice, "参数错误", "") return } - err = cache.Ei.RemoveArticle(context.Background(), id) + err = internal.Ei.RemoveArticle(context.Background(), id) if err != nil { responseNotice(c, NoticeNotice, err.Error(), "") return @@ -442,7 +440,7 @@ func handleAPITrashRecover(c *gin.Context) { return } - err = cache.Ei.UpdateArticle(context.Background(), id, map[string]interface{}{ + err = internal.Ei.UpdateArticle(context.Background(), id, map[string]interface{}{ "deleted_at": time.Time{}, "is_draft": true, }) @@ -473,14 +471,12 @@ func handleAPIQiniuUpload(c *gin.Context) { } filename := strings.ToLower(header.Filename) - params := internal.UploadParams{ + params := qiniu.UploadParams{ Name: filename, Size: s.Size(), Data: file, - - Conf: config.Conf.EiBlogApp.Qiniu, } - url, err := internal.QiniuUpload(params) + url, err := internal.QiniuClient.Upload(params) if err != nil { logrus.Error("handleAPIQiniuUpload.QiniuUpload: ", err) c.String(http.StatusBadRequest, err.Error()) @@ -505,12 +501,10 @@ func handleAPIQiniuDelete(c *gin.Context) { return } - params := internal.DeleteParams{ + params := qiniu.DeleteParams{ Name: name, - - Conf: config.Conf.EiBlogApp.Qiniu, } - err := internal.QiniuDelete(params) + err := internal.QiniuClient.Delete(params) if err != nil { logrus.Error("handleAPIQiniuDelete.QiniuDelete: ", err) } diff --git a/pkg/core/eiblog/file/file.go b/cmd/eiblog/handler/file/file.go similarity index 97% rename from pkg/core/eiblog/file/file.go rename to cmd/eiblog/handler/file/file.go index da88ba0..0438daf 100644 --- a/pkg/core/eiblog/file/file.go +++ b/cmd/eiblog/handler/file/file.go @@ -1,4 +1,3 @@ -// Package file provides ... package file import ( diff --git a/pkg/core/eiblog/file/timer.go b/cmd/eiblog/handler/file/timer.go similarity index 84% rename from pkg/core/eiblog/file/timer.go rename to cmd/eiblog/handler/file/timer.go index 2617d68..14dd2e0 100644 --- a/pkg/core/eiblog/file/timer.go +++ b/cmd/eiblog/handler/file/timer.go @@ -1,4 +1,3 @@ -// Package file provides ... package file import ( @@ -7,8 +6,8 @@ import ( "text/template" "time" - "github.com/eiblog/eiblog/pkg/cache" - "github.com/eiblog/eiblog/pkg/config" + "github.com/eiblog/eiblog/cmd/eiblog/config" + "github.com/eiblog/eiblog/cmd/eiblog/handler/internal" "github.com/eiblog/eiblog/tools" "github.com/sirupsen/logrus" @@ -43,12 +42,12 @@ func timerFeed() { } now := time.Now() - _, _, articles := cache.Ei.PageArticleFE(1, 20) + _, _, articles := internal.Ei.PageArticleFE(1, 20) params := map[string]interface{}{ - "Title": cache.Ei.Blogger.BTitle, - "SubTitle": cache.Ei.Blogger.SubTitle, - "Host": config.Conf.EiBlogApp.Host, - "FeedrURL": config.Conf.EiBlogApp.FeedRPC.FeedrURL, + "Title": internal.Ei.Blogger.BTitle, + "SubTitle": internal.Ei.Blogger.SubTitle, + "Host": config.Conf.Host, + "FeedrURL": config.Conf.FeedRPC.FeedrURL, "BuildDate": now.Format(time.RFC1123Z), "Articles": articles, } @@ -75,8 +74,8 @@ func timerSitemap() { } params := map[string]interface{}{ - "Articles": cache.Ei.Articles, - "Host": config.Conf.EiBlogApp.Host, + "Articles": internal.Ei.Articles, + "Host": config.Conf.Host, } f, err := os.OpenFile("assets/sitemap.xml", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) if err != nil { @@ -100,9 +99,9 @@ func generateOpensearch() { return } params := map[string]string{ - "BTitle": cache.Ei.Blogger.BTitle, - "SubTitle": cache.Ei.Blogger.SubTitle, - "Host": config.Conf.EiBlogApp.Host, + "BTitle": internal.Ei.Blogger.BTitle, + "SubTitle": internal.Ei.Blogger.SubTitle, + "Host": config.Conf.Host, } f, err := os.OpenFile("assets/opensearch.xml", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) if err != nil { @@ -125,7 +124,7 @@ func generateRobots() { return } params := map[string]string{ - "Host": config.Conf.EiBlogApp.Host, + "Host": config.Conf.Host, } f, err := os.OpenFile("assets/robots.txt", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) if err != nil { @@ -148,7 +147,7 @@ func generateCrossdomain() { return } params := map[string]string{ - "Host": config.Conf.EiBlogApp.Host, + "Host": config.Conf.Host, } f, err := os.OpenFile("assets/crossdomain.xml", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) if err != nil { diff --git a/pkg/cache/cache.go b/cmd/eiblog/handler/internal/cache.go similarity index 93% rename from pkg/cache/cache.go rename to cmd/eiblog/handler/internal/cache.go index 5b49865..07f7328 100644 --- a/pkg/cache/cache.go +++ b/cmd/eiblog/handler/internal/cache.go @@ -1,5 +1,5 @@ -// Package cache provides ... -package cache +// Package internal provides ... +package internal import ( "bytes" @@ -11,10 +11,8 @@ import ( "sync" "time" - "github.com/eiblog/eiblog/pkg/cache/render" - "github.com/eiblog/eiblog/pkg/cache/store" - "github.com/eiblog/eiblog/pkg/config" - "github.com/eiblog/eiblog/pkg/internal" + "github.com/eiblog/eiblog/cmd/eiblog/config" + "github.com/eiblog/eiblog/cmd/eiblog/handler/internal/store" "github.com/eiblog/eiblog/pkg/model" "github.com/eiblog/eiblog/tools" @@ -42,7 +40,7 @@ func init() { // init timezone var err error tools.TimeLocation, err = time.LoadLocation( - config.Conf.EiBlogApp.General.Timezone) + config.Conf.General.Timezone) if err != nil { panic(err) } @@ -113,7 +111,7 @@ func (c *Cache) RepArticle(oldArticle, newArticle *model.Article) { defer c.lock.Unlock() c.ArticlesMap[newArticle.Slug] = newArticle - render.GenerateExcerptMarkdown(newArticle) + GenerateExcerptMarkdown(newArticle) if newArticle.ID < ArticleStartID { return } @@ -273,7 +271,7 @@ func (c *Cache) refreshCache(article *model.Article, del bool) { return } // 添加文章 - defer render.GenerateExcerptMarkdown(article) + defer GenerateExcerptMarkdown(article) c.ArticlesMap[article.Slug] = article c.Articles = append([]*model.Article{article}, c.Articles...) @@ -404,13 +402,12 @@ func (c *Cache) redelArticle(article *model.Article) { // loadOrInit 读取数据或初始化 func (c *Cache) loadOrInit() error { - blogapp := config.Conf.EiBlogApp // blogger blogger := &model.Blogger{ - BlogName: strings.Title(blogapp.Account.Username), + BlogName: strings.Title(config.Conf.Account.Username), SubTitle: "Rome was not built in one day.", BeiAn: "蜀ICP备xxxxxxxx号-1", - BTitle: fmt.Sprintf("%s's Blog", strings.Title(blogapp.Account.Username)), + BTitle: fmt.Sprintf("%s's Blog", strings.Title(config.Conf.Account.Username)), Copyright: `本站使用「署名 4.0 国际」创作共享协议,转载请注明作者及原网址。`, } created, err := c.LoadInsertBlogger(context.Background(), blogger) @@ -421,7 +418,7 @@ func (c *Cache) loadOrInit() error { if created { // init articles: about blogroll about := &model.Article{ ID: 1, // 固定ID - Author: blogapp.Account.Username, + Author: config.Conf.Account.Username, Title: "关于", Slug: "about", CreatedAt: time.Time{}.AddDate(0, 0, 1), @@ -431,10 +428,10 @@ func (c *Cache) loadOrInit() error { return err } // 推送到 disqus - go internal.ThreadCreate(about, blogger.BTitle) + go DisqusClient.ThreadCreate(about, blogger.BTitle) blogroll := &model.Article{ ID: 2, // 固定ID - Author: blogapp.Account.Username, + Author: config.Conf.Account.Username, Title: "友情链接", Slug: "blogroll", CreatedAt: time.Time{}.AddDate(0, 0, 7), @@ -445,11 +442,11 @@ func (c *Cache) loadOrInit() error { } } // account - pwd := tools.EncryptPasswd(blogapp.Account.Username, - blogapp.Account.Password) + pwd := tools.EncryptPasswd(config.Conf.Account.Username, + config.Conf.Account.Password) account := &model.Account{ - Username: blogapp.Account.Username, + Username: config.Conf.Account.Username, Password: pwd, } _, err = c.LoadInsertAccount(context.Background(), account) @@ -475,7 +472,7 @@ func (c *Cache) loadOrInit() error { } for i, v := range articles { // 渲染页面 - render.GenerateExcerptMarkdown(v) + GenerateExcerptMarkdown(v) c.ArticlesMap[v.Slug] = v // 分析文章 @@ -520,7 +517,7 @@ func (c *Cache) regeneratePages() { } buf.WriteString("\n") } - c.PageSeries = string(render.PageRender(buf.Bytes())) + c.PageSeries = string(PageRender(buf.Bytes())) case PageArchive: sort.Sort(c.Archives) buf := bytes.Buffer{} @@ -553,7 +550,7 @@ func (c *Cache) regeneratePages() { } } } - c.PageArchives = string(render.PageRender(buf.Bytes())) + c.PageArchives = string(PageRender(buf.Bytes())) } } } @@ -576,7 +573,7 @@ func (c *Cache) timerDisqus() { ticker := time.NewTicker(5 * time.Hour) for range ticker.C { - err := internal.PostsCount(c.ArticlesMap) + err := DisqusClient.PostsCount(c.ArticlesMap) if err != nil { logrus.Error("cache.timerDisqus.PostsCount: ", err) } diff --git a/cmd/eiblog/handler/internal/internal.go b/cmd/eiblog/handler/internal/internal.go new file mode 100644 index 0000000..0d99ed4 --- /dev/null +++ b/cmd/eiblog/handler/internal/internal.go @@ -0,0 +1,38 @@ +package internal + +import ( + "github.com/eiblog/eiblog/cmd/eiblog/config" + "github.com/eiblog/eiblog/pkg/third/disqus" + "github.com/eiblog/eiblog/pkg/third/es" + "github.com/eiblog/eiblog/pkg/third/pinger" + "github.com/eiblog/eiblog/pkg/third/qiniu" + + "github.com/sirupsen/logrus" +) + +var ( + ESClient *es.ESClient + DisqusClient *disqus.DisqusClient + QiniuClient *qiniu.QiniuClient + Pinger *pinger.Pinger +) + +func init() { + var err error + ESClient, err = es.NewESClient(config.Conf.ESHost) + if err != nil { + logrus.Fatal("init es client: ", err) + } + DisqusClient, err = disqus.NewDisqusClient(config.Conf.Host, config.Conf.Disqus) + if err != nil { + logrus.Fatal("init disqus client: ", err) + } + QiniuClient, err = qiniu.NewQiniuClient(config.Conf.Qiniu) + if err != nil { + logrus.Fatal("init qiniu client: ", err) + } + Pinger, err = pinger.NewPinger(config.Conf.Host, config.Conf.FeedRPC) + if err != nil { + logrus.Fatal("init pinger: ", err) + } +} diff --git a/pkg/cache/render/render.go b/cmd/eiblog/handler/internal/render.go similarity index 84% rename from pkg/cache/render/render.go rename to cmd/eiblog/handler/internal/render.go index 09a2f8a..429583d 100644 --- a/pkg/cache/render/render.go +++ b/cmd/eiblog/handler/internal/render.go @@ -1,11 +1,10 @@ -// Package render provides ... -package render +package internal import ( "regexp" "strings" - "github.com/eiblog/eiblog/pkg/config" + "github.com/eiblog/eiblog/cmd/eiblog/config" "github.com/eiblog/eiblog/pkg/model" "github.com/eiblog/eiblog/tools" @@ -37,7 +36,7 @@ const ( var ( // 渲染markdown操作和截取摘要操作 - regIdentifier = regexp.MustCompile(config.Conf.EiBlogApp.General.Identifier) + regIdentifier = regexp.MustCompile(config.Conf.General.Identifier) // header regHeader = regexp.MustCompile("") ) @@ -50,11 +49,9 @@ func PageRender(md []byte) []byte { // GenerateExcerptMarkdown 生成预览和描述 func GenerateExcerptMarkdown(article *model.Article) { - blogapp := config.Conf.EiBlogApp - - if strings.HasPrefix(article.Content, blogapp.General.DescPrefix) { + if strings.HasPrefix(article.Content, config.Conf.General.DescPrefix) { index := strings.Index(article.Content, "\r\n") - prefix := article.Content[len(blogapp.General.DescPrefix):index] + prefix := article.Content[len(config.Conf.General.DescPrefix):index] article.Desc = tools.IgnoreHTMLTag(prefix) article.Content = article.Content[index:] @@ -77,7 +74,7 @@ func GenerateExcerptMarkdown(article *model.Article) { return } uc := []rune(article.Content) - length := blogapp.General.Length + length := config.Conf.General.Length if len(uc) < length { length = len(uc) } diff --git a/pkg/cache/store/mongodb.go b/cmd/eiblog/handler/internal/store/mongodb.go similarity index 98% rename from pkg/cache/store/mongodb.go rename to cmd/eiblog/handler/internal/store/mongodb.go index 08763cd..32d0ac6 100644 --- a/pkg/cache/store/mongodb.go +++ b/cmd/eiblog/handler/internal/store/mongodb.go @@ -326,11 +326,6 @@ func (db *mongodb) LoadArticleList(ctx context.Context, search SearchArticles) ( return articles, int(count), nil } -// DropDatabase drop eiblog database -func (db *mongodb) DropDatabase(ctx context.Context) error { - return db.Database(mongoDBName).Drop(ctx) -} - // counter counter type counter struct { Name string diff --git a/pkg/cache/store/mongodb_test.go b/cmd/eiblog/handler/internal/store/mongodb_test.go similarity index 100% rename from pkg/cache/store/mongodb_test.go rename to cmd/eiblog/handler/internal/store/mongodb_test.go diff --git a/pkg/cache/store/rdbms.go b/cmd/eiblog/handler/internal/store/rdbms.go similarity index 100% rename from pkg/cache/store/rdbms.go rename to cmd/eiblog/handler/internal/store/rdbms.go diff --git a/pkg/cache/store/store.go b/cmd/eiblog/handler/internal/store/store.go similarity index 98% rename from pkg/cache/store/store.go rename to cmd/eiblog/handler/internal/store/store.go index 16a77c8..bd943be 100644 --- a/pkg/cache/store/store.go +++ b/cmd/eiblog/handler/internal/store/store.go @@ -64,9 +64,6 @@ type Store interface { LoadArticle(ctx context.Context, id int) (*model.Article, error) // LoadArticleList 查找文章列表 LoadArticleList(ctx context.Context, search SearchArticles) (model.SortedArticles, int, error) - - // 危险操作 - DropDatabase(ctx context.Context) error } // Driver 存储驱动 diff --git a/pkg/core/eiblog/page/be.go b/cmd/eiblog/handler/page/be.go similarity index 73% rename from pkg/core/eiblog/page/be.go rename to cmd/eiblog/handler/page/be.go index 9d42800..d53a181 100644 --- a/pkg/core/eiblog/page/be.go +++ b/cmd/eiblog/handler/page/be.go @@ -1,4 +1,3 @@ -// Package page provides ... package page import ( @@ -10,20 +9,20 @@ import ( "net/http" "strconv" - "github.com/eiblog/eiblog/pkg/cache" - "github.com/eiblog/eiblog/pkg/cache/store" - "github.com/eiblog/eiblog/pkg/config" - "github.com/eiblog/eiblog/pkg/core/eiblog" + "github.com/eiblog/eiblog/cmd/eiblog/config" + "github.com/eiblog/eiblog/cmd/eiblog/handler/internal" + "github.com/eiblog/eiblog/cmd/eiblog/handler/internal/store" + "github.com/eiblog/eiblog/pkg/middleware" "github.com/gin-gonic/gin" "github.com/sirupsen/logrus" ) // baseBEParams 基础参数 -func baseBEParams(c *gin.Context) gin.H { +func baseBEParams(_ *gin.Context) gin.H { return gin.H{ - "Author": cache.Ei.Account.Username, - "Qiniu": config.Conf.EiBlogApp.Qiniu, + "Author": internal.Ei.Account.Username, + "Qiniu": config.Conf.Qiniu, } } @@ -31,22 +30,22 @@ func baseBEParams(c *gin.Context) gin.H { func handleLoginPage(c *gin.Context) { logout := c.Query("logout") if logout == "true" { - eiblog.SetLogout(c) - } else if eiblog.IsLogined(c) { + middleware.SetLogout(c) + } else if middleware.IsLogined(c) { c.Redirect(http.StatusFound, "/admin/profile") return } - params := gin.H{"BTitle": cache.Ei.Blogger.BTitle} + params := gin.H{"BTitle": internal.Ei.Blogger.BTitle} renderHTMLAdminLayout(c, "login.html", params) } // handleAdminProfile 个人配置 func handleAdminProfile(c *gin.Context) { params := baseBEParams(c) - params["Title"] = "个人配置 | " + cache.Ei.Blogger.BTitle + params["Title"] = "个人配置 | " + internal.Ei.Blogger.BTitle params["Path"] = c.Request.URL.Path params["Console"] = true - params["Ei"] = cache.Ei + params["Ei"] = internal.Ei renderHTMLAdminLayout(c, "admin-profile", params) } @@ -61,20 +60,20 @@ func handleAdminPost(c *gin.Context) { params := baseBEParams(c) id, err := strconv.Atoi(c.Query("cid")) if err == nil && id > 0 { - article, _ := cache.Ei.LoadArticle(context.Background(), id) + article, _ := internal.Ei.LoadArticle(context.Background(), id) if article != nil { - params["Title"] = "编辑文章 | " + cache.Ei.Blogger.BTitle + params["Title"] = "编辑文章 | " + internal.Ei.Blogger.BTitle params["Edit"] = article } } if params["Title"] == nil { - params["Title"] = "撰写文章 | " + cache.Ei.Blogger.BTitle + params["Title"] = "撰写文章 | " + internal.Ei.Blogger.BTitle } params["Path"] = c.Request.URL.Path - params["Domain"] = config.Conf.EiBlogApp.Host - params["Series"] = cache.Ei.Series + params["Domain"] = config.Conf.Host + params["Series"] = internal.Ei.Series var tags []T - for tag := range cache.Ei.TagArticles { + for tag := range internal.Ei.TagArticles { tags = append(tags, T{tag, tag}) } str, _ := json.Marshal(tags) @@ -97,15 +96,15 @@ func handleAdminPosts(c *gin.Context) { vals := c.Request.URL.Query() params := baseBEParams(c) - params["Title"] = "文章管理 | " + cache.Ei.Blogger.BTitle + params["Title"] = "文章管理 | " + internal.Ei.Blogger.BTitle params["Manage"] = true params["Path"] = c.Request.URL.Path - params["Series"] = cache.Ei.Series + params["Series"] = internal.Ei.Series params["Serie"] = se params["KW"] = kw var max int - params["List"], max = cache.Ei.PageArticleBE(se, kw, false, false, - pg, config.Conf.EiBlogApp.General.PageSize) + params["List"], max = internal.Ei.PageArticleBE(se, kw, false, false, + pg, config.Conf.General.PageSize) if pg < max { vals.Set("page", fmt.Sprint(pg+1)) params["Next"] = vals.Encode() @@ -126,10 +125,10 @@ func handleAdminPosts(c *gin.Context) { // handleAdminSeries 专题列表 func handleAdminSeries(c *gin.Context) { params := baseBEParams(c) - params["Title"] = "专题管理 | " + cache.Ei.Blogger.BTitle + params["Title"] = "专题管理 | " + internal.Ei.Blogger.BTitle params["Manage"] = true params["Path"] = c.Request.URL.Path - params["List"] = cache.Ei.Series + params["List"] = internal.Ei.Series renderHTMLAdminLayout(c, "admin-series", params) } @@ -138,11 +137,11 @@ func handleAdminSerie(c *gin.Context) { params := baseBEParams(c) id, err := strconv.Atoi(c.Query("mid")) - params["Title"] = "新增专题 | " + cache.Ei.Blogger.BTitle + params["Title"] = "新增专题 | " + internal.Ei.Blogger.BTitle if err == nil && id > 0 { - for _, v := range cache.Ei.Series { + for _, v := range internal.Ei.Series { if v.ID == id { - params["Title"] = "编辑专题 | " + cache.Ei.Blogger.BTitle + params["Title"] = "编辑专题 | " + internal.Ei.Blogger.BTitle params["Edit"] = v break } @@ -156,10 +155,10 @@ func handleAdminSerie(c *gin.Context) { // handleAdminTags 标签列表 func handleAdminTags(c *gin.Context) { params := baseBEParams(c) - params["Title"] = "标签管理 | " + cache.Ei.Blogger.BTitle + params["Title"] = "标签管理 | " + internal.Ei.Blogger.BTitle params["Manage"] = true params["Path"] = c.Request.URL.Path - params["List"] = cache.Ei.TagArticles + params["List"] = internal.Ei.TagArticles renderHTMLAdminLayout(c, "admin-tags", params) } @@ -170,7 +169,7 @@ func handleDraftDelete(c *gin.Context) { c.JSON(http.StatusBadRequest, gin.H{"error": "参数错误"}) return } - err = cache.Ei.RemoveArticle(context.Background(), id) + err = internal.Ei.RemoveArticle(context.Background(), id) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "删除错误"}) return @@ -182,7 +181,7 @@ func handleDraftDelete(c *gin.Context) { func handleAdminDraft(c *gin.Context) { params := baseBEParams(c) - params["Title"] = "草稿箱 | " + cache.Ei.Blogger.BTitle + params["Title"] = "草稿箱 | " + internal.Ei.Blogger.BTitle params["Manage"] = true params["Path"] = c.Request.URL.Path var err error @@ -191,7 +190,7 @@ func handleAdminDraft(c *gin.Context) { Limit: 9999, Fields: map[string]interface{}{store.SearchArticleDraft: true}, } - params["List"], _, err = cache.Ei.LoadArticleList(context.Background(), search) + params["List"], _, err = internal.Ei.LoadArticleList(context.Background(), search) if err != nil { logrus.Error("handleDraft.LoadDraftArticles: ", err) c.Status(http.StatusBadRequest) @@ -204,7 +203,7 @@ func handleAdminDraft(c *gin.Context) { // handleAdminTrash 回收箱页 func handleAdminTrash(c *gin.Context) { params := baseBEParams(c) - params["Title"] = "回收箱 | " + cache.Ei.Blogger.BTitle + params["Title"] = "回收箱 | " + internal.Ei.Blogger.BTitle params["Manage"] = true params["Path"] = c.Request.URL.Path var err error @@ -213,7 +212,7 @@ func handleAdminTrash(c *gin.Context) { Limit: 9999, Fields: map[string]interface{}{store.SearchArticleTrash: true}, } - params["List"], _, err = cache.Ei.LoadArticleList(context.Background(), search) + params["List"], _, err = internal.Ei.LoadArticleList(context.Background(), search) if err != nil { logrus.Error("handleTrash.LoadArticleList: ", err) } @@ -223,7 +222,7 @@ func handleAdminTrash(c *gin.Context) { // handleAdminGeneral 基本设置 func handleAdminGeneral(c *gin.Context) { params := baseBEParams(c) - params["Title"] = "基本设置 | " + cache.Ei.Blogger.BTitle + params["Title"] = "基本设置 | " + internal.Ei.Blogger.BTitle params["Setting"] = true params["Path"] = c.Request.URL.Path renderHTMLAdminLayout(c, "admin-general", params) @@ -232,7 +231,7 @@ func handleAdminGeneral(c *gin.Context) { // handleAdminDiscussion 阅读设置 func handleAdminDiscussion(c *gin.Context) { params := baseBEParams(c) - params["Title"] = "阅读设置 | " + cache.Ei.Blogger.BTitle + params["Title"] = "阅读设置 | " + internal.Ei.Blogger.BTitle params["Setting"] = true params["Path"] = c.Request.URL.Path renderHTMLAdminLayout(c, "admin-discussion", params) diff --git a/pkg/core/eiblog/page/fe.go b/cmd/eiblog/handler/page/fe.go similarity index 75% rename from pkg/core/eiblog/page/fe.go rename to cmd/eiblog/handler/page/fe.go index b7966b0..69d0f9b 100644 --- a/pkg/core/eiblog/page/fe.go +++ b/cmd/eiblog/handler/page/fe.go @@ -1,4 +1,3 @@ -// Package page provides ... package page import ( @@ -13,9 +12,9 @@ import ( "strings" "time" - "github.com/eiblog/eiblog/pkg/cache" - "github.com/eiblog/eiblog/pkg/config" - "github.com/eiblog/eiblog/pkg/internal" + "github.com/eiblog/eiblog/cmd/eiblog/config" + "github.com/eiblog/eiblog/cmd/eiblog/handler/internal" + "github.com/eiblog/eiblog/pkg/third/disqus" "github.com/eiblog/eiblog/tools" "github.com/gin-gonic/gin" @@ -28,20 +27,20 @@ func baseFEParams(c *gin.Context) gin.H { cookie, err := c.Request.Cookie("v") if err != nil || cookie.Value != - fmt.Sprint(config.Conf.EiBlogApp.StaticVersion) { - version = config.Conf.EiBlogApp.StaticVersion + fmt.Sprint(config.Conf.StaticVersion) { + version = config.Conf.StaticVersion } return gin.H{ - "BlogName": cache.Ei.Blogger.BlogName, - "SubTitle": cache.Ei.Blogger.SubTitle, - "BTitle": cache.Ei.Blogger.BTitle, - "BeiAn": cache.Ei.Blogger.BeiAn, - "Domain": config.Conf.EiBlogApp.Host, + "BlogName": internal.Ei.Blogger.BlogName, + "SubTitle": internal.Ei.Blogger.SubTitle, + "BTitle": internal.Ei.Blogger.BTitle, + "BeiAn": internal.Ei.Blogger.BeiAn, + "Domain": config.Conf.Host, "CopyYear": time.Now().Year(), - "Twitter": config.Conf.EiBlogApp.Twitter, - "Qiniu": config.Conf.EiBlogApp.Qiniu, - "Disqus": config.Conf.EiBlogApp.Disqus, - "AdSense": config.Conf.EiBlogApp.Google.AdSense, + "Twitter": config.Conf.Twitter, + "Qiniu": config.Conf.Qiniu, + "Disqus": config.Conf.Disqus, + "AdSense": config.Conf.Google.AdSense, "Version": version, } } @@ -59,16 +58,16 @@ func handleNotFound(c *gin.Context) { // handleHomePage 首页 func handleHomePage(c *gin.Context) { params := baseFEParams(c) - params["Title"] = cache.Ei.Blogger.BTitle + " | " + cache.Ei.Blogger.SubTitle - params["Description"] = "博客首页," + cache.Ei.Blogger.SubTitle + params["Title"] = internal.Ei.Blogger.BTitle + " | " + internal.Ei.Blogger.SubTitle + params["Description"] = "博客首页," + internal.Ei.Blogger.SubTitle params["Path"] = c.Request.URL.Path params["CurrentPage"] = "blog-home" pn, err := strconv.Atoi(c.Query("pn")) if err != nil || pn < 1 { pn = 1 } - params["Prev"], params["Next"], params["List"] = cache.Ei.PageArticleFE(pn, - config.Conf.EiBlogApp.General.PageNum) + params["Prev"], params["Next"], params["List"] = internal.Ei.PageArticleFE(pn, + config.Conf.General.PageNum) renderHTMLHomeLayout(c, "home", params) } @@ -76,13 +75,13 @@ func handleHomePage(c *gin.Context) { // handleArticlePage 文章页 func handleArticlePage(c *gin.Context) { slug := c.Param("slug") - if !strings.HasSuffix(slug, ".html") || cache.Ei.ArticlesMap[slug[:len(slug)-5]] == nil { + if !strings.HasSuffix(slug, ".html") || internal.Ei.ArticlesMap[slug[:len(slug)-5]] == nil { handleNotFound(c) return } - article := cache.Ei.ArticlesMap[slug[:len(slug)-5]] + article := internal.Ei.ArticlesMap[slug[:len(slug)-5]] params := baseFEParams(c) - params["Title"] = article.Title + " | " + cache.Ei.Blogger.BTitle + params["Title"] = article.Title + " | " + internal.Ei.Blogger.BTitle params["Path"] = c.Request.URL.Path params["CurrentPage"] = "post-" + article.Slug params["Article"] = article @@ -91,21 +90,21 @@ func handleArticlePage(c *gin.Context) { switch slug { case "blogroll.html": name = "blogroll" - params["Description"] = "友情连接," + cache.Ei.Blogger.SubTitle + params["Description"] = "友情连接," + internal.Ei.Blogger.SubTitle case "about.html": name = "about" - params["Description"] = "关于作者," + cache.Ei.Blogger.SubTitle + params["Description"] = "关于作者," + internal.Ei.Blogger.SubTitle default: - params["Description"] = article.Desc + "," + cache.Ei.Blogger.SubTitle + params["Description"] = article.Desc + "," + internal.Ei.Blogger.SubTitle name = "article" - params["Copyright"] = cache.Ei.Blogger.Copyright + params["Copyright"] = internal.Ei.Blogger.Copyright if !article.UpdatedAt.IsZero() { - params["Days"] = int(time.Now().Sub(article.UpdatedAt).Hours()) / 24 + params["Days"] = int(time.Since(article.UpdatedAt).Hours()) / 24 } else { - params["Days"] = int(time.Now().Sub(article.CreatedAt).Hours()) / 24 + params["Days"] = int(time.Since(article.CreatedAt).Hours()) / 24 } if article.SerieID > 0 { - for _, series := range cache.Ei.Series { + for _, series := range internal.Ei.Series { if series.ID == article.SerieID { params["Serie"] = series } @@ -118,30 +117,30 @@ func handleArticlePage(c *gin.Context) { // handleSeriesPage 专题页 func handleSeriesPage(c *gin.Context) { params := baseFEParams(c) - params["Title"] = "专题 | " + cache.Ei.Blogger.BTitle - params["Description"] = "专题列表," + cache.Ei.Blogger.SubTitle + params["Title"] = "专题 | " + internal.Ei.Blogger.BTitle + params["Description"] = "专题列表," + internal.Ei.Blogger.SubTitle params["Path"] = c.Request.URL.Path params["CurrentPage"] = "series" - params["Article"] = cache.Ei.PageSeries + params["Article"] = internal.Ei.PageSeries renderHTMLHomeLayout(c, "series", params) } // handleArchivePage 归档页 func handleArchivePage(c *gin.Context) { params := baseFEParams(c) - params["Title"] = "归档 | " + cache.Ei.Blogger.BTitle - params["Description"] = "博客归档," + cache.Ei.Blogger.SubTitle + params["Title"] = "归档 | " + internal.Ei.Blogger.BTitle + params["Description"] = "博客归档," + internal.Ei.Blogger.SubTitle params["Path"] = c.Request.URL.Path params["CurrentPage"] = "archives" - params["Article"] = cache.Ei.PageArchives + params["Article"] = internal.Ei.PageArchives renderHTMLHomeLayout(c, "archives", params) } // handleSearchPage 搜索页 func handleSearchPage(c *gin.Context) { params := baseFEParams(c) - params["Title"] = "站内搜索 | " + cache.Ei.Blogger.BTitle - params["Description"] = "站内搜索," + cache.Ei.Blogger.SubTitle + params["Title"] = "站内搜索 | " + internal.Ei.Blogger.BTitle + params["Description"] = "站内搜索," + internal.Ei.Blogger.SubTitle params["Path"] = "" params["CurrentPage"] = "search-post" @@ -154,29 +153,29 @@ func handleSearchPage(c *gin.Context) { params["Word"] = q vals := c.Request.URL.Query() - result, err := internal.ElasticSearch(q, config.Conf.EiBlogApp.General.PageNum, start-1) + result, err := internal.ESClient.ElasticSearch(q, config.Conf.General.PageNum, start-1) if err != nil { logrus.Error("HandleSearchPage.ElasticSearch: ", err) } else { result.Took /= 1000 for i, v := range result.Hits.Hits { - article := cache.Ei.ArticlesMap[v.Source.Slug] + article := internal.Ei.ArticlesMap[v.Source.Slug] if len(v.Highlight.Content) == 0 && article != nil { result.Hits.Hits[i].Highlight.Content = []string{article.Excerpt} } } params["SearchResult"] = result - if num := start - config.Conf.EiBlogApp.General.PageNum; num > 0 { + if num := start - config.Conf.General.PageNum; num > 0 { vals.Set("start", fmt.Sprint(num)) params["Prev"] = vals.Encode() } - if num := start + config.Conf.EiBlogApp.General.PageNum; result.Hits.Total >= num { + if num := start + config.Conf.General.PageNum; result.Hits.Total >= num { vals.Set("start", fmt.Sprint(num)) params["Next"] = vals.Encode() } } } else { - params["HotWords"] = config.Conf.EiBlogApp.HotWords + params["HotWords"] = config.Conf.HotWords } renderHTMLHomeLayout(c, "search", params) } @@ -200,11 +199,11 @@ func handleDisqusList(c *gin.Context) { slug := c.Param("slug") cursor := c.Query("cursor") - artc := cache.Ei.ArticlesMap[slug] + artc := internal.Ei.ArticlesMap[slug] if artc != nil { dcs.Data.Thread = artc.Thread } - postsList, err := internal.PostsList(artc, cursor) + postsList, err := internal.DisqusClient.PostsList(artc, cursor) if err != nil { logrus.Error("hadnleDisqusList.PostsList: ", err) dcs.ErrNo = 0 @@ -236,10 +235,10 @@ func handleDisqusList(c *gin.Context) { if artc != nil && artc.Thread == "" { if dcs.Data.Thread != "" { artc.Thread = dcs.Data.Thread - } else if internal.ThreadDetails(artc) == nil { + } else if internal.DisqusClient.ThreadDetails(artc) == nil { dcs.Data.Thread = artc.Thread } - cache.Ei.UpdateArticle(context.Background(), artc.ID, + internal.Ei.UpdateArticle(context.Background(), artc.ID, map[string]interface{}{ "thread": artc.Thread, }) @@ -253,9 +252,9 @@ func handleDisqusPage(c *gin.Context) { c.String(http.StatusOK, "出错啦。。。") return } - article := cache.Ei.ArticlesMap[array[0]] + article := internal.Ei.ArticlesMap[array[0]] params := gin.H{ - "Title": "发表评论 | " + cache.Ei.Blogger.BTitle, + "Title": "发表评论 | " + internal.Ei.Blogger.BTitle, "ATitle": article.Title, "Thread": array[1], "Slug": article.Slug, @@ -300,7 +299,7 @@ func handleDisqusCreate(c *gin.Context) { } logrus.Infof("email: %s comments: %s", email, thread) - comment := internal.PostComment{ + comment := disqus.PostComment{ Message: msg, Parent: c.PostForm("parent"), Thread: thread, @@ -309,14 +308,14 @@ func handleDisqusCreate(c *gin.Context) { Identifier: identifier, IPAddress: c.ClientIP(), } - postDetail, err := internal.PostCreate(&comment) + postDetail, err := internal.DisqusClient.PostCreate(&comment) if err != nil { logrus.Error("handleDisqusCreate.PostCreate: ", err) resp.ErrNo = 1 resp.ErrMsg = "提交评论失败,请重试" return } - err = internal.PostApprove(postDetail.Response.ID) + err = internal.DisqusClient.PostApprove(postDetail.Response.ID) if err != nil { logrus.Error("handleDisqusCreate.PostApprove: ", err) resp.ErrNo = 1 @@ -341,8 +340,8 @@ func handleBeaconPage(c *gin.Context) { ua := c.Request.UserAgent() vals := c.Request.URL.Query() - vals.Set("v", config.Conf.EiBlogApp.Google.V) - vals.Set("tid", config.Conf.EiBlogApp.Google.Tid) + vals.Set("v", config.Conf.Google.V) + vals.Set("tid", config.Conf.Google.Tid) cookie, _ := c.Cookie("u") vals.Set("cid", cookie) @@ -354,7 +353,7 @@ func handleBeaconPage(c *gin.Context) { vals.Set("_p", fmt.Sprint(201226219+rand.Intn(499999999))) // random page load hash vals.Set("_ee", "1") // external event go func() { - url := config.Conf.EiBlogApp.Google.URL + "?" + vals.Encode() + url := config.Conf.Google.URL + "?" + vals.Encode() req, err := http.NewRequest("POST", url, nil) if err != nil { logrus.Error("HandleBeaconPage.NewRequest: ", err) diff --git a/pkg/core/eiblog/page/page.go b/cmd/eiblog/handler/page/page.go similarity index 94% rename from pkg/core/eiblog/page/page.go rename to cmd/eiblog/handler/page/page.go index 835bd91..a878ef3 100644 --- a/pkg/core/eiblog/page/page.go +++ b/cmd/eiblog/handler/page/page.go @@ -1,12 +1,12 @@ -// Package page provides ... package page import ( "io/fs" "path/filepath" + "strings" "text/template" - "github.com/eiblog/eiblog/pkg/config" + "github.com/eiblog/eiblog/cmd/eiblog/config" "github.com/eiblog/eiblog/tools" "github.com/gin-gonic/gin" @@ -20,7 +20,7 @@ func init() { root := filepath.Join(config.WorkDir, "website") files := tools.ReadDirFiles(root, func(fi fs.DirEntry) bool { name := fi.Name() - if name == ".DS_Store" { + if strings.HasPrefix(name, ".") { return true } // should not read template dir diff --git a/pkg/core/backup/swag/swag.go b/cmd/eiblog/handler/swag/swag.go similarity index 76% rename from pkg/core/backup/swag/swag.go rename to cmd/eiblog/handler/swag/swag.go index f52f37d..3c63870 100644 --- a/pkg/core/backup/swag/swag.go +++ b/cmd/eiblog/handler/swag/swag.go @@ -1,8 +1,7 @@ -// Package swag provides ... package swag import ( - _ "github.com/eiblog/eiblog/pkg/core/backup/docs" // docs + _ "github.com/eiblog/eiblog/cmd/eiblog/docs" // docs "github.com/gin-gonic/gin" swaggerFiles "github.com/swaggo/files" diff --git a/cmd/eiblog/main.go b/cmd/eiblog/main.go index 48a1984..b164f5d 100644 --- a/cmd/eiblog/main.go +++ b/cmd/eiblog/main.go @@ -2,52 +2,48 @@ package main import ( - "fmt" "path/filepath" - "github.com/eiblog/eiblog/pkg/config" - "github.com/eiblog/eiblog/pkg/core/eiblog" - "github.com/eiblog/eiblog/pkg/core/eiblog/admin" - "github.com/eiblog/eiblog/pkg/core/eiblog/file" - "github.com/eiblog/eiblog/pkg/core/eiblog/page" - "github.com/eiblog/eiblog/pkg/core/eiblog/swag" - "github.com/eiblog/eiblog/pkg/mid" + "github.com/eiblog/eiblog/cmd/eiblog/config" + "github.com/eiblog/eiblog/cmd/eiblog/handler/admin" + "github.com/eiblog/eiblog/cmd/eiblog/handler/file" + "github.com/eiblog/eiblog/cmd/eiblog/handler/page" + "github.com/eiblog/eiblog/cmd/eiblog/handler/swag" + + "github.com/eiblog/eiblog/pkg/middleware" "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" ) func main() { - fmt.Println("Hi, it's App " + config.Conf.EiBlogApp.Name) + logrus.Info("Hi, it's App " + config.Conf.Name) endRun := make(chan error, 1) runHTTPServer(endRun) - fmt.Println(<-endRun) + logrus.Fatal(<-endRun) } func runHTTPServer(endRun chan error) { - if !config.Conf.EiBlogApp.EnableHTTP { - return - } - - if config.Conf.RunMode == config.ModeProd { + if config.Conf.RunMode.IsReleaseMode() { gin.SetMode(gin.ReleaseMode) } e := gin.Default() // middleware - e.Use(mid.UserMiddleware()) - e.Use(mid.SessionMiddleware(mid.SessionOpts{ - Name: "su", - Secure: config.Conf.RunMode == config.ModeProd, - Secret: []byte("ZGlzvcmUoMTAsICI="), - })) + e.Use(middleware.UserMiddleware()) + e.Use(middleware.SessionMiddleware( + middleware.SessionOpts{ + Name: "su", + Secure: config.Conf.RunMode.IsReleaseMode(), + Secret: []byte("ZGlzvcmUoMTAsICI="), + })) // swag swag.RegisterRoutes(e) // static files, page - root := filepath.Join(config.WorkDir, "assets") - e.Static("/static", root) + e.Static("/static", filepath.Join(config.WorkDir, "assets")) // static files file.RegisterRoutes(e) @@ -57,16 +53,15 @@ func runHTTPServer(endRun chan error) { admin.RegisterRoutes(e) // admin router - group := e.Group("/admin", eiblog.AuthFilter) + group := e.Group("/admin", middleware.AuthFilter) { page.RegisterRoutesAuthz(group) admin.RegisterRoutesAuthz(group) } // start - address := fmt.Sprintf(":%d", config.Conf.EiBlogApp.HTTPPort) go func() { - endRun <- e.Run(address) + endRun <- e.Run(config.Conf.Listen) }() - fmt.Println("HTTP server running on: " + address) + logrus.Info("HTTP server running on: " + config.Conf.Listen) } diff --git a/docker-compose.yml b/compose.yml similarity index 98% rename from docker-compose.yml rename to compose.yml index 196fa96..5b133cb 100644 --- a/docker-compose.yml +++ b/compose.yml @@ -1,4 +1,3 @@ -version: '3' services: mongodb: image: mongo:3.2 @@ -10,6 +9,7 @@ services: volumes: - ${PWD}/esdata:/usr/share/elasticsearch/data restart: always + eiblog: image: deepzz0/eiblog:latest volumes: @@ -25,6 +25,7 @@ services: ports: - 127.0.0.1:9000:9000 restart: always + backup: image: deepzz0/backup:latest #command: ./backend --restore true diff --git a/conf/README.md b/conf/README.md deleted file mode 100644 index 116b26b..0000000 --- a/conf/README.md +++ /dev/null @@ -1,3 +0,0 @@ -Configuration file templates or default configs. - -Put your confd or consul-template template files here. diff --git a/conf/app.yml b/conf/app.yml deleted file mode 100644 index 47428b7..0000000 --- a/conf/app.yml +++ /dev/null @@ -1,66 +0,0 @@ -appname: eiblog -database: - driver: sqlite - source: ./db.sqlite -eshost: # http://elasticsearch:9200 -eiblogapp: - mode: - name: cmd-eiblog - enablehttp: true - httpport: 9000 - host: example.com - staticversion: 1 # 静态文件版本 - hotwords: # 热搜词 - - docker - - mongodb - - curl - - dns - general: # 常规配置 - pagenum: 10 # 首页展示文章数量 - pagesize: 20 # 管理界面 - startid: 11 # 起始ID,预留id不时之需, 不用管 - descprefix: "Desc:" # 文章描述前缀 - identifier: # 截取预览标识 - length: 400 # 自动截取预览, 字符数 - timezone: Asia/Shanghai # 时区 - disqus: # 评论相关 - shortname: xxxxxx - publickey: wdSgxRm9rdGAlLKFcFdToBe3GT4SibmV7Y8EjJQ0r4GWXeKtxpopMAeIeoI2dTEg - accesstoken: 50023908f39f4607957e909b495326af - google: # 谷歌分析 - url: https://www.google-analytics.com/g/collect - tid: G-xxxxxxxxxx - v: "2" - adsense: - qiniu: # 七牛OSS - bucket: eiblog - domain: st.deepzz.com - accesskey: MB6AXl_Sj_mmFsL-Lt59Dml2Vmy2o8XMmiCbbSeC - secretkey: BIrMy0fsZ0_SHNceNXk3eDuo7WmVYzj2-zrmd5Tf - twitter: # twitter card - card: summary - site: deepzz02 - image: st.deepzz.com/static/img/avatar.jpg - address: twitter.com/deepzz02 - feedrpc: # rss ping - feedrurl: https://deepzz.superfeedr.com/ - pingrpc: - - http://ping.baidu.com/ping/RPC2 - - http://rpc.pingomatic.com/ - # 数据初始化操作,可到博客后台修改 - account: - username: deepzz # *后台登录用户名 - password: deepzz # *登录明文密码 -backupapp: - mode: - name: cmd-backup - enablehttp: true - httpport: 9001 - backupto: qiniu # 备份到七牛云 - interval: 7d # 多久备份一次 - validity: 60 # 保存时长days - qiniu: # 七牛OSS - bucket: backup - domain: st.deepzz.com - accesskey: MB6AXl_Sj_mmFsL-Lt59Dml2Vmy2o8XMmiCbbSeC - secretkey: BIrMy0fsZ0_SHNceNXk3eDuo7WmVYzj2-zrmd5Tf diff --git a/go.mod b/go.mod index 42bc9df..b4fdd87 100644 --- a/go.mod +++ b/go.mod @@ -10,9 +10,9 @@ require ( github.com/qiniu/go-sdk/v7 v7.11.0 github.com/satori/go.uuid v1.2.0 github.com/sirupsen/logrus v1.9.3 - github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 - github.com/swaggo/gin-swagger v1.3.3 - github.com/swaggo/swag v1.7.4 + github.com/swaggo/files v1.0.1 + github.com/swaggo/gin-swagger v1.6.0 + github.com/swaggo/swag v1.16.4 go.mongodb.org/mongo-driver v1.5.4 gopkg.in/yaml.v3 v3.0.1 gorm.io/driver/clickhouse v0.4.2 diff --git a/go.sum b/go.sum index 4de1382..e9d9c33 100644 --- a/go.sum +++ b/go.sum @@ -36,6 +36,7 @@ github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1/go.mod h1:dkChI7Tbtx7H1Tj7TqGSZMOeGpMP5gLHtjroHd4agiI= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= +github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= @@ -55,14 +56,15 @@ github.com/eiblog/blackfriday v0.0.0-20161010144836-c0ec111761ae/go.mod h1:HzHqT github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/gzip v0.0.3 h1:etUaeesHhEORpZMp18zoOhepboiWnFtXrBZxszWUn4k= -github.com/gin-contrib/gzip v0.0.3/go.mod h1:YxxswVZIqOvcHEQpsSn+QF5guQtO1dCfy0shBPy4jFc= +github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d4= +github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= github.com/gin-contrib/sessions v0.0.4 h1:gq4fNa1Zmp564iHP5G6EBuktilEos8VKhe2sza1KMgo= github.com/gin-contrib/sessions v0.0.4/go.mod h1:pQ3sIyviBBGcxgyR8mkeJuXbeV3h3NYmhJADQTq5+Vo= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= +github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= +github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= @@ -74,13 +76,13 @@ github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiU github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM= -github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg= -github.com/go-openapi/spec v0.20.3 h1:uH9RQ6vdyPSs2pSy9fL8QPspDF2AMIMPtmK5coSSjtQ= -github.com/go-openapi/spec v0.20.3/go.mod h1:gG4F8wdEDN+YPBMVnzE85Rbhf+Th2DTvA9nFPQ5AYEg= +github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M= +github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng= -github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= @@ -92,9 +94,10 @@ github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.8.0/go.mod h1:9JhgTzTaE31GZDpH/HSvHiRJrJ3iKAgqqH0Bl/Ocjdk= +github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= +github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= @@ -127,9 +130,10 @@ github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWe github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= +github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.4.3/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= @@ -233,6 +237,8 @@ github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= +github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -257,6 +263,8 @@ github.com/paulmach/orb v0.7.1/go.mod h1:FWRlTgl88VI1RBx/MkrwWDRhQ96ctqMCh8boXhm github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY= github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= +github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= +github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I= @@ -289,7 +297,6 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh github.com/shirou/gopsutil v2.19.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= @@ -318,21 +325,25 @@ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 h1:PyYN9JH5jY9j6av01SpfRMb+1DWg/i3MbGOKPxJ2wjM= -github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E= -github.com/swaggo/gin-swagger v1.3.3 h1:XHyYmeNVFG5PbyWHG4jXtxOm2P4kiZapDCWsyDDiQ/I= -github.com/swaggo/gin-swagger v1.3.3/go.mod h1:ymsZuGpbbu+S7ZoQ49QPpZoDBj6uqhb8WizgQPVgWl0= -github.com/swaggo/swag v1.7.4 h1:up+ixy8yOqJKiFcuhMgkuYuF4xnevuhnFAXXF8OSfNg= -github.com/swaggo/swag v1.7.4/go.mod h1:zD8h6h4SPv7t3l+4BKdRquqW1ASWjKZgT6Qv9z3kNqI= +github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE= +github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg= +github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+zy8M= +github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= +github.com/swaggo/swag v1.8.12/go.mod h1:lNfm6Gg+oAq3zRJQNEMBE66LIJKM44mxFqhEEgy2its= +github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A= +github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo= +github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= +github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= @@ -365,35 +376,41 @@ golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -415,10 +432,11 @@ golang.org/x/sys v0.0.0-20191220220014-0732a990476f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -426,19 +444,26 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -446,12 +471,14 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= @@ -460,10 +487,10 @@ golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -471,6 +498,8 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1N golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -488,6 +517,7 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/clickhouse v0.4.2 h1:vt7WkXX0u5SeCDyR4w/Jz0ce25/tYqgoP3UUERgMZmY= @@ -506,3 +536,4 @@ gorm.io/gorm v1.25.2-0.20230610234218-206613868439/go.mod h1:L4uxeKpfBml98NYqVqw gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls= gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= +sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8= diff --git a/pkg/config/config.go b/pkg/config/config.go index 6b986bf..d350a03 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -4,172 +4,51 @@ package config import ( "os" "path/filepath" - "strings" - - "gopkg.in/yaml.v3" ) -var ( - // Conf config instance - Conf Config - - // ModeDev run mode as development - ModeDev = "dev" - // ModeProd run mode as production - ModeProd = "prod" - // WorkDir workspace dir - WorkDir string +// RunMode 列表 +const ( + RunModeDev RunMode = "dev" // 开发环境 + RunModeProd RunMode = "pro" // 生产环境 ) -// Mode run mode -type Mode struct { - Name string `yaml:"name"` - EnableHTTP bool `yaml:"enablehttp"` - HTTPPort int `yaml:"httpport"` - EnableGRPC bool `yaml:"enablegrpc"` - GRPCPort int `yaml:"grpcport"` - Host string `yaml:"host"` +// RunMode 运行模式 +type RunMode string + +// IsReleaseMode 是否 +func (mode RunMode) IsReleaseMode() bool { + return mode == RunModeProd } -// Database sql database -type Database struct { - Driver string `yaml:"driver"` - Source string `yaml:"source"` +// IsDevMode 是否时开发模式 +func (mode RunMode) IsDevMode() bool { + return mode == RunModeDev } -// General common -type General struct { - PageNum int `yaml:"pagenum"` // 前台每页文章数量 - PageSize int `yaml:"pagesize"` // 后台每页文章数量 - StartID int `yaml:"startid"` // 文章启始ID - DescPrefix string `yaml:"descprefix"` // 文章描述前缀 - Identifier string `yaml:"identifier"` // 文章截取标识 - Length int `yaml:"length"` // 文章预览长度 - Timezone string `yaml:"timezone"` // 时区 +// IsRunMode 是否是runmode +func (mode RunMode) IsRunMode() bool { + return mode == RunModeDev || mode == RunModeProd } -// Disqus comments -type Disqus struct { - ShortName string `yaml:"shortname"` - PublicKey string `yaml:"publickey"` - AccessToken string `yaml:"accesstoken"` -} - -// Twitter card -type Twitter struct { - Card string `yaml:"card"` - Site string `yaml:"site"` - Image string `yaml:"image"` - Address string `yaml:"address"` -} - -// Google analytics -type Google struct { - URL string `yaml:"url"` - Tid string `yaml:"tid"` - V string `yaml:"v"` - AdSense string `yaml:"adsense"` -} - -// Qiniu oss -type Qiniu struct { - Bucket string `yaml:"bucket"` - Domain string `yaml:"domain"` - AccessKey string `yaml:"accesskey"` - SecretKey string `yaml:"secretkey"` -} - -// FeedRPC feedr -type FeedRPC struct { - FeedrURL string `yaml:"feedrurl"` - PingRPC []string `yaml:"pingrpc"` -} - -// Account info -type Account struct { - Username string `yaml:"username"` // * - Password string `yaml:"password"` // * - Email string `yaml:"email"` - PhoneNumber string `yaml:"phonenumber"` - Address string `yaml:"address"` -} - -// Blogger info -type Blogger struct { - BlogName string `yaml:"blogname"` - SubTitle string `yaml:"subtitle"` - BeiAn string `yaml:"beian"` - BTitle string `yaml:"btitle"` - Copyright string `yaml:"copyright"` -} - -// EiBlogApp config -type EiBlogApp struct { - Mode - - StaticVersion int `yaml:"staticversion"` - HotWords []string `yaml:"hotwords"` - General General `yaml:"general"` - Disqus Disqus `yaml:"disqus"` - Google Google `yaml:"google"` - Qiniu Qiniu `yaml:"qiniu"` - Twitter Twitter `yaml:"twitter"` - FeedRPC FeedRPC `yaml:"feedrpc"` - Account Account `yaml:"account"` - Blogger Blogger `yaml:"blogger"` -} - -// BackupApp config -type BackupApp struct { - Mode - - BackupTo string `yaml:"backupto"` - Interval string `yaml:"interval"` // circle backup, default: 7d - Validity int `yaml:"validity"` // storage days, default: 60 - Qiniu Qiniu `yaml:"qiniu"` // qiniu config -} - -// Config app config -type Config struct { - RunMode string `yaml:"runmode"` - AppName string `yaml:"appname"` - Database Database `yaml:"database"` - ESHost string `yaml:"eshost"` - EiBlogApp EiBlogApp `yaml:"eiblogapp"` - BackupApp BackupApp `yaml:"backupapp"` -} - -// load config file -func init() { - // compatibility linux and windows - var err error - WorkDir = workDir() - path := filepath.Join(WorkDir, "conf", "app.yml") - - data, err := os.ReadFile(path) +// WalkWorkDir walk work dir +func WalkWorkDir() (string, error) { + gopath := os.Getenv("GOPATH") + workDir, err := os.Getwd() if err != nil { - panic(err) + return "", err } - err = yaml.Unmarshal(data, &Conf) - if err != nil { - panic(err) - } - // read run mode from env - Conf.RunMode = ModeDev - if runmode := os.Getenv("RUN_MODE"); runmode == ModeProd { - Conf.RunMode = runmode - } - // read env - readDBEnv() -} + // find work dir, try 3 times + for gopath != workDir && workDir != "/" { + dir := filepath.Join(workDir, "etc") -func readDBEnv() { - key := strings.ToUpper(Conf.AppName) + "_DB_DRIVER" - if d := os.Getenv(key); d != "" { - Conf.Database.Driver = d - } - key = strings.ToUpper(Conf.AppName) + "_DB_SOURCE" - if s := os.Getenv(key); s != "" { - Conf.Database.Source = s + _, err := os.Stat(dir) + if err == nil { + break + } + if !os.IsNotExist(err) { + return "", err + } + workDir = filepath.Dir(workDir) } + return workDir, nil } diff --git a/pkg/config/dev.go b/pkg/config/dev.go deleted file mode 100644 index 8601ed1..0000000 --- a/pkg/config/dev.go +++ /dev/null @@ -1,29 +0,0 @@ -// +build !prod - -// Package config provides ... -package config - -import ( - "os" - "path" - "path/filepath" -) - -// workDir recognize workspace dir -var workDir = func() string { - wd, err := os.Getwd() - if err != nil { - panic(err) - } - for wd != "" { - name := filepath.Join(wd, "conf") - _, err := os.Stat(name) - if err != nil { - dir, _ := path.Split(wd) - wd = path.Clean(dir) - continue - } - return wd - } - return "" -} diff --git a/pkg/config/enums.go b/pkg/config/enums.go new file mode 100644 index 0000000..3433513 --- /dev/null +++ b/pkg/config/enums.go @@ -0,0 +1,124 @@ +package config + +// APIMode 应用配置 +type APIMode struct { + // 运行模式,可根据不同模式做相关判断,如日志打印等 + RunMode RunMode + + // 服务名称,如 eiblog, backup + Name string + // 监听地址,如 0.0.0.0:9000 + Listen string + // 所属域名,如 deepzz.com + Host string + // 一般的应用都会有个密钥,可以用这个字段 + Secret string +} + +// Database 数据库配置 +type Database struct { + // 数据库驱动,如 sqlite, mysql, postgres 等 + Driver string + // 数据库连接字符串,如 + // sqlite:./db.sqlite + // mysql:root:123456@tcp(127.0.0.1:3306)/eiblog?charset=utf8mb4&parseTime=True&loc=Local + Source string +} + +// Disqus 评论配置 +type Disqus struct { + // 短名称,如 deepzz + ShortName string + // 公共密钥 wdSgxRm9rdGAlLKFcFdToBe3GT4SibmV7Y8EjJQ0r4GWXeKtxpopMAeIeoI2dTEg + PublicKey string + // 访问令牌, 需自行创建 + AccessToken string +} + +// Twitter 社交配置 +type Twitter struct { + // 卡片, 可选 summary, summary_large_image, player + Card string + // id号, 如 deepzz02 + Site string + // 图片, 如 st.deepzz.cn/static/img/avatar.jpg + Image string + // 地址, 如 twitter.com/deepzz02 + Address string +} + +// Google 分析配置 +type Google struct { + // url, 如 https://www.google-analytics.com/g/collect + URL string + // tid, 如 G-S085VRC5PF + Tid string + // v, 如 "2" + V string + // 如果开启广发, 配置 + AdSense string +} + +// Qiniu 对象存储配置 +type Qiniu struct { + // bucket, 如 eiblog + Bucket string + // domain, 如 st.deepzz.cn + Domain string + // accesskey, 如 1234567890 + AccessKey string + // secretkey, 如 1234567890 + SecretKey string +} + +// FeedRPC 订阅配置 +type FeedRPC struct { + // feedrurl, 如 https://deepzz.superfeedr.com/ + FeedrURL string + // pingrpc, 如 http://ping.baidu.com/ping/RPC2, http://rpc.pingomatic.com/ + PingRPC []string +} + +// General 博客通用配置 +type General struct { + // 前台每页文章数量, 一般配置为 10 + PageNum int + // 后台每页文章数量, 一般配置为 20 + PageSize int + // 文章描述前缀, 一般配置为 Desc: + DescPrefix string + // 文章截取标识, 一般配置为 + Identifier string + // 文章预览长度, 一般配置为 400 + Length int + // 时区, 一般配置为 Asia/Shanghai + Timezone string +} + +// Account 账户配置 +type Account struct { + // *必须配置, 后台登录用户名 + Username string + // *必须配置, 后台登录密码。登录后请后台立即修改 + Password string + // 邮箱, 用于显示 + Email string + // 手机号, 用于显示 + PhoneNumber string + // 地址, 用于显示 + Address string +} + +// Blogger 博客配置, 无需配置,程序默认初始化,可在后台更改 +type Blogger struct { + // 博客名称, 如 deepzz + BlogName string + // 格言, 如 Rome was not built in one day. + SubTitle string + // 备案号, 不填则不显示在网站底部, 如 蜀ICP备xxxxxxxx号-1 + BeiAn string + // 标题, 如 deepzz's Blog + BTitle string + // 版权, 如 本站使用「署名 4.0 国际」创作共享协议,转载请注明作者及原网址。 + Copyright string // 版权 +} diff --git a/pkg/config/pro.go b/pkg/config/pro.go deleted file mode 100644 index 75fe577..0000000 --- a/pkg/config/pro.go +++ /dev/null @@ -1,7 +0,0 @@ -// +build prod - -// Package config provides ... -package config - -// workDir production use current dir -var workDir = func() string { return "" } diff --git a/pkg/connector/db/db.go b/pkg/connector/db/db.go new file mode 100644 index 0000000..08b90df --- /dev/null +++ b/pkg/connector/db/db.go @@ -0,0 +1,46 @@ +package db + +import ( + "context" + "errors" + "net/url" + "time" + + "github.com/eiblog/eiblog/pkg/config" + + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/mongo/readpref" +) + +// NewMDB new mongodb +// https://docs.mongodb.com/manual/reference/connection-string/ +// mongodb://db0.example.com,db1.example.com,db2.example.com/dbname?replicaSet=myRepl&w=majority&wtimeoutMS=5000 +func NewMDB(opts config.Database) (*mongo.Database, error) { + if opts.Driver != "mongodb" { + return nil, errors.New("db: driver must be mongodb, but " + opts.Driver) + } + u, err := url.Parse(opts.Source) + if err != nil { + return nil, errors.New("db: " + err.Error()) + } + database := u.Path + if database == "" { + return nil, errors.New("db: please specify a database") + } + database = database[1:] + ctx, cancel := context.WithTimeout(context.Background(), time.Second*2) + defer cancel() + + // remove database + u.Path = "" + client, err := mongo.Connect(ctx, options.Client().ApplyURI(u.String())) + if err != nil { + return nil, err + } + err = client.Ping(ctx, readpref.Primary()) + if err != nil { + return nil, err + } + return client.Database(database), nil +} diff --git a/pkg/core/backup/api.go b/pkg/core/backup/api.go deleted file mode 100644 index 8c8daaa..0000000 --- a/pkg/core/backup/api.go +++ /dev/null @@ -1,8 +0,0 @@ -// Package backup provides ... -package backup - -// @title APP Demo API -// @version 1.0 -// @description This is a sample server celler server. - -// @BasePath /api diff --git a/pkg/core/backup/docs/docs.go b/pkg/core/backup/docs/docs.go deleted file mode 100644 index c182a22..0000000 --- a/pkg/core/backup/docs/docs.go +++ /dev/null @@ -1,80 +0,0 @@ -// Package docs GENERATED BY THE COMMAND ABOVE; DO NOT EDIT -// This file was generated by swaggo/swag -package docs - -import ( - "bytes" - "encoding/json" - "strings" - "text/template" - - "github.com/swaggo/swag" -) - -var doc = `{ - "schemes": {{ marshal .Schemes }}, - "swagger": "2.0", - "info": { - "description": "{{escape .Description}}", - "title": "{{.Title}}", - "contact": {}, - "version": "{{.Version}}" - }, - "host": "{{.Host}}", - "basePath": "{{.BasePath}}", - "paths": {} -}` - -type swaggerInfo struct { - Version string - Host string - BasePath string - Schemes []string - Title string - Description string -} - -// SwaggerInfo holds exported Swagger Info so clients can modify it -var SwaggerInfo = swaggerInfo{ - Version: "1.0", - Host: "", - BasePath: "/api", - Schemes: []string{}, - Title: "APP Demo API", - Description: "This is a sample server celler server.", -} - -type s struct{} - -func (s *s) ReadDoc() string { - sInfo := SwaggerInfo - sInfo.Description = strings.Replace(sInfo.Description, "\n", "\\n", -1) - - t, err := template.New("swagger_info").Funcs(template.FuncMap{ - "marshal": func(v interface{}) string { - a, _ := json.Marshal(v) - return string(a) - }, - "escape": func(v interface{}) string { - // escape tabs - str := strings.Replace(v.(string), "\t", "\\t", -1) - // replace " with \", and if that results in \\", replace that with \\\" - str = strings.Replace(str, "\"", "\\\"", -1) - return strings.Replace(str, "\\\\\"", "\\\\\\\"", -1) - }, - }).Parse(doc) - if err != nil { - return doc - } - - var tpl bytes.Buffer - if err := t.Execute(&tpl, sInfo); err != nil { - return doc - } - - return tpl.String() -} - -func init() { - swag.Register(swag.Name, &s{}) -} diff --git a/pkg/core/backup/docs/swagger.json b/pkg/core/backup/docs/swagger.json deleted file mode 100644 index 5cb49bd..0000000 --- a/pkg/core/backup/docs/swagger.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "description": "This is a sample server celler server.", - "title": "APP Demo API", - "contact": {}, - "version": "1.0" - }, - "basePath": "/api", - "paths": {} -} \ No newline at end of file diff --git a/pkg/core/backup/docs/swagger.yaml b/pkg/core/backup/docs/swagger.yaml deleted file mode 100644 index 79e4c37..0000000 --- a/pkg/core/backup/docs/swagger.yaml +++ /dev/null @@ -1,8 +0,0 @@ -basePath: /api -info: - contact: {} - description: This is a sample server celler server. - title: APP Demo API - version: "1.0" -paths: {} -swagger: "2.0" diff --git a/pkg/core/eiblog/api.go b/pkg/core/eiblog/api.go deleted file mode 100644 index dcf0d28..0000000 --- a/pkg/core/eiblog/api.go +++ /dev/null @@ -1,56 +0,0 @@ -// Package eiblog provides ... -package eiblog - -import ( - "net/http" - - "github.com/gin-contrib/sessions" - "github.com/gin-gonic/gin" -) - -// @title APP Demo API -// @version 1.0 -// @description This is a sample server celler server. - -// @BasePath /api - -// AuthFilter auth filter -func AuthFilter(c *gin.Context) { - if !IsLogined(c) { - c.Abort() - c.Status(http.StatusUnauthorized) - c.Redirect(http.StatusFound, "/admin/login") - return - } - - c.Next() -} - -// SetLogin login user -func SetLogin(c *gin.Context, username string) { - session := sessions.Default(c) - session.Set("username", username) - session.Save() -} - -// SetLogout logout user -func SetLogout(c *gin.Context) { - session := sessions.Default(c) - session.Delete("username") - session.Save() -} - -// IsLogined account logined -func IsLogined(c *gin.Context) bool { - return GetUsername(c) != "" -} - -// GetUsername get logined account -func GetUsername(c *gin.Context) string { - session := sessions.Default(c) - username := session.Get("username") - if username == nil { - return "" - } - return username.(string) -} diff --git a/pkg/core/eiblog/docs/docs.go b/pkg/core/eiblog/docs/docs.go deleted file mode 100644 index c182a22..0000000 --- a/pkg/core/eiblog/docs/docs.go +++ /dev/null @@ -1,80 +0,0 @@ -// Package docs GENERATED BY THE COMMAND ABOVE; DO NOT EDIT -// This file was generated by swaggo/swag -package docs - -import ( - "bytes" - "encoding/json" - "strings" - "text/template" - - "github.com/swaggo/swag" -) - -var doc = `{ - "schemes": {{ marshal .Schemes }}, - "swagger": "2.0", - "info": { - "description": "{{escape .Description}}", - "title": "{{.Title}}", - "contact": {}, - "version": "{{.Version}}" - }, - "host": "{{.Host}}", - "basePath": "{{.BasePath}}", - "paths": {} -}` - -type swaggerInfo struct { - Version string - Host string - BasePath string - Schemes []string - Title string - Description string -} - -// SwaggerInfo holds exported Swagger Info so clients can modify it -var SwaggerInfo = swaggerInfo{ - Version: "1.0", - Host: "", - BasePath: "/api", - Schemes: []string{}, - Title: "APP Demo API", - Description: "This is a sample server celler server.", -} - -type s struct{} - -func (s *s) ReadDoc() string { - sInfo := SwaggerInfo - sInfo.Description = strings.Replace(sInfo.Description, "\n", "\\n", -1) - - t, err := template.New("swagger_info").Funcs(template.FuncMap{ - "marshal": func(v interface{}) string { - a, _ := json.Marshal(v) - return string(a) - }, - "escape": func(v interface{}) string { - // escape tabs - str := strings.Replace(v.(string), "\t", "\\t", -1) - // replace " with \", and if that results in \\", replace that with \\\" - str = strings.Replace(str, "\"", "\\\"", -1) - return strings.Replace(str, "\\\\\"", "\\\\\\\"", -1) - }, - }).Parse(doc) - if err != nil { - return doc - } - - var tpl bytes.Buffer - if err := t.Execute(&tpl, sInfo); err != nil { - return doc - } - - return tpl.String() -} - -func init() { - swag.Register(swag.Name, &s{}) -} diff --git a/pkg/core/eiblog/docs/swagger.json b/pkg/core/eiblog/docs/swagger.json deleted file mode 100644 index 5cb49bd..0000000 --- a/pkg/core/eiblog/docs/swagger.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "description": "This is a sample server celler server.", - "title": "APP Demo API", - "contact": {}, - "version": "1.0" - }, - "basePath": "/api", - "paths": {} -} \ No newline at end of file diff --git a/pkg/core/eiblog/docs/swagger.yaml b/pkg/core/eiblog/docs/swagger.yaml deleted file mode 100644 index 79e4c37..0000000 --- a/pkg/core/eiblog/docs/swagger.yaml +++ /dev/null @@ -1,8 +0,0 @@ -basePath: /api -info: - contact: {} - description: This is a sample server celler server. - title: APP Demo API - version: "1.0" -paths: {} -swagger: "2.0" diff --git a/pkg/internal/CHANGELOG.md b/pkg/internal/CHANGELOG.md deleted file mode 100644 index aed0e0d..0000000 --- a/pkg/internal/CHANGELOG.md +++ /dev/null @@ -1,10 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. - -### [2.2.17](https://github.com/eiblog/eiblog/compare/v2.2.16...v2.2.17) (2025-04-22) - - -### Bug Fixes - -* backup file auto delete ([0fe849a](https://github.com/eiblog/eiblog/commit/0fe849ae67de36f2d249e3306ac7d098bc057070)) diff --git a/pkg/internal/http.go b/pkg/internal/http.go deleted file mode 100644 index 78e6f3e..0000000 --- a/pkg/internal/http.go +++ /dev/null @@ -1,139 +0,0 @@ -// Package internal provides ... -package internal - -import ( - "bytes" - "crypto/tls" - "fmt" - "net" - "net/http" - "net/url" - "strings" - "time" -) - -var httpClient = &http.Client{ - Transport: &http.Transport{ - Proxy: http.ProxyFromEnvironment, - DialContext: (&net.Dialer{ - Timeout: 30 * time.Second, - KeepAlive: 30 * time.Second, - DualStack: true, - }).DialContext, - ForceAttemptHTTP2: true, - MaxIdleConns: 100, - IdleConnTimeout: 90 * time.Second, - TLSHandshakeTimeout: 10 * time.Second, - ExpectContinueTimeout: 1 * time.Second, - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - }, - }, -} - -func newRequest(method, rawurl string, data interface{}) (*http.Request, error) { - u, err := url.Parse(rawurl) - if err != nil { - return nil, err - } - originHost := u.Host - // 获取主机IP - host, port, err := net.SplitHostPort(u.Host) - if err != nil { - addrErr := err.(*net.AddrError) - if addrErr.Err != "missing port in address" { - return nil, err - } - // set default value - host = originHost - switch u.Scheme { - case "http": - port = "80" - case "https": - port = "443" - } - } - ips, err := net.LookupHost(host) - if err != nil { - return nil, err - } - if len(ips) == 0 { - return nil, fmt.Errorf("http: not found ip(%s)", u.Host) - } - host = net.JoinHostPort(ips[0], port) - u.Host = host - // 创建HTTP Request - var req *http.Request - switch raw := data.(type) { - case url.Values: - req, err = http.NewRequest(method, u.String(), - strings.NewReader(raw.Encode())) - req.Header.Set("Content-Type", "application/x-www-form-urlencoded") - case []byte: - req, err = http.NewRequest(method, u.String(), - bytes.NewReader(raw)) - case nil: - req, err = http.NewRequest(method, u.String(), nil) - default: - return nil, fmt.Errorf("http: unsupported data type: %T", data) - } - if err != nil { - return nil, err - } - // 设置Host - req.Host = originHost - return req, nil -} - -// httpHead HTTP HEAD请求 -func httpHead(rawurl string) (*http.Response, error) { - req, err := newRequest(http.MethodHead, rawurl, nil) - if err != nil { - return nil, err - } - return httpClient.Do(req) -} - -// httpGet HTTP GET请求 -func httpGet(rawurl string) (*http.Response, error) { - req, err := newRequest(http.MethodGet, rawurl, nil) - if err != nil { - return nil, err - } - // 发起请求 - return httpClient.Do(req) -} - -// httpPost HTTP POST请求, 自动识别是否是form -func httpPost(rawurl string, data interface{}) (*http.Response, error) { - req, err := newRequest(http.MethodPost, rawurl, data) - if err != nil { - return nil, err - } - // 发起请求 - return httpClient.Do(req) -} - -// httpPostHeader HTTP POST请求,自定义Header -func httpPostHeader(rawurl string, data interface{}, - header http.Header) (*http.Response, error) { - - req, err := newRequest(http.MethodPost, rawurl, data) - if err != nil { - return nil, err - } - // set header - req.Header = header - // 发起请求 - return httpClient.Do(req) -} - -// httpPut HTTP PUT请求 -func httpPut(rawurl string, data interface{}) (*http.Response, error) { - req, err := newRequest(http.MethodPut, rawurl, data) - if err != nil { - return nil, err - } - // 发起请求 - return httpClient.Do(req) -} diff --git a/pkg/mid/language.go b/pkg/mid/language.go deleted file mode 100644 index f6a30f8..0000000 --- a/pkg/mid/language.go +++ /dev/null @@ -1,55 +0,0 @@ -// Package mid provides ... -package mid - -import ( - "strings" - - "github.com/gin-gonic/gin" -) - -// LangOpts 语言选项 -type LangOpts struct { - CookieName string - Default string - Supported []string -} - -// isExist language -func (opts LangOpts) isExist(l string) bool { - for _, v := range opts.Supported { - if v == l { - return true - } - } - return false -} - -// LangMiddleware set language -func LangMiddleware(opts LangOpts) gin.HandlerFunc { - return func(c *gin.Context) { - lang, err := c.Cookie(opts.CookieName) - // found cookie - if err == nil { - c.Set(opts.CookieName, lang) - return - } - // set cookie - al := strings.ToLower(c.GetHeader("Accept-Language")) - if al != "" { - // choose default if not supported - lang = opts.Default - - langs := strings.Split(al, ",") - for _, v := range langs { - if opts.isExist(v) { - lang = v - break - } - } - } else { - lang = opts.Default - } - c.SetCookie(opts.CookieName, lang, 86400*365, "/", "", false, false) - c.Set(opts.CookieName, lang) - } -} diff --git a/pkg/mid/session.go b/pkg/mid/session.go deleted file mode 100644 index 173d647..0000000 --- a/pkg/mid/session.go +++ /dev/null @@ -1,34 +0,0 @@ -// Package mid provides ... -package mid - -import ( - "github.com/gin-contrib/sessions" - "github.com/gin-contrib/sessions/cookie" - "github.com/gin-gonic/gin" -) - -// SessionOpts 设置选项 -type SessionOpts struct { - Name string - Secure bool // required - Secret []byte // required - // redis store - RedisAddr string - RedisPwd string -} - -// SessionMiddleware session中间件 -func SessionMiddleware(opts SessionOpts) gin.HandlerFunc { - store := cookie.NewStore(opts.Secret) - store.Options(sessions.Options{ - MaxAge: 86400 * 30, - Path: "/", - Secure: opts.Secure, - HttpOnly: true, - }) - name := "SESSIONID" - if opts.Name != "" { - name = opts.Name - } - return sessions.Sessions(name, store) -} diff --git a/pkg/mid/u.go b/pkg/mid/u.go deleted file mode 100644 index d123080..0000000 --- a/pkg/mid/u.go +++ /dev/null @@ -1,18 +0,0 @@ -// Package mid provides ... -package mid - -import ( - "github.com/gin-gonic/gin" - uuid "github.com/satori/go.uuid" -) - -// UserMiddleware 用户cookie标记 -func UserMiddleware() gin.HandlerFunc { - return func(c *gin.Context) { - cookie, err := c.Cookie("u") - if err != nil || cookie == "" { - u1 := uuid.NewV4().String() - c.SetCookie("u", u1, 86400*730, "/", "", true, true) - } - } -} diff --git a/pkg/middleware/session.go b/pkg/middleware/session.go new file mode 100644 index 0000000..2a511ef --- /dev/null +++ b/pkg/middleware/session.go @@ -0,0 +1,88 @@ +package middleware + +import ( + "net/http" + + "github.com/gin-contrib/sessions" + "github.com/gin-contrib/sessions/cookie" + "github.com/gin-gonic/gin" + uuid "github.com/satori/go.uuid" +) + +// SessionOpts 设置选项 +type SessionOpts struct { + Name string + Secure bool // required + Secret []byte // required + // redis store + RedisAddr string + RedisPwd string +} + +// SessionMiddleware session中间件 +func SessionMiddleware(opts SessionOpts) gin.HandlerFunc { + store := cookie.NewStore(opts.Secret) + store.Options(sessions.Options{ + MaxAge: 86400 * 30, + Path: "/", + Secure: opts.Secure, + HttpOnly: true, + }) + name := "SESSIONID" + if opts.Name != "" { + name = opts.Name + } + return sessions.Sessions(name, store) +} + +// UserMiddleware 用户cookie标记 +func UserMiddleware() gin.HandlerFunc { + return func(c *gin.Context) { + cookie, err := c.Cookie("u") + if err != nil || cookie == "" { + u1 := uuid.NewV4().String() + c.SetCookie("u", u1, 86400*730, "/", "", true, true) + } + } +} + +// AuthFilter auth filter +func AuthFilter(c *gin.Context) { + if !IsLogined(c) { + c.Abort() + c.Status(http.StatusUnauthorized) + c.Redirect(http.StatusFound, "/admin/login") + return + } + + c.Next() +} + +// SetLogin login user +func SetLogin(c *gin.Context, username string) { + session := sessions.Default(c) + session.Set("username", username) + session.Save() +} + +// SetLogout logout user +func SetLogout(c *gin.Context) { + session := sessions.Default(c) + session.Delete("username") + session.Save() +} + +// IsLogined account logined +func IsLogined(c *gin.Context) bool { + return GetUsername(c) != "" +} + +// GetUsername get logined account +func GetUsername(c *gin.Context) string { + session := sessions.Default(c) + username := session.Get("username") + if username == nil { + return "" + } + return username.(string) +} diff --git a/pkg/internal/disqus.go b/pkg/third/disqus/disqus.go similarity index 68% rename from pkg/internal/disqus.go rename to pkg/third/disqus/disqus.go index a78d0fc..4a1a44a 100644 --- a/pkg/internal/disqus.go +++ b/pkg/third/disqus/disqus.go @@ -1,5 +1,4 @@ -// Package internal provides ... -package internal +package disqus import ( "encoding/json" @@ -26,13 +25,19 @@ const ( disqusAPIKey = "E8Uh5l5fHZ6gD8U3KycjAIAk46f68Zw7C6eW8WSjZvCLXebZ7p0r1yrYDrLilk2F" ) -func checkDisqusConfig() error { - if config.Conf.EiBlogApp.Disqus.ShortName != "" && - config.Conf.EiBlogApp.Disqus.PublicKey != "" && - config.Conf.EiBlogApp.Disqus.AccessToken != "" { - return nil +// DisqusClient disqus client +type DisqusClient struct { + Host string + + Conf config.Disqus +} + +// NewDisqusClient new disqus client +func NewDisqusClient(host string, conf config.Disqus) (*DisqusClient, error) { + if conf.ShortName == "" || conf.PublicKey == "" || conf.AccessToken == "" { + return nil, errors.New("disqus: config incompleted") } - return errors.New("disqus: config incompleted") + return &DisqusClient{Host: host, Conf: conf}, nil } // postsCountResp 评论数量响应 @@ -46,14 +51,10 @@ type postsCountResp struct { } // PostsCount 获取文章评论数量 -func PostsCount(articles map[string]*model.Article) error { - if err := checkDisqusConfig(); err != nil { - return err - } - +func (cli *DisqusClient) PostsCount(articles map[string]*model.Article) error { vals := url.Values{} - vals.Set("api_key", config.Conf.EiBlogApp.Disqus.PublicKey) - vals.Set("forum", config.Conf.EiBlogApp.Disqus.ShortName) + vals.Set("api_key", cli.Conf.PublicKey) + vals.Set("forum", cli.Conf.ShortName) // batch get var count, index int for _, article := range articles { @@ -65,7 +66,7 @@ func PostsCount(articles map[string]*model.Article) error { continue } count = 0 - resp, err := httpGet(apiPostsCount + "?" + vals.Encode()) + resp, err := http.DefaultClient.Get(apiPostsCount + "?" + vals.Encode()) if err != nil { return err } @@ -127,20 +128,16 @@ type postDetail struct { } // PostsList 评论列表 -func PostsList(article *model.Article, cursor string) (*PostsListResp, error) { - if err := checkDisqusConfig(); err != nil { - return nil, err - } - +func (cli *DisqusClient) PostsList(article *model.Article, cursor string) (*PostsListResp, error) { vals := url.Values{} vals.Set("api_key", disqusAPIKey) - vals.Set("forum", config.Conf.EiBlogApp.Disqus.ShortName) + vals.Set("forum", cli.Conf.ShortName) vals.Set("thread:ident", "post-"+article.Slug) vals.Set("cursor", cursor) vals.Set("order", "popular") vals.Set("limit", "50") - resp, err := httpGet(apiPostsList + "?" + vals.Encode()) + resp, err := http.DefaultClient.Get(apiPostsList + "?" + vals.Encode()) if err != nil { return nil, err } @@ -181,10 +178,7 @@ type PostCreateResp struct { } // PostCreate 评论文章 -func PostCreate(pc *PostComment) (*PostCreateResp, error) { - if err := checkDisqusConfig(); err != nil { - return nil, err - } +func (cli *DisqusClient) PostCreate(pc *PostComment) (*PostCreateResp, error) { vals := url.Values{} vals.Set("api_key", disqusAPIKey) vals.Set("message", pc.Message) @@ -194,8 +188,14 @@ func PostCreate(pc *PostComment) (*PostCreateResp, error) { vals.Set("author_name", pc.AuthorName) // vals.Set("state", "approved") - header := http.Header{"Referer": {"https://disqus.com"}} - resp, err := httpPostHeader(apiPostCreate, vals, header) + req, err := http.NewRequest(http.MethodPost, apiPostCreate, strings.NewReader(vals.Encode())) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + req.Header.Set("Referer", "https://disqus.com") + + resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } @@ -225,18 +225,19 @@ type approvedResp struct { } // PostApprove 批准评论 -func PostApprove(post string) error { - if err := checkDisqusConfig(); err != nil { - return err - } - +func (cli *DisqusClient) PostApprove(post string) error { vals := url.Values{} - vals.Set("api_key", config.Conf.EiBlogApp.Disqus.PublicKey) - vals.Set("access_token", config.Conf.EiBlogApp.Disqus.AccessToken) + vals.Set("api_key", disqusAPIKey) + vals.Set("access_token", cli.Conf.AccessToken) vals.Set("post", post) - header := http.Header{"Referer": {"https://disqus.com"}} - resp, err := httpPostHeader(apiPostApprove, vals, header) + req, err := http.NewRequest(http.MethodPost, apiPostApprove, strings.NewReader(vals.Encode())) + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + req.Header.Set("Referer", "https://disqus.com") + if err != nil { + return err + } + resp, err := http.DefaultClient.Do(req) if err != nil { return err } @@ -264,26 +265,28 @@ type threadCreateResp struct { } // ThreadCreate 创建thread -func ThreadCreate(article *model.Article, btitle string) error { - if err := checkDisqusConfig(); err != nil { - return err - } - +func (cli *DisqusClient) ThreadCreate(article *model.Article, btitle string) error { vals := url.Values{} - vals.Set("api_key", config.Conf.EiBlogApp.Disqus.PublicKey) - vals.Set("access_token", config.Conf.EiBlogApp.Disqus.AccessToken) - vals.Set("forum", config.Conf.EiBlogApp.Disqus.ShortName) + vals.Set("api_key", disqusAPIKey) + vals.Set("access_token", cli.Conf.AccessToken) + vals.Set("forum", cli.Conf.ShortName) vals.Set("title", article.Title+" | "+btitle) vals.Set("identifier", "post-"+article.Slug) - urlPath := fmt.Sprintf("https://%s/post/%s.html", config.Conf.EiBlogApp.Host, article.Slug) + urlPath := fmt.Sprintf("https://%s/post/%s.html", cli.Host, article.Slug) vals.Set("url", urlPath) - resp, err := httpPost(apiThreadCreate, vals) + req, err := http.NewRequest(http.MethodPost, apiThreadCreate, strings.NewReader(vals.Encode())) if err != nil { return err } + req.Header.Set("Content-Type", "application/x-www-form-urlencoded") + req.Header.Set("Referer", "https://disqus.com") + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } b, err := io.ReadAll(resp.Body) if err != nil { return err @@ -311,18 +314,14 @@ type threadDetailsResp struct { } // ThreadDetails thread详细 -func ThreadDetails(article *model.Article) error { - if err := checkDisqusConfig(); err != nil { - return err - } - +func (cli *DisqusClient) ThreadDetails(article *model.Article) error { vals := url.Values{} - vals.Set("api_key", config.Conf.EiBlogApp.Disqus.PublicKey) - vals.Set("access_token", config.Conf.EiBlogApp.Disqus.AccessToken) - vals.Set("forum", config.Conf.EiBlogApp.Disqus.ShortName) + vals.Set("api_key", disqusAPIKey) + vals.Set("access_token", cli.Conf.AccessToken) + vals.Set("forum", cli.Conf.ShortName) vals.Set("thread:ident", "post-"+article.Slug) - resp, err := httpGet(apiThreadDetails + "?" + vals.Encode()) + resp, err := http.DefaultClient.Get(apiThreadDetails + "?" + vals.Encode()) if err != nil { return err } diff --git a/pkg/internal/es.go b/pkg/third/es/es.go similarity index 66% rename from pkg/internal/es.go rename to pkg/third/es/es.go index 932c99f..9eb088c 100644 --- a/pkg/internal/es.go +++ b/pkg/third/es/es.go @@ -1,5 +1,4 @@ -// Package internal provides ... -package internal +package es import ( "bytes" @@ -12,7 +11,6 @@ import ( "strings" "time" - "github.com/eiblog/eiblog/pkg/config" "github.com/eiblog/eiblog/pkg/model" "github.com/eiblog/eiblog/tools" @@ -29,30 +27,26 @@ const ( ElasticType = "article" ) -func init() { - if checkESConfig() != nil { - return - } - - mappings := fmt.Sprintf(`{"mappings":{"%s":{"properties":{"content":{"analyzer":"ik_syno","search_analyzer":"ik_syno","term_vector":"with_positions_offsets","type":"string"},"date":{"index":"not_analyzed","type":"date"},"slug":{"type":"string"},"tag":{"index":"not_analyzed","type":"string"},"title":{"analyzer":"ik_syno","search_analyzer":"ik_syno","term_vector":"with_positions_offsets","type":"string"}}}}}`, "article") - err := createIndexAndMappings(ElasticIndex, ElasticType, []byte(mappings)) - if err != nil { - panic(err) - } +// ESClient es client +type ESClient struct { + Host string } -func checkESConfig() error { - if config.Conf.ESHost == "" { - return errors.New("es: elasticsearch not config") +// NewESClient new es client +func NewESClient(host string) (*ESClient, error) { + if host == "" { + return nil, errors.New("es: elasticsearch host is empty") } - return nil + es := &ESClient{Host: host} + err := es.createIndexAndMappings(ElasticIndex, ElasticType) + if err != nil { + return nil, err + } + return es, nil } // ElasticSearch 搜索文章 -func ElasticSearch(query string, size, from int) (*SearchIndexResult, error) { - if err := checkESConfig(); err != nil { - return nil, err - } +func (cli *ESClient) ElasticSearch(query string, size, from int) (*SearchIndexResult, error) { // 分析查询 var ( regTerm = regexp.MustCompile(`(tag|slug|date):`) @@ -100,17 +94,13 @@ func ElasticSearch(query string, size, from int) (*SearchIndexResult, error) { // 判断是否为空,判断搜索方式 dsl := fmt.Sprintf("{"+SearchFilter+"}", strings.Join(filter, ",")) if kw != "" { - dsl = strings.Replace(strings.Replace(`{"highlight":{"fields":{"content":{},"title":{}},"post_tags":["\u003c/b\u003e"],"pre_tags":["\u003cb\u003e"]},"query":{"dis_max":{"queries":[{"match":{"title":{"boost":4,"minimum_should_match":"50%","query":"$1"}}},{"match":{"content":{"boost":4,"minimum_should_match":"75%","query":"$1"}}},{"match":{"tag":{"boost":2,"minimum_should_match":"100%","query":"$1"}}},{"match":{"slug":{"boost":1,"minimum_should_match":"100%","query":"$1"}}}],"tie_breaker":0.3}},$2}`, "$1", kw, -1), "$2", fmt.Sprintf(SearchFilter, strings.Join(filter, ",")), -1) + dsl = strings.ReplaceAll(strings.ReplaceAll(`{"highlight":{"fields":{"content":{},"title":{}},"post_tags":["\u003c/b\u003e"],"pre_tags":["\u003cb\u003e"]},"query":{"dis_max":{"queries":[{"match":{"title":{"boost":4,"minimum_should_match":"50%","query":"$1"}}},{"match":{"content":{"boost":4,"minimum_should_match":"75%","query":"$1"}}},{"match":{"tag":{"boost":2,"minimum_should_match":"100%","query":"$1"}}},{"match":{"slug":{"boost":1,"minimum_should_match":"100%","query":"$1"}}}],"tie_breaker":0.3}},$2}`, "$1", kw), "$2", fmt.Sprintf(SearchFilter, strings.Join(filter, ","))) } - return indexQueryDSL(ElasticIndex, ElasticType, size, from, []byte(dsl)) + return cli.indexQueryDSL(ElasticIndex, ElasticType, size, from, []byte(dsl)) } // ElasticAddIndex 添加或更新索引 -func ElasticAddIndex(article *model.Article) error { - if err := checkESConfig(); err != nil { - return err - } - +func (cli *ESClient) ElasticAddIndex(article *model.Article) error { img := tools.PickFirstImage(article.Content) mapping := map[string]interface{}{ "title": article.Title, @@ -121,20 +111,16 @@ func ElasticAddIndex(article *model.Article) error { "date": article.CreatedAt, } data, _ := json.Marshal(mapping) - return indexOrUpdateDocument(ElasticIndex, ElasticType, article.ID, data) + return cli.indexOrUpdateDocument(ElasticIndex, ElasticType, article.ID, data) } // ElasticDelIndex 删除索引 -func ElasticDelIndex(ids []int) error { - if err := checkESConfig(); err != nil { - return err - } - +func (cli *ESClient) ElasticDelIndex(ids []int) error { var target []string for _, id := range ids { target = append(target, fmt.Sprint(id)) } - return deleteIndexDocument(ElasticIndex, ElasticType, target) + return cli.deleteIndexDocument(ElasticIndex, ElasticType, target) } // indicesCreateResult 索引创建结果 @@ -143,9 +129,11 @@ type indicesCreateResult struct { } // createIndexAndMappings 创建索引和映射关系 -func createIndexAndMappings(index, typ string, mappings []byte) error { - rawurl := fmt.Sprintf("%s/%s/%s", config.Conf.ESHost, index, typ) - resp, err := httpHead(rawurl) +func (cli *ESClient) createIndexAndMappings(index, typ string) error { + mappings := fmt.Sprintf(`{"mappings":{"%s":{"properties":{"content":{"analyzer":"ik_syno","search_analyzer":"ik_syno","term_vector":"with_positions_offsets","type":"string"},"date":{"index":"not_analyzed","type":"date"},"slug":{"type":"string"},"tag":{"index":"not_analyzed","type":"string"},"title":{"analyzer":"ik_syno","search_analyzer":"ik_syno","term_vector":"with_positions_offsets","type":"string"}}}}}`, typ) + + rawurl := fmt.Sprintf("%s/%s/%s", cli.Host, index, typ) + resp, err := http.DefaultClient.Head(rawurl) if err != nil { return err } @@ -154,8 +142,13 @@ func createIndexAndMappings(index, typ string, mappings []byte) error { return nil } - rawurl = fmt.Sprintf("%s/%s", config.Conf.ESHost, index) - resp, err = httpPut(rawurl, mappings) + rawurl = fmt.Sprintf("%s/%s", cli.Host, index) + req, err := http.NewRequest(http.MethodPut, rawurl, bytes.NewReader([]byte(mappings))) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + resp, err = http.DefaultClient.Do(req) if err != nil { return err } @@ -176,9 +169,15 @@ func createIndexAndMappings(index, typ string, mappings []byte) error { } // indexOrUpdateDocument 创建或更新索引 -func indexOrUpdateDocument(index, typ string, id int, doc []byte) (err error) { - rawurl := fmt.Sprintf("%s/%s/%s/%d", config.Conf.ESHost, index, typ, id) - resp, err := httpPut(rawurl, doc) +func (cli *ESClient) indexOrUpdateDocument(index, typ string, id int, doc []byte) (err error) { + rawurl := fmt.Sprintf("%s/%s/%s/%d", cli.Host, index, typ, id) + + req, err := http.NewRequest(http.MethodPut, rawurl, bytes.NewReader(doc)) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + resp, err := http.DefaultClient.Do(req) if err != nil { return err } @@ -205,7 +204,7 @@ type deleteIndexResult struct { } // deleteIndexDocument 删除文档 -func deleteIndexDocument(index, typ string, ids []string) error { +func (cli *ESClient) deleteIndexDocument(index, typ string, ids []string) error { buf := bytes.Buffer{} for _, id := range ids { dd := deleteIndexReq{Index: index, Type: typ, ID: id} @@ -214,8 +213,13 @@ func deleteIndexDocument(index, typ string, ids []string) error { buf.Write(b) buf.WriteByte('\n') } - rawurl := fmt.Sprintf("%s/_bulk", config.Conf.ESHost) - resp, err := httpPost(rawurl, buf.Bytes()) + rawurl := fmt.Sprintf("%s/_bulk", cli.Host) + req, err := http.NewRequest(http.MethodPost, rawurl, bytes.NewReader(buf.Bytes())) + if err != nil { + return err + } + req.Header.Set("Content-Type", "application/json") + resp, err := http.DefaultClient.Do(req) if err != nil { return err } @@ -264,10 +268,10 @@ type SearchIndexResult struct { } // indexQueryDSL 语句查询文档 -func indexQueryDSL(index, typ string, size, from int, dsl []byte) (*SearchIndexResult, error) { - rawurl := fmt.Sprintf("%s/%s/%s/_search?size=%d&from=%d", config.Conf.ESHost, +func (c *ESClient) indexQueryDSL(index, typ string, size, from int, dsl []byte) (*SearchIndexResult, error) { + rawurl := fmt.Sprintf("%s/%s/%s/_search?size=%d&from=%d", c.Host, index, typ, size, from) - resp, err := httpPost(rawurl, dsl) + resp, err := http.Post(rawurl, "application/json", bytes.NewReader(dsl)) if err != nil { return nil, err } diff --git a/pkg/internal/pinger.go b/pkg/third/pinger/pinger.go similarity index 62% rename from pkg/internal/pinger.go rename to pkg/third/pinger/pinger.go index 53ad056..590cdb4 100644 --- a/pkg/internal/pinger.go +++ b/pkg/third/pinger/pinger.go @@ -1,5 +1,4 @@ -// Package internal provides ... -package internal +package pinger import ( "bytes" @@ -14,29 +13,50 @@ import ( "github.com/sirupsen/logrus" ) -// feedrPingFunc http://.superfeedr.com/ -var feedrPingFunc = func(btitle, slug string) error { - feedrHost := config.Conf.EiBlogApp.FeedRPC.FeedrURL - if feedrHost == "" { - return nil - } +// Pinger pinger +type Pinger struct { + Host string + Conf config.FeedRPC +} + +// NewPinger new pinger +func NewPinger(host string, conf config.FeedRPC) (*Pinger, error) { + if conf.FeedrURL == "" { + return nil, fmt.Errorf("feedr url is empty") + } + return &Pinger{Host: host, Conf: conf}, nil +} + +// PingFunc ping blog article to SE +func (p *Pinger) PingFunc(btitle, slug string) { + err := p.feedrPingFunc(btitle, slug) + if err != nil { + logrus.Error("pinger: PingFunc feedr: ", err) + } + err = p.rpcPingFunc(btitle, slug) + if err != nil { + logrus.Error("pinger: PingFunc: rpc: ", err) + } +} + +// feedrPingFunc http://.superfeedr.com/ +func (p *Pinger) feedrPingFunc(btitle, slug string) error { vals := url.Values{} vals.Set("hub.mode", "publish") - vals.Add("hub.url", fmt.Sprintf("https://%s/post/%s.html", - config.Conf.BackupApp.Host, slug)) - resp, err := httpPost(feedrHost, vals) + vals.Add("hub.url", fmt.Sprintf("https://%s/post/%s.html", p.Host, slug)) + resp, err := http.DefaultClient.PostForm(p.Conf.FeedrURL, vals) if err != nil { return err } defer resp.Body.Close() + data, err := io.ReadAll(resp.Body) if err != nil { return err } if resp.StatusCode != 204 { - return fmt.Errorf("pinger: status code: %d, %s", - resp.StatusCode, string(data)) + return fmt.Errorf("pinger: status code: %d, %s", resp.StatusCode, string(data)) } return nil } @@ -61,16 +81,13 @@ type rpcValue struct { } // rpcPingFunc ping rpc -var rpcPingFunc = func(btitle, slug string) error { - if len(config.Conf.EiBlogApp.FeedRPC.PingRPC) == 0 { - return nil - } +func (p *Pinger) rpcPingFunc(btitle, slug string) error { param := rpcPingParam{MethodName: "weblogUpdates.extendedPing"} param.Params.Param = [4]rpcValue{ - 0: rpcValue{Value: btitle}, - 1: rpcValue{Value: "https://" + config.Conf.EiBlogApp.Host}, - 2: rpcValue{Value: fmt.Sprintf("https://%s/post/%s.html", config.Conf.EiBlogApp.Host, slug)}, - 3: rpcValue{Value: "https://" + config.Conf.EiBlogApp.Host + "/rss.html"}, + 0: {Value: btitle}, + 1: {Value: "https://" + p.Host}, + 2: {Value: fmt.Sprintf("https://%s/post/%s.html", p.Host, slug)}, + 3: {Value: "https://" + p.Host + "/rss.html"}, } buf := bytes.Buffer{} buf.WriteString(xml.Header) @@ -81,13 +98,15 @@ var rpcPingFunc = func(btitle, slug string) error { data := buf.Bytes() header := http.Header{} header.Set("Content-Type", "text/xml") - for _, addr := range config.Conf.EiBlogApp.FeedRPC.PingRPC { - resp, err := httpPostHeader(addr, data, header) + + for _, addr := range p.Conf.PingRPC { + resp, err := http.DefaultClient.Post(addr, "text/xml", bytes.NewReader(data)) if err != nil { logrus.Error("rpcPingFunc.httpPostHeader: ", err) continue } defer resp.Body.Close() + data, err := io.ReadAll(resp.Body) if err != nil { logrus.Error("rpcPingFunc.ReadAll: ", err) @@ -99,15 +118,3 @@ var rpcPingFunc = func(btitle, slug string) error { } return nil } - -// PingFunc ping blog article to SE -func PingFunc(btitle, slug string) { - err := feedrPingFunc(btitle, slug) - if err != nil { - logrus.Error("pinger: PingFunc feedr: ", err) - } - err = rpcPingFunc(btitle, slug) - if err != nil { - logrus.Error("pinger: PingFunc: rpc: ", err) - } -} diff --git a/pkg/internal/qiniu.go b/pkg/third/qiniu/qiniu.go similarity index 58% rename from pkg/internal/qiniu.go rename to pkg/third/qiniu/qiniu.go index 44a74ce..2222ad7 100644 --- a/pkg/internal/qiniu.go +++ b/pkg/third/qiniu/qiniu.go @@ -1,5 +1,4 @@ -// Package internal provides ... -package internal +package qiniu import ( "context" @@ -15,39 +14,49 @@ import ( "github.com/qiniu/go-sdk/v7/storage" ) +// QiniuClient qiniu client +type QiniuClient struct { + Conf config.Qiniu +} + +// NewQiniuClient new qiniu client +func NewQiniuClient(conf config.Qiniu) (*QiniuClient, error) { + if conf.AccessKey == "" || + conf.SecretKey == "" || + conf.Bucket == "" || + conf.Domain == "" { + return nil, errors.New("qiniu config error") + } + return &QiniuClient{Conf: conf}, nil +} + // UploadParams upload params type UploadParams struct { Name string Size int64 Data io.Reader NoCompletePath bool - - Conf config.Qiniu } -// QiniuUpload 上传文件 -func QiniuUpload(params UploadParams) (string, error) { - if params.Conf.AccessKey == "" || - params.Conf.SecretKey == "" { - return "", errors.New("qiniu config error") - } +// Upload 上传文件 +func (cli *QiniuClient) Upload(params UploadParams) (string, error) { key := params.Name if !params.NoCompletePath { key = filepath.Base(params.Name) } - mac := qbox.NewMac(params.Conf.AccessKey, - params.Conf.SecretKey) + mac := qbox.NewMac(cli.Conf.AccessKey, + cli.Conf.SecretKey) // 设置上传策略 putPolicy := &storage.PutPolicy{ - Scope: params.Conf.Bucket, + Scope: cli.Conf.Bucket, Expires: 3600, InsertOnly: 1, } // 上传token uploadToken := putPolicy.UploadToken(mac) // 上传配置 - region, err := storage.GetRegion(params.Conf.AccessKey, params.Conf.Bucket) + region, err := storage.GetRegion(cli.Conf.AccessKey, cli.Conf.Bucket) if err != nil { return "", err } @@ -65,7 +74,7 @@ func QiniuUpload(params UploadParams) (string, error) { if err != nil { return "", err } - url := "https://" + params.Conf.Domain + "/" + key + url := "https://" + cli.Conf.Domain + "/" + key return url, nil } @@ -74,21 +83,19 @@ type DeleteParams struct { Name string Days int NoCompletePath bool - - Conf config.Qiniu } // QiniuDelete 删除文件 -func QiniuDelete(params DeleteParams) error { +func (cli *QiniuClient) Delete(params DeleteParams) error { key := params.Name if !params.NoCompletePath { key = completeQiniuKey(params.Name) } - mac := qbox.NewMac(params.Conf.AccessKey, - params.Conf.SecretKey) + mac := qbox.NewMac(cli.Conf.AccessKey, + cli.Conf.SecretKey) // 上传配置 - region, err := storage.GetRegion(params.Conf.AccessKey, params.Conf.Bucket) + region, err := storage.GetRegion(cli.Conf.AccessKey, cli.Conf.Bucket) if err != nil { return err } @@ -100,24 +107,22 @@ func QiniuDelete(params DeleteParams) error { bucketManager := storage.NewBucketManager(mac, cfg) // Delete if params.Days > 0 { - return bucketManager.DeleteAfterDays(params.Conf.Bucket, key, params.Days) + return bucketManager.DeleteAfterDays(cli.Conf.Bucket, key, params.Days) } - return bucketManager.Delete(params.Conf.Bucket, key) + return bucketManager.Delete(cli.Conf.Bucket, key) } // ContentParams list params type ContentParams struct { Prefix string - - Conf config.Qiniu } -// QiniuContent 获取文件列表 -func QiniuContent(params ContentParams) ([]byte, error) { - mac := qbox.NewMac(params.Conf.AccessKey, - params.Conf.SecretKey) +// Content 获取文件内容 +func (cli *QiniuClient) Content(params ContentParams) ([]byte, error) { + mac := qbox.NewMac(cli.Conf.AccessKey, + cli.Conf.SecretKey) // region - region, err := storage.GetRegion(params.Conf.AccessKey, params.Conf.Bucket) + region, err := storage.GetRegion(cli.Conf.AccessKey, cli.Conf.Bucket) if err != nil { return nil, err } @@ -128,7 +133,7 @@ func QiniuContent(params ContentParams) ([]byte, error) { // manager bucketManager := storage.NewBucketManager(mac, cfg) // list file - files, _, _, _, err := bucketManager.ListFiles(params.Conf.Bucket, params.Prefix, "", "", 1) + files, _, _, _, err := bucketManager.ListFiles(cli.Conf.Bucket, params.Prefix, "", "", 1) if err != nil { return nil, err } @@ -136,7 +141,7 @@ func QiniuContent(params ContentParams) ([]byte, error) { return nil, errors.New("no file") } deadline := time.Now().Add(time.Second * 60).Unix() - url := storage.MakePrivateURLv2(mac, "https://"+params.Conf.Domain, files[0].Key, deadline) + url := storage.MakePrivateURLv2(mac, "https://"+cli.Conf.Domain, files[0].Key, deadline) resp, err := http.Get(url) if err != nil { return nil, err @@ -151,27 +156,16 @@ func completeQiniuKey(name string) string { ext := filepath.Ext(name) switch ext { - case ".bmp", ".png", ".jpg", - ".gif", ".ico", ".jpeg": - + case ".bmp", ".png", ".jpg", ".gif", ".ico", ".jpeg": name = "blog/img/" + name case ".mov", ".mp4": name = "blog/video/" + name - case ".go", ".js", ".css", - ".cpp", ".php", ".rb", - ".java", ".py", ".sql", - ".lua", ".html", ".sh", - ".xml", ".cs": - + case ".go", ".js", ".css", ".cpp", ".php", ".rb", ".java", + ".py", ".sql", ".lua", ".html", ".sh", ".xml", ".cs": name = "blog/code/" + name - case ".txt", ".md", ".ini", - ".yaml", ".yml", ".doc", - ".ppt", ".pdf": - + case ".txt", ".md", ".ini", ".yaml", ".yml", ".doc", ".ppt", ".pdf": name = "blog/document/" + name - case ".zip", ".rar", ".tar", - ".gz": - + case ".zip", ".rar", ".tar", ".gz": name = "blog/archive/" + name default: name = "blog/other/" + name diff --git a/pkg/internal/qiniu_test.go b/pkg/third/qiniu/qiniu_test.go similarity index 55% rename from pkg/internal/qiniu_test.go rename to pkg/third/qiniu/qiniu_test.go index 99b5177..84782c5 100644 --- a/pkg/internal/qiniu_test.go +++ b/pkg/third/qiniu/qiniu_test.go @@ -1,5 +1,4 @@ -// Package internal provides ... -package internal +package qiniu import ( "os" @@ -10,6 +9,16 @@ import ( ) func TestQiniuUpload(t *testing.T) { + cli, err := NewQiniuClient(config.Qiniu{ + AccessKey: os.Getenv("QINIU_ACCESSKEY"), + SecretKey: os.Getenv("QINIU_SECRETKEY"), + Bucket: os.Getenv("QINIU_BUCKET"), + Domain: os.Getenv("QINIU_DOMAIN"), + }) + if err != nil { + t.Errorf("NewQiniuClient error = %v", err) + return + } f, _ := os.Open("qiniu_test.go") fi, _ := f.Stat() @@ -27,17 +36,11 @@ func TestQiniuUpload(t *testing.T) { Name: "test-" + time.Now().Format("200601021504059999") + ".go", Size: fi.Size(), Data: f, - Conf: config.Qiniu{ - AccessKey: os.Getenv("QINIU_ACCESSKEY"), - SecretKey: os.Getenv("QINIU_SECRETKEY"), - Bucket: os.Getenv("QINIU_BUCKET"), - Domain: "bu.st.deepzz.com", - }, }}, false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := QiniuUpload(tt.args.params) + got, err := cli.Upload(tt.args.params) if (err != nil) != tt.wantErr { t.Errorf("QiniuUpload() error = %v, wantErr %v", err, tt.wantErr) return @@ -48,15 +51,21 @@ func TestQiniuUpload(t *testing.T) { } func TestQiniuContent(t *testing.T) { - params := ContentParams{ - Conf: config.Qiniu{ - AccessKey: os.Getenv("QINIU_ACCESSKEY"), - SecretKey: os.Getenv("QINIU_SECRETKEY"), - Bucket: os.Getenv("QINIU_BUCKET"), - Domain: "bu.st.deepzz.com", - }, + cli, err := NewQiniuClient(config.Qiniu{ + AccessKey: os.Getenv("QINIU_ACCESSKEY"), + SecretKey: os.Getenv("QINIU_SECRETKEY"), + Bucket: os.Getenv("QINIU_BUCKET"), + Domain: os.Getenv("QINIU_DOMAIN"), + }) + if err != nil { + t.Errorf("NewQiniuClient error = %v", err) + return } - _, err := QiniuContent(params) + + params := ContentParams{ + Prefix: "blog/", + } + _, err = cli.Content(params) if err != nil { t.Errorf("QiniuList error = %v", err) } diff --git a/scripts/dist_tar.sh b/scripts/dist_tar.sh index afe9113..5edf8de 100755 --- a/scripts/dist_tar.sh +++ b/scripts/dist_tar.sh @@ -5,7 +5,7 @@ set -e _tag="$1" _arch=$(go env GOARCH) -for file in pkg/core/*; do +for file in cmd/*; do app="$(basename $file)"; # tar platform for os in linux darwin windows; do diff --git a/scripts/swag_init.sh b/scripts/swag_init.sh index efcaede..179ad24 100755 --- a/scripts/swag_init.sh +++ b/scripts/swag_init.sh @@ -1,8 +1,8 @@ #!/usr/bin/env sh -for file in pkg/core/*; do +for file in cmd/*; do if test -d $file; then - cd $file && swag init -g api.go; + cd $file && swag init -g main.go; cd -; fi done