feat(backend): analytics server initial setup

This commit is contained in:
Shekar Siri 2024-10-15 15:54:06 +02:00
parent d0df66b539
commit c6a55b18a8
6 changed files with 191 additions and 0 deletions

2
.gitignore vendored
View file

@ -1,6 +1,8 @@
public
.cache
node_modules
backend/pkg/mod
backend/pkg/sumdb
*DS_Store
*.env
*.log

9
backend.iml Normal file
View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$/backend" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View file

@ -0,0 +1,58 @@
package main
import (
"context"
"openreplay/backend/internal/http/server"
"openreplay/backend/pkg/analytics"
"openreplay/backend/pkg/analytics/api"
"openreplay/backend/pkg/db/postgres/pool"
"openreplay/backend/pkg/logger"
"os"
"os/signal"
"syscall"
config "openreplay/backend/internal/config/analytics"
)
func main() {
ctx := context.Background()
log := logger.New()
cfg := config.New(log)
pgConn, err := pool.New(cfg.Postgres.String())
if err != nil {
log.Fatal(ctx, "can't init postgres connection: %s", err)
}
defer pgConn.Close()
services, err := analytics.NewServiceBuilder(log, cfg, pgConn)
if err != nil {
log.Fatal(ctx, "can't init services: %s", err)
}
router, err := api.NewRouter(cfg, log, services)
if err != nil {
log.Fatal(ctx, "failed while creating router: %s", err)
}
analyticsServer, err := server.New(router.GetHandler(), cfg.HTTPHost, cfg.HTTPPort, cfg.HTTPTimeout)
if err != nil {
log.Fatal(ctx, "failed while creating server: %s", err)
}
go func() {
if err := analyticsServer.Start(); err != nil {
log.Fatal(ctx, "http server error: %s", err)
}
}()
log.Info(ctx, "server successfully started on port %s", cfg.HTTPPort)
// Wait stop signal to shut down server gracefully
sigchan := make(chan os.Signal, 1)
signal.Notify(sigchan, syscall.SIGINT, syscall.SIGTERM)
<-sigchan
log.Info(ctx, "shutting down the server")
analyticsServer.Stop()
}

View file

@ -0,0 +1,36 @@
package analytics
import (
"time"
"openreplay/backend/internal/config/common"
"openreplay/backend/internal/config/configurator"
"openreplay/backend/internal/config/objectstorage"
"openreplay/backend/internal/config/redis"
"openreplay/backend/pkg/env"
"openreplay/backend/pkg/logger"
)
type Config struct {
common.Config
common.Postgres
redis.Redis
objectstorage.ObjectsConfig
FSDir string `env:"FS_DIR,required"`
HTTPHost string `env:"HTTP_HOST,default="`
HTTPPort string `env:"HTTP_PORT,required"`
HTTPTimeout time.Duration `env:"HTTP_TIMEOUT,default=60s"`
JsonSizeLimit int64 `env:"JSON_SIZE_LIMIT,default=131072"` // 128KB
UseAccessControlHeaders bool `env:"USE_CORS,default=false"`
ProjectExpiration time.Duration `env:"PROJECT_EXPIRATION,default=10m"`
JWTSecret string `env:"JWT_SECRET,required"`
MinimumStreamDuration int `env:"MINIMUM_STREAM_DURATION,default=15000"` // 15s
WorkerID uint16
}
func New(log logger.Logger) *Config {
cfg := &Config{WorkerID: env.WorkerID()}
configurator.Process(log, cfg)
return cfg
}

View file

@ -0,0 +1,59 @@
package api
import (
"fmt"
"github.com/gorilla/mux"
"net/http"
analyticsConfig "openreplay/backend/internal/config/analytics"
"openreplay/backend/pkg/analytics"
"openreplay/backend/pkg/logger"
"sync"
)
type Router struct {
log logger.Logger
cfg *analyticsConfig.Config
router *mux.Router
mutex *sync.RWMutex
services *analytics.ServicesBuilder
}
func NewRouter(cfg *analyticsConfig.Config, log logger.Logger, services *analytics.ServicesBuilder) (*Router, error) {
switch {
case cfg == nil:
return nil, fmt.Errorf("config is empty")
case services == nil:
return nil, fmt.Errorf("services is empty")
case log == nil:
return nil, fmt.Errorf("logger is empty")
}
e := &Router{
log: log,
cfg: cfg,
mutex: &sync.RWMutex{},
services: services,
}
e.init()
return e, nil
}
func (e *Router) init() {
e.router = mux.NewRouter()
// Root route
e.router.HandleFunc("/", e.ping)
// Analytics routes
// e.router.HandleFunc("/v1/analytics", e.createAnalytics).Methods("POST", "OPTIONS")
// e.router.HandleFunc("/v1/analytics/{id}", e.getAnalytics).Methods("GET", "OPTIONS")
// e.router.HandleFunc("/v1/analytics/{id}", e.updateAnalytics).Methods("PATCH", "OPTIONS")
// e.router.HandleFunc("/v1/analytics", e.getAnalytics).Methods("GET", "OPTIONS")
}
func (e *Router) ping(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}
func (e *Router) GetHandler() http.Handler {
return e.router
}

View file

@ -0,0 +1,27 @@
package analytics
import (
"openreplay/backend/internal/config/analytics"
"openreplay/backend/pkg/db/postgres/pool"
"openreplay/backend/pkg/flakeid"
"openreplay/backend/pkg/logger"
"openreplay/backend/pkg/objectstorage"
"openreplay/backend/pkg/objectstorage/store"
)
type ServicesBuilder struct {
Flaker *flakeid.Flaker
ObjStorage objectstorage.ObjectStorage
}
func NewServiceBuilder(log logger.Logger, cfg *analytics.Config, pgconn pool.Pool) (*ServicesBuilder, error) {
objStore, err := store.NewStore(&cfg.ObjectsConfig)
if err != nil {
return nil, err
}
flaker := flakeid.NewFlaker(cfg.WorkerID)
return &ServicesBuilder{
Flaker: flaker,
ObjStorage: objStore,
}, nil
}