diff options
Diffstat (limited to 'src/lib.go')
-rw-r--r-- | src/lib.go | 292 |
1 files changed, 19 insertions, 273 deletions
@@ -3,25 +3,21 @@ package papo import ( "bufio" "bytes" - "crypto/rand" "database/sql" - "encoding/hex" "errors" "flag" "fmt" - "io" - // "log" "log/slog" - "math/big" "net" "os" "regexp" "runtime/debug" "strings" "sync" - "syscall" "time" + g "euandre.org/gobang/src" + _ "github.com/mattn/go-sqlite3" ) @@ -33,245 +29,14 @@ var ( Colour string ) - -// FIXME: finish rewriting -// -// lastV7time is the last time we returned stored as: -// -// 52 bits of time in milliseconds since epoch -// 12 bits of (fractional nanoseconds) >> 8 -var lastV7Time int64 -var timeMu sync.Mutex -// getV7Time returns the time in milliseconds and nanoseconds / 256. -// The returned (milli << (12 + seq)) is guaranteed to be greater than -// (milli << (12 + seq)) returned by any previous call to getV7Time. -// `seq` Sequence number is between 0 and 3906 (nanoPerMilli >> 8) -func getV7Time(nano int64) (int64, int64) { - const nanoPerMilli = 1000000 - - milli := nano / nanoPerMilli - seq := (nano - (milli * nanoPerMilli)) >> 8 - now := milli << (12 + seq) - - timeMu.Lock() - defer timeMu.Unlock() - if now <= lastV7Time { - now = lastV7Time + 1 - milli = now >> 12 - seq = now & 0xfff - } - lastV7Time = now - return milli, seq -} - -const lengthUUID = 16 - -type UUID struct { - bytes [lengthUUID]byte -} - -func NewUUID() UUID { - var buf [lengthUUID]byte - _, err := io.ReadFull(rand.Reader, buf[7:]) - FatalIf(err) - - buf[6] = (buf[6] & 0x0f) | 0x40 // Version 4 - buf[8] = (buf[8] & 0x3f) | 0x80 // Variant is 10 - - t, s := getV7Time(time.Now().UnixNano()) - - buf[0] = byte(t >> 40) - buf[1] = byte(t >> 32) - buf[2] = byte(t >> 24) - buf[3] = byte(t >> 16) - buf[4] = byte(t >> 8) - buf[5] = byte(t >> 0) - - buf[6] = 0x70 | (0x0f & byte(s >> 8)) - buf[7] = byte(s) - return UUID { bytes: buf } -} - -func UUIDToString(uuid UUID) string { - const dashCount = 4 - const encodedLength = (lengthUUID * 2) + dashCount - dst := [encodedLength]byte { - 0, 0, 0, 0, - 0, 0, 0, 0, - '-', - 0, 0, 0, 0, - '-', - 0, 0, 0, 0, - '-', - 0, 0, 0, 0, - '-', - 0, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, 0, 0, - } - - hex.Encode(dst[ 0:8], uuid.bytes[0:4]) - hex.Encode(dst[ 9:13], uuid.bytes[4:6]) - hex.Encode(dst[14:18], uuid.bytes[6:8]) - hex.Encode(dst[19:23], uuid.bytes[8:10]) - hex.Encode(dst[24:36], uuid.bytes[10:]) - - return string(dst[:]) -} - - -func Debug(message string, type_ string, args ...any) { - slog.Debug( - message, - append( - []any { - "id", UUIDToString(NewUUID()), - "kind", "log", - "type", type_, - }, - args..., - )..., - ) -} - -func Info(message string, type_ string, args ...any) { - slog.Info( - message, - append( - []any { - "id", UUIDToString(NewUUID()), - "kind", "log", - "type", type_, - }, - args..., - )..., - ) -} - -func Warning(message string, type_ string, args ...any) { - slog.Warn( - message, - append( - []any { - "id", UUIDToString(NewUUID()), - "kind", "log", - "type", type_, - }, - args..., - )..., - ) -} - -func Error(message string, type_ string, args ...any) { - slog.Error( - message, - append( - []any { - "id", UUIDToString(NewUUID()), - "kind", "log", - "type", type_, - }, - args..., - )..., - ) -} - -func Metric(type_ string, label string, args ...any) { - slog.Info( - "_", - append( - []any { - "id", UUIDToString(NewUUID()), - "kind", "metric", - "type", type_, - "label", label, - }, - args..., - )..., - ) -} - -type Gauge struct { - Inc func(...any) - Dec func(...any) -} - -var zero = big.NewInt(0) -var one = big.NewInt(1) -func MakeGauge(label string, staticArgs ...any) Gauge { - count := big.NewInt(0) - emitGauge := func(dynamicArgs ...any) { - if count.Cmp(zero) == -1 { - Error( - "Gauge went negative", - "process-metric", - append( - []any { "value", count }, - append( - staticArgs, - dynamicArgs..., - )..., - )..., - ) - return // avoid wrong metrics being emitted - } - Metric( - "gauge", label, - // TODO: we'll have slices.Concat on Go 1.22 - append( - []any { "value", count }, - append( - staticArgs, - dynamicArgs..., - )..., - )..., - ) - } - return Gauge { - Inc: func(dynamicArgs ...any) { - count.Add(count, one) - emitGauge(dynamicArgs...) - }, - Dec: func(dynamicArgs ...any) { - count.Sub(count, one) - emitGauge(dynamicArgs...) - }, - } -} - -func MakeCounter(label string) func(...any) { - return func(args ...any) { - Metric( - "counter", label, - append([]any { "value", 1 }, args...)..., - ) - } -} - -var EmitActiveConnection = MakeGauge("active-connections") -var EmitNicksInChannel = MakeGauge("nicks-in-channel") -var EmitReceivedMessage = MakeCounter("received-message") +var EmitActiveConnection = g.MakeGauge("active-connections") +var EmitNicksInChannel = g.MakeGauge("nicks-in-channel") +var EmitReceivedMessage = g.MakeCounter("received-message") const pingFrequency = time.Duration(30) * time.Second const pongMaxLatency = time.Duration(5) * time.Second -func Fatal(err error) { - Error( - "Fatal error", "fatal-error", - "error", err, - "stack", string(debug.Stack()), - ) - syscall.Kill(os.Getpid(), syscall.SIGABRT) - os.Exit(3) -} - -func FatalIf(err error) { - if err != nil { - Fatal(err) - } -} - type Channel struct { } @@ -439,13 +204,13 @@ func HandleConnection(ctx *Context, conn net.Conn) { func IRCdLoop(ctx *Context, publicSocketPath string) { listener, err := net.Listen("unix", publicSocketPath) - FatalIf(err) - Info("IRCd started", "component-up", "component", "ircd") + g.FatalIf(err) + g.Info("IRCd started", "component-up", "component", "ircd") for { conn, err := listener.Accept() if err != nil { - Warning( + g.Warning( "Error accepting a public IRCd connection", "accept-connection", "err", err, @@ -459,13 +224,13 @@ func IRCdLoop(ctx *Context, publicSocketPath string) { func CommandListenerLoop(ctx *Context, commandSocketPath string) { listener, err := net.Listen("unix", commandSocketPath) - FatalIf(err) - Info("command listener started", "component-up", "component", "command-listener") + g.FatalIf(err) + g.Info("command listener started", "component-up", "component", "command-listener") for { conn, err := listener.Accept() if err != nil { - Warning( + g.Warning( "Error accepting a command connection", "accept-command", "err", err, @@ -479,7 +244,7 @@ func CommandListenerLoop(ctx *Context, commandSocketPath string) { } func TransactorLoop(ctx *Context) { - Info("transactor started", "component-up", "component", "transactor") + g.Info("transactor started", "component-up", "component", "transactor") EmitActiveConnection.Inc() for tx := range ctx.tx { @@ -487,29 +252,10 @@ func TransactorLoop(ctx *Context) { } } -func SetLoggerOutput(w io.Writer) { - slog.SetDefault(slog.New(slog.NewJSONHandler(w, &slog.HandlerOptions { - AddSource: true, - })).With( - slog.Group( - "info", - "pid", os.Getpid(), - "ppid", os.Getppid(), - "puuid", UUIDToString(NewUUID()), - ), - )) -} - -func SetTraceback() { - if os.Getenv("GOTRACEBACK") == "" { - debug.SetTraceback("crash") - } -} - func SetHostname() { var err error Hostname, err = os.Hostname() - FatalIf(err) + g.FatalIf(err) } func SetEnvironmentVariables() { @@ -526,13 +272,12 @@ func SetEnvironmentVariables() { func InitDB(databasePath string) *sql.DB { DB, err := sql.Open("sqlite3", databasePath) - FatalIf(err) + g.FatalIf(err) return DB } -func init() { - SetLoggerOutput(os.Stdout) - SetTraceback() +func Init() { + g.Init() SetHostname() SetEnvironmentVariables() } @@ -540,10 +285,10 @@ func init() { func Start(ctx *Context, publicSocketPath string, commandSocketPath string) { buildInfo, ok := debug.ReadBuildInfo() if !ok { - Fatal(errors.New("error on debug.ReadBuildInfo()")) + g.Fatal(errors.New("error on debug.ReadBuildInfo()")) } - Info("-", "lifecycle-event", + g.Info("-", "lifecycle-event", "event", "starting-server", slog.Group( "go", @@ -595,6 +340,7 @@ var ( ) func Main() { + Init() flag.Parse() ctx := BuildContext(*databasePath) Start(ctx, *publicSocketPath, *commandSocketPath) |