123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301 |
- package main
- import (
- "fmt"
- "git.swzry.com/zry/GoHiedaLogger/hieda_ginutil"
- "git.swzry.com/zry/GoHiedaLogger/hieda_yamlutil"
- "git.swzry.com/zry/GoHiedaLogger/hiedalog"
- "git.swzry.com/zry/pathutils"
- "github.com/gin-gonic/gin"
- "github.com/pascaldekloe/jwt"
- "gopkg.in/yaml.v2"
- "io"
- "io/ioutil"
- "os"
- "os/exec"
- "path"
- "path/filepath"
- "strconv"
- "strings"
- "text/template"
- "time"
- )
- const TimeFormatLayout = "2006-01-02 15:04:05"
- type Program struct {
- localLogWriter io.Writer
- hyu *hieda_yamlutil.HiedaLogYamlUtil
- ge *gin.Engine
- config YamlDef_PoweroffConfig
- executableFileName string
- programPath string
- }
- func (p *Program) SetLocalLogWriter(writer io.Writer) {
- p.localLogWriter = writer
- }
- func (p *Program) Start() error {
- var err error
- p.executableFileName, err = filepath.Abs(os.Args[0])
- if err != nil {
- _, _ = fmt.Fprintln(p.localLogWriter, "Failed get executable path: ", err.Error())
- return err
- }
- p.programPath = filepath.Dir(p.executableFileName)
- ok := p.initLogger()
- if !ok {
- return fmt.Errorf("faild init logger")
- }
- ok = p.readConfig()
- if !ok {
- return fmt.Errorf("faild load poweroffd config")
- }
- p.ge = gin.Default()
- if p.hyu != nil {
- glucfg := hieda_ginutil.GinLoggerConfig{
- Logger: p.hyu.Logger,
- ModuleName: "webserver",
- LevelMapFunc: hieda_ginutil.GetDefaultLevelMapFunc(),
- }
- gl := hieda_ginutil.GinLoggerWithComplexLogger(glucfg)
- p.ge.Use(gl)
- }
- p.ge.GET("/", p.homepage)
- p.ge.GET("/api/poweroff.satori", p.poweroff)
- p.ge.GET("/jwt-tool/", p.jwtGenTool)
- p.ge.POST("/api/jwt-tool.satori", p.jwtGenToolBackend)
- if p.config.Listen.TCP.Enable {
- p.printLog("webtcp", hiedalog.DLN_INFO, "Loading...")
- go func() {
- err := p.ge.Run(p.config.Listen.TCP.Listen)
- if err != nil {
- p.printLog("webtcp", hiedalog.DLN_ERROR, "Faild run TCP listener: %s", err.Error())
- }
- p.printLog("webtcp", hiedalog.DLN_INFO, "Listener end.")
- }()
- }
- if p.config.Listen.SockFile.Enable {
- p.printLog("webunix", hiedalog.DLN_INFO, "Loading...")
- if e, _ := pathutils.PathExists(p.config.Listen.SockFile.Filepath); e {
- err := os.Remove(p.config.Listen.SockFile.Filepath)
- if err != nil {
- p.printLog("webunix", hiedalog.DLN_ERROR, "Faild remove old unix sock file: %s", err.Error())
- }
- }
- go func() {
- err := p.ge.RunUnix(p.config.Listen.SockFile.Filepath)
- if err != nil {
- p.printLog("webunix", hiedalog.DLN_ERROR, "Faild run Unix sockfile listener: %s", err.Error())
- }
- p.printLog("webunix", hiedalog.DLN_INFO, "Listener end.")
- }()
- }
- return nil
- }
- func (p *Program) Stop() error {
- if p.hyu != nil {
- p.hyu.SafeShutdown()
- }
- os.Exit(0)
- return nil
- }
- func (p *Program) OtherOperation(op string, args []string) string {
- return fmt.Sprintf("Invalid command '%s'.", op)
- }
- func (p *Program) GetStatus() (status string, hasExtra bool, extra map[string]string) {
- return "running", false, map[string]string{}
- }
- func (p *Program) initLogger() bool {
- ycfd, err := ioutil.ReadFile(path.Join(p.programPath, "log.config.yaml"))
- if err != nil {
- _, _ = fmt.Fprintln(p.localLogWriter, "Failed read file 'log.config.yaml':", err)
- return false
- }
- var ycd hieda_yamlutil.CommonLogConfigYAML
- err = yaml.Unmarshal(ycfd, &ycd)
- if err != nil {
- _, _ = fmt.Fprintln(p.localLogWriter, "Failed parse file 'log.config.yaml':", err)
- return false
- }
- p.hyu, err = hieda_yamlutil.CreateHiedaLoggerFromYAMLData(ycd, true)
- if err != nil {
- _, _ = fmt.Fprintln(p.localLogWriter, "Failed Init Logger:", err)
- return false
- }
- p.hyu.Logger.LogString("logger", hiedalog.DLN_INFO, "Logger initialized.")
- return true
- }
- func (p *Program) readConfig() bool {
- ycfd, err := ioutil.ReadFile(path.Join(p.programPath, "poweroff.config.yaml"))
- if err != nil {
- p.printLog("config", hiedalog.DLN_FATAL, "Failed read config file 'poweroff.config.yaml':%s", err)
- return false
- }
- err = yaml.Unmarshal(ycfd, &(p.config))
- if err != nil {
- p.printLog("config", hiedalog.DLN_FATAL, "Failed parse config file 'poweroff.config.yaml':%s", err)
- return false
- }
- return true
- }
- func (p *Program) homepage(ctx *gin.Context) {
- ctx.Header("content-type", "text/html")
- ctx.String(200, Html_Home)
- }
- func (p *Program) jwtGenTool(ctx *gin.Context) {
- ctx.Header("content-type", "text/html")
- ctx.String(200, Html_jwtTool)
- }
- func (p *Program) jwtGenToolBackend(ctx *gin.Context) {
- jwtkey := ctx.Request.PostFormValue("jwtkey")
- caller := ctx.Request.PostFormValue("caller")
- msg := ctx.Request.PostFormValue("msg")
- clm := jwt.Claims{}
- clm.Issuer = caller
- ntm := jwt.NewNumericTime(time.Now())
- clm.Issued = ntm
- clm.NotBefore = ntm
- exptime := time.Now().Add(5 * time.Minute)
- clm.Expires = jwt.NewNumericTime(exptime)
- clm.Set = map[string]interface{}{
- "msg": msg,
- }
- tok, err := clm.HMACSign(jwt.HS256, []byte(jwtkey))
- if err != nil {
- ctx.Header("content-type", "text/html")
- ctx.String(200, Html_jwtToolFail, err.Error())
- return
- }
- otpl := template.New("result")
- tpl, err := otpl.Parse(Html_jwtToolResult)
- if err != nil {
- ctx.Header("content-type", "text/html")
- ctx.String(200, Html_jwtToolFail, err.Error())
- return
- }
- sb := strings.Builder{}
- err = tpl.Execute(&sb, map[string]string{
- "token": string(tok),
- "expire": exptime.Format(TimeFormatLayout),
- })
- if err != nil {
- ctx.Header("content-type", "text/html")
- ctx.String(200, Html_jwtToolFail, err.Error())
- return
- }
- ctx.Header("content-type", "text/html")
- ctx.String(200, sb.String())
- return
- }
- func (p *Program) poweroff(ctx *gin.Context) {
- jwtstr := ctx.Request.FormValue("token")
- vclm, err := jwt.HMACCheck([]byte(jwtstr), []byte(p.config.Token.JwtKey))
- if err != nil {
- if p.hyu != nil {
- ld := map[string]string{
- "type": "auth_failed",
- "client_ip": ctx.ClientIP(),
- }
- p.hyu.Logger.LogComplex("auth", hiedalog.DLN_INFO, ld)
- }
- ctx.JSON(200, gin.H{
- "suc": false,
- "err": "auth failed",
- })
- return
- }
- isr := vclm.Issuer
- var msg string
- imsg, ok := vclm.Set["msg"]
- if !ok {
- msg = "<No Message>"
- }
- msg, ok = imsg.(string)
- if !ok {
- msg = "<No Message>"
- }
- if p.hyu != nil {
- ld := map[string]string{
- "caller": isr,
- "msg": msg,
- "client_ip": ctx.ClientIP(),
- "time": time.Now().Format(TimeFormatLayout),
- "timestamp": strconv.FormatInt(time.Now().Unix(), 10),
- }
- p.hyu.Logger.LogComplex("record", hiedalog.DLN_INFO, ld)
- }
- if p.config.PoweroffLock {
- p.printLog("shutdown", hiedalog.DLN_WARN, "WARNING: 'poweroff_lock' option is enable. it will not shutdown.")
- ctx.JSON(200, gin.H{
- "suc": true,
- "caller": isr,
- "msg": msg,
- "client_ip": ctx.ClientIP(),
- "time": time.Now().Format(TimeFormatLayout),
- "timestamp": strconv.FormatInt(time.Now().Unix(), 10),
- "poweroff_lock": p.config.PoweroffLock,
- })
- } else {
- ok := p.doShutdown()
- if !ok {
- ctx.JSON(200, gin.H{
- "suc": false,
- "err": "exec shutdown commands failed",
- })
- } else {
- ctx.JSON(200, gin.H{
- "suc": true,
- "caller": isr,
- "msg": msg,
- "client_ip": ctx.ClientIP(),
- "time": time.Now().Format(TimeFormatLayout),
- "timestamp": strconv.FormatInt(time.Now().Unix(), 10),
- "poweroff_lock": p.config.PoweroffLock,
- })
- }
- }
- }
- func (p *Program) printLog(m string, lv string, f string, a ...interface{}) {
- fs := fmt.Sprintf(f, a...)
- if p.hyu != nil {
- p.hyu.Logger.LogString(m, lv, fs)
- } else {
- _, _ = fmt.Fprintln(p.localLogWriter, fs)
- }
- }
- func (p *Program) execCmd(cmd string) error {
- c := exec.Command(cmd, "")
- return c.Run()
- }
- func (p *Program) doShutdown() bool {
- for i := 0; i < 3; i++ {
- err := p.execCmd("/bin/sync")
- if err != nil {
- p.printLog("shutdown", hiedalog.DLN_WARN, "exec sync error: %s", err.Error())
- return false
- }
- }
- err := p.execCmd("/sbin/poweroff")
- if err != nil {
- p.printLog("shutdown", hiedalog.DLN_WARN, "exec poweroff error: %s", err.Error())
- return false
- }
- if p.hyu != nil {
- p.hyu.SafeShutdown()
- }
- return true
- }
|