gostart/main.go

215 lines
4.7 KiB
Go
Raw Normal View History

2022-11-29 19:55:00 -07:00
package main
import (
"context"
"crypto/tls"
"database/sql"
"embed"
"flag"
2022-12-02 20:53:05 -07:00
"fmt"
2023-05-18 13:03:47 -06:00
"io/fs"
2022-11-29 19:55:00 -07:00
"log"
"net/http"
"os"
"time"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
2022-12-02 20:53:05 -07:00
"github.com/go-chi/render"
2022-11-29 19:55:00 -07:00
_ "modernc.org/sqlite"
"suah.dev/gostart/data"
"tailscale.com/client/tailscale"
"tailscale.com/tsnet"
2023-06-07 11:57:42 -06:00
"tailscale.com/types/logger"
2022-11-29 19:55:00 -07:00
)
2024-05-11 07:50:03 -06:00
var (
//go:embed schema.sql
schema string
2022-11-29 19:55:00 -07:00
2024-05-11 07:50:03 -06:00
//go:embed assets
assets embed.FS
2024-05-11 14:24:49 -06:00
appCtx, cancel = context.WithTimeout(context.Background(), 30*time.Second)
2024-05-11 07:50:03 -06:00
)
2022-11-29 19:55:00 -07:00
var app = &App{
tsServer: &tsnet.Server{},
tsLocalClient: &tailscale.LocalClient{},
}
func main() {
2024-05-11 07:50:03 -06:00
defer cancel()
2022-11-29 19:55:00 -07:00
name := flag.String("name", "startpage", "name of service")
key := flag.String("key", "", "path to file containing the api key")
watchInterval := flag.Int64("refresh", 5, "number of minutes between watch refresh")
2022-12-02 20:53:05 -07:00
dbFile := flag.String("db", ":memory:", "path to on-disk database file")
2022-11-29 19:55:00 -07:00
tokenFile := flag.String("auth", "", "path to file containing GH auth token")
2023-05-18 12:54:16 -06:00
dev := flag.Bool("dev", false, "develop mode, serve live files from ./assets")
2022-11-29 19:55:00 -07:00
flag.Parse()
2022-12-02 20:53:05 -07:00
db, err := sql.Open("sqlite", fmt.Sprintf("%s?cache=shared&mode=rwc", *dbFile))
if err != nil {
2022-12-05 15:45:39 -07:00
log.Fatal("can't open database: ", err)
2022-11-29 19:55:00 -07:00
}
dbExists := false
2022-12-02 20:53:05 -07:00
if *dbFile == ":memory:" {
err := tmpDBPopulate(db)
if err != nil {
log.Fatal(err)
}
2023-04-23 19:12:26 -06:00
dbExists = true
2022-12-02 20:53:05 -07:00
} else {
if _, err := os.Stat(*dbFile); os.IsNotExist(err) {
log.Println("Creating database..")
2024-05-11 14:24:49 -06:00
ctx := context.Background()
if _, err := db.ExecContext(ctx, schema); err != nil {
2022-12-05 15:45:39 -07:00
log.Fatal("can't create database schema: ", err)
2022-12-02 20:53:05 -07:00
}
}
dbExists = true
2023-04-23 19:12:26 -06:00
}
app.watches = &WatchResults{}
app.queries = data.New(db)
app.tsServer = &tsnet.Server{
Hostname: *name,
}
2023-06-07 11:57:42 -06:00
if *dev {
app.tsServer.Logf = logger.Discard
}
2023-04-23 19:12:26 -06:00
app.tsLocalClient, err = app.tsServer.LocalClient()
if err != nil {
log.Fatal("can't get ts local client: ", err)
}
/*
go func() {
time.Sleep(6 * time.Second)
dbExists = true
}()
*/
2022-11-29 19:55:00 -07:00
if *key != "" {
keyData, err := os.ReadFile(*key)
if err != nil {
2022-12-05 15:45:39 -07:00
log.Fatal("can't read key file: ", err)
2022-11-29 19:55:00 -07:00
}
app.tsServer.AuthKey = string(keyData)
}
ln, err := app.tsServer.Listen("tcp", ":443")
if err != nil {
2022-12-05 15:45:39 -07:00
log.Fatal("can't listen: ", err)
2022-11-29 19:55:00 -07:00
}
defer func() {
err := app.tsServer.Close()
if err != nil {
2022-12-05 15:45:39 -07:00
log.Fatal("can't close ts server: ", err)
2022-11-29 19:55:00 -07:00
}
}()
router := chi.NewRouter()
2022-11-29 19:55:00 -07:00
router.Use(middleware.Logger)
router.Use(OwnerCtx)
2022-11-29 19:55:00 -07:00
2023-06-07 11:58:14 -06:00
ghToken := os.Getenv("GH_AUTH_TOKEN")
if *tokenFile != "" && ghToken == "" {
tfBytes, err := os.ReadFile(*tokenFile)
if err != nil {
log.Fatal("can't read token file: ", err)
}
ghToken = string(tfBytes)
}
if ghToken == "" {
log.Fatal("can't operate without GH_AUTH_TOKEN")
}
2023-05-18 13:03:47 -06:00
var liveServer http.Handler
2023-05-18 12:54:16 -06:00
if *dev {
2023-05-18 13:03:47 -06:00
liveServer = http.FileServer(http.Dir("./assets"))
2023-05-18 12:54:16 -06:00
} else {
2023-05-18 13:03:47 -06:00
embFS, _ := fs.Sub(assets, "assets")
liveServer = http.FileServer(http.FS(embFS))
2023-05-18 12:54:16 -06:00
}
2023-05-18 13:03:47 -06:00
router.Mount("/", liveServer)
router.Route("/pullrequests", func(r chi.Router) {
2022-11-29 19:55:00 -07:00
r.Use(render.SetContentType(render.ContentTypeJSON))
r.Get("/", pullrequestsGET)
r.Delete("/{prID:[0-9]+}", pullrequestsDELETE)
r.Post("/", pullrequestsPOST)
})
router.Route("/links", func(r chi.Router) {
2022-11-29 19:55:00 -07:00
r.Use(render.SetContentType(render.ContentTypeJSON))
r.Get("/", linksGET)
2022-12-02 20:53:05 -07:00
r.Delete("/{linkID:[0-9]+}", linkDELETE)
2022-11-29 19:55:00 -07:00
r.Post("/", linksPOST)
})
router.Route("/watches", func(r chi.Router) {
2022-11-29 19:55:00 -07:00
r.Use(render.SetContentType(render.ContentTypeJSON))
r.Get("/", watchitemGET)
2022-12-02 20:53:05 -07:00
r.Delete("/{watchID:[0-9]+}", watchitemDELETE)
r.Post("/", watchitemPOST)
})
router.Route("/prignores", func(r chi.Router) {
2022-12-04 19:03:59 -07:00
r.Use(render.SetContentType(render.ContentTypeJSON))
r.Post("/", prignorePOST)
r.Get("/", prignoreGET)
r.Delete("/{ignoreID:[0-9]+}", prignoreDELETE)
2022-12-04 19:03:59 -07:00
})
router.Route("/icons", func(r chi.Router) {
2022-12-05 20:45:42 -07:00
r.Use(IconCacher)
2022-12-02 20:53:05 -07:00
r.Get("/{linkID:[0-9]+}", iconGET)
2022-11-29 19:55:00 -07:00
})
router.Route("/update-icons", func(r chi.Router) {
2023-07-25 07:20:09 -06:00
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
updateIcons()
w.Header().Add("Content-type", "application/json")
w.WriteHeader(200)
w.Write([]byte(`{"update": true}`))
})
})
2022-11-29 19:55:00 -07:00
go func() {
2022-12-06 20:03:32 -07:00
for {
if dbExists && ghToken != "" {
var err error
app.watches, err = UpdateWatches(ghToken)
if err != nil {
log.Println("can't update watches: ", err)
}
time.Sleep(time.Duration(*watchInterval) * time.Minute)
} else {
time.Sleep(3 * time.Second)
2022-12-06 20:03:32 -07:00
}
2022-11-29 19:55:00 -07:00
}
2022-12-06 20:03:32 -07:00
2022-11-29 19:55:00 -07:00
}()
2022-12-02 20:53:05 -07:00
go func() {
if dbExists {
for {
2023-07-25 07:20:09 -06:00
updateIcons()
time.Sleep(24 * time.Hour)
2022-12-02 20:53:05 -07:00
}
} else {
time.Sleep(3 * time.Second)
2022-12-02 20:53:05 -07:00
}
}()
2022-11-29 19:55:00 -07:00
hs := &http.Server{
Handler: router,
2022-11-29 19:55:00 -07:00
TLSConfig: &tls.Config{
GetCertificate: app.tsLocalClient.GetCertificate,
},
}
log.Panic(hs.ServeTLS(ln, "", ""))
}