mirror of
https://github.com/hanzo-fi/stack.git
synced 2026-10-30 20:34:43 +00:00
119 lines
2.6 KiB
Go
119 lines
2.6 KiB
Go
package backend
|
|
|
|
import (
|
|
"math/rand"
|
|
"net/http"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
|
|
"github.com/formancehq/ledger/internal/storage/sqlutils"
|
|
|
|
sharedapi "github.com/formancehq/go-libs/api"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/formancehq/go-libs/logging"
|
|
"github.com/formancehq/ledger/internal/opentelemetry/tracer"
|
|
)
|
|
|
|
var (
|
|
r *rand.Rand
|
|
mu sync.Mutex
|
|
)
|
|
|
|
const (
|
|
ErrOutdatedSchema = "OUTDATED_SCHEMA"
|
|
)
|
|
|
|
func init() {
|
|
r = rand.New(rand.NewSource(time.Now().UnixNano()))
|
|
}
|
|
|
|
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
|
|
|
|
func randomTraceID(n int) string {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
|
|
b := make([]rune, n)
|
|
for i := range b {
|
|
b[i] = letterRunes[r.Intn(len(letterRunes))]
|
|
}
|
|
return string(b)
|
|
}
|
|
|
|
func LedgerMiddleware(
|
|
resolver Backend,
|
|
excludePathFromSchemaCheck []string,
|
|
) func(handler http.Handler) http.Handler {
|
|
return func(handler http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
name := chi.URLParam(r, "ledger")
|
|
if name == "" {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
ctx, span := tracer.Start(r.Context(), name)
|
|
defer span.End()
|
|
|
|
r = r.WithContext(ctx)
|
|
|
|
loggerFields := map[string]any{
|
|
"ledger": name,
|
|
}
|
|
if span.SpanContext().TraceID().IsValid() {
|
|
loggerFields["trace-id"] = span.SpanContext().TraceID().String()
|
|
} else {
|
|
loggerFields["trace-id"] = randomTraceID(10)
|
|
}
|
|
|
|
r = r.WithContext(logging.ContextWithFields(r.Context(), loggerFields))
|
|
|
|
l, err := resolver.GetLedgerEngine(r.Context(), name)
|
|
if err != nil {
|
|
switch {
|
|
case sqlutils.IsNotFoundError(err):
|
|
sharedapi.WriteErrorResponse(w, http.StatusNotFound, "LEDGER_NOT_FOUND", err)
|
|
default:
|
|
sharedapi.InternalServerError(w, r, err)
|
|
}
|
|
return
|
|
}
|
|
|
|
pathWithoutLedger := r.URL.Path[1:]
|
|
nextSlash := strings.Index(pathWithoutLedger, "/")
|
|
if nextSlash >= 0 {
|
|
pathWithoutLedger = pathWithoutLedger[nextSlash:]
|
|
} else {
|
|
pathWithoutLedger = ""
|
|
}
|
|
|
|
excluded := false
|
|
for _, path := range excludePathFromSchemaCheck {
|
|
if pathWithoutLedger == path {
|
|
excluded = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !excluded {
|
|
isUpToDate, err := l.IsDatabaseUpToDate(ctx)
|
|
if err != nil {
|
|
sharedapi.BadRequest(w, sharedapi.ErrorInternal, err)
|
|
return
|
|
}
|
|
if !isUpToDate {
|
|
sharedapi.BadRequest(w, ErrOutdatedSchema, errors.New("You need to upgrade your ledger schema to the last version"))
|
|
return
|
|
}
|
|
}
|
|
|
|
handler.ServeHTTP(w, r.WithContext(ContextWithLedger(r.Context(), l)))
|
|
})
|
|
}
|
|
}
|