// Scene is specified on the SceneManager interface. func (m *cookieSceneManager) Scene(ctx Context) (scene.Scene, error) { cookie, err := ctx.Request().Cookie(sceneID) if err != nil && err != http.ErrNoCookie { return nil, err } request := &sceneRequest{ responseChan: make(chan *sceneResponse, 1), } if err == http.ErrNoCookie { request.id = "" } else { request.id = cookie.Value } select { case m.requestChan <- request: case <-m.loop.IsStopping(): return nil, errors.New(ErrSceneManagement, errorMessages, "stopping") } m.requestChan <- request select { case response := <-request.responseChan: cookie = &http.Cookie{ Name: sceneID, Value: response.id, } http.SetCookie(ctx.ResponseWriter(), cookie) return response.scene, nil case <-m.loop.IsStopping(): return nil, errors.New(ErrSceneManagement, errorMessages, "stopping") } }
// WaitFlagLimited is specified on the Scene interface. func (s *scene) WaitFlagLimited(topic string, timeout time.Duration) error { // Add signal channel. command := &envelope{ kind: wait, signaling: &signaling{ topic: topic, signalChan: make(chan struct{}, 1), }, respChan: make(chan *envelope, 1), } _, err := s.command(command) if err != nil { return err } // Wait for signal. var timeoutChan <-chan time.Time if timeout > 0 { timeoutChan = time.After(timeout) } select { case <-s.backend.IsStopping(): err = s.Wait() if err == nil { err = errors.New(ErrSceneEnded, errorMessages) } return err case <-command.signaling.signalChan: return nil case <-timeoutChan: return errors.New(ErrWaitedTooLong, errorMessages, topic) } }
// backendLoop runs the backend loop of the scene. func (s *scene) backendLoop(l loop.Loop) (err error) { // Defer cleanup. defer func() { cerr := s.cleanupAllProps() if err == nil { err = cerr } }() // Init timers. var watchdog <-chan time.Time var clapperboard <-chan time.Time if s.absolute > 0 { clapperboard = time.After(s.absolute) } // Run loop. for { if s.inactivity > 0 { watchdog = time.After(s.inactivity) } select { case <-l.ShallStop(): return nil case timeout := <-watchdog: return errors.New(ErrTimeout, errorMessages, "inactivity", timeout) case timeout := <-clapperboard: return errors.New(ErrTimeout, errorMessages, "absolute", timeout) case command := <-s.commandChan: s.processCommand(command) } } }
// CommentNode implements the Builder interface. func (nb *NodeBuilder) CommentNode(comment string) error { if nb.done { return errors.New(ErrBuilder, errorMessages, "building is already done") } if len(nb.stack) > 0 { nb.stack[len(nb.stack)-1].appendCommentNode(comment) return nil } return errors.New(ErrBuilder, errorMessages, "no opening tag for comment") }
// RawNode implements the Builder interface. func (nb *NodeBuilder) RawNode(raw string) error { if nb.done { return errors.New(ErrBuilder, errorMessages, "building is already done") } if len(nb.stack) > 0 { nb.stack[len(nb.stack)-1].appendRawNode(raw) return nil } return errors.New(ErrBuilder, errorMessages, "no opening tag for raw text") }
// ValueAt returns the value at index. func (rs *ResultSet) ValueAt(index int) (Value, error) { if len(rs.items) < index+1 { return nil, errors.New(ErrIllegalItemIndex, errorMessages, index, len(rs.items)) } value, ok := rs.items[index].(Value) if !ok { return nil, errors.New(ErrIllegalItemType, errorMessages, index, "value") } return value, nil }
// ResultSetAt returns the nested result set at index. func (rs *ResultSet) ResultSetAt(index int) (*ResultSet, error) { if len(rs.items) < index-1 { return nil, errors.New(ErrIllegalItemIndex, errorMessages, index, len(rs.items)) } resultSet, ok := rs.items[index].(*ResultSet) if !ok { return nil, errors.New(ErrIllegalItemType, errorMessages, index, "result set") } return resultSet, nil }
// receiveResponse retrieves a response from the server. func (r *resp) receiveResponse() *response { // Receive first line. line, err := r.reader.ReadBytes('\n') if err != nil { rerr := errors.Annotate(err, ErrConnectionBroken, errorMessages, "receive after "+r.cmd) return &response{receivingError, 0, nil, rerr} } content := line[1 : len(line)-2] // First byte defines kind. switch line[0] { case '+': // Status response. return &response{statusResponse, 0, line[:len(line)-2], nil} case '-': // Error response. return &response{errorResponse, 0, line[:len(line)-2], nil} case ':': // Integer response. return &response{integerResponse, 0, content, nil} case '$': // Bulk response or null bulk response. count, err := strconv.Atoi(string(content)) if err != nil { return &response{receivingError, 0, nil, errors.Annotate(err, ErrServerResponse, errorMessages)} } if count == -1 { // Null bulk response. return &response{nullBulkResponse, 0, nil, nil} } // Receive the bulk data. toRead := count + 2 buffer := make([]byte, toRead) n, err := io.ReadFull(r.reader, buffer) if err != nil { return &response{receivingError, 0, nil, err} } if n < toRead { return &response{receivingError, 0, nil, errors.New(ErrServerResponse, errorMessages)} } return &response{bulkResponse, 0, buffer[0:count], nil} case '*': // Array reply. Check for timeout. length, err := strconv.Atoi(string(content)) if err != nil { return &response{receivingError, 0, nil, errors.Annotate(err, ErrServerResponse, errorMessages)} } if length == -1 { // Timeout. return &response{timeoutError, 0, nil, nil} } return &response{arrayResponse, length, nil, nil} } return &response{receivingError, 0, nil, errors.New(ErrInvalidResponse, errorMessages, string(line))} }
// checkIDs checks if the passed IDs are valid. It is only // called internally, so no locking. func (r *registry) checkIDs(emitterID string, subscriberIDs ...string) error { for _, subscriberID := range subscriberIDs { if subscriberID == emitterID { return errors.New(ErrInvalidID, errorMessages, subscriberID) } if _, ok := r.cellers[subscriberID]; !ok { return errors.New(ErrInvalidID, errorMessages, subscriberID) } } return nil }
// Validate checks if the enclosure is valid. func (e *Enclosure) Validate() error { if e.Length < 1 { return errors.New(ErrValidation, errorMessages, "item enclosure length %d is too small", e.Length) } if e.Type == "" { return errors.New(ErrValidation, errorMessages, "item enclosure type must not be empty") } if _, err := url.Parse(e.URL); err != nil { return errors.Annotate(err, ErrParsing, errorMessages, "item enclosure url") } return nil }
// Respond is specified on the Event interface. func (e *event) Respond(response interface{}) error { responseChanPayload, ok := e.Payload().Get(ResponseChanPayload) if !ok { return errors.New(ErrInvalidResponseEvent, errorMessages, "no response channel") } responseChan, ok := responseChanPayload.(chan interface{}) if !ok { return errors.New(ErrInvalidResponseEvent, errorMessages, "invalid response channel") } responseChan <- response return nil }
// Validate checks if the cloud is valid. func (c *Cloud) Validate() error { if c.Domain == "" { return errors.New(ErrValidation, errorMessages, "cloud domain must not be empty") } if c.Path == "" || c.Path[0] != '/' { return errors.New(ErrValidation, errorMessages, "cloud path %q must not be empty and has to start with a slash", c.Path) } if c.Port < 1 || c.Port > 65535 { return errors.New(ErrValidation, errorMessages, "cloud port %d is out of range", c.Port) } return nil }
// EndTagNode implements the Builder interface. func (nb *NodeBuilder) EndTagNode() error { if nb.done { return errors.New(ErrBuilder, errorMessages, "building is already done") } switch l := len(nb.stack); l { case 0: return errors.New(ErrBuilder, errorMessages, "no opening tag") case 1: nb.done = true default: nb.stack[l-2].appendChild(nb.stack[l-1]) nb.stack = nb.stack[:l-1] } return nil }
// Validate checks if the text input is valid. func (t *TextInput) Validate() error { if t.Description == "" { return errors.New(ErrValidation, errorMessages, "text input description must not be empty") } if _, err := url.Parse(t.Link); err != nil { return errors.Annotate(err, ErrParsing, errorMessages, "text input link") } if t.Name == "" { return errors.New(ErrValidation, errorMessages, "text input name must not be empty") } if t.Title == "" { return errors.New(ErrValidation, errorMessages, "text input title must not be empty") } return nil }
// ScoredValues returns the alternating values as scored values slice. If // withscores is false the result set contains no scores and so they are // set to 0.0 in the returned scored values. func (rs *ResultSet) ScoredValues(withscores bool) (ScoredValues, error) { svs := ScoredValues{} sv := ScoredValue{} for index, item := range rs.items { value, ok := item.(Value) if !ok { return nil, errors.New(ErrIllegalItemType, errorMessages, index, "value") } if withscores { // With scores, so alternating values and scores. if index%2 == 0 { sv.Value = value } else { score, err := value.Float64() if err != nil { return nil, err } sv.Score = score svs = append(svs, sv) sv = ScoredValue{} } } else { // No scores, only values. sv.Value = value svs = append(svs, sv) sv = ScoredValue{} } } return svs, nil }
// receiveResultSet receives all responses and converts them into a result set. func (r *resp) receiveResultSet() (*ResultSet, error) { defer func() { r.cmd = "-none-" }() result := newResultSet() current := result for { response := r.receiveResponse() switch response.kind { case receivingError: return nil, response.err case timeoutError: return nil, errors.New(ErrTimeout, errorMessages) case statusResponse, errorResponse, integerResponse, bulkResponse, nullBulkResponse: current.append(response.value()) case arrayResponse: switch { case current == result && current.Len() == 0: current.length = response.length case !current.allReceived(): next := newResultSet() next.parent = current current.append(next) current = next current.length = response.length } } // Check if all values are received. current = current.nextResultSet() if current == nil { return result, nil } } }
// Get implements the Value interface. func (v *value) Get() (string, error) { sv, err := v.changer.Value() if err != nil { return "", errors.New(ErrInvalidPath, errorMessages, pathToString(v.path)) } return sv, nil }
// NewEvent creates a new event with the given topic and payload. func NewEvent(topic string, payload interface{}, ctx context.Context) (Event, error) { if topic == "" { return nil, errors.New(ErrNoTopic, errorMessages) } p := NewPayload(payload) return &event{topic, p, ctx}, nil }
// BeginTagNode implements the sml.Builder interface. func (b *configBuilder) BeginTagNode(tag string) error { switch { case b.values == nil && tag != "config": return errors.New(ErrIllegalConfigSource, errorMessages, `does not start with "config" node`) case b.values == nil: b.stack = collections.NewStringStack(tag) b.values = collections.NewKeyStringValueTree(tag, "", false) default: b.stack.Push(tag) changer := b.values.Create(b.stack.All()...) if changer.Error() != nil { return errors.New(ErrIllegalConfigSource, errorMessages, changer.Error()) } } return nil }
// NewEvent creates a new event with the given topic and payload. func NewEvent(topic string, payload interface{}, scene scene.Scene) (Event, error) { if topic == "" { return nil, errors.New(ErrNoTopic, errorMessages) } p := NewPayload(payload) return &event{topic, p, scene}, nil }
// Peek implements the Stack interface. func (s stack) Peek() (interface{}, error) { lv := len(s.values) if lv == 0 { return nil, errors.New(ErrEmpty, errorMessages) } v := s.values[lv-1] return v, nil }
// Peek implements the StringStack interface. func (s *stringStack) Peek() (string, error) { lv := len(s.values) if lv == 0 { return "", errors.New(ErrEmpty, errorMessages) } v := s.values[lv-1] return v, nil }
// checkRecovering checks if the backend can be recovered. func (c *Crontab) checkRecovering(rs loop.Recoverings) (loop.Recoverings, error) { if rs.Frequency(12, time.Minute) { logger.Errorf("crontab cannot be recovered: %v", rs.Last().Reason) return nil, errors.New(ErrCrontabCannotBeRecovered, errorMessages, rs.Last().Reason) } logger.Warningf("crontab recovered: %v", rs.Last().Reason) return rs.Trim(12), nil }
// ProcessEvent implements the Subscriber interface. func (c *cell) ProcessEvent(event Event) error { emitTimeoutTicks := 0 for { select { case c.eventc <- event: return nil case <-c.loop.IsStopping(): return errors.New(ErrInactive, errorMessages, c.id) case <-c.emitTimeoutTicker.C: emitTimeoutTicks++ if emitTimeoutTicks > c.emitTimeout { op := fmt.Sprintf("emitting %q to %q", event.Topic(), c.id) return errors.New(ErrTimeout, errorMessages, op) } } } }
// Validate checks if the skip hours are valid. func (s *SkipHours) Validate() error { for _, hour := range s.Hours { if hour < 0 || hour > 23 { return errors.New(ErrValidation, errorMessages, "skip hour %d is out of range from 0 to 23", hour) } } return nil }
// ReadGenericJSON is specified on the Context interface. func (ctx *context) ReadGenericJSON() (map[string]interface{}, error) { if !ctx.HasContentType(ContentTypeJSON) { return nil, errors.New(ErrInvalidContentType, errorMessages, ContentTypeJSON) } data := map[string]interface{}{} err := ctx.ReadJSON(&data) return data, err }
// TextNode implements the Builder interface. func (tb *KeyStringValueTreeBuilder) TextNode(text string) error { if tb.done { return errors.New(ErrBuilder, errorMessages, "building is already done") } value, err := tb.tree.At(tb.stack.All()...).Value() if err != nil { return errors.Annotate(err, ErrBuilder, errorMessages) } if value != "" { return errors.New(ErrBuilder, errorMessages, "node has multiple values") } text = strings.TrimSpace(text) if text != "" { _, err = tb.tree.At(tb.stack.All()...).SetValue(text) } return err }
// checkRecovering checks if the backend can be recovered. func (b *stdBackend) checkRecovering(rs loop.Recoverings) (loop.Recoverings, error) { if rs.Frequency(12, time.Minute) { logger.Errorf("standard monitor cannot be recovered: %v", rs.Last().Reason) return nil, errors.New(ErrMonitoringCannotBeRecovered, errorMessages, rs.Last().Reason) } logger.Warningf("standard monitor recovered: %v", rs.Last().Reason) return rs.Trim(12), nil }
// subscribe subscribes cells to an emitter. func (r *registry) subscribe(emitterID string, subscriberIDs ...string) error { r.mutex.Lock() defer r.mutex.Unlock() ec, ok := r.cells[emitterID] if !ok { return errors.New(ErrInvalidID, errorMessages, emitterID) } for _, subscriberID := range subscriberIDs { if sc, ok := r.cells[subscriberID]; ok { ec.subscribers.add(sc) sc.emitters.add(ec) } else { return errors.New(ErrInvalidID, errorMessages, subscriberID) } } return nil }
// updateSubscribers sets the subscribers of the cell. func (c *cell) updateSubscribers(cells []*cell) error { select { case c.subscriberc <- cells: case <-c.loop.IsStopping(): return errors.New(ErrInactive, errorMessages, c.id) } return nil }