Move the logic from the storage to the query API

This commit is contained in:
Brendan Abolivier 2017-08-23 12:58:18 +01:00
parent 9a9275559c
commit 360e5f944f
No known key found for this signature in database
GPG key ID: 8EF1500759F70623
2 changed files with 93 additions and 79 deletions

View file

@ -40,6 +40,9 @@ type RoomserverQueryAPIDatabase interface {
// Lookup the numeric IDs for a list of events. // Lookup the numeric IDs for a list of events.
// Returns an error if there was a problem talking to the database. // Returns an error if there was a problem talking to the database.
EventNIDs(eventIDs []string) (map[string]types.EventNID, error) EventNIDs(eventIDs []string) (map[string]types.EventNID, error)
// Lookup the event IDs for a batch of event numeric IDs.
// Returns an error if the retrieval went wrong.
EventIDs(eventNIDs []types.EventNID) (map[types.EventNID]string, error)
// Save a given room alias with the room ID it refers to. // Save a given room alias with the room ID it refers to.
// Returns an error if there was a problem talking to the database. // Returns an error if there was a problem talking to the database.
SetRoomAlias(alias string, roomID string) error SetRoomAlias(alias string, roomID string) error
@ -52,13 +55,16 @@ type RoomserverQueryAPIDatabase interface {
// Remove a given room alias. // Remove a given room alias.
// Returns an error if there was a problem talking to the database. // Returns an error if there was a problem talking to the database.
RemoveRoomAlias(alias string) error RemoveRoomAlias(alias string) error
// Lookup the join events for all members in a room as requested by a given // Lookup the membership of a given user in a given room.
// user. If the user is currently in the room, returns the room's current // Returns the numeric ID of the latest membership event sent from this user
// members, if not returns an empty array (TODO: Fix it) // in this room, along a boolean set to true if the user is still in this room,
// If the user requesting the list of members has never been in the room, // false if not.
// returns nil. // Returns an error if there was a problem talking to the database.
// If there was an issue retrieving the events, returns an error. GetMembership(roomNID types.RoomNID, requestSenderUserID string) (membershipEventNID types.EventNID, stillInRoom bool, err error)
GetMembershipEvents(roomNID types.RoomNID, requestSenderUserID string) (events []types.Event, err error) // Lookup the "join" membership event numeric IDs for all user that are
// currently members of a given room.
// Returns an error if there was a problem talking to the database.
GetJoinMembershipEventNIDsForRoom(roomNID types.RoomNID) ([]types.EventNID, error)
} }
// RoomserverQueryAPI is an implementation of api.RoomserverQueryAPI // RoomserverQueryAPI is an implementation of api.RoomserverQueryAPI
@ -199,12 +205,12 @@ func (r *RoomserverQueryAPI) QueryMembershipsForRoom(
return err return err
} }
events, err := r.DB.GetMembershipEvents(roomNID, request.Sender) membershipEventNID, stillInRoom, err := r.DB.GetMembership(roomNID, request.Sender)
if err != nil { if err != nil {
return nil return nil
} }
if events == nil { if membershipEventNID == 0 {
response.HasBeenInRoom = false response.HasBeenInRoom = false
response.JoinEvents = nil response.JoinEvents = nil
return nil return nil
@ -212,6 +218,24 @@ func (r *RoomserverQueryAPI) QueryMembershipsForRoom(
response.HasBeenInRoom = true response.HasBeenInRoom = true
response.JoinEvents = []gomatrixserverlib.ClientEvent{} response.JoinEvents = []gomatrixserverlib.ClientEvent{}
var events []types.Event
if stillInRoom {
var eventNIDs []types.EventNID
eventNIDs, err = r.DB.GetJoinMembershipEventNIDsForRoom(roomNID)
if err != nil {
return err
}
events, err = r.DB.Events(eventNIDs)
} else {
events, err = r.getMembershipsBeforeEventNID(membershipEventNID)
}
if err != nil {
return err
}
for _, event := range events { for _, event := range events {
clientEvent := gomatrixserverlib.ToClientEvent(event.Event, gomatrixserverlib.FormatAll) clientEvent := gomatrixserverlib.ToClientEvent(event.Event, gomatrixserverlib.FormatAll)
response.JoinEvents = append(response.JoinEvents, clientEvent) response.JoinEvents = append(response.JoinEvents, clientEvent)
@ -220,6 +244,59 @@ func (r *RoomserverQueryAPI) QueryMembershipsForRoom(
return nil return nil
} }
// getMembershipsBeforeEventNID takes the numeric ID of an event and fetches the state
// of the event's room as it was when this event was fired, then filters the state events to
// only keep the "m.room.member" events with a "join" membership. These events are returned.
// Returns an error if there was an issue fetching the events.
func (r *RoomserverQueryAPI) getMembershipsBeforeEventNID(eventNID types.EventNID) ([]types.Event, error) {
events := []types.Event{}
// Lookup the event NID
eIDs, err := r.DB.EventIDs([]types.EventNID{eventNID})
if err != nil {
return nil, err
}
eventIDs := []string{eIDs[eventNID]}
prevState, err := r.DB.StateAtEventIDs(eventIDs)
if err != nil {
return nil, err
}
// Fetch the state as it was when this event was fired
stateEntries, err := state.LoadCombinedStateAfterEvents(r.DB, prevState)
if err != nil {
return nil, err
}
var eventNIDs []types.EventNID
for _, entry := range stateEntries {
// Filter the events to retrieve to only keep the membership events
if entry.EventStateKeyNID == types.MRoomMemberNID {
eventNIDs = append(eventNIDs, entry.EventNID)
}
}
// Get all of the events in this state
stateEvents, err := r.DB.Events(eventNIDs)
if err != nil {
return nil, err
}
// Filter the events to only keep the "join" membership events
for _, event := range stateEvents {
membership, err := event.Membership()
if err != nil {
return nil, err
}
if membership == "join" {
events = append(events, event)
}
}
return events, nil
}
// SetupHTTP adds the RoomserverQueryAPI handlers to the http.ServeMux. // SetupHTTP adds the RoomserverQueryAPI handlers to the http.ServeMux.
func (r *RoomserverQueryAPI) SetupHTTP(servMux *http.ServeMux) { func (r *RoomserverQueryAPI) SetupHTTP(servMux *http.ServeMux) {
servMux.Handle( servMux.Handle(

View file

@ -19,7 +19,6 @@ import (
// Import the postgres database driver. // Import the postgres database driver.
_ "github.com/lib/pq" _ "github.com/lib/pq"
"github.com/matrix-org/dendrite/roomserver/state"
"github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/roomserver/types"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
) )
@ -509,8 +508,8 @@ func (u *membershipUpdater) SetToLeave(senderUserID string, eventID string) ([]s
return inviteEventIDs, nil return inviteEventIDs, nil
} }
// GetMembershipEvents implements query.RoomserverQueryAPIDB // GetMembership implements query.RoomserverQueryAPIDB
func (d *Database) GetMembershipEvents(roomNID types.RoomNID, requestSenderUserID string) (events []types.Event, err error) { func (d *Database) GetMembership(roomNID types.RoomNID, requestSenderUserID string) (membershipEventNID types.EventNID, stillInRoom bool, err error) {
txn, err := d.db.Begin() txn, err := d.db.Begin()
if err != nil { if err != nil {
return return
@ -525,79 +524,17 @@ func (d *Database) GetMembershipEvents(roomNID types.RoomNID, requestSenderUserI
senderMembershipEventNID, senderMembership, err := d.statements.selectMembershipFromRoomAndTarget(roomNID, requestSenderUserNID) senderMembershipEventNID, senderMembership, err := d.statements.selectMembershipFromRoomAndTarget(roomNID, requestSenderUserNID)
if err == sql.ErrNoRows { if err == sql.ErrNoRows {
// The user has never been a member of that room // The user has never been a member of that room
return nil, nil return 0, false, nil
} else if err != nil { } else if err != nil {
return return
} }
if senderMembership == membershipStateJoin { return senderMembershipEventNID, senderMembership == membershipStateJoin, nil
// The user is still in the room: Send the current list of joined members
var joinEventNIDs []types.EventNID
joinEventNIDs, err = d.statements.selectMembershipsFromRoomAndMembership(roomNID, membershipStateJoin)
if err != nil {
return nil, err
}
events, err = d.Events(joinEventNIDs)
} else {
// The user isn't in the room anymore: Send the list of joined user from
// when the user left
events, err = d.getMembershipsBeforeEventNID(senderMembershipEventNID)
}
return
} }
// getMembershipsBeforeEventNID takes the numeric ID of an event and fetches the state // GetJoinMembershipEventNIDsForRoom implements query.RoomserverQueryAPIDB
// of the event's room as it was when this event was fired, then filters the state events to func (d *Database) GetJoinMembershipEventNIDsForRoom(roomNID types.RoomNID) ([]types.EventNID, error) {
// only keep the "m.room.member" events with a "join" membership. These events are returned. return d.statements.selectMembershipsFromRoomAndMembership(roomNID, membershipStateJoin)
// Returns an error if there was an issue fetching the events.
func (d *Database) getMembershipsBeforeEventNID(eventNID types.EventNID) ([]types.Event, error) {
events := []types.Event{}
// Lookup the event NID
eIDs, err := d.EventIDs([]types.EventNID{eventNID})
if err != nil {
return nil, err
}
eventIDs := []string{eIDs[eventNID]}
prevState, err := d.StateAtEventIDs(eventIDs)
if err != nil {
return nil, err
}
// Fetch the state as it was when this event was fired
stateEntries, err := state.LoadCombinedStateAfterEvents(d, prevState)
if err != nil {
return nil, err
}
var eventNIDs []types.EventNID
for _, entry := range stateEntries {
if entry.EventStateKeyNID == types.MRoomMemberNID {
eventNIDs = append(eventNIDs, entry.EventNID)
}
}
// Get all of the events in this state
stateEvents, err := d.Events(eventNIDs)
if err != nil {
return nil, err
}
// Filter the events to only keep the "join" membership events
for _, event := range stateEvents {
membership, err := event.Membership()
if err != nil {
return nil, err
}
if membership == "join" {
events = append(events, event)
}
}
return events, nil
} }
type transaction struct { type transaction struct {