From 7100009ab18165bd0fc9750232110084b1a98c53 Mon Sep 17 00:00:00 2001 From: Antonio De Lucreziis Date: Fri, 3 Mar 2023 17:42:37 +0100 Subject: [PATCH] fix: updated project name and sl documentation --- cmd/build/main.go | 11 +- cmd/devserver/main.go | 11 +- cmd/server/main.go | 11 +- go.mod | 4 +- services/config/config.go | 2 +- services/database/database.go | 5 +- services/server/articles/articles.go | 7 +- services/server/dev/dev.go | 7 +- services/server/listaUtenti/lista-utenti.go | 8 +- .../server/listaUtenti/lista-utenti_test.go | 9 +- services/server/router/router.go | 7 +- services/server/routes/routes.go | 2 +- services/server/server.go | 10 +- sl/sl.go | 127 +++++++----------- 14 files changed, 97 insertions(+), 124 deletions(-) diff --git a/cmd/build/main.go b/cmd/build/main.go index 7871c5a..44edb38 100644 --- a/cmd/build/main.go +++ b/cmd/build/main.go @@ -4,11 +4,12 @@ import ( "encoding/json" "log" "os" - "phc/website/services/config" - "phc/website/services/database" - "phc/website/services/server" - "phc/website/services/server/dev" - "phc/website/sl" + + "git.phc.dm.unipi.it/phc/website/services/config" + "git.phc.dm.unipi.it/phc/website/services/database" + "git.phc.dm.unipi.it/phc/website/services/server" + "git.phc.dm.unipi.it/phc/website/services/server/dev" + "git.phc.dm.unipi.it/phc/website/sl" ) func main() { diff --git a/cmd/devserver/main.go b/cmd/devserver/main.go index 1eccc28..96ba918 100644 --- a/cmd/devserver/main.go +++ b/cmd/devserver/main.go @@ -5,11 +5,12 @@ import ( "io" "log" "os/exec" - "phc/website/model" - "phc/website/services/config" - "phc/website/services/database" - "phc/website/services/server" - "phc/website/sl" + + "git.phc.dm.unipi.it/phc/website/model" + "git.phc.dm.unipi.it/phc/website/services/config" + "git.phc.dm.unipi.it/phc/website/services/database" + "git.phc.dm.unipi.it/phc/website/services/server" + "git.phc.dm.unipi.it/phc/website/sl" ) func main() { diff --git a/cmd/server/main.go b/cmd/server/main.go index f155e4b..921ec16 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -2,11 +2,12 @@ package main import ( "log" - "phc/website/model" - "phc/website/services/config" - "phc/website/services/database" - "phc/website/services/server" - "phc/website/sl" + + "git.phc.dm.unipi.it/phc/website/model" + "git.phc.dm.unipi.it/phc/website/services/config" + "git.phc.dm.unipi.it/phc/website/services/database" + "git.phc.dm.unipi.it/phc/website/services/server" + "git.phc.dm.unipi.it/phc/website/sl" ) func main() { diff --git a/go.mod b/go.mod index c994325..3fa4459 100644 --- a/go.mod +++ b/go.mod @@ -1,15 +1,15 @@ -module phc/website +module git.phc.dm.unipi.it/phc/website go 1.19 require ( + github.com/alecthomas/repr v0.2.0 github.com/gofiber/fiber/v2 v2.41.0 github.com/joho/godotenv v1.4.0 github.com/valyala/fasthttp v1.43.0 ) require ( - github.com/alecthomas/repr v0.2.0 // indirect github.com/andybalholm/brotli v1.0.4 // indirect github.com/klauspost/compress v1.15.9 // indirect github.com/mattn/go-colorable v0.1.13 // indirect diff --git a/services/config/config.go b/services/config/config.go index b28038c..a8cde77 100644 --- a/services/config/config.go +++ b/services/config/config.go @@ -1,7 +1,7 @@ package config import ( - "phc/website/sl" + "git.phc.dm.unipi.it/phc/website/sl" "github.com/joho/godotenv" ) diff --git a/services/database/database.go b/services/database/database.go index 5029eb3..18ac5b8 100644 --- a/services/database/database.go +++ b/services/database/database.go @@ -2,8 +2,9 @@ package database import ( "fmt" - "phc/website/model" - "phc/website/sl" + + "git.phc.dm.unipi.it/phc/website/model" + "git.phc.dm.unipi.it/phc/website/sl" ) var Slot = sl.NewSlot[Database]() diff --git a/services/server/articles/articles.go b/services/server/articles/articles.go index 5705453..9f50af2 100644 --- a/services/server/articles/articles.go +++ b/services/server/articles/articles.go @@ -2,9 +2,10 @@ package articles import ( "html/template" - "phc/website/services/server/dev" - "phc/website/services/server/router" - "phc/website/sl" + + "git.phc.dm.unipi.it/phc/website/services/server/dev" + "git.phc.dm.unipi.it/phc/website/services/server/router" + "git.phc.dm.unipi.it/phc/website/sl" ) func Configure(l *sl.ServiceLocator) error { diff --git a/services/server/dev/dev.go b/services/server/dev/dev.go index a2d4547..d478960 100644 --- a/services/server/dev/dev.go +++ b/services/server/dev/dev.go @@ -6,9 +6,10 @@ import ( "io" "log" "path" - "phc/website/services/config" - "phc/website/services/server/routes" - "phc/website/sl" + + "git.phc.dm.unipi.it/phc/website/services/config" + "git.phc.dm.unipi.it/phc/website/services/server/routes" + "git.phc.dm.unipi.it/phc/website/sl" "github.com/alecthomas/repr" "github.com/gofiber/fiber/v2" diff --git a/services/server/listaUtenti/lista-utenti.go b/services/server/listaUtenti/lista-utenti.go index a281c7c..964441c 100644 --- a/services/server/listaUtenti/lista-utenti.go +++ b/services/server/listaUtenti/lista-utenti.go @@ -1,10 +1,10 @@ package listaUtenti import ( - "phc/website/services/database" - "phc/website/services/server/router" - "phc/website/services/server/routes" - "phc/website/sl" + "git.phc.dm.unipi.it/phc/website/services/database" + "git.phc.dm.unipi.it/phc/website/services/server/router" + "git.phc.dm.unipi.it/phc/website/services/server/routes" + "git.phc.dm.unipi.it/phc/website/sl" "github.com/gofiber/fiber/v2" ) diff --git a/services/server/listaUtenti/lista-utenti_test.go b/services/server/listaUtenti/lista-utenti_test.go index de48e01..87f48a0 100644 --- a/services/server/listaUtenti/lista-utenti_test.go +++ b/services/server/listaUtenti/lista-utenti_test.go @@ -6,12 +6,13 @@ import ( "io" "net" "net/http" - "phc/website/model" - "phc/website/services/database" - "phc/website/services/server/routes" - "phc/website/sl" "testing" + "git.phc.dm.unipi.it/phc/website/model" + "git.phc.dm.unipi.it/phc/website/services/database" + "git.phc.dm.unipi.it/phc/website/services/server/routes" + "git.phc.dm.unipi.it/phc/website/sl" + "github.com/gofiber/fiber/v2" "github.com/valyala/fasthttp" "github.com/valyala/fasthttp/fasthttputil" diff --git a/services/server/router/router.go b/services/server/router/router.go index bcde8d3..c95276b 100644 --- a/services/server/router/router.go +++ b/services/server/router/router.go @@ -4,9 +4,10 @@ import ( "bytes" "log" "os" - "phc/website/services/server/dev" - "phc/website/services/server/routes" - "phc/website/sl" + + "git.phc.dm.unipi.it/phc/website/services/server/dev" + "git.phc.dm.unipi.it/phc/website/services/server/routes" + "git.phc.dm.unipi.it/phc/website/sl" "github.com/gofiber/fiber/v2" ) diff --git a/services/server/routes/routes.go b/services/server/routes/routes.go index 45c2e28..1797249 100644 --- a/services/server/routes/routes.go +++ b/services/server/routes/routes.go @@ -1,7 +1,7 @@ package routes import ( - "phc/website/sl" + "git.phc.dm.unipi.it/phc/website/sl" "github.com/gofiber/fiber/v2" ) diff --git a/services/server/server.go b/services/server/server.go index 42944ab..bf72474 100644 --- a/services/server/server.go +++ b/services/server/server.go @@ -1,11 +1,11 @@ package server import ( - "phc/website/services/server/articles" - "phc/website/services/server/dev" - "phc/website/services/server/listaUtenti" - "phc/website/services/server/routes" - "phc/website/sl" + "git.phc.dm.unipi.it/phc/website/services/server/articles" + "git.phc.dm.unipi.it/phc/website/services/server/dev" + "git.phc.dm.unipi.it/phc/website/services/server/listaUtenti" + "git.phc.dm.unipi.it/phc/website/services/server/routes" + "git.phc.dm.unipi.it/phc/website/sl" "github.com/gofiber/fiber/v2" ) diff --git a/sl/sl.go b/sl/sl.go index ec7ef98..38b0838 100644 --- a/sl/sl.go +++ b/sl/sl.go @@ -1,32 +1,46 @@ +// 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]. As slots should be unique 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. package sl import ( "fmt" "log" + "os" ) -type SlotKey[T any] *struct{} +// Logger is the debug logger, in the future this will be disabled and discard by default. +// +// As this is the service locator module it was meaning less to pass this through the ServiceLocator itself (without making the whole module more complex) +var Logger *log.Logger = log.New(os.Stderr, "[sl]", log.LstdFlags) -func NewSlot[T any]() SlotKey[T] { - return SlotKey[T](new(struct{})) +// slot is just a "typed" unique "symbol". +type slot[T any] *struct{} + +// NewSlot is the only way to create instances of the slot type. Each instance is unique. +// +// This then lets you attach a service instance of type "T" to a [ServiceLocator] object. +func NewSlot[T any]() slot[T] { + return slot[T](new(struct{})) } -type slot struct { +// slotEntry represents a service that can lazily initialized (using "createFunc"). Once initialized the instance is kept in the "value" field. The field "typeName" just for debugging purposes. +type slotEntry struct { createFunc func(*ServiceLocator) (any, error) created bool value any - typ string + typeName string } -func (s *slot) checkInitialized(l *ServiceLocator) error { +func (s *slotEntry) checkInitialized(l *ServiceLocator) error { if !s.created { v, err := s.createFunc(l) if err != nil { return err } - log.Printf(`initialized lazy value of type %T for slot of type %s`, v, s.typ) + Logger.Printf(`initialized lazy value of type %T for slot of type %s`, v, s.typeName) s.created = true s.value = v @@ -35,20 +49,25 @@ func (s *slot) checkInitialized(l *ServiceLocator) error { return nil } +// 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]. type ServiceLocator struct { - providers map[any]*slot + providers map[any]*slotEntry } +// New creates a new [ServiceLocator] context to pass around in the application. func New() *ServiceLocator { return &ServiceLocator{ - providers: map[any]*slot{}, + providers: map[any]*slotEntry{}, } } -func InjectValue[T any](l *ServiceLocator, slotKey SlotKey[T], value T) T { - log.Printf(`injected value of type %T for slot of type %s`, value, getTypeName[T]()) +// 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. +// +// 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(`injected value of type %T for slot of type %s`, value, getTypeName[T]()) - l.providers[slotKey] = &slot{ + l.providers[slotKey] = &slotEntry{ nil, true, value, @@ -57,20 +76,26 @@ func InjectValue[T any](l *ServiceLocator, slotKey SlotKey[T], value T) T { return value } -func InjectLazy[T any](l *ServiceLocator, slotKey SlotKey[T], createFunc func(*ServiceLocator) (T, error)) { - log.Printf(`injected lazy for slot of type %s`, getTypeName[T]()) +// InjectLazy 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(`injected lazy for slot of type %s`, getTypeName[T]()) - l.providers[slotKey] = &slot{ + l.providers[slotKey] = &slotEntry{ createFunc: func(l *ServiceLocator) (any, error) { return createFunc(l) }, - created: false, - value: nil, - typ: getTypeName[T](), + created: false, + value: nil, + typeName: getTypeName[T](), } } -func Use[T any](l *ServiceLocator, slotKey SlotKey[T]) (T, error) { +// Use retrieves the value of type T associated with the given slot key from 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 is returned. +func Use[T any](l *ServiceLocator, slotKey slot[T]) (T, error) { var zero T slot, ok := l.providers[slotKey] @@ -85,71 +110,11 @@ func Use[T any](l *ServiceLocator, slotKey SlotKey[T]) (T, error) { v := slot.value.(T) - log.Printf(`using slot of type %s with value of type %T`, getTypeName[T](), v) + Logger.Printf(`using slot of type %s with value of type %T`, getTypeName[T](), v) return v, nil } -// // Require forces the initialization of a slot -// func Require[T any](l *ServiceLocator, slotKey SlotKey[T]) error { -// var zero T - -// slot, ok := l.providers[slotKey] -// if !ok { -// return fmt.Errorf(`no injected value for type %T`, zero) -// } - -// return slot.checkInitialized(l) -// } - -// // MustRequire forces the initialization of a slot or panics if the slot is missing -// func MustRequire[T any](l *ServiceLocator, slotKey SlotKey[T]) { -// err := Require(l, slotKey) -// if err != nil { -// panic(err) -// } -// } - -// // Inject will set the implementation for "S" to "value" (the service will be initialized when needed after all of its dependencies) -// func Inject[S Service](l *Context, value S) { -// key := getTypeName[S]() -// log.Printf(`injecting value of type %T for interface %s`, value, key) - -// l.providers[key] = &provider{false, nil, value} -// } - -// // InjectValue will set the implementation for "S" to "value" and mark this service as already initialized (as this is just a constant) -// func InjectValue[S Service](l *Context, value S) S { -// key := getTypeName[S]() -// log.Printf(`injecting value of type %T for interface %s`, value, key) - -// l.providers[key] = &provider{true, nil, value} -// return value -// } - -// // Use will retrive from the service locator the implementation set for the type "T" and initialize the service if yet to be initialized -// func Use[T Service](l *Context) (T, error) { -// provider, ok := l.providers[getTypeName[T]()] -// if !ok { -// var zero T -// return zero, fmt.Errorf(`no injected value for type "%T"`, zero) -// } - -// if provider.initialized { -// service := provider.service.(T) -// return service, nil -// } - -// log.Printf(`initializing %T`, provider.service) -// if err := provider.service.Initialize(l); err != nil { -// var zero T -// return zero, err -// } - -// provider.initialized = true -// service := provider.service.(T) -// return service, nil -// } - +// getTypeName is a trick to get the name of a type (even if it is an interface type) func getTypeName[T any]() string { var zero T return fmt.Sprintf(`%T`, &zero)[1:]