Compare commits
3 Commits
b73723b5f5
...
extension
Author | SHA1 | Date | |
---|---|---|---|
8b85f60e63 | |||
fe90d81b5d | |||
9343970672 |
@ -10,7 +10,7 @@ type testCommandRequest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestSimpleCommandExec(t *testing.T) {
|
func TestSimpleCommandExec(t *testing.T) {
|
||||||
bus := NewBus()
|
dispatcher := NewDispatcher()
|
||||||
|
|
||||||
handlerCalled := false
|
handlerCalled := false
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ func TestSimpleCommandExec(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
bus.RegisterCommand(
|
dispatcher.RegisterCommand(
|
||||||
MatchCommandRequest(&testCommandRequest{}),
|
MatchCommandRequest(&testCommandRequest{}),
|
||||||
CommandHandlerFunc(handleTestCommand),
|
CommandHandlerFunc(handleTestCommand),
|
||||||
)
|
)
|
||||||
@ -29,7 +29,7 @@ func TestSimpleCommandExec(t *testing.T) {
|
|||||||
}
|
}
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
result, err := bus.Exec(ctx, cmd)
|
result, err := dispatcher.Exec(ctx, cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestBasicCommandMiddleware(t *testing.T) {
|
func TestBasicCommandMiddleware(t *testing.T) {
|
||||||
bus := NewBus()
|
dispatcher := NewDispatcher()
|
||||||
|
|
||||||
handlerCalled := false
|
handlerCalled := false
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ func TestBasicCommandMiddleware(t *testing.T) {
|
|||||||
return CommandHandlerFunc(fn)
|
return CommandHandlerFunc(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
bus.RegisterCommand(
|
dispatcher.RegisterCommand(
|
||||||
MatchCommandRequest(&testCommandRequest{}),
|
MatchCommandRequest(&testCommandRequest{}),
|
||||||
CommandHandlerFunc(handleTestCommand),
|
CommandHandlerFunc(handleTestCommand),
|
||||||
commandMiddleware,
|
commandMiddleware,
|
||||||
@ -37,7 +37,7 @@ func TestBasicCommandMiddleware(t *testing.T) {
|
|||||||
}
|
}
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
result, err := bus.Exec(ctx, cmd)
|
result, err := dispatcher.Exec(ctx, cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
1
example/extendable/.gitignore
vendored
Normal file
1
example/extendable/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/bin
|
11
example/extendable/Makefile
Normal file
11
example/extendable/Makefile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
build: extension
|
||||||
|
go build -o ./bin/app ./
|
||||||
|
|
||||||
|
extension:
|
||||||
|
go build -o ./bin/myext.so -buildmode=plugin ./myext
|
||||||
|
|
||||||
|
watch:
|
||||||
|
modd
|
||||||
|
|
||||||
|
run:
|
||||||
|
./bin/app
|
23
example/extendable/main.go
Normal file
23
example/extendable/main.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"gitlab.com/wpetit/goweb/extension"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
reg := extension.NewRegistry()
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
extensions, err := reg.LoadAll(ctx, "./bin/*.so")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(errors.WithStack(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ext := range extensions {
|
||||||
|
log.Printf("Loaded extension '%s', version '%s'", ext.ExtensionName(), ext.ExtensionVersion())
|
||||||
|
}
|
||||||
|
}
|
6
example/extendable/modd.conf
Normal file
6
example/extendable/modd.conf
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
**/*.go
|
||||||
|
modd.conf
|
||||||
|
Makefile {
|
||||||
|
prep: make build
|
||||||
|
prep: make run
|
||||||
|
}
|
12
example/extendable/myext/extension.go
Normal file
12
example/extendable/myext/extension.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
type MyExtension struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *MyExtension) ExtensionName() string {
|
||||||
|
return "my.extension"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *MyExtension) ExtensionVersion() string {
|
||||||
|
return "0.0.0"
|
||||||
|
}
|
11
example/extendable/myext/main.go
Normal file
11
example/extendable/myext/main.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"gitlab.com/wpetit/goweb/extension"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RegisterExtension(ctx context.Context) (extension.Extension, error) {
|
||||||
|
return &MyExtension{}, nil
|
||||||
|
}
|
8
extension/error.go
Normal file
8
extension/error.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package extension
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalidRegisterFunc = errors.New("invalid register func")
|
||||||
|
ErrInvalidExtension = errors.New("invalid extension")
|
||||||
|
)
|
6
extension/extension.go
Normal file
6
extension/extension.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package extension
|
||||||
|
|
||||||
|
type Extension interface {
|
||||||
|
ExtensionName() string
|
||||||
|
ExtensionVersion() string
|
||||||
|
}
|
101
extension/registry.go
Normal file
101
extension/registry.go
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
package extension
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"path/filepath"
|
||||||
|
"plugin"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Registry struct {
|
||||||
|
extensions map[string]Extension
|
||||||
|
mutex sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Registry) Load(ctx context.Context, path string) (Extension, error) {
|
||||||
|
p, err := plugin.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
registerFuncSymbol, err := p.Lookup("RegisterExtension")
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
register, ok := registerFuncSymbol.(func(context.Context) (Extension, error))
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.WithStack(ErrInvalidRegisterFunc)
|
||||||
|
}
|
||||||
|
|
||||||
|
ext, err := register(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ext == nil {
|
||||||
|
return nil, errors.WithStack(ErrInvalidExtension)
|
||||||
|
}
|
||||||
|
|
||||||
|
r.mutex.Lock()
|
||||||
|
r.extensions[ext.ExtensionName()] = ext
|
||||||
|
r.mutex.Unlock()
|
||||||
|
|
||||||
|
return ext, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Registry) LoadAll(ctx context.Context, pattern string) ([]Extension, error) {
|
||||||
|
extensions := make([]Extension, 0)
|
||||||
|
|
||||||
|
matches, err := filepath.Glob(pattern)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range matches {
|
||||||
|
ext, err := r.Load(ctx, m)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
extensions = append(extensions, ext)
|
||||||
|
}
|
||||||
|
|
||||||
|
return extensions, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Registry) Extensions() []Extension {
|
||||||
|
r.mutex.RLock()
|
||||||
|
defer r.mutex.RUnlock()
|
||||||
|
|
||||||
|
extensions := make([]Extension, 0, len(r.extensions))
|
||||||
|
for _, e := range r.extensions {
|
||||||
|
extensions = append(extensions, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
return extensions
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExtensionFilterFunc func(ext Extension) bool
|
||||||
|
|
||||||
|
func (r *Registry) Filter(filter ExtensionFilterFunc) []Extension {
|
||||||
|
r.mutex.RLock()
|
||||||
|
defer r.mutex.RUnlock()
|
||||||
|
|
||||||
|
extensions := make([]Extension, 0, len(r.extensions))
|
||||||
|
for _, e := range r.extensions {
|
||||||
|
if filter(e) {
|
||||||
|
extensions = append(extensions, e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return extensions
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRegistry() *Registry {
|
||||||
|
return &Registry{
|
||||||
|
extensions: make(map[string]Extension),
|
||||||
|
}
|
||||||
|
}
|
@ -20,7 +20,9 @@ func Example_usage() {
|
|||||||
|
|
||||||
// On expose le service "template" avec l'implémentation
|
// On expose le service "template" avec l'implémentation
|
||||||
// basée sur le moteur de rendu HTML de la librairie standard
|
// basée sur le moteur de rendu HTML de la librairie standard
|
||||||
container.Provide(template.ServiceName, html.ServiceProvider("./templates"))
|
container.Provide(template.ServiceName, html.ServiceProvider(
|
||||||
|
html.NewDirectoryLoader("./templates"),
|
||||||
|
))
|
||||||
|
|
||||||
router := chi.NewRouter()
|
router := chi.NewRouter()
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user