Commit: Bulk unfinished work

This commit is contained in:
2026-01-22 17:39:04 +01:00
parent 6c46b4efcc
commit 3a9acc42a2
68 changed files with 5047 additions and 1064 deletions

32
fx/echo.go Normal file
View File

@@ -0,0 +1,32 @@
package fx
import (
"fmt"
"io"
"net/http"
"os"
)
// EchoHandler is an http.Handler that copies its request body
// back to the response.
type EchoHandler struct{}
// NewEchoHandler builds a new EchoHandler.
func NewEchoHandler() *EchoHandler {
return &EchoHandler{}
}
// ServeHTTP handles an HTTP request to the /echo endpoint.
func (*EchoHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if _, err := io.Copy(w, r.Body); err != nil {
fmt.Fprintln(os.Stderr, "Failed to handle request:", err)
}
}
func (e *EchoHandler) Handler() http.Handler {
return e
}
func (*EchoHandler) Path() string {
return "/echo"
}

View File

@@ -0,0 +1,9 @@
package interfaces
import "context"
type BasicIntegration interface {
OnStart(context.Context) error
OnStop(context.Context) error
Invoke()
}

View File

@@ -0,0 +1 @@
package stores

View File

@@ -0,0 +1,17 @@
package stores
import "context"
type Message struct {
Id int
From string
Subject string
Body string
}
type MessageStore interface {
AddMessage(ctx context.Context, m *Message) error
GetMessage(ctx context.Context, id int) (*Message, error)
ListMessages(ctx context.Context) ([]*Message, error)
RemoveMessage(ctx context.Context, id int) error
}

View File

@@ -0,0 +1 @@
package stores

View File

@@ -0,0 +1,44 @@
package stores
import (
"errors"
"strconv"
)
type Session struct {
Token string
UserID uint
MandantId uint
}
func (s *Session) Deserialize(t string, m map[string]string) (*Session, error) {
userid, err := strconv.Atoi(m["userid"])
if err != nil {
return nil, errors.New("Userid from cache not an int")
}
mandantid, err := strconv.Atoi(m["mandantid"])
if err != nil {
return nil, errors.New("Mandantid from cache not an int")
}
s.Token = t
s.UserID = uint(userid)
s.MandantId = uint(mandantid)
return s, nil
}
func (s *Session) Serialize() map[string]string {
m := make(map[string]string)
m["userid"] = strconv.Itoa(int(s.UserID))
m["mandantid"] = strconv.Itoa(int(s.MandantId))
return m
}
type SessionStore interface {
AddSession(s *Session)
GetSessionFromToken(token string) (*Session, error)
RemoveSession(token string)
SetMandantInSession(token string, mandantId uint) error
}

View File

@@ -0,0 +1 @@
package stores

137
fx/logger.go Normal file
View File

