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 }