edge/pkg/module/fetch/module.go

124 lines
2.6 KiB
Go

package fetch
import (
"context"
"forge.cadoles.com/arcad/edge/pkg/app"
"forge.cadoles.com/arcad/edge/pkg/bus"
"github.com/dop251/goja"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/logger"
)
type Module struct {
server *app.Server
bus bus.Bus
}
func (m *Module) Name() string {
return "fetch"
}
func (m *Module) Export(export *goja.Object) {
funcs := map[string]any{
"get": m.get,
}
for name, fn := range funcs {
if err := export.Set(name, fn); err != nil {
panic(errors.Wrapf(err, "could not set '%s' function", name))
}
}
}
func (m *Module) get(call goja.FunctionCall, rt *goja.Runtime) goja.Value {
// ctx := util.AssertContext(call.Argument(0), rt)
return nil
}
func (m *Module) handleMessages() {
ctx := context.Background()
fetchErrs := m.bus.Reply(ctx, AddressFetchRequest, func(env bus.Envelope) (any, error) {
fetchRequest, ok := env.Message().(*FetchRequest)
if !ok {
return nil, errors.Wrapf(bus.ErrUnexpectedMessage, "expected fetch request, got '%T'", env.Message())
}
res, err := m.handleFetchRequest(fetchRequest)
if err != nil {
logger.Error(ctx, "could not handle fetch request", logger.CapturedE(errors.WithStack(err)))
return nil, errors.WithStack(err)
}
logger.Debug(ctx, "fetch request response", logger.F("response", res))
return res, nil
})
for err := range fetchErrs {
logger.Fatal(ctx, "error while replying to fetch requests", logger.CapturedE(errors.WithStack(err)))
}
}
func (m *Module) handleFetchRequest(req *FetchRequest) (*FetchResponse, error) {
res := &FetchResponse{}
ctx := logger.With(
req.Context,
logger.F("url", req.URL.String()),
logger.F("remoteAddr", req.RemoteAddr),
logger.F("requestID", req.RequestID),
)
rawResult, err := m.server.ExecFuncByName(ctx, "onClientFetch", ctx, req.URL.String(), req.RemoteAddr)
if err != nil {
if errors.Is(err, app.ErrFuncDoesNotExist) {
res.Allow = false
return res, nil
}
return nil, errors.WithStack(err)
}
result, ok := rawResult.(map[string]interface{})
if !ok {
return nil, errors.Errorf(
"unexpected onClientFetch result: expected 'map[string]interface{}', got '%T'",
rawResult,
)
}
var allow bool
rawAllow, exists := result["allow"]
if !exists {
allow = false
} else {
allow, ok = rawAllow.(bool)
if !ok {
return nil, errors.Errorf("invalid 'allow' result property: got type '%T', expected type '%T'", rawAllow, false)
}
}
res.Allow = allow
return res, nil
}
func ModuleFactory(bus bus.Bus) app.ServerModuleFactory {
return func(server *app.Server) app.ServerModule {
mod := &Module{
bus: bus,
server: server,
}
go mod.handleMessages()
return mod
}
}