@@ -0,0 +1,137 @@
package fx
import (
"context"
"log/slog"
"time"
"go.uber.org/fx"
"go.opentelemetry.io/contrib/bridges/otelslog"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp"
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
"go.opentelemetry.io/otel/log/global"
"go.opentelemetry.io/otel/propagation"
olog "go.opentelemetry.io/otel/sdk/log"
"go.opentelemetry.io/otel/sdk/metric"
"go.opentelemetry.io/otel/sdk/trace"
)
func NewOtelTracerProvider(lc fx.Lifecycle) *trace.TracerProvider {
tp, err := newTracerProvider()
if err != nil {
panic(err)
}
lc.Append(fx.Hook{
OnStop: func(ctx context.Context) error {
return tp.Shutdown(ctx)
},
})
return tp
}
func NewOtelMeterProvider(lc fx.Lifecycle) *metric.MeterProvider {
mp, err := newMeterProvider()
if err != nil {
panic(err)
}
lc.Append(fx.Hook{
OnStop: func(ctx context.Context) error {
return mp.Shutdown(ctx)
},
})
return mp
}
func NewOtelLoggerProvider(lc fx.Lifecycle) *olog.LoggerProvider {
lp, err := newLoggerProvider()
if err != nil {
panic(err)
}
lc.Append(fx.Hook{
OnStop: func(ctx context.Context) error {
return lp.Shutdown(ctx)
},
})
return lp
}
func NewLogger(loggerProvider *olog.LoggerProvider) *slog.Logger {
logger := otelslog.NewLogger("Application", otelslog.WithLoggerProvider(loggerProvider))
return logger
}
// setupOTelSDK bootstraps the OpenTelemetry pipeline.
// If it does not return an error, make sure to call shutdown for proper cleanup.
func SetupOTelSDK(tracerProvider *trace.TracerProvider, meterProvider *metric.MeterProvider, loggerProvider *olog.LoggerProvider) {
// Set up propagator.
prop := newPropagator()
otel.SetTextMapPropagator(prop)
// Set up trace provider.
otel.SetTracerProvider(tracerProvider)
otel.SetMeterProvider(meterProvider)
// Set up logger provider.
global.SetLoggerProvider(loggerProvider)
}
func newPropagator() propagation.TextMapPropagator {
return propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{},
propagation.Baggage{},
)
}
func newTracerProvider() (*trace.TracerProvider, error) {
traceExporter, err := otlptracehttp.New(context.Background())
if err != nil {
return nil, err
}
tracerProvider := trace.NewTracerProvider(
trace.WithBatcher(traceExporter,
// Default is 5s. Set to 1s for demonstrative purposes.
trace.WithBatchTimeout(time.Second)),
)
return tracerProvider, nil
}
func newMeterProvider() (*metric.MeterProvider, error) {
metricExporter, err := otlpmetrichttp.New(context.Background())
if err != nil {
return nil, err
}
meterProvider := metric.NewMeterProvider(
metric.WithReader(metric.NewPeriodicReader(metricExporter,
// Default is 1m. Set to 3s for demonstrative purposes.
metric.WithInterval(3*time.Second))),
)
return meterProvider, nil
}
func newLoggerProvider() (*olog.LoggerProvider, error) {
logExporter, err := otlploghttp.New(context.Background())
if err != nil {
return nil, err
}
loggerProvider := olog.NewLoggerProvider(
olog.WithProcessor(olog.NewBatchProcessor(logExporter)),
)
logger := otelslog.NewLogger("sloger", otelslog.WithLoggerProvider(loggerProvider))
logger.Info("Hello")
return loggerProvider, nil
}

56
fx/routes.go Normal file
View File

@@ -0,0 +1,56 @@
package fx
import (
"log/slog"
"net/http"
"os"
connectcors "connectrpc.com/cors"
"github.com/rs/cors"
)
type Handler interface {
Handler() http.Handler
Path() string
}
type route struct {
path string
handler http.Handler
}
func NewRoute(path string, handler http.Handler) Handler {
return &route{
path: path,
handler: handler,
}
}
func (r *route) Handler() http.Handler {
return r.handler
}
func (r *route) Path() string {
return r.path
}
// NewServeMux builds a ServeMux that will route requests
// to the given EchoHandler.
func NewServeMux(handlers []Handler, logger *slog.Logger) http.Handler {
mux := http.NewServeMux()
for _, h := range handlers {
logger.Debug("Registering route", "path", h.Path())
mux.Handle(h.Path(), h.Handler())
}
handler := cors.New(cors.Options{
AllowedOrigins: []string{"http://10.8.0.3:3001", "http://10.8.0.3:3001/", os.Getenv("FRONTEND_URI")}, // replace with your domain
AllowedMethods: connectcors.AllowedMethods(),
AllowedHeaders: append(connectcors.AllowedHeaders(), "authentication", "Authentication"),
ExposedHeaders: connectcors.ExposedHeaders(),
AllowCredentials: true,
}).Handler(mux)
return handler
}

40
fx/server.go Normal file
View File

@@ -0,0 +1,40 @@
package fx
import (
"context"
"fmt"
"net/http"
"go.uber.org/fx"
)
func NewHTTPServer(lc fx.Lifecycle, handler http.Handler) *http.Server {
p := new(http.Protocols)
p.SetHTTP1(true)
// Use h2c so we can serve HTTP/2 without TLS.
p.SetUnencryptedHTTP2(true)
srv := &http.Server{
Addr: ":3002",
Protocols: p,
Handler: handler,
}
lc.Append(fx.Hook{
OnStart: func(ctx context.Context) error {
go func() {
fmt.Println("Listening on :3002")
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
panic(err)
}
}()
return nil
},
OnStop: func(ctx context.Context) error {
return srv.Shutdown(ctx)
},
})
return srv
}