main.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // This file is subject to a 1-clause BSD license.
  2. // Its contents can be found in the enclosed LICENSE file.
  3. package main
  4. import (
  5. "flag"
  6. "fmt"
  7. "log"
  8. "os"
  9. "path/filepath"
  10. "notabug.org/mouz/bot/app"
  11. "notabug.org/mouz/bot/app/logger"
  12. "notabug.org/mouz/bot/irc"
  13. "notabug.org/mouz/bot/plugins"
  14. )
  15. func main() {
  16. // Parse command line arguments and load the bot profile.
  17. profile := parseArgs()
  18. // Write PID file. It may be needed by a process supervisor.
  19. writePid()
  20. // Create and run the bot.
  21. err := run(profile)
  22. if err != nil {
  23. log.Fatal("[bot]", err)
  24. }
  25. }
  26. // writePid writes a file with process' pid. This is used by supervisors.
  27. // like systemd to track the process state.
  28. func writePid() {
  29. fd, err := os.Create("app.pid")
  30. if err != nil {
  31. log.Println("[bot] Create PID file:", err)
  32. return
  33. }
  34. fmt.Fprintf(fd, "%d", os.Getpid())
  35. fd.Close()
  36. }
  37. // parseArgs parses and validates command line arguments.
  38. func parseArgs() irc.Profile {
  39. flag.Usage = func() {
  40. fmt.Println("usage:", os.Args[0], "[options] <profile directory>")
  41. flag.PrintDefaults()
  42. }
  43. newconf := flag.Bool("new", false, "Create a new, default configuration file and exit.")
  44. version := flag.Bool("version", false, "Display version information.")
  45. flag.Parse()
  46. if *version {
  47. fmt.Println(app.Version())
  48. os.Exit(0)
  49. }
  50. if flag.NArg() == 0 {
  51. flag.Usage()
  52. os.Exit(1)
  53. }
  54. // Read and validate the profile root directory.
  55. root, err := filepath.Abs(flag.Arg(0))
  56. if err != nil {
  57. fmt.Fprintln(os.Stderr, err)
  58. os.Exit(1)
  59. }
  60. // Set root as current working directory.
  61. err = os.Chdir(root)
  62. if err != nil {
  63. fmt.Fprintln(os.Stderr, err)
  64. os.Exit(1)
  65. }
  66. // Create a new bot profile instance.
  67. profile := irc.NewProfile(root)
  68. // If applicable, save a new, default profile and exit.
  69. if *newconf {
  70. err := profile.Save()
  71. if err != nil {
  72. fmt.Fprintln(os.Stderr, err)
  73. os.Exit(1)
  74. }
  75. fmt.Println("New configuration saved.")
  76. fmt.Println("Please edit it and relaunch the program.")
  77. os.Exit(0)
  78. }
  79. // Load an existing profile.
  80. err = profile.Load()
  81. if err != nil {
  82. fmt.Fprintln(os.Stderr, err)
  83. os.Exit(1)
  84. }
  85. return profile
  86. }
  87. // run creates a new connection to the server and begins processing
  88. // incoming messages and OS signals. This call will not return for as long
  89. // as the connection is active.
  90. func run(p irc.Profile) error {
  91. // Initialize the log and ensure it is properly stopped when we are done.
  92. logger.Init("logs")
  93. defer logger.Shutdown()
  94. log.Printf("[bot] Running %s version %d.%d.%s",
  95. app.Name, app.VersionMajor, app.VersionMinor, app.VersionRevision)
  96. defer log.Println("[bot] Shutting down")
  97. // Initialize plugins.
  98. plugins.Load(p)
  99. defer plugins.Unload(p)
  100. // Create te bot, open the connection and spin up the client's read loop
  101. // in a separate goroutine.
  102. var bot Bot
  103. bot.profile = p
  104. bot.client = NewClient(bot.PayloadHandler)
  105. return bot.Run()
  106. }