main.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. package main
  2. import (
  3. "context"
  4. "encoding/json"
  5. "flag"
  6. "fmt"
  7. "io"
  8. "io/ioutil"
  9. "net"
  10. "net/http"
  11. "os"
  12. "time"
  13. "git.lattuga.net/boyska/circolog"
  14. )
  15. var globalOpts struct {
  16. ctlSock string
  17. verbose bool
  18. debug bool
  19. }
  20. var ctl http.Client
  21. type commandFunc func([]string) error
  22. var cmdMap map[string]commandFunc
  23. func init() {
  24. cmdMap = map[string]commandFunc{
  25. // TODO: implement set and get of config at runtime
  26. //"set": setCmd,
  27. //"get": getCmd,
  28. "status": statusCmd,
  29. "pause": pauseCmd,
  30. "reload": reloadCmd,
  31. "restart": restartCmd,
  32. "help": helpCmd,
  33. }
  34. }
  35. //func setCmd(ctlSock string, args []string) error {}
  36. //func getCmd(ctlSock string, args []string) error {}
  37. func statusCmd(args []string) error {
  38. flagset := flag.NewFlagSet(args[0], flag.ExitOnError)
  39. outFormat := flagset.String("format", "plain", "Which format to use as output for this command (json, pretty, plain)")
  40. flagset.Parse(args[1:])
  41. resp, err := ctl.Get("http://unix/status")
  42. if err != nil {
  43. return err
  44. }
  45. defer resp.Body.Close()
  46. respBytes, err := ioutil.ReadAll(resp.Body)
  47. if err != nil {
  48. return err
  49. }
  50. respJSON := make(map[string]circolog.StatusResponse)
  51. err = json.Unmarshal(respBytes, &respJSON)
  52. if err != nil {
  53. return err
  54. }
  55. switch *outFormat {
  56. case "json":
  57. fmt.Printf("%s", string(respBytes))
  58. case "pretty":
  59. prettyJSON, err := json.MarshalIndent(respJSON, "", " ")
  60. if err != nil {
  61. return err
  62. }
  63. fmt.Printf("%s\n", prettyJSON)
  64. case "plain":
  65. fmt.Printf("Buffer Length: %d\n", respJSON["status"].Size)
  66. fmt.Printf("Server Status: %s\n", respJSON["status"].Status())
  67. }
  68. return nil
  69. }
  70. func pauseCmd(args []string) error {
  71. var dontChangeAgain time.Duration
  72. flagset := flag.NewFlagSet(args[0], flag.ExitOnError)
  73. waitTime := flagset.Duration("wait-time", dontChangeAgain, "How long to wait before untoggling the state, defaults to never")
  74. flagset.Parse(args[1:])
  75. postBody := make(map[string][]string)
  76. if *waitTime != dontChangeAgain {
  77. postBody["waitTime"] = []string{fmt.Sprintf("%s", *waitTime)}
  78. }
  79. if globalOpts.debug {
  80. fmt.Println("[DEBUG] postBody:", postBody)
  81. }
  82. resp, err := ctl.PostForm("http://unix/pause/toggle", postBody)
  83. if globalOpts.verbose {
  84. defer resp.Body.Close()
  85. bodyBytes, err := ioutil.ReadAll(resp.Body)
  86. if err != nil {
  87. return err
  88. }
  89. fmt.Println(string(bodyBytes))
  90. }
  91. return err
  92. }
  93. func reloadCmd(args []string) error {
  94. return nil
  95. }
  96. func restartCmd(args []string) error {
  97. return nil
  98. }
  99. func helpCmd(args []string) error {
  100. usage(os.Stdout)
  101. os.Exit(0)
  102. return nil
  103. }
  104. func usage(w io.Writer) {
  105. fmt.Fprintf(w, "USAGE: %s [globalOpts] [SUBCOMMAND] [opts]\n", os.Args[0])
  106. fmt.Fprintf(w, "\nSUBCOMMANDS:\n\n")
  107. for command := range cmdMap {
  108. fmt.Fprintf(w, "\t%s\n", command)
  109. }
  110. }
  111. func parseAndRun(args []string) {
  112. cmdName := args[0]
  113. cmdToRun, ok := cmdMap[cmdName]
  114. if !ok {
  115. fmt.Fprintf(os.Stderr, "Unknown subcommand: %s\n", cmdName)
  116. usage(os.Stderr)
  117. os.Exit(2)
  118. }
  119. // from here: https://gist.github.com/teknoraver/5ffacb8757330715bcbcc90e6d46ac74
  120. ctl = http.Client{
  121. Transport: &http.Transport{
  122. DialContext: func(_ context.Context, _, _ string) (net.Conn, error) {
  123. return net.Dial("unix", globalOpts.ctlSock)
  124. },
  125. },
  126. }
  127. err := cmdToRun(args)
  128. if err != nil {
  129. fmt.Fprintf(os.Stderr, "Error:\n%s\n", err)
  130. os.Exit(1)
  131. }
  132. }
  133. func main() {
  134. flag.StringVar(&globalOpts.ctlSock, "ctl-socket", "/tmp/circologd-ctl.sock",
  135. "Path to a unix domain socket for the control server; leave empty to disable")
  136. flag.BoolVar(&globalOpts.verbose, "verbose", false, "Print more output")
  137. flag.BoolVar(&globalOpts.debug, "debug", false, "Print debugging info")
  138. flag.Parse()
  139. args := flag.Args()
  140. if len(args) == 0 {
  141. usage(os.Stderr)
  142. os.Exit(-1)
  143. }
  144. parseAndRun(args)
  145. }