forked from phc/website
chore: refactored sl and added an hooks system
modified: cmd/dev-server/main.go, cmd/server/main.go
Aggiornati per utilizzare il nuovo sistema degli hooks, ora nei "main" vanno
solo chiamate "ProvideValue", "Provide" e "ProvideHook" ed una finale
di "Invoke" o "Use". Mentre nei vari servizi vanno solo chiamate "Use"
o "UseHook"
modified: libs/sl/sl.go
Rinominati "InjectValue" e "InjectLazy" a "Provide" e "ProvideFunc", altro
refactor di varie cose ed aggiunto il concetto degli hook per poter
iniettare anche più di un servizio dentro un altro in un preciso ordine.
modified: server/config/config.go
Lieve refactor ed aggiunta la variabile "NPM_COMMAND" configurabile per la
fase di development.
modified: server/listautenti/listautenti.go
Ora questo è un vero e proprio servizio "state-less", fornisce solo una
funzione che monta tutte le route necessarie a questo servizio. Più avanti
dipenderà da LDAP quindi forse sarà leggermente più complicato.
modified: server/listautenti/listautenti_test.go
Aggiornato questo test, ora usa il nuovo sistema e funge di nuovo.
deleted: server/routes/routes.go
Il sistema degli hook è stato introdotto anche per semplificare questa cosa
che ora infatti non serve più.
modified: server/server.go
Ora il server non chiama più "InjectValue" con i sotto-router ma espone solo
un hook che passa i sotto router come parametri, in questo modo è più
facile aggiungere e togliere servizi direttamente alla radice quando viene
configurata tutta l'applicazione.
This commit is contained in:
+20
-12
@@ -24,9 +24,15 @@ func init() {
|
||||
func main() {
|
||||
l := sl.New()
|
||||
|
||||
cfg := sl.InjectValue(l, config.Slot, config.TestingDevelopmentConfig)
|
||||
//
|
||||
// Setup the application
|
||||
//
|
||||
|
||||
sl.InjectValue[database.Database](l, database.Slot, &database.Memory{
|
||||
// Config
|
||||
sl.ProvideFunc(l, config.Slot, config.Configure)
|
||||
|
||||
// Database
|
||||
sl.Provide[database.Database](l, database.Slot, &database.Memory{
|
||||
Users: []model.User{
|
||||
{
|
||||
Id: "e39ad8d5-a087-4cb2-8fd7-5a6ca3f6a534",
|
||||
@@ -43,21 +49,23 @@ func main() {
|
||||
},
|
||||
})
|
||||
|
||||
sl.InjectLazy(l, server.Slot, server.Configure)
|
||||
sl.InjectLazy(l, listautenti.Slot, listautenti.Configure)
|
||||
// Server
|
||||
sl.ProvideFunc(l, server.Slot, server.Configure)
|
||||
sl.ProvideHook(l, server.ApiRoutesHook,
|
||||
listautenti.MountApiRoutesHook,
|
||||
)
|
||||
|
||||
srv, err := sl.Use(l, server.Slot)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
//
|
||||
// Start the application
|
||||
//
|
||||
|
||||
go func() {
|
||||
log.Fatal(srv.Router.Listen(cfg.Host))
|
||||
}()
|
||||
sl.MustInvoke(l, server.Slot)
|
||||
|
||||
r, w := io.Pipe()
|
||||
|
||||
cmd := exec.Command("pnpm", "run", "dev")
|
||||
cfg := sl.MustUse(l, config.Slot)
|
||||
|
||||
cmd := exec.Command(cfg.NpmCommand, "run", "dev")
|
||||
cmd.Stdout = w
|
||||
|
||||
go func() {
|
||||
|
||||
+20
-8
@@ -10,18 +10,22 @@ import (
|
||||
|
||||
"git.phc.dm.unipi.it/phc/website/server/config"
|
||||
"git.phc.dm.unipi.it/phc/website/server/database"
|
||||
"git.phc.dm.unipi.it/phc/website/server/listautenti"
|
||||
"git.phc.dm.unipi.it/phc/website/server/model"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := sl.New()
|
||||
|
||||
cfg := sl.InjectValue(l, config.Slot, config.Config{
|
||||
Mode: "production",
|
||||
Host: ":4000",
|
||||
})
|
||||
//
|
||||
// Setup the application
|
||||
//
|
||||
|
||||
sl.InjectValue[database.Database](l, database.Slot, &database.Memory{
|
||||
// Config
|
||||
sl.Provide(l, config.Slot, config.ExampleProductionConfig)
|
||||
|
||||
// Database
|
||||
sl.Provide[database.Database](l, database.Slot, &database.Memory{
|
||||
Users: []model.User{
|
||||
{
|
||||
Id: "e39ad8d5-a087-4cb2-8fd7-5a6ca3f6a534",
|
||||
@@ -38,10 +42,18 @@ func main() {
|
||||
},
|
||||
})
|
||||
|
||||
srv, err := server.Configure(l)
|
||||
// Server
|
||||
sl.ProvideFunc(l, server.Slot, server.Configure)
|
||||
sl.ProvideHook(l, server.ApiRoutesHook,
|
||||
listautenti.MountApiRoutesHook,
|
||||
)
|
||||
|
||||
//
|
||||
// Start the application
|
||||
//
|
||||
|
||||
err := sl.Invoke(l, server.Slot)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Fatal(srv.Router.Listen(cfg.Host))
|
||||
}
|
||||
|
||||
+134
-41
@@ -1,20 +1,20 @@
|
||||
// The [sl] package has two main concepts, the [ServiceLocator] itself is the
|
||||
// main object that one should pass around through the application. A
|
||||
// [ServiceLocator] has a list of slots that can be filled with
|
||||
// [InjectLazy] and [InjectValue] and retrieved with [Use]. Slots should
|
||||
// [ProvideFunc] and [Provide] and retrieved with [Use]. Slots should
|
||||
// be unique by type and they can only be created with the [NewSlot] function.
|
||||
//
|
||||
// The usual way to use this module is to make slots for Go interfaces and
|
||||
// then pass implementations using the [InjectValue] and
|
||||
// [InjectLazy] functions.
|
||||
// then pass implementations using the [Provide] and
|
||||
// [ProvideFunc] functions.
|
||||
//
|
||||
// Services can be of various types:
|
||||
// - a service with no dependencies can be directly injected inside a
|
||||
// ServiceLocator using [InjectValue].
|
||||
// ServiceLocator using [Provide].
|
||||
// - a service with dependencies on other service should use
|
||||
// [InjectLazy]. This lets the service to initialize itself when needed
|
||||
// [ProvideFunc]. This lets the service configure itself when needed
|
||||
// and makes the developer not think about correctly ordering the
|
||||
// initialization of its dependencies
|
||||
// recursive configuration of its dependencies.
|
||||
// - a service can also be private, in this case the slot for a service
|
||||
// should be a private field in the service package. This kind of
|
||||
// services should also provide a way to inject them into a
|
||||
@@ -40,8 +40,16 @@ import (
|
||||
var Logger *log.Logger = log.New(os.Stderr, "[service locator] ", log.Lmsgprefix)
|
||||
|
||||
// slot is just a "typed" unique "symbol".
|
||||
//
|
||||
// This must be defined like so and not for example "struct{ typeName string }"
|
||||
// because we might want to have more slots for the same type.
|
||||
type slot[T any] *struct{}
|
||||
|
||||
type Hook[T any] func(*ServiceLocator, T) error
|
||||
|
||||
// hook is just a typed unique symbol
|
||||
type hook[T any] *struct{}
|
||||
|
||||
// NewSlot is the only way to create instances of the slot type. Each instance
|
||||
// is unique.
|
||||
//
|
||||
@@ -51,85 +59,110 @@ func NewSlot[T any]() slot[T] {
|
||||
return slot[T](new(struct{}))
|
||||
}
|
||||
|
||||
// slotEntry represents a service that can lazily initialized
|
||||
// (using "createFunc"). Once initialized the instance is kept in the "value"
|
||||
// NewHook is the only way to create instances of the hook type. Each instance
|
||||
// is unique.
|
||||
//
|
||||
// This lets you have a service dispatch an hook
|
||||
func NewHook[T any]() hook[T] {
|
||||
return hook[T](new(struct{}))
|
||||
}
|
||||
|
||||
// slotEntry represents a service that can lazily configured
|
||||
// (using "configureFunc"). Once configured the instance is kept in the "value"
|
||||
// field and "created" will always be "true". The field "typeName" just for
|
||||
// debugging purposes.
|
||||
type slotEntry struct {
|
||||
// typeName is just used for debugging purposes
|
||||
typeName string
|
||||
|
||||
createFunc func(*ServiceLocator) (any, error)
|
||||
created bool
|
||||
// configureFunc is used by lazily provided slot values to tell how to
|
||||
// configure them self when required
|
||||
configureFunc func(*ServiceLocator) (any, error)
|
||||
|
||||
// configured tells if this slot is already configured
|
||||
configured bool
|
||||
|
||||
// value for this slot
|
||||
value any
|
||||
}
|
||||
|
||||
func (s *slotEntry) checkInitialized(l *ServiceLocator) error {
|
||||
if !s.created {
|
||||
v, err := s.createFunc(l)
|
||||
// checkConfigured tries to call configure on this slot entry if not already configured
|
||||
func (s *slotEntry) checkConfigured(l *ServiceLocator) error {
|
||||
if !s.configured {
|
||||
v, err := s.configureFunc(l)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Logger.Printf(`[slot: %s] initialized value of type %T`, s.typeName, v)
|
||||
Logger.Printf(`[slot: %s] configured service of type %T`, s.typeName, v)
|
||||
|
||||
s.created = true
|
||||
s.configured = true
|
||||
s.value = v
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type hookEntry struct {
|
||||
// typeName is just used for debugging purposes
|
||||
typeName string
|
||||
|
||||
// listeners is a list of functions to call when this hook is called
|
||||
listeners []func(*ServiceLocator, any) error
|
||||
}
|
||||
|
||||
// ServiceLocator is the main context passed around to retrive service
|
||||
// instances, the interface uses generics so to inject and retrive service
|
||||
// instances you should use the functions [InjectValue], [InjectLazy] and
|
||||
// [Use].
|
||||
// instances you should use the functions [Provide], [ProvideFunc] and [Use].
|
||||
// This is essentially a dictionary indexed by slots that are them self just
|
||||
// typed unique symbols
|
||||
type ServiceLocator struct {
|
||||
providers map[any]*slotEntry
|
||||
hooks map[any]*hookEntry
|
||||
}
|
||||
|
||||
// New creates a new [ServiceLocator] context to pass around in the application.
|
||||
func New() *ServiceLocator {
|
||||
return &ServiceLocator{
|
||||
providers: map[any]*slotEntry{},
|
||||
hooks: map[any]*hookEntry{},
|
||||
}
|
||||
}
|
||||
|
||||
// InjectValue will inject a concrete instance inside the ServiceLocator "l"
|
||||
// for the given "slotKey". This should be used for injecting "static"
|
||||
// services, for instances whose construction depend on other services you
|
||||
// should use the [InjectLazy] function.
|
||||
// Provide will inject a concrete instance inside the ServiceLocator "l" for
|
||||
// the given "slotKey". This should be used for injecting "static" services, for
|
||||
// instances whose construction depend on other services you should use the
|
||||
// [ProvideFunc] function.
|
||||
//
|
||||
// This is generic over "T" to check that instances for the given slot type
|
||||
// check as "T" can also be an interface.
|
||||
func InjectValue[T any](l *ServiceLocator, slotKey slot[T], value T) T {
|
||||
Logger.Printf(`[slot: %s] injected value of type %T`, getTypeName[T](), value)
|
||||
func Provide[T any](l *ServiceLocator, slotKey slot[T], value T) T {
|
||||
typeName := getTypeName[T]()
|
||||
|
||||
Logger.Printf(`[slot: %s] provided value of type %T`, typeName, value)
|
||||
|
||||
l.providers[slotKey] = &slotEntry{
|
||||
getTypeName[T](),
|
||||
nil,
|
||||
true,
|
||||
value,
|
||||
typeName: typeName,
|
||||
configured: true,
|
||||
value: value,
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// InjectLazy will inject an instance inside the given ServiceLocator
|
||||
// ProvideFunc will inject an instance inside the given ServiceLocator
|
||||
// and "slotKey" that is created only when requested with a call to the
|
||||
// [Use] function.
|
||||
//
|
||||
// This is generic over "T" to check that instances for the given slot type
|
||||
// check as "T" can also be an interface.
|
||||
func InjectLazy[T any](l *ServiceLocator, slotKey slot[T], createFunc func(*ServiceLocator) (T, error)) {
|
||||
Logger.Printf(`[slot: %s] injected lazy`, getTypeName[T]())
|
||||
func ProvideFunc[T any](l *ServiceLocator, slotKey slot[T], createFunc func(*ServiceLocator) (T, error)) {
|
||||
typeName := getTypeName[T]()
|
||||
Logger.Printf(`[slot: %s] inject lazy provider`, typeName)
|
||||
|
||||
l.providers[slotKey] = &slotEntry{
|
||||
createFunc: func(l *ServiceLocator) (any, error) {
|
||||
return createFunc(l)
|
||||
},
|
||||
created: false,
|
||||
value: nil,
|
||||
typeName: getTypeName[T](),
|
||||
typeName: typeName,
|
||||
configureFunc: func(l *ServiceLocator) (any, error) { return createFunc(l) },
|
||||
configured: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +170,7 @@ func InjectLazy[T any](l *ServiceLocator, slotKey slot[T], createFunc func(*Serv
|
||||
// the provided ServiceLocator instance.
|
||||
//
|
||||
// If the ServiceLocator does not have a value for the slot key, or if the
|
||||
// value wasn't correctly initialized (in the case of a lazy slot), an error
|
||||
// value wasn't correctly configured (in the case of a lazy slot), an error
|
||||
// is returned.
|
||||
func Use[T any](l *ServiceLocator, slotKey slot[T]) (T, error) {
|
||||
var zero T
|
||||
@@ -147,7 +180,7 @@ func Use[T any](l *ServiceLocator, slotKey slot[T]) (T, error) {
|
||||
return zero, fmt.Errorf(`no injected value for type %s`, getTypeName[T]())
|
||||
}
|
||||
|
||||
err := slot.checkInitialized(l)
|
||||
err := slot.checkConfigured(l)
|
||||
if err != nil {
|
||||
return zero, err
|
||||
}
|
||||
@@ -158,24 +191,84 @@ func Use[T any](l *ServiceLocator, slotKey slot[T]) (T, error) {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func Invoke[T any](l *ServiceLocator, slotKey slot[T]) error {
|
||||
func MustUse[T any](l *ServiceLocator, slotKey slot[T]) T {
|
||||
v, err := Use(l, slotKey)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
func Invoke[T any](l *ServiceLocator, slotKey slot[T]) error {
|
||||
slot, ok := l.providers[slotKey]
|
||||
if !ok {
|
||||
return fmt.Errorf(`no injected value for type %s`, getTypeName[T]())
|
||||
}
|
||||
|
||||
err := slot.checkInitialized(l)
|
||||
err := slot.checkConfigured(l)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v := slot.value.(T)
|
||||
|
||||
Logger.Printf(`[slot: %s] using slot with value of type %T`, getTypeName[T](), v)
|
||||
Logger.Printf(`[slot: %s] invoked slot with value of type %T`, getTypeName[T](), v)
|
||||
return nil
|
||||
}
|
||||
|
||||
func MustInvoke[T any](l *ServiceLocator, slotKey slot[T]) {
|
||||
if err := Invoke(l, slotKey); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func ProvideHook[T any](l *ServiceLocator, hookKey hook[T], listeners ...Hook[T]) {
|
||||
typeName := getTypeName[T]()
|
||||
Logger.Printf(`[hook: %s] injecting hooks`, typeName)
|
||||
|
||||
// cast type safe listeners to internal untyped version to put inside the hook map
|
||||
anyListeners := make([]func(*ServiceLocator, any) error, len(listeners))
|
||||
for i, l := range listeners {
|
||||
ll := l
|
||||
anyListeners[i] = func(l *ServiceLocator, a any) error {
|
||||
t, ok := a.(T)
|
||||
if !ok {
|
||||
panic(`illegal state`)
|
||||
}
|
||||
|
||||
return ll(l, t)
|
||||
}
|
||||
}
|
||||
|
||||
l.hooks[hookKey] = &hookEntry{
|
||||
typeName: typeName,
|
||||
listeners: anyListeners,
|
||||
}
|
||||
}
|
||||
|
||||
func UseHook[T any](l *ServiceLocator, hookKey hook[T], value T) error {
|
||||
hookEntry, ok := l.hooks[hookKey]
|
||||
if !ok {
|
||||
return fmt.Errorf(`no injected hooks for hook of type %s`, hookEntry.typeName)
|
||||
}
|
||||
|
||||
Logger.Printf(`[hook: %s] calling hook with value of type %T`, hookEntry.typeName, value)
|
||||
for _, hookFunc := range hookEntry.listeners {
|
||||
if err := hookFunc(l, value); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func MustUseHook[T any](l *ServiceLocator, hookKey hook[T], value T) {
|
||||
if err := UseHook(l, hookKey, value); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// getTypeName is a trick to get the name of a type (even if it is an
|
||||
// interface type)
|
||||
func getTypeName[T any]() string {
|
||||
|
||||
+21
-12
@@ -9,37 +9,46 @@ import (
|
||||
type Config struct {
|
||||
Mode string
|
||||
Host string
|
||||
|
||||
NpmCommand string
|
||||
}
|
||||
|
||||
var Slot = sl.NewSlot[Config]()
|
||||
|
||||
func setFromEnvOrDefault(target *string, m map[string]string, key string, defaultValue string) {
|
||||
v, ok := m[key]
|
||||
if ok {
|
||||
*target = v
|
||||
} else {
|
||||
*target = defaultValue
|
||||
}
|
||||
}
|
||||
|
||||
func Configure(l *sl.ServiceLocator) (Config, error) {
|
||||
m, err := godotenv.Read(".env")
|
||||
env, err := godotenv.Read(".env")
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
}
|
||||
|
||||
var cfg Config
|
||||
|
||||
cfg.Mode = "production"
|
||||
if v, ok := m["MODE"]; ok {
|
||||
cfg.Mode = v
|
||||
}
|
||||
|
||||
cfg.Host = ":4000"
|
||||
if v, ok := m["HOST"]; ok {
|
||||
cfg.Host = v
|
||||
}
|
||||
setFromEnvOrDefault(&cfg.Mode, env, "MODE", "production")
|
||||
setFromEnvOrDefault(&cfg.Host, env, "HOST", ":4000")
|
||||
setFromEnvOrDefault(&cfg.NpmCommand, env, "NPM_COMMAND", "npm")
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
var TestingProductionConfig = Config{
|
||||
var ExampleProductionConfig = Config{
|
||||
Mode: "production",
|
||||
Host: ":4000",
|
||||
|
||||
NpmCommand: "npm",
|
||||
}
|
||||
|
||||
var TestingDevelopmentConfig = Config{
|
||||
var ExampleDevelopmentConfig = Config{
|
||||
Mode: "development",
|
||||
Host: ":4000",
|
||||
|
||||
NpmCommand: "npm",
|
||||
}
|
||||
|
||||
@@ -6,25 +6,15 @@ import (
|
||||
"git.phc.dm.unipi.it/phc/website/libs/sl"
|
||||
|
||||
"git.phc.dm.unipi.it/phc/website/server/database"
|
||||
"git.phc.dm.unipi.it/phc/website/server/routes"
|
||||
)
|
||||
|
||||
type ListaUtenti struct{}
|
||||
|
||||
var Slot = sl.NewSlot[*ListaUtenti]()
|
||||
|
||||
func Configure(l *sl.ServiceLocator) (*ListaUtenti, error) {
|
||||
func MountApiRoutesHook(l *sl.ServiceLocator, api fiber.Router) error {
|
||||
db, err := sl.Use(l, database.Slot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
r, err := sl.Use(l, routes.Root)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r.Get("/api/lista-utenti", func(c *fiber.Ctx) error {
|
||||
api.Get("/lista-utenti", func(c *fiber.Ctx) error {
|
||||
users, err := db.ReadUsers()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -34,5 +24,5 @@ func Configure(l *sl.ServiceLocator) (*ListaUtenti, error) {
|
||||
return c.JSON(users)
|
||||
})
|
||||
|
||||
return &ListaUtenti{}, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -10,23 +10,22 @@ import (
|
||||
|
||||
"gotest.tools/assert"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/valyala/fasthttp"
|
||||
"github.com/valyala/fasthttp/fasthttputil"
|
||||
|
||||
"git.phc.dm.unipi.it/phc/website/libs/db"
|
||||
"git.phc.dm.unipi.it/phc/website/libs/sl"
|
||||
"git.phc.dm.unipi.it/phc/website/libs/util"
|
||||
"git.phc.dm.unipi.it/phc/website/server"
|
||||
|
||||
"git.phc.dm.unipi.it/phc/website/server/config"
|
||||
"git.phc.dm.unipi.it/phc/website/server/database"
|
||||
"git.phc.dm.unipi.it/phc/website/server/listautenti"
|
||||
"git.phc.dm.unipi.it/phc/website/server/model"
|
||||
"git.phc.dm.unipi.it/phc/website/server/routes"
|
||||
)
|
||||
|
||||
func TestApiListaUtenti(t *testing.T) {
|
||||
r := fiber.New()
|
||||
|
||||
memDB := &database.Memory{
|
||||
Users: []model.User{
|
||||
{
|
||||
@@ -45,23 +44,35 @@ func TestApiListaUtenti(t *testing.T) {
|
||||
}
|
||||
|
||||
l := sl.New()
|
||||
sl.InjectValue(l, config.Slot, config.TestingProductionConfig)
|
||||
sl.InjectValue[database.Database](l, database.Slot, memDB)
|
||||
sl.InjectValue(l, routes.Root, fiber.Router(r))
|
||||
listautenti.Configure(l)
|
||||
|
||||
// Config
|
||||
sl.Provide(l, config.Slot, config.ExampleProductionConfig)
|
||||
|
||||
// Database
|
||||
sl.Provide[database.Database](l, database.Slot, memDB)
|
||||
|
||||
// Server
|
||||
sl.ProvideFunc(l, server.Slot, server.Configure)
|
||||
sl.ProvideHook(l, server.ApiRoutesHook,
|
||||
listautenti.MountApiRoutesHook,
|
||||
)
|
||||
|
||||
// Initialize server instance
|
||||
srv, err := sl.Use(l, server.Slot)
|
||||
assert.NilError(t, err)
|
||||
|
||||
//
|
||||
// Try doing the request
|
||||
//
|
||||
|
||||
req, err := http.NewRequest("GET", "http://localhost:4000/api/lista-utenti", nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NilError(t, err)
|
||||
|
||||
ln := fasthttputil.NewInmemoryListener()
|
||||
defer ln.Close()
|
||||
|
||||
go func() {
|
||||
err := fasthttp.Serve(ln, r.Handler())
|
||||
err := fasthttp.Serve(ln, srv.Router.Handler())
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to serve: %v", err))
|
||||
}
|
||||
@@ -76,27 +87,23 @@ func TestApiListaUtenti(t *testing.T) {
|
||||
}
|
||||
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NilError(t, err)
|
||||
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
assert.NilError(t, err)
|
||||
|
||||
assert.Equal(t, string(body), util.CompactIndentedLines(`
|
||||
[
|
||||
{
|
||||
"Id":"claire",
|
||||
"Id":"e39ad8d5-a087-4cb2-8fd7-5a6ca3f6a534",
|
||||
"Username":"claire-doe",
|
||||
"FullName":"Claire Doe",
|
||||
"Nickname":"claire-doe",
|
||||
"Email":"claire.doe@example.org"
|
||||
},
|
||||
{
|
||||
"Id":"john",
|
||||
"Id":"9b7109cd-95a1-41e9-a9f6-001a32c20ca1",
|
||||
"Username":"john-smith",
|
||||
"FullName":"John Smith",
|
||||
"Nickname":"john-smith",
|
||||
"Email":"john.smith@example.org"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"git.phc.dm.unipi.it/phc/website/libs/sl"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
var Root = sl.NewSlot[fiber.Router]()
|
||||
+19
-7
@@ -1,9 +1,10 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"git.phc.dm.unipi.it/phc/website/libs/sl"
|
||||
"git.phc.dm.unipi.it/phc/website/server/listautenti"
|
||||
"git.phc.dm.unipi.it/phc/website/server/routes"
|
||||
"git.phc.dm.unipi.it/phc/website/server/config"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
@@ -12,15 +13,26 @@ type Server struct{ Router *fiber.App }
|
||||
|
||||
var Slot = sl.NewSlot[*Server]()
|
||||
|
||||
var ApiRoutesHook = sl.NewHook[fiber.Router]()
|
||||
|
||||
func Configure(l *sl.ServiceLocator) (*Server, error) {
|
||||
r := fiber.New(fiber.Config{})
|
||||
r.Static("/assets", "./out/frontend/assets")
|
||||
|
||||
sl.InjectValue(l, routes.Root, fiber.Router(r))
|
||||
|
||||
if err := sl.Invoke(l, listautenti.Slot); err != nil {
|
||||
cfg, err := sl.Use(l, config.Slot)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := fiber.New(fiber.Config{})
|
||||
r.Static("/assets", "./out/frontend/assets")
|
||||
|
||||
api := r.Group("/api")
|
||||
if err := sl.UseHook(l, ApiRoutesHook, api); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go func() {
|
||||
log.Fatal(r.Listen(cfg.Host))
|
||||
}()
|
||||
|
||||
return &Server{r}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user