diff --git a/src/cmd/cmd.go b/src/cmd/cmd.go index 3aa6d48..5beb1ab 100644 --- a/src/cmd/cmd.go +++ b/src/cmd/cmd.go @@ -31,7 +31,7 @@ func InitCmd() (*cobra.Command, error) { //rootCmd.GenPowerShellCompletion(os.Stdout) //rootCmd.GenZshCompletion(os.Stdout) - conf.InitAppConfig() + conf.LoadAppConfig() err := rootCmd.Execute() return rootCmd, err @@ -61,10 +61,13 @@ func initConfCmd() *cobra.Command { func initServerCmd() *cobra.Command { serverCmd := &cobra.Command{ Use: "server", - Short: "服务相关命令", - Long: "配置服务相关参数, 如监听端口,监听地址等", + Short: "服务端命令", + Long: "acme-mana服务端相关命令, 配置服务相关参数, 如监听端口,监听地址等", Run: func(cmd *cobra.Command, args []string) { - cmd.Help() + err := cmd.Help() + if err != nil { + return + } }, } editCmd := &cobra.Command{ @@ -274,7 +277,7 @@ func acmeCmd() *cobra.Command { acmeCmd := &cobra.Command{ Use: "acme", Short: "ACME相关命令", - Long: "ACME相关命令", + Long: "acme.sh原生命令", Run: func(cmd *cobra.Command, args []string) { cmd.Help() }, diff --git a/src/common/variable.go b/src/common/variable.go index 93aa393..3ece2e6 100644 --- a/src/common/variable.go +++ b/src/common/variable.go @@ -1,10 +1,7 @@ package common import ( - "acme-mana/src/model" "github.com/spf13/cobra" ) var RootCmd *cobra.Command - -var AppConf *model.AppConfig diff --git a/src/conf/conf.go b/src/conf/conf.go new file mode 100644 index 0000000..fdfea0c --- /dev/null +++ b/src/conf/conf.go @@ -0,0 +1,63 @@ +package conf + +// AppConfig +// 配置文件 +type AppConfig struct { + // 服务器配置 + Server *ServerConf `json:"server" yaml:"server"` + // 网页配置 + Web *WebConf `json:"web" yaml:"web"` + // 任务配置 + Task *TaskConf `json:"task" yaml:"task"` + // 认证配置 + Providers *[]ProviderConf `json:"provider" yaml:"provider"` + // 证书配置 + Certs *[]CertConf `json:"cert" yaml:"cert"` +} + +// ServerConf 服务端配置 +type ServerConf struct { + // 监听地址 + Host string `json:"host" yaml:"host"` + // 监听端口 + Port int `json:"port" yaml:"port"` + // 通信密钥, DES 加密 + Key string `json:"key" yaml:"key"` +} + +// WebConf 网页服务配置 +type WebConf struct { + // 是否启用 + Enable bool `json:"enable" yaml:"enable"` + // 监听地址 + Host string `json:"host" yaml:"host"` + // 监听端口 + Port int `json:"port" yaml:"port"` +} + +// TaskConf 定时任务配置 +type TaskConf struct { + // 启动延迟时间, 单位: 毫秒, 默认: 0 + Delay int `json:"delay" yaml:"delay"` + // 间隔时间 + Interval int `json:"interval" yaml:"interval"` +} + +// ProviderConf 三方认证配置 +type ProviderConf struct { + // 认证名称 + Name string `json:"name" yaml:"name"` + // 认证类型 + Type string `json:"type" yaml:"type"` + // 认证配置 + Conf map[string]string `json:"conf" yaml:"conf"` +} + +// CertConf 证书配置 +type CertConf struct { + Name string `json:"name" yaml:"name"` + Provider string `json:"use" yaml:"provider"` + Dir string `json:"dir" yaml:"dir"` + Email string `json:"email" yaml:"email"` + Host []string `json:"host" yaml:"host"` +} diff --git a/src/conf/func.go b/src/conf/func.go new file mode 100644 index 0000000..89d3056 --- /dev/null +++ b/src/conf/func.go @@ -0,0 +1,129 @@ +package conf + +import "log" + +func Config() *AppConfig { + return appConf +} + +func EditServer(host string, port int, key string) *AppConfig { + appConf.Server.Host = host + appConf.Server.Port = port + appConf.Server.Key = key + WriteConfig() + return appConf +} + +func EditWeb(host string, port int) *AppConfig { + appConf.Web.Host = host + appConf.Web.Port = port + WriteConfig() + return appConf +} + +func ExecWeb(run bool) *AppConfig { + appConf.Web.Enable = run + WriteConfig() + return appConf +} + +func EditTask(delay int, interval int) *AppConfig { + appConf.Task.Delay = delay + appConf.Task.Interval = interval + WriteConfig() + return appConf +} + +func FindProvider(name string) (*ProviderConf, int) { + for index, provider := range *appConf.Providers { + if provider.Name == name { + return &provider, index + } + } + return nil, -1 +} + +func AddProvider(name string, typeName string, conf map[string]string) *AppConfig { + provider, _ := FindProvider(name) + if provider != nil { + log.Fatal("已存在相同名称的配置") + return nil + } + provider = &ProviderConf{ + Name: name, + Type: typeName, + Conf: conf, + } + providers := *appConf.Providers + newProviders := append(providers, *provider) + appConf.Providers = &newProviders + return appConf +} + +func EditProvider(name string, typeName string, conf map[string]string) *AppConfig { + provider, _ := FindProvider(name) + if provider == nil { + log.Fatal("不存在该配置") + return nil + } + provider.Type = typeName + provider.Conf = conf + WriteConfig() + return appConf +} + +func RmProvider(name string) *AppConfig { + _, index := FindProvider(name) + if index == -1 { + log.Fatal("不存在该配置") + } + providers := *appConf.Providers + newProviders := append(providers[:index], providers[index+1:]...) + appConf.Providers = &newProviders + return appConf +} + +func FindCert(name string) (*CertConf, int) { + for index, cert := range *appConf.Certs { + if cert.Name == name { + return &cert, index + } + } + return nil, -1 +} +func FindCertByProvider(provider string) *[]CertConf { + var result []CertConf + for _, cert := range *appConf.Certs { + if cert.Provider == provider { + result = append(result, cert) + } + } + return &result +} + +func AddCert(cert *CertConf) *AppConfig { + certs := *appConf.Certs + newCerts := append(certs, *cert) + appConf.Certs = &newCerts + return appConf +} +func EditCert(name string, cert *CertConf) *AppConfig { + _, index := FindCert(name) + if index == -1 { + log.Fatal("不存在该配置") + } + certs := *appConf.Certs + certs[index] = *cert + appConf.Certs = &certs + return appConf +} +func RmCert(name string) *AppConfig { + _, index := FindCert(name) + if index == -1 { + log.Fatal("不存在该配置") + } + certs := *appConf.Certs + newCerts := append(certs[:index], certs[index+1:]...) + appConf.Certs = &newCerts + return appConf +} diff --git a/src/conf/util.go b/src/conf/mana.go similarity index 50% rename from src/conf/util.go rename to src/conf/mana.go index da35c60..1004c9c 100644 --- a/src/conf/util.go +++ b/src/conf/mana.go @@ -2,54 +2,43 @@ package conf import ( "acme-mana/src/common" - "acme-mana/src/model" "acme-mana/src/util" "gopkg.in/yaml.v3" "log" "os" ) -func readAppConfig(c *model.AppConfig) *model.AppConfig { - confFile, err := common.RootCmd.PersistentFlags().GetString("conf") - if err != nil { - log.Fatalln("读取配置文件参数失败") - } - - _, err = os.Stat(confFile) - if os.IsNotExist(err) { +func LoadAppConfig() { + // 读取配置文件位置 + confFile := getConfFile() + // 判断配资文件是否存在 + if _, err := os.Stat(confFile); os.IsNotExist(err) { log.Println("配置文件不存在, 自动创建") - writeConf(c, confFile) + config := defaultAppConfig() + log.Println("默认配置文件创建成功") + log.Println("服务器通信密钥: " + config.Server.Key) + appConf = config + writeConf(appConf, confFile) + } else { + appConf = readAppConfig(appConf) } - - file, err := os.ReadFile(confFile) - if err != nil { - log.Fatalln("读取配置文件失败") - } - //var conf = &model.AppConfig{} - err = yaml.Unmarshal(file, c) - if err != nil { - log.Fatalln("解析配置文件失败") - } - return c -} - -func InitAppConfig() { - common.AppConf = DefaultAppConfig() } +// RefreshConfig 刷新配置 func RefreshConfig() { - readAppConfig(common.AppConf) + readAppConfig(appConf) } +// WriteConfig 写入配置文件 func WriteConfig() { confFile, err := common.RootCmd.PersistentFlags().GetString("conf") if err != nil { log.Fatalln("读取配置文件参数失败") } - writeConf(common.AppConf, confFile) + writeConf(appConf, confFile) } -func writeConf(c *model.AppConfig, file string) { +func writeConf(c *AppConfig, file string) { out, err := yaml.Marshal(c) if err != nil { log.Fatalln("序列化配置文件失败") @@ -61,13 +50,22 @@ func writeConf(c *model.AppConfig, file string) { } } -func DefaultAppConfig() *model.AppConfig { - return &model.AppConfig{ - Server: &model.ServerConf{ +// DefaultAppConfig 默认配置 +func defaultAppConfig() *AppConfig { + serverKey := util.RandomStr(32) + + return &AppConfig{ + Server: &ServerConf{ Host: "0.0.0.0", Port: 36851, + Key: serverKey, }, - Task: &model.TaskConf{ + Web: &WebConf{ + Enable: false, + Host: "0.0.0.0", + Port: 36852, + }, + Task: &TaskConf{ Delay: 0, Interval: 0, }, @@ -75,3 +73,27 @@ func DefaultAppConfig() *model.AppConfig { Providers: nil, } } + +// getConfFile 获取配置文件位置 +func getConfFile() string { + confFile, err := common.RootCmd.PersistentFlags().GetString("conf") + if err != nil { + log.Fatalln("读取配置文件参数失败") + } + return confFile +} + +// readAppConfig 读取配置文件 +func readAppConfig(c *AppConfig) *AppConfig { + confFile := getConfFile() + file, err := os.ReadFile(confFile) + if err != nil { + log.Fatalln("读取配置文件失败") + } + //var conf = &model.AppConfig{} + err = yaml.Unmarshal(file, c) + if err != nil { + log.Fatalln("解析配置文件失败") + } + return c +} diff --git a/src/conf/variable.go b/src/conf/variable.go new file mode 100644 index 0000000..03183ec --- /dev/null +++ b/src/conf/variable.go @@ -0,0 +1,3 @@ +package conf + +var appConf *AppConfig diff --git a/src/http/server.go b/src/http/server.go index 9173a38..09b8355 100644 --- a/src/http/server.go +++ b/src/http/server.go @@ -11,7 +11,10 @@ var service *gin.Engine var isRunning bool func Start() { - + if isRunning { + return + } + go start() } func Stop() { diff --git a/src/model/conf.go b/src/model/conf.go deleted file mode 100644 index d291e95..0000000 --- a/src/model/conf.go +++ /dev/null @@ -1,34 +0,0 @@ -package model - -type AppConfig struct { - Server *ServerConf `json:"server" yaml:"server"` - Task *TaskConf `json:"task" yaml:"task"` - Certs *[]CertConf `json:"cert" yaml:"cert"` - Providers *[]ProviderConf `json:"provider" yaml:"provider"` -} - -type ServerConf struct { - Host string `json:"host" yaml:"host"` - Port int `json:"port" yaml:"port"` -} - -type TaskConf struct { - // 启动延迟时间, 单位: 毫秒, 默认: 0 - Delay int `json:"delay" yaml:"delay"` - // 间隔时间 - Interval int `json:"interval" yaml:"interval"` -} - -type ProviderConf struct { - Name string `json:"name" yaml:"name"` - Type string `json:"type" yaml:"type"` - Conf map[string]string `json:"conf" yaml:"conf"` -} - -type CertConf struct { - Name string `json:"name" yaml:"name"` - Provider string `json:"use" yaml:"provider"` - Dir string `json:"dir" yaml:"dir"` - Email string `json:"email" yaml:"email"` - Host []string `json:"host" yaml:"host"` -} diff --git a/src/server/handle/cert.go b/src/server/handle/cert.go new file mode 100644 index 0000000..0ea6c2e --- /dev/null +++ b/src/server/handle/cert.go @@ -0,0 +1,18 @@ +package handle + +import ( + "github.com/gin-gonic/gin" + "log" +) + +func GetCert(context *gin.Context) { + log.Println("get cert") +} + +func RefreshCert(context *gin.Context) { + log.Fatalln("refresh cert") +} + +func domainList(context *gin.Context) { + log.Fatalln("domain list") +} diff --git a/src/server/http-server.go b/src/server/http-server.go new file mode 100644 index 0000000..14833af --- /dev/null +++ b/src/server/http-server.go @@ -0,0 +1,64 @@ +package server + +import ( + "acme-mana/src/conf" + "acme-mana/src/server/handle" + "context" + "errors" + "github.com/gin-gonic/gin" + "log" + "net/http" + "strconv" + "time" +) + +type HttpServer struct { + server *http.Server `json:"server"` + status bool + engine *gin.Engine +} + +func (s *HttpServer) InitServer() { + s.engine = gin.Default() + s.register() + s.status = false + + config := conf.Config() + var serverConf = config.Server + s.server = &http.Server{ + Addr: serverConf.Host + ":" + strconv.Itoa(serverConf.Port), + Handler: s.engine, + } +} + +func (s *HttpServer) Start() { + go func() { + if err := s.server.ListenAndServe(); !errors.Is(err, http.ErrServerClosed) { + log.Printf("listen: %s\n\n", err) + s.status = true + } else { + s.status = false + } + }() +} + +func (s *HttpServer) Stop() { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + err := httpServer.server.Shutdown(ctx) + s.status = false + if err != nil { + log.Fatalln("Server Shutdown:", err) + } +} + +func Status() bool { + return httpServer.status +} + +func (s *HttpServer) register() { + service := s.engine + service.GET("/api/v1/refresh", handle.RefreshCert) + service.GET("/api/v1/cert", handle.GetCert) + service.GET("/api/v1/domain/list", handle.GetCert) +} diff --git a/src/server/variable.go b/src/server/variable.go new file mode 100644 index 0000000..a26af1c --- /dev/null +++ b/src/server/variable.go @@ -0,0 +1,3 @@ +package server + +var httpServer *HttpServer diff --git a/src/util/random.go b/src/util/random.go new file mode 100644 index 0000000..02c25cb --- /dev/null +++ b/src/util/random.go @@ -0,0 +1,17 @@ +package util + +import ( + "math/rand" + "time" +) + +const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" + +func RandomStr(size int) string { + rand.NewSource(time.Now().UnixNano()) + b := make([]byte, size) + for i := range b { + b[i] = letterBytes[rand.Intn(len(letterBytes))] + } + return string(b) +}