package main import ( "flag" "fmt" "log" "net/http" "net/netip" "os" "os/signal" "path" "strings" "syscall" "time" dwhttp "git.arav.su/Arav/dwelling-home/internal/http" mfsqlite "git.arav.su/Arav/dwelling-home/pkg/mindflow/database/sqlite" "git.arav.su/Arav/dwelling-home/web" "git.arav.su/Arav/httpr" gb "git.arav.su/Arav/justguestbook" ) var version string var showVersion *bool = flag.Bool("v", false, "show version") var listenAddress *string = flag.String("l", "/var/run/dwelling-home/sock", "listen address (ip:port|unix_path)") var captchaExpiry *time.Duration = flag.Duration("ce", 10*time.Minute, "CAPTCHA expiry (e.g. 5m, 60s)") var guestbookOwner *string = flag.String("gbo", "Admin", "name of a guestbook owner") var guestbookPageSize *int64 = flag.Int64("gbp", 60, "size of a guestbook page") var databasesPath *string = flag.String("db", "/var/lib/dwelling-home", "path to a directory where to store DB files") func main() { flag.Parse() if *showVersion { fmt.Println("dwelling-home Ver.", version, "\nCopyright (c) 2023 Alexander \"Arav\" Andreev ") return } log.SetFlags(log.Llongfile) var network string if !strings.ContainsRune(*listenAddress, ':') { network = "unix" defer os.Remove(*listenAddress) } else { ap, err := netip.ParseAddrPort(*listenAddress) if err != nil { log.Fatalln(err) } else if !ap.IsValid() { log.Fatalln(*listenAddress, "is not valid") } if ap.Addr().Is4() { network = "tcp4" } else if ap.Addr().Is6() { network = "tcp6" } } guestbookDB, err := gb.NewSQLiteDB(path.Join(*databasesPath, "guestbook.sqlite")) if err != nil { log.Fatalln(err) } defer guestbookDB.Close() mindflowDB, err := mfsqlite.New(path.Join(*databasesPath, "mindflow.sqlite")) if err != nil { log.Fatalln(err) } defer mindflowDB.Close() hand := dwhttp.NewHandlers(*captchaExpiry, *guestbookOwner, *guestbookPageSize, guestbookDB, mindflowDB) r := httpr.New() r.NotFoundHandler = func(w http.ResponseWriter, _ *http.Request) { web.ErrorXXX("/ Not Found", "", "", http.StatusNotFound, w) } r.ServeStatic("/assets/*filepath", web.Assets()) r.Handler(http.MethodGet, "/favicon.ico", dwhttp.FaviconIco) r.Handler(http.MethodGet, "/robots.txt", dwhttp.RobotsTxt) r.Handler(http.MethodGet, "/rss.xml", hand.RSS) r.Handler(http.MethodGet, "/sitemap.xml", dwhttp.SitemapXml) r.Handler(http.MethodGet, "/", hand.Index) r.Handler(http.MethodGet, "/stuff", hand.Stuff) r.Handler(http.MethodGet, "/stuff/article/*filepath", hand.Article) r.Handler(http.MethodGet, "/mindflow", hand.Mindflow) r.Handler(http.MethodGet, "/mindflow/admin", hand.MindflowAdmin) r.Handler(http.MethodGet, "/about", hand.About) r.Handler(http.MethodGet, "/guestbook", hand.Guestbook) r.Handler(http.MethodGet, "/guestbook/admin", hand.GuestbookAdmin) captchaApi := dwhttp.NewCaptchaApiHandlers(*captchaExpiry) r.Handler(http.MethodPost, "/api/captcha", captchaApi.New) r.Handler(http.MethodPost, "/api/captcha/:id", captchaApi.Solve) r.Handler(http.MethodGet, "/api/captcha/:id/image", captchaApi.Image) guestbookApi := dwhttp.NewGuestbookApiHandlers(*guestbookOwner, *guestbookPageSize, guestbookDB) r.Handler(http.MethodPost, "/api/guestbook", guestbookApi.New) r.Handler(http.MethodPatch, "/api/guestbook/:id", guestbookApi.Edit) r.Handler(http.MethodDelete, "/api/guestbook/:id", guestbookApi.Delete) r.Handler(http.MethodPost, "/api/guestbook/:id/reply", guestbookApi.Reply) r.Handler(http.MethodPatch, "/api/guestbook/:id/reply", guestbookApi.EditReply) r.Handler(http.MethodDelete, "/api/guestbook/:id/reply", guestbookApi.DeleteReply) mindflowApi := dwhttp.NewMindflowApiHandlers(mindflowDB) r.Handler(http.MethodPost, "/api/mindflow", mindflowApi.NewPost) r.Handler(http.MethodPatch, "/api/mindflow/:id", mindflowApi.EditPost) r.Handler(http.MethodDelete, "/api/mindflow/:id", mindflowApi.DeletePost) r.Handler(http.MethodPost, "/api/mindflow/category", mindflowApi.NewCategory) r.Handler(http.MethodPatch, "/api/mindflow/category/:id", mindflowApi.EditCategory) r.Handler(http.MethodDelete, "/api/mindflow/category/:id", mindflowApi.DeleteCategory) srv := dwhttp.NewHttpServer(r) if err := srv.Start(network, *listenAddress); err != nil { log.Fatalln(err) } defer func() { if err := srv.Stop(); err != nil { log.Fatalln(err) } }() doneSignal := make(chan os.Signal, 1) signal.Notify(doneSignal, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) <-doneSignal }