func (s syncService) FullSync(user ct.UserId, limit uint) (*types.InitialSync, types.Error) { maxMessage := s.messageSource.Max() maxPresence := s.presenceSource.Max() maxTyping := s.typingSource.Max() userSet, err := s.membershipStore.Peers(user) if err != nil { return nil, err } indexedPresences, err := s.presenceSource.Range(&user, userSet, nil, 0, maxPresence, limit) if err != nil { return nil, err } presences := indexedToEvents(indexedPresences) rooms, err := s.membershipStore.Rooms(user) summaries := make([]types.RoomSummary, len(rooms)) if err != nil { return nil, err } end := types.NewStreamToken(maxMessage, maxPresence, maxTyping) for i, room := range rooms { if err := s.roomSummary(&summaries[i], user, room, end, limit); err != nil { return nil, err } } initialSync := types.InitialSync{end, presences, summaries} return &initialSync, nil }
func (s syncService) RoomSync(user ct.UserId, room ct.RoomId, limit uint) (*types.RoomInitialSync, types.Error) { maxMessage := s.messageSource.Max() maxPresence := s.presenceSource.Max() maxTyping := s.typingSource.Max() userSet := map[ct.UserId]struct{}{} users, err := s.membershipStore.Users(room) if err != nil { return nil, err } for _, user := range users { userSet[user] = struct{}{} } indexedPresences, err := s.presenceSource.Range(&user, userSet, nil, 0, maxPresence, limit) if err != nil { return nil, err } presences := indexedToEvents(indexedPresences) sync := types.RoomInitialSync{ Presence: presences, } end := types.NewStreamToken(maxMessage, maxPresence, maxTyping) if err := s.roomSummary(&sync.RoomSummary, user, room, end, limit); err != nil { return nil, err } return &sync, nil }
func (e roomsEndpoint) getMessages(req *http.Request, params httprouter.Params) interface{} { room, user, err := e.getRoomAndUser(req, params) if err != nil { return err } var from *types.StreamToken var to *types.StreamToken query := req.URL.Query() fromStr := query.Get("from") toStr := query.Get("to") dir := query.Get("dir") limitStr := query.Get("limit") if fromStr != "" { token, err := types.ParseStreamToken(fromStr) if err != nil { return types.BadQueryError(err.Error()) } from = &token } if toStr != "" { token, err := types.ParseStreamToken(toStr) if err != nil { return types.BadQueryError(err.Error()) } to = &token } if dir == "b" { token := types.NewStreamToken(0, 0, 0) to = &token } var limit uint64 var parseErr error if limitStr == "" { limit = 10 //TODO: make configurable } else { limit, parseErr = strconv.ParseUint(limitStr, 10, 32) if parseErr != nil { return types.BadQueryError(parseErr.Error()) } if limit > 100 { limit = 100 //TODO: make configurable } } eventRange, err := e.eventService.Messages(user, room, from, to, uint(limit)) log.Println("TO", to, eventRange) if err != nil { return err } return eventRange }
func (e eventsEndpoint) getEvents(req *http.Request) interface{} { authedUser, err := readAccessToken(e.userService, e.tokenService, req) if err != nil { return err } query := urlQuery{req.URL.Query()} from, err := query.parseStreamToken("from") if err != nil { return err } to, err := query.parseStreamToken("to") if err != nil { return err } limit, err := query.parseUint("limit", 10) if err != nil { return err } if limit > 100 { limit = 100 //TODO: make configurable } timeout, err := query.parseUint("timeout", 5000) if err != nil { return err } if timeout > 60000 { timeout = 60000 //TODO: make configurable } if timeout < 100 { timeout = 100 } dir := query.Get("dir") if dir == "b" { token := types.NewStreamToken(0, 0, 0) to = &token } cancel := make(chan struct{}) go func(timeout time.Duration) { time.Sleep(timeout) close(cancel) }(time.Millisecond * time.Duration(timeout)) chunk, err := e.eventService.Range(authedUser, from, to, uint(limit), cancel) if err != nil { return err } return chunk }
func (s syncService) roomSummary( summary *types.RoomSummary, user ct.UserId, room ct.RoomId, end types.StreamToken, limit uint, ) types.Error { roomSet := map[ct.RoomId]struct{}{ room: struct{}{}, } messages, err := s.messageSource.Range(nil, nil, roomSet, end.MessageIndex, 0, limit) if err != nil { return err } startIndex := end.MessageIndex if len(messages) > 0 { startIndex = messages[0].Index() } start := types.NewStreamToken(startIndex, end.PresenceIndex, end.TypingIndex) eventRange := types.NewEventStreamRange(indexedToEvents(messages), start, end) states, err := s.rooms.EntireRoomState(room) if err != nil { return err } membershipState, err := s.rooms.RoomState(room, types.EventTypeMembership, user.String()) if err != nil { return err } membership := membershipState.Content.(*types.MembershipEventContent).Membership joinRuleState, err := s.rooms.RoomState(room, types.EventTypeJoinRules, "") if err != nil { return err } joinRule := joinRuleState.Content.(*types.JoinRulesEventContent).JoinRule visibility := joinRule.ToVisibility() summary.Membership = membership summary.RoomId = room summary.Messages = eventRange summary.State = states summary.Visibility = visibility return nil }
func (s eventService) Range( user ct.UserId, from, to *types.StreamToken, limit uint, cancel chan struct{}, ) (chunk *types.EventStreamRange, err types.Error) { var eventCh chan ct.IndexedEvent if from == nil || to == nil || from.MessageIndex > to.MessageIndex { eventCh, err = s.asyncEventSource.Listen(user, cancel) if err != nil { return nil, err } } maxMessage := s.messageSource.Max() maxPresence := s.presenceSource.Max() maxTyping := s.typingSource.Max() var fromMessage uint64 var fromPresence uint64 var fromTyping uint64 if from != nil { fromMessage = from.MessageIndex if fromMessage > maxMessage { fromMessage = maxMessage } fromPresence = from.PresenceIndex if fromPresence > maxPresence { fromPresence = maxPresence } fromTyping = from.TypingIndex if fromTyping > maxTyping { fromTyping = maxTyping } } else { fromMessage = maxMessage fromPresence = maxPresence fromTyping = maxTyping } var toMessage uint64 var toPresence uint64 var toTyping uint64 if to != nil { toMessage = to.MessageIndex toPresence = to.PresenceIndex toTyping = to.TypingIndex } else { toMessage = maxMessage toPresence = maxPresence toTyping = maxTyping } userSet, err := s.membershipStore.Peers(user) if err != nil { return nil, err } roomSet := map[ct.RoomId]struct{}{} rooms, err := s.membershipStore.Rooms(user) if err != nil { return nil, err } for _, room := range rooms { roomSet[room] = struct{}{} } messages, err := s.messageSource.Range(&user, userSet, roomSet, fromMessage, toMessage, limit) if err != nil { return nil, err } presences, err := s.presenceSource.Range(&user, userSet, roomSet, fromPresence, toPresence, limit) if err != nil { return nil, err } typings, err := s.typingSource.Range(&user, userSet, roomSet, fromTyping, toTyping, limit) if err != nil { return nil, err } log.Printf("getting events from %d to %d, max %d, %#v", fromMessage, toMessage, maxMessage, eventCh) if eventCh != nil { blocking := true if to != nil && toMessage <= maxMessage && toPresence <= maxPresence && toTyping <= maxTyping { blocking = false } gotEvent := false var event ct.IndexedEvent if blocking && len(messages)+len(presences)+len(typings) == 0 { event, gotEvent = <-eventCh } else { select { case event, gotEvent = <-eventCh: default: } } log.Printf("async event: %#v blocking: %#v len: %#v", event, blocking, len(messages)+len(presences)+len(typings)) if gotEvent && uint(len(messages)) < limit { eventType := event.Event().GetEventType() if eventType == types.EventTypePresence { if len(presences) == 0 || presences[len(presences)-1].Index() < event.Index() { if to == nil || event.Index() < toPresence { presences = append(presences, event) } } } else if eventType == types.EventTypeTyping { if len(typings) == 0 || typings[len(typings)-1].Index() < event.Index() { if to == nil || event.Index() < toTyping { typings = append(typings, event) } } } else { if len(messages) == 0 || messages[len(messages)-1].Index() < event.Index() { if to == nil || event.Index() < toMessage { messages = append(messages, event) } } } } } messageIndex := fromMessage presenceIndex := fromPresence typingIndex := fromTyping if len(messages) > 0 { messageIndex = messages[len(messages)-1].Index() + 1 } if len(presences) > 0 { presenceIndex = presences[len(presences)-1].Index() + 1 } if len(typings) > 0 { typingIndex = typings[len(typings)-1].Index() + 1 } start := types.NewStreamToken(fromMessage, fromPresence, fromTyping) end := types.NewStreamToken(messageIndex, presenceIndex, typingIndex) events := make([]ct.Event, len(messages)+len(presences)+len(typings)) for i, _ := range events { if i < len(messages) { events[i] = messages[i].Event() } else { i -= len(messages) if i < len(presences) { events[len(messages)+i] = presences[i].Event() } else { i -= len(presences) events[len(messages)+len(presences)+i] = typings[i].Event() } } } log.Printf("got events from %d to %d: %#v", fromMessage, messageIndex, events) chunk = types.NewEventStreamRange(events, start, end) return chunk, nil // ch = eventMux.listen(user) // to = eventBuffer.max // atomic // resultChan = make(chan, limit) // result = [] // found = 0 // event = indices[from] // while found < limit && event.index < to: // event = event.next // if filter.test(user, event): // resultChan <- event // found += 1 // if found < limit { // switch { // new <- ch // if new.index > to: // default: // } // new = readAll(ch) // } }
func (s eventService) Messages( user ct.UserId, room ct.RoomId, from, to *types.StreamToken, limit uint, ) (eventRange *types.EventStreamRange, err types.Error) { maxMessage := s.messageSource.Max() var fromMessage uint64 var presenceIndex uint64 var typingIndex uint64 if from != nil { fromMessage = from.MessageIndex presenceIndex = from.PresenceIndex typingIndex = from.TypingIndex if fromMessage > maxMessage { fromMessage = maxMessage } } else { fromMessage = maxMessage presenceIndex = s.presenceSource.Max() typingIndex = s.typingSource.Max() } var toMessage uint64 if to != nil { toMessage = to.MessageIndex } else { toMessage = maxMessage } log.Println("to message", toMessage, to) roomSet := map[ct.RoomId]struct{}{ room: struct{}{}, } messages, err := s.messageSource.Range(nil, nil, roomSet, fromMessage, toMessage, limit) if err != nil { return nil, err } log.Printf("getting messages from %d to %d, max %d", fromMessage, toMessage, maxMessage) messagesStart := fromMessage messagesEnd := fromMessage if len(messages) > 0 { messagesStart = messages[0].Index() messagesEnd = messages[len(messages)-1].Index() + 1 } if to != nil && to.MessageIndex < fromMessage { messagesEnd, messagesStart = messagesStart, messagesEnd } start := types.NewStreamToken(messagesStart, presenceIndex, typingIndex) end := types.NewStreamToken(messagesEnd, presenceIndex, typingIndex) events := make([]ct.Event, len(messages)) for i, _ := range events { events[i] = messages[i].Event() } log.Printf("got messages from %d to %d: %#v", messagesStart, messagesEnd, events) eventRange = types.NewEventStreamRange(events, start, end) return eventRange, nil }