func (d *Database) notify(event string, object *fosp.Object) { dbLog.Debug("Event %s on object %s occured", event, object.URL) users := subscribedUsers(object, event, 0) dbLog.Debug("Users %v should be notified", users) for _, user := range users { notification := fosp.NewNotification(event, object.URL) if event != fosp.DELETED { if serialized, err := json.Marshal(object); err == nil { notification.Body = bytes.NewBuffer(serialized) } else { dbLog.Error("Unable to serialize object %s for sending notification :: %s", object.URL, err) continue } } d.server.routeNotification(user, notification) } }
func parseMessage(in io.Reader) (msg fosp.Message, seq uint64, err error) { var ( firstLine []byte rawurl string isPrefix bool readerErr error fragments [][]byte code int msgURL *url.URL reader *bufio.Reader ok bool ) err = errors.New("Failed to parse message, unknown error") if reader, ok = in.(*bufio.Reader); !ok { reader = bufio.NewReader(in) } if firstLine, isPrefix, readerErr = reader.ReadLine(); isPrefix { err = errors.New("First line of message is too long") return } else if readerErr != nil && readerErr != io.EOF { err = newNestedError("Reader error", readerErr) return } if fragments = bytes.Split(firstLine, []byte(" ")); len(fragments) < 2 { err = errors.New("First line does not consist of at least 2 parts") return } identifier := string(fragments[0]) switch identifier { case fosp.OPTIONS, fosp.AUTH, fosp.GET, fosp.LIST, fosp.CREATE, fosp.PATCH, fosp.DELETE, fosp.READ, fosp.WRITE: if len(fragments) != 3 { err = errors.New("Request line does not consist of 3 parts") return } rawurl = string(fragments[1]) if rawurl != "*" { rawurl = "fosp://" + string(fragments[1]) if msgURL, err = url.Parse(rawurl); err != nil { err = errors.New("Invalid request URL") return } msgURL.Path = path.Clean(msgURL.Path) if msgURL.Path == "." { msgURL.Path = "/" } } if seq, err = strconv.ParseUint(string(fragments[2]), 10, 64); err != nil || seq < 1 { err = newNestedError("The request sequence number is not valid", err) return } req := fosp.NewRequest(identifier, msgURL) if req.Header, err = textproto.NewReader(reader).ReadMIMEHeader(); err != nil && err != io.EOF { err = newNestedError("The request header is not valid", err) return } req.Body = reader return req, seq, nil case fosp.SUCCEEDED, fosp.FAILED: if len(fragments) != 3 { err = errors.New("Response line does not consist of 3 parts") return } if code, err = strconv.Atoi(string(fragments[1])); err != nil { err = newNestedError("Status code is invalid", err) return } if seq, err = strconv.ParseUint(string(fragments[2]), 10, 64); err != nil || seq < 1 { err = newNestedError("The response sequence number is not valid", err) if seq < 1 { err = errors.New("The sequence number is 0") } return } resp := fosp.NewResponse(identifier, uint(code)) if resp.Header, err = textproto.NewReader(reader).ReadMIMEHeader(); err != nil && err != io.EOF { err = newNestedError("The response header is not valid", err) return } resp.Body = reader return resp, seq, nil case fosp.CREATED, fosp.UPDATED, fosp.DELETED: if len(fragments) != 2 { err = errors.New("Notification line does not consist of 2 parts") return } rawurl = string(fragments[1]) if rawurl != "*" { rawurl = "fosp://" + string(fragments[1]) if msgURL, err = url.Parse(rawurl); err != nil { err = errors.New("Invalid request URL") return } msgURL.Path = path.Clean(msgURL.Path) if msgURL.Path == "." { msgURL.Path = "/" } } evt := fosp.NewNotification(identifier, msgURL) if evt.Header, err = textproto.NewReader(reader).ReadMIMEHeader(); err != nil && err != io.EOF { err = newNestedError("The notification header is not valid", err) return } evt.Body = reader return evt, seq, nil default: err = errors.New("Unrecognized identifier " + identifier) return } }