|
|
@ -5,31 +5,42 @@ import ( |
|
|
|
"crypto/rand" |
|
|
|
"database/sql" |
|
|
|
"encoding/hex" |
|
|
|
"flag" |
|
|
|
"fmt" |
|
|
|
"log" |
|
|
|
"net/http" |
|
|
|
"os" |
|
|
|
"os/signal" |
|
|
|
"path" |
|
|
|
"syscall" |
|
|
|
"time" |
|
|
|
|
|
|
|
"git.aiterp.net/lucifer/lucifer/light" |
|
|
|
"git.aiterp.net/lucifer/lucifer/models" |
|
|
|
|
|
|
|
"github.com/gorilla/mux" |
|
|
|
|
|
|
|
"git.aiterp.net/lucifer/lucifer/controllers" |
|
|
|
"git.aiterp.net/lucifer/lucifer/database/sqlite" |
|
|
|
"git.aiterp.net/lucifer/lucifer/internal/config" |
|
|
|
"git.aiterp.net/lucifer/lucifer/light" |
|
|
|
"git.aiterp.net/lucifer/lucifer/middlewares" |
|
|
|
"git.aiterp.net/lucifer/lucifer/models" |
|
|
|
"github.com/gorilla/mux" |
|
|
|
|
|
|
|
_ "git.aiterp.net/lucifer/lucifer/light/hue" |
|
|
|
) |
|
|
|
|
|
|
|
func main() { |
|
|
|
// Setup
|
|
|
|
// Flag Variables
|
|
|
|
var uiDir string |
|
|
|
|
|
|
|
// Parse Flags
|
|
|
|
flag.StringVar(&uiDir, "uidir", "/var/www/", "UI directory") |
|
|
|
flag.Parse() |
|
|
|
|
|
|
|
// Configuration
|
|
|
|
conf, err := config.Load("./config.yaml", "/etc/lucifer/lucifer.yaml") |
|
|
|
if err != nil { |
|
|
|
log.Fatalln("Failed to load configuration:", err) |
|
|
|
} |
|
|
|
|
|
|
|
// Database
|
|
|
|
err = sqlite.Initialize(conf.DB.FileName) |
|
|
|
if err != nil { |
|
|
|
log.Fatalln("Failed to set up database:", err) |
|
|
@ -58,8 +69,57 @@ func main() { |
|
|
|
// Background Tasks
|
|
|
|
go lightService.SyncLoop(context.TODO()) |
|
|
|
|
|
|
|
// TODO: Listen in another goroutine and have SIGINT/SIGTERM handlers with graceful shutdown.
|
|
|
|
http.ListenAndServe(conf.Server.Address, router) |
|
|
|
// Server UI in production
|
|
|
|
stat, err := os.Stat(uiDir) |
|
|
|
if err != nil || !stat.IsDir() { |
|
|
|
log.Println("ui directory not found, skipping UI routes") |
|
|
|
} else { |
|
|
|
// Static files
|
|
|
|
router.PathPrefix("/static/").Handler(http.FileServer(http.Dir(uiDir))) |
|
|
|
router.PathPrefix("/favicon.ico").Handler(http.FileServer(http.Dir(uiDir))) |
|
|
|
router.PathPrefix("/manifest.json").Handler(http.FileServer(http.Dir(uiDir))) |
|
|
|
router.PathPrefix("/index.html").Handler(http.FileServer(http.Dir(uiDir))) |
|
|
|
|
|
|
|
// Serve index on any other path
|
|
|
|
router.PathPrefix("/").HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
|
|
|
http.ServeFile(w, r, path.Join(uiDir, "index.html")) |
|
|
|
}) |
|
|
|
} |
|
|
|
|
|
|
|
// Setup webserver
|
|
|
|
server := http.Server{Addr: conf.Server.Address, Handler: router} |
|
|
|
webserverErrCh := make(chan error) |
|
|
|
go func() { |
|
|
|
log.Println("Listening on", conf.Server.Address) |
|
|
|
webserverErrCh <- server.ListenAndServe() |
|
|
|
}() |
|
|
|
|
|
|
|
// Setup quit signal listener
|
|
|
|
signalCh := make(chan os.Signal) |
|
|
|
signal.Notify(signalCh, os.Interrupt, os.Kill, syscall.SIGTERM) |
|
|
|
|
|
|
|
// Run until interrupt or server death
|
|
|
|
select { |
|
|
|
case signal := <-signalCh: |
|
|
|
{ |
|
|
|
log.Println("Stopping due to signal:", signal) |
|
|
|
|
|
|
|
timeout, cancel := context.WithTimeout(context.Background(), time.Second*5) |
|
|
|
defer cancel() |
|
|
|
|
|
|
|
err := server.Shutdown(timeout) |
|
|
|
if err != nil { |
|
|
|
log.Println("Warning: graceful shutdown timed out.") |
|
|
|
} |
|
|
|
|
|
|
|
os.Exit(0) |
|
|
|
} |
|
|
|
case err := <-webserverErrCh: |
|
|
|
{ |
|
|
|
log.Println("Listening failed:", err) |
|
|
|
os.Exit(1) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
func setupAdmin(users models.UserRepository, groups models.GroupRepository) { |
|
|
|