The main server, and probably only repository in this org.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

169 lines
4.4 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. package main
  2. import (
  3. "context"
  4. "crypto/rand"
  5. "database/sql"
  6. "encoding/hex"
  7. "flag"
  8. "fmt"
  9. "log"
  10. "net/http"
  11. "os"
  12. "os/signal"
  13. "path"
  14. "syscall"
  15. "time"
  16. "git.aiterp.net/lucifer/lucifer/controllers"
  17. "git.aiterp.net/lucifer/lucifer/database/sqlite"
  18. "git.aiterp.net/lucifer/lucifer/internal/config"
  19. "git.aiterp.net/lucifer/lucifer/light"
  20. "git.aiterp.net/lucifer/lucifer/middlewares"
  21. "git.aiterp.net/lucifer/lucifer/models"
  22. "github.com/gorilla/mux"
  23. _ "git.aiterp.net/lucifer/lucifer/light/hue"
  24. )
  25. func main() {
  26. // Flag Variables
  27. var uiDir string
  28. // Parse Flags
  29. flag.StringVar(&uiDir, "uidir", "/var/www/", "UI directory")
  30. flag.Parse()
  31. // Configuration
  32. conf, err := config.Load("./config.yaml", "/etc/lucifer/lucifer.yaml")
  33. if err != nil {
  34. log.Fatalln("Failed to load configuration:", err)
  35. }
  36. // Database
  37. err = sqlite.Initialize(conf.DB.FileName)
  38. if err != nil {
  39. log.Fatalln("Failed to set up database:", err)
  40. }
  41. // Initialize
  42. setupAdmin(sqlite.UserRepository, sqlite.GroupRepository)
  43. // Services
  44. lightService := light.NewService(sqlite.BridgeRepository, sqlite.LightRepository, sqlite.GroupRepository, sqlite.ButtonRepository)
  45. // Controllers
  46. userController := controllers.NewUserController(sqlite.UserRepository, sqlite.SessionRepository)
  47. groupController := controllers.NewGroupController(sqlite.GroupRepository, sqlite.UserRepository, sqlite.LightRepository)
  48. lightController := controllers.NewLightController(lightService, sqlite.GroupRepository, sqlite.UserRepository, sqlite.LightRepository)
  49. bridgeController := controllers.NewBridgeController(lightService, sqlite.GroupRepository)
  50. // Router
  51. router := mux.NewRouter()
  52. router.Use(middlewares.Session(sqlite.SessionRepository, sqlite.UserRepository))
  53. groupController.Mount(router, "/api/group/")
  54. userController.Mount(router, "/api/user/")
  55. lightController.Mount(router, "/api/light/")
  56. bridgeController.Mount(router, "/api/bridge/")
  57. // Background Tasks
  58. go lightService.SyncLoop(context.TODO())
  59. // Server UI in production
  60. stat, err := os.Stat(uiDir)
  61. if err != nil || !stat.IsDir() {
  62. log.Println("ui directory not found, skipping UI routes")
  63. } else {
  64. // Static files
  65. router.PathPrefix("/static/").Handler(http.FileServer(http.Dir(uiDir)))
  66. router.PathPrefix("/favicon.ico").Handler(http.FileServer(http.Dir(uiDir)))
  67. router.PathPrefix("/manifest.json").Handler(http.FileServer(http.Dir(uiDir)))
  68. router.PathPrefix("/index.html").Handler(http.FileServer(http.Dir(uiDir)))
  69. // Serve index on any other path
  70. router.PathPrefix("/").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  71. http.ServeFile(w, r, path.Join(uiDir, "index.html"))
  72. })
  73. }
  74. // Setup webserver
  75. server := http.Server{Addr: conf.Server.Address, Handler: router}
  76. webserverErrCh := make(chan error)
  77. go func() {
  78. log.Println("Listening on", conf.Server.Address)
  79. webserverErrCh <- server.ListenAndServe()
  80. }()
  81. // Setup quit signal listener
  82. signalCh := make(chan os.Signal)
  83. signal.Notify(signalCh, os.Interrupt, os.Kill, syscall.SIGTERM)
  84. // Run until interrupt or server death
  85. select {
  86. case signal := <-signalCh:
  87. {
  88. log.Println("Stopping due to signal:", signal)
  89. timeout, cancel := context.WithTimeout(context.Background(), time.Second*5)
  90. defer cancel()
  91. err := server.Shutdown(timeout)
  92. if err != nil {
  93. log.Println("Warning: graceful shutdown timed out.")
  94. }
  95. os.Exit(0)
  96. }
  97. case err := <-webserverErrCh:
  98. {
  99. log.Println("Listening failed:", err)
  100. os.Exit(1)
  101. }
  102. }
  103. }
  104. func setupAdmin(users models.UserRepository, groups models.GroupRepository) {
  105. ctx, cancel := context.WithTimeout(context.Background(), time.Second*15)
  106. defer cancel()
  107. admin, err := users.FindByName(ctx, "Admin")
  108. if err != nil {
  109. if err != sql.ErrNoRows {
  110. log.Fatalln("Could not check for admin user:", err)
  111. }
  112. admin = models.User{Name: "Admin"}
  113. admin.SetPassword("123456")
  114. admin, err = users.Insert(ctx, admin)
  115. if err != nil {
  116. fmt.Println("Failed to insert admin username:", err)
  117. }
  118. }
  119. buf := make([]byte, 16)
  120. _, err = rand.Read(buf)
  121. if err != nil {
  122. log.Fatalln("Could not get random bytes:", err)
  123. }
  124. password := hex.EncodeToString(buf)
  125. admin.SetPassword(password)
  126. err = users.Update(ctx, admin)
  127. if err != nil {
  128. log.Println("Could not update admin password:", err)
  129. } else {
  130. log.Println("Administrator: Admin /", password)
  131. }
  132. groups.UpdatePermissions(ctx, models.GroupPermission{
  133. UserID: admin.ID,
  134. GroupID: 0,
  135. Read: true,
  136. Write: true,
  137. Create: true,
  138. Delete: true,
  139. Manage: true,
  140. })
  141. }