app.go 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. // Package cmd provides the ntfy CLI application
  2. package cmd
  3. import (
  4. "fmt"
  5. "github.com/urfave/cli/v2"
  6. "github.com/urfave/cli/v2/altsrc"
  7. "heckel.io/ntfy/config"
  8. "heckel.io/ntfy/server"
  9. "log"
  10. "os"
  11. )
  12. // New creates a new CLI application
  13. func New() *cli.App {
  14. flags := []cli.Flag{
  15. &cli.StringFlag{Name: "config", Aliases: []string{"c"}, EnvVars: []string{"NTFY_CONFIG_FILE"}, Value: "/etc/ntfy/config.yml", DefaultText: "/etc/ntfy/config.yml", Usage: "config file"},
  16. altsrc.NewStringFlag(&cli.StringFlag{Name: "listen-http", Aliases: []string{"l"}, EnvVars: []string{"NTFY_LISTEN_HTTP"}, Value: config.DefaultListenHTTP, Usage: "ip:port used to as listen address"}),
  17. altsrc.NewDurationFlag(&cli.DurationFlag{Name: "keepalive-interval", Aliases: []string{"k"}, EnvVars: []string{"NTFY_KEEPALIVE_INTERVAL"}, Value: config.DefaultKeepaliveInterval, Usage: "default interval of keepalive messages"}),
  18. }
  19. return &cli.App{
  20. Name: "ntfy",
  21. Usage: "Simple pub-sub notification service",
  22. UsageText: "ntfy [OPTION..]",
  23. HideHelp: true,
  24. HideVersion: true,
  25. EnableBashCompletion: true,
  26. UseShortOptionHandling: true,
  27. Reader: os.Stdin,
  28. Writer: os.Stdout,
  29. ErrWriter: os.Stderr,
  30. Action: execRun,
  31. Before: initConfigFileInputSource("config", flags),
  32. Flags: flags,
  33. }
  34. }
  35. func execRun(c *cli.Context) error {
  36. // Read all the options
  37. listenHTTP := c.String("listen-http")
  38. keepaliveInterval := c.Duration("keepalive-interval")
  39. // Run main bot, can be killed by signal
  40. conf := config.New(listenHTTP)
  41. conf.KeepaliveInterval = keepaliveInterval
  42. s := server.New(conf)
  43. if err := s.Run(); err != nil {
  44. log.Fatalln(err)
  45. }
  46. log.Printf("Exiting.")
  47. return nil
  48. }
  49. // initConfigFileInputSource is like altsrc.InitInputSourceWithContext and altsrc.NewYamlSourceFromFlagFunc, but checks
  50. // if the config flag is exists and only loads it if it does. If the flag is set and the file exists, it fails.
  51. func initConfigFileInputSource(configFlag string, flags []cli.Flag) cli.BeforeFunc {
  52. return func(context *cli.Context) error {
  53. configFile := context.String(configFlag)
  54. if context.IsSet(configFlag) && !fileExists(configFile) {
  55. return fmt.Errorf("config file %s does not exist", configFile)
  56. } else if !context.IsSet(configFlag) && !fileExists(configFile) {
  57. return nil
  58. }
  59. inputSource, err := altsrc.NewYamlSourceFromFile(configFile)
  60. if err != nil {
  61. return err
  62. }
  63. return altsrc.ApplyInputSourceValues(context, inputSource, flags)
  64. }
  65. }
  66. func fileExists(filename string) bool {
  67. stat, _ := os.Stat(filename)
  68. return stat != nil
  69. }