2022-01-15 16:32:49 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"database/sql"
|
|
|
|
"database/sql/driver"
|
|
|
|
"embed"
|
|
|
|
"flag"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
|
|
|
|
|
|
|
"github.com/tailscale/sqlite"
|
|
|
|
"tailscale.com/tsnet"
|
|
|
|
"tailscale.com/types/logger"
|
|
|
|
"within.website/ln"
|
|
|
|
"within.website/ln/ex"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
twitchDateFormat = `Mon Jan 02 2006` // Fri Dec 17 2021
|
|
|
|
sqliteDateFormat = "2006-01-02" // 2006-02-01
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
dbLoc = flag.String("db", "var/twitchalitics.db", "path to SQLite database file")
|
|
|
|
hostname = flag.String("hostname", "twitchalitics", "hostname to use on your tailnet")
|
|
|
|
tsLogLoc = flag.String("ts-log-loc", "/mnt/fast/share/twitchalitics.ts.log", "path for Tailscale to dump logs")
|
|
|
|
|
|
|
|
//go:embed schema/*
|
|
|
|
schemaFS embed.FS
|
|
|
|
)
|
|
|
|
|
|
|
|
func getDB() (*sql.DB, error) {
|
|
|
|
connInitFunc := func(ctx context.Context, conn driver.ConnPrepareContext) error {
|
|
|
|
err := sqlite.ExecScript(conn.(sqlite.SQLConn), "PRAGMA journal_mode=WAL;")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
schema, err := schemaFS.ReadFile("schema/schema.sql")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return sqlite.ExecScript(conn.(sqlite.SQLConn), string(schema))
|
|
|
|
}
|
|
|
|
|
|
|
|
db := sql.OpenDB(sqlite.Connector(*dbLoc, connInitFunc, nil))
|
|
|
|
err := db.Ping()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return db, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getLogFout(fname string) (func(), logger.Logf, error) {
|
|
|
|
os.Remove(fname)
|
|
|
|
fout, err := os.Create(fname)
|
|
|
|
if err != nil {
|
|
|
|
return nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
done := func() { fout.Close() }
|
|
|
|
lgr := log.New(fout, "", log.LstdFlags)
|
|
|
|
return done, lgr.Printf, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
os.Setenv("TAILSCALE_USE_WIP_CODE", "true")
|
|
|
|
|
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
db, err := getDB()
|
|
|
|
if err != nil {
|
|
|
|
ln.FatalErr(ctx, err)
|
|
|
|
}
|
|
|
|
defer db.Close()
|
|
|
|
|
2022-01-17 13:55:31 +00:00
|
|
|
ln.Log(ctx, ln.Info("starting up..."), ln.F{"db": *dbLoc, "hostname": hostname, "ts-log-loc": *tsLogLoc})
|
|
|
|
|
2022-01-15 16:32:49 +00:00
|
|
|
done, tsLgr, err := getLogFout(*tsLogLoc)
|
|
|
|
if err != nil {
|
|
|
|
ln.FatalErr(ctx, err)
|
|
|
|
}
|
|
|
|
defer done()
|
|
|
|
|
|
|
|
srv := &tsnet.Server{
|
|
|
|
Hostname: *hostname,
|
|
|
|
Logf: tsLgr,
|
|
|
|
}
|
|
|
|
|
|
|
|
_ = srv
|
|
|
|
|
|
|
|
go plainHTTPRedirect(ctx, srv)
|
|
|
|
ln.FatalErr(ctx, NewServer(db, srv).ListenAndServe())
|
|
|
|
}
|
|
|
|
|
|
|
|
func plainHTTPRedirect(ctx context.Context, srv *tsnet.Server) {
|
|
|
|
l, err := srv.Listen("tcp", ":80")
|
|
|
|
if err != nil {
|
|
|
|
ln.FatalErr(ctx, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
ln.Log(ctx, ln.Info("listening on :80 to forward to HTTPS"))
|
|
|
|
|
|
|
|
err = http.Serve(l, ex.HTTPLog(http.RedirectHandler("https://twitchalitics.shark-harmonic.ts.net", http.StatusPermanentRedirect)))
|
|
|
|
ln.FatalErr(ctx, err)
|
|
|
|
}
|