Zippytal-Node/zoneRequestScheduler.go

138 lines
3.8 KiB
Go

package localserver
import (
"context"
"fmt"
)
type ZoneRequestScheduler struct {
handlersPublishers []chan<- *ZoneRequest
}
type ZoneRequest struct {
ReqType string `json:"reqType"`
Payload map[string]interface{} `json:"payload"`
From string `json:"from"`
}
type ZoneResponse struct {
Type string `json:"type"`
To string `json:"to"`
From string `json:"from"`
Payload map[string]interface{} `json:"payload"`
}
type ZoneRequestHandler interface {
Init(ctx context.Context, authorizedMembers []string) (err error)
Subscribe(ctx context.Context, publisher <-chan *ZoneRequest) (reqChan chan *ZoneRequest, done chan struct{}, errCh chan error)
handleZoneRequest(ctx context.Context, req *ZoneRequest) (err error)
}
func verifyFieldsString(payload map[string]interface{}, fields ...string) (err error) {
for _, field := range fields {
if _, ok := payload[field]; !ok {
err = fmt.Errorf("no field %s in payload", field)
return
} else if _, ok := payload[field].(string); !ok {
err = fmt.Errorf("field %s in payload is not a string", field)
return
}
}
return
}
func verifyFieldsBool(payload map[string]interface{}, fields ...string) (err error) {
for _, field := range fields {
if _, ok := payload[field]; !ok {
err = fmt.Errorf("no field %s in payload", field)
return
} else if _, ok := payload[field].(bool); !ok {
err = fmt.Errorf("field %s in payload is not a bool", field)
return
}
}
return
}
func verifyFieldsFloat64(payload map[string]interface{}, fields ...string) (err error) {
for _, field := range fields {
if _, ok := payload[field]; !ok {
err = fmt.Errorf("no field %s in payload", field)
return
} else if _, ok := payload[field].(float64); !ok {
err = fmt.Errorf("field %s in payload is not a float64", field)
return
}
}
return
}
func verifyFieldsSliceInterface(payload map[string]interface{}, fields ...string) (err error) {
for _, field := range fields {
if _, ok := payload[field]; !ok {
err = fmt.Errorf("no field %s in payload", field)
return
} else if _, ok := payload[field].([]any); !ok {
err = fmt.Errorf("field %s in payload is not a []interface{}", field)
return
}
}
return
}
func NewZoneRequestScheduler(authorizedMembers []string, handlers ...ZoneRequestHandler) (zoneRequestScheduler *ZoneRequestScheduler, handlerErrCh chan error) {
zoneRequestScheduler = new(ZoneRequestScheduler)
zoneRequestScheduler.handlersPublishers = make([]chan<- *ZoneRequest, 0)
handlerErrCh = make(chan error)
reqChans := []chan *ZoneRequest{}
for _, handler := range handlers {
publisher := make(chan *ZoneRequest)
zoneRequestScheduler.handlersPublishers = append(zoneRequestScheduler.handlersPublishers, publisher)
reqChan, done, errCh := handler.Subscribe(context.Background(), publisher)
go func(done <-chan struct{}, errCh <-chan error) {
for {
select {
case <-done:
return
case handlerErrCh <- <-errCh:
}
}
}(done, errCh)
reqChans = append(reqChans, reqChan)
}
for _, reqChan := range reqChans {
go func(reqChan <-chan *ZoneRequest) {
done, errCh := zoneRequestScheduler.Schedule(reqChan)
for {
select {
case <-done:
return
case e := <-errCh:
logger.Println("from there", e)
}
}
}(reqChan)
}
for i, handler := range handlers {
if ierr := handler.Init(context.Background(), authorizedMembers); ierr != nil {
logger.Println(ierr)
}
logger.Println("init done for handler", i)
}
return
}
func (zrs *ZoneRequestScheduler) Schedule(reqChan <-chan *ZoneRequest) (done chan struct{}, errCh chan error) {
done, errCh = make(chan struct{}), make(chan error)
go func() {
for req := range reqChan {
for _, publisher := range zrs.handlersPublishers {
publisher <- req
}
}
done <- struct{}{}
}()
return
}