go-ssb-room/cmd/server/main.go

270 lines
6.1 KiB
Go
Raw Normal View History

2021-01-25 10:39:05 +00:00
// SPDX-License-Identifier: MIT
2021-01-25 12:23:03 +00:00
// go-roomsrv hosts the database and p2p server for replication.
2021-01-25 10:39:05 +00:00
// It supplies various flags to contol options.
2021-01-25 12:23:03 +00:00
// See 'go-roomsrv -h' for a list and their usage.
2021-01-25 10:39:05 +00:00
package main
import (
"context"
"encoding/base64"
"flag"
"fmt"
2021-01-25 12:23:03 +00:00
"net"
2021-01-25 10:39:05 +00:00
"os"
"os/signal"
"os/user"
"path/filepath"
2021-01-25 12:23:03 +00:00
"strings"
2021-01-25 10:39:05 +00:00
"syscall"
"time"
// debug
"net/http"
_ "net/http/pprof"
kitlog "github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"
2021-02-08 16:47:42 +00:00
_ "github.com/mattn/go-sqlite3"
2021-01-25 12:23:03 +00:00
"go.cryptoscope.co/muxrpc/v2/debug"
"github.com/ssb-ngi-pointer/go-ssb-room/admindb/sqlite"
"github.com/ssb-ngi-pointer/go-ssb-room/internal/repo"
"github.com/ssb-ngi-pointer/go-ssb-room/roomsrv"
mksrv "github.com/ssb-ngi-pointer/go-ssb-room/roomsrv"
"github.com/ssb-ngi-pointer/go-ssb-room/web/handlers"
2021-01-25 10:39:05 +00:00
)
var (
// flags
flagDisableUNIXSock bool
2021-02-04 10:36:02 +00:00
listenAddrShsMux string
listenAddrHTTP string
listenAddrDebug string
logToFile string
repoDir string
2021-01-25 10:39:05 +00:00
// helper
log kitlog.Logger
// juicy bits
appKey string
)
// Version and Build are set by ldflags
var (
Version = "snapshot"
Build = ""
flagPrintVersion bool
)
func checkFatal(err error) {
checkAndLog(err)
if err != nil {
os.Exit(1)
}
}
func checkAndLog(err error) {
if err != nil {
level.Error(log).Log("event", "fatal error", "err", err)
}
}
func initFlags() {
u, err := user.Current()
checkFatal(err)
flag.StringVar(&appKey, "shscap", "1KHLiKZvAvjbY1ziZEHMXawbCEIM6qwjCDm3VYRan/s=", "secret-handshake app-key (or capability)")
2021-02-04 10:36:02 +00:00
flag.StringVar(&listenAddrShsMux, "lismux", ":8008", "address to listen on for secret-handshake+muxrpc")
flag.StringVar(&listenAddrHTTP, "lishttp", ":3000", "address to listen on for HTTP requests")
2021-01-25 10:39:05 +00:00
flag.BoolVar(&flagDisableUNIXSock, "nounixsock", false, "disable the UNIX socket RPC interface")
2021-01-28 14:06:51 +00:00
flag.StringVar(&repoDir, "repo", filepath.Join(u.HomeDir, ".ssb-go-room"), "where to put the log and indexes")
2021-01-25 10:39:05 +00:00
2021-02-04 10:36:02 +00:00
flag.StringVar(&listenAddrDebug, "dbg", "localhost:6078", "listen addr for metrics and pprof HTTP server")
2021-02-04 13:13:52 +00:00
flag.StringVar(&logToFile, "logs", "", "where to write debug output to (default is just stderr)")
2021-01-25 10:39:05 +00:00
flag.BoolVar(&flagPrintVersion, "version", false, "print version number and build date")
flag.Parse()
if logToFile != "" {
logDir := filepath.Join(repoDir, logToFile)
os.MkdirAll(logDir, 0700) // nearly everything is a log here so..
logFileName := fmt.Sprintf("%s-%s.log",
filepath.Base(os.Args[0]),
time.Now().Format("2006-01-02_15-04"))
logFile, err := os.Create(filepath.Join(logDir, logFileName))
if err != nil {
panic(err) // logging not ready yet...
}
2021-01-25 12:23:03 +00:00
log = kitlog.NewJSONLogger(kitlog.NewSyncWriter(logFile))
2021-01-25 10:39:05 +00:00
} else {
2021-01-25 12:23:03 +00:00
log = kitlog.NewLogfmtLogger(os.Stderr)
2021-01-25 10:39:05 +00:00
}
}
2021-01-25 12:23:03 +00:00
func runroomsrv() error {
2021-01-25 10:39:05 +00:00
initFlags()
if flagPrintVersion {
log.Log("version", Version, "build", Build)
return nil
}
ctx, cancel := context.WithCancel(context.Background())
2021-02-04 13:13:52 +00:00
defer cancel()
2021-01-25 10:39:05 +00:00
ak, err := base64.StdEncoding.DecodeString(appKey)
if err != nil {
2021-02-04 10:36:02 +00:00
return fmt.Errorf("application key: %w", err)
2021-01-25 10:39:05 +00:00
}
2021-01-25 12:23:03 +00:00
opts := []roomsrv.Option{
roomsrv.WithLogger(log),
roomsrv.WithAppKey(ak),
roomsrv.WithRepoPath(repoDir),
2021-02-04 10:36:02 +00:00
roomsrv.WithListenAddr(listenAddrShsMux),
2021-01-25 17:41:36 +00:00
roomsrv.WithUNIXSocket(!flagDisableUNIXSock),
2021-01-25 12:23:03 +00:00
}
2021-01-25 10:39:05 +00:00
2021-01-25 12:23:03 +00:00
if logToFile != "" {
opts = append(opts, roomsrv.WithPostSecureConnWrapper(func(conn net.Conn) (net.Conn, error) {
parts := strings.Split(conn.RemoteAddr().String(), "|")
if len(parts) != 2 {
return conn, nil
}
muxrpcDumpDir := filepath.Join(
repoDir,
logToFile,
parts[1], // key first
parts[0],
)
return debug.WrapDump(muxrpcDumpDir, conn)
}))
}
2021-01-25 10:39:05 +00:00
2021-02-04 10:36:02 +00:00
if listenAddrDebug != "" {
2021-01-25 10:39:05 +00:00
go func() {
// http.Handle("/metrics", promhttp.Handler())
2021-02-04 10:36:02 +00:00
level.Debug(log).Log("starting", "metrics", "addr", listenAddrDebug)
err := http.ListenAndServe(listenAddrDebug, nil)
2021-01-25 10:39:05 +00:00
checkAndLog(err)
}()
}
2021-02-11 15:43:19 +00:00
r := repo.New(repoDir)
// open the sqlite version of the admindb
db, err := sqlite.Open(r)
if err != nil {
return fmt.Errorf("failed to initiate database: %w", err)
}
2021-02-04 13:13:52 +00:00
// create the shs+muxrpc server
2021-02-11 15:43:19 +00:00
roomsrv, err := mksrv.New(db.AllowList, opts...)
2021-01-25 10:39:05 +00:00
if err != nil {
2021-02-04 10:36:02 +00:00
return fmt.Errorf("failed to instantiate ssb server: %w", err)
2021-01-25 10:39:05 +00:00
}
2021-02-08 11:57:14 +00:00
// open the HTTP listener
httpLis, err := net.Listen("tcp", listenAddrHTTP)
if err != nil {
return fmt.Errorf("failed to open listener for HTTPdashboard: %w", err)
}
2021-01-25 10:39:05 +00:00
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
sig := <-c
level.Warn(log).Log("event", "killed", "msg", "received signal, shutting down", "signal", sig.String())
cancel()
2021-01-25 12:23:03 +00:00
roomsrv.Shutdown()
2021-02-08 11:57:14 +00:00
httpLis.Close()
2021-01-25 10:39:05 +00:00
time.Sleep(2 * time.Second)
2021-01-25 12:23:03 +00:00
err := roomsrv.Close()
2021-01-25 10:39:05 +00:00
checkAndLog(err)
time.Sleep(2 * time.Second)
os.Exit(0)
}()
2021-02-04 13:13:52 +00:00
// setup web dashboard handlers
2021-02-08 11:57:14 +00:00
dashboardH, err := handlers.New(
kitlog.With(log, "package", "web"),
2021-02-08 11:57:14 +00:00
repo.New(repoDir),
roomsrv.StateManager,
2021-02-08 16:47:42 +00:00
db.AuthWithSSB,
db.AuthFallback,
2021-02-11 15:43:19 +00:00
db.AllowList,
2021-02-08 11:57:14 +00:00
)
2021-02-04 13:13:52 +00:00
if err != nil {
return fmt.Errorf("failed to create HTTPdashboard handler: %w", err)
}
// TODO: setup other http goodies (such as CSRF and CSP)
2021-02-04 10:36:02 +00:00
level.Info(log).Log(
"event", "serving",
"ID", roomsrv.Whoami().Ref(),
"shsmuxaddr", listenAddrShsMux,
2021-02-04 13:13:52 +00:00
"httpaddr", listenAddrHTTP,
2021-02-04 10:36:02 +00:00
"version", Version,
"build", Build,
)
2021-02-04 13:13:52 +00:00
// start serving http connections
go func() {
2021-02-08 11:57:14 +00:00
srv := http.Server{
Addr: httpLis.Addr().String(),
// Good practice to set timeouts to avoid Slowloris attacks.
WriteTimeout: time.Second * 15,
ReadTimeout: time.Second * 15,
IdleTimeout: time.Second * 60,
Handler: dashboardH,
}
err = srv.Serve(httpLis)
2021-02-04 13:13:52 +00:00
if err != nil {
level.Error(log).Log("event", "http serve failed", "err", err)
}
}()
// start serving shs+muxrpc connections
2021-01-25 10:39:05 +00:00
for {
// Note: This is where the serving starts ;)
2021-01-25 12:23:03 +00:00
err = roomsrv.Network.Serve(ctx)
2021-01-25 10:39:05 +00:00
if err != nil {
2021-01-25 12:23:03 +00:00
level.Warn(log).Log("event", "roomsrv node.Serve returned", "err", err)
2021-01-25 10:39:05 +00:00
}
time.Sleep(1 * time.Second)
select {
case <-ctx.Done():
2021-01-25 12:23:03 +00:00
err := roomsrv.Close()
2021-01-25 10:39:05 +00:00
return err
default:
}
}
}
func main() {
2021-01-25 12:23:03 +00:00
if err := runroomsrv(); err != nil {
fmt.Fprintf(os.Stderr, "go-ssb-room: %s\n", err)
2021-01-25 10:39:05 +00:00
os.Exit(1)
}
}