Add Query API for querying events by ID (#129)
parent
1b6e06aa59
commit
ef7b934d51
|
@ -41,6 +41,7 @@ type QueryLatestEventsAndStateResponse struct {
|
||||||
// The latest events in the room.
|
// The latest events in the room.
|
||||||
LatestEvents []gomatrixserverlib.EventReference
|
LatestEvents []gomatrixserverlib.EventReference
|
||||||
// The state events requested.
|
// The state events requested.
|
||||||
|
// This list will be in an arbitrary order.
|
||||||
StateEvents []gomatrixserverlib.Event
|
StateEvents []gomatrixserverlib.Event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,9 +66,30 @@ type QueryStateAfterEventsResponse struct {
|
||||||
// If some of previous events do not exist this will be false and StateEvents will be empty.
|
// If some of previous events do not exist this will be false and StateEvents will be empty.
|
||||||
PrevEventsExist bool
|
PrevEventsExist bool
|
||||||
// The state events requested.
|
// The state events requested.
|
||||||
|
// This list will be in an arbitrary order.
|
||||||
StateEvents []gomatrixserverlib.Event
|
StateEvents []gomatrixserverlib.Event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QueryEventsByIDRequest is a request to QueryEventsByID
|
||||||
|
type QueryEventsByIDRequest struct {
|
||||||
|
// The event IDs to look up.
|
||||||
|
EventIDs []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueryEventsByIDResponse is a response to QueryEventsByID
|
||||||
|
type QueryEventsByIDResponse struct {
|
||||||
|
// Copy of the request for debugging.
|
||||||
|
QueryEventsByIDRequest
|
||||||
|
// A list of events with the requested IDs.
|
||||||
|
// If the roomserver does not have a copy of a requested event
|
||||||
|
// then it will omit that event from the list.
|
||||||
|
// If the roomserver thinks it has a copy of the event, but
|
||||||
|
// fails to read it from the database then it will fail
|
||||||
|
// the entire request.
|
||||||
|
// This list will be in an arbitrary order.
|
||||||
|
Events []gomatrixserverlib.Event
|
||||||
|
}
|
||||||
|
|
||||||
// RoomserverQueryAPI is used to query information from the room server.
|
// RoomserverQueryAPI is used to query information from the room server.
|
||||||
type RoomserverQueryAPI interface {
|
type RoomserverQueryAPI interface {
|
||||||
// Query the latest events and state for a room from the room server.
|
// Query the latest events and state for a room from the room server.
|
||||||
|
@ -81,6 +103,12 @@ type RoomserverQueryAPI interface {
|
||||||
request *QueryStateAfterEventsRequest,
|
request *QueryStateAfterEventsRequest,
|
||||||
response *QueryStateAfterEventsResponse,
|
response *QueryStateAfterEventsResponse,
|
||||||
) error
|
) error
|
||||||
|
|
||||||
|
// Query a list of events by event ID.
|
||||||
|
QueryEventsByID(
|
||||||
|
request *QueryEventsByIDRequest,
|
||||||
|
response *QueryEventsByIDResponse,
|
||||||
|
) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// RoomserverQueryLatestEventsAndStatePath is the HTTP path for the QueryLatestEventsAndState API.
|
// RoomserverQueryLatestEventsAndStatePath is the HTTP path for the QueryLatestEventsAndState API.
|
||||||
|
@ -89,6 +117,9 @@ const RoomserverQueryLatestEventsAndStatePath = "/api/roomserver/QueryLatestEven
|
||||||
// RoomserverQueryStateAfterEventsPath is the HTTP path for the QueryStateAfterEvents API.
|
// RoomserverQueryStateAfterEventsPath is the HTTP path for the QueryStateAfterEvents API.
|
||||||
const RoomserverQueryStateAfterEventsPath = "/api/roomserver/QueryStateAfterEvents"
|
const RoomserverQueryStateAfterEventsPath = "/api/roomserver/QueryStateAfterEvents"
|
||||||
|
|
||||||
|
// RoomserverQueryEventsByIDPath is the HTTP path for the QueryEventsByID API.
|
||||||
|
const RoomserverQueryEventsByIDPath = "/api/roomserver/QueryEventsByID"
|
||||||
|
|
||||||
// NewRoomserverQueryAPIHTTP creates a RoomserverQueryAPI implemented by talking to a HTTP POST API.
|
// NewRoomserverQueryAPIHTTP creates a RoomserverQueryAPI implemented by talking to a HTTP POST API.
|
||||||
// If httpClient is nil then it uses the http.DefaultClient
|
// If httpClient is nil then it uses the http.DefaultClient
|
||||||
func NewRoomserverQueryAPIHTTP(roomserverURL string, httpClient *http.Client) RoomserverQueryAPI {
|
func NewRoomserverQueryAPIHTTP(roomserverURL string, httpClient *http.Client) RoomserverQueryAPI {
|
||||||
|
@ -121,6 +152,15 @@ func (h *httpRoomserverQueryAPI) QueryStateAfterEvents(
|
||||||
return postJSON(h.httpClient, apiURL, request, response)
|
return postJSON(h.httpClient, apiURL, request, response)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QueryEventsByID implements RoomserverQueryAPI
|
||||||
|
func (h *httpRoomserverQueryAPI) QueryEventsByID(
|
||||||
|
request *QueryEventsByIDRequest,
|
||||||
|
response *QueryEventsByIDResponse,
|
||||||
|
) error {
|
||||||
|
apiURL := h.roomserverURL + RoomserverQueryEventsByIDPath
|
||||||
|
return postJSON(h.httpClient, apiURL, request, response)
|
||||||
|
}
|
||||||
|
|
||||||
func postJSON(httpClient http.Client, apiURL string, request, response interface{}) error {
|
func postJSON(httpClient http.Client, apiURL string, request, response interface{}) error {
|
||||||
jsonBytes, err := json.Marshal(request)
|
jsonBytes, err := json.Marshal(request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -35,6 +35,9 @@ type RoomserverQueryAPIDatabase interface {
|
||||||
// Lookup event references for the latest events in the room and the current state snapshot.
|
// Lookup event references for the latest events in the room and the current state snapshot.
|
||||||
// Returns an error if there was a problem talking to the database.
|
// Returns an error if there was a problem talking to the database.
|
||||||
LatestEventIDs(roomNID types.RoomNID) ([]gomatrixserverlib.EventReference, types.StateSnapshotNID, error)
|
LatestEventIDs(roomNID types.RoomNID) ([]gomatrixserverlib.EventReference, types.StateSnapshotNID, error)
|
||||||
|
// Lookup the numeric IDs for a list of events.
|
||||||
|
// Returns an error if there was a problem talking to the database.
|
||||||
|
EventNIDs(eventIDs []string) (map[string]types.EventNID, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RoomserverQueryAPI is an implementation of RoomserverQueryAPI
|
// RoomserverQueryAPI is an implementation of RoomserverQueryAPI
|
||||||
|
@ -46,7 +49,7 @@ type RoomserverQueryAPI struct {
|
||||||
func (r *RoomserverQueryAPI) QueryLatestEventsAndState(
|
func (r *RoomserverQueryAPI) QueryLatestEventsAndState(
|
||||||
request *api.QueryLatestEventsAndStateRequest,
|
request *api.QueryLatestEventsAndStateRequest,
|
||||||
response *api.QueryLatestEventsAndStateResponse,
|
response *api.QueryLatestEventsAndStateResponse,
|
||||||
) (err error) {
|
) error {
|
||||||
response.QueryLatestEventsAndStateRequest = *request
|
response.QueryLatestEventsAndStateRequest = *request
|
||||||
roomNID, err := r.DB.RoomNID(request.RoomID)
|
roomNID, err := r.DB.RoomNID(request.RoomID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -81,7 +84,7 @@ func (r *RoomserverQueryAPI) QueryLatestEventsAndState(
|
||||||
func (r *RoomserverQueryAPI) QueryStateAfterEvents(
|
func (r *RoomserverQueryAPI) QueryStateAfterEvents(
|
||||||
request *api.QueryStateAfterEventsRequest,
|
request *api.QueryStateAfterEventsRequest,
|
||||||
response *api.QueryStateAfterEventsResponse,
|
response *api.QueryStateAfterEventsResponse,
|
||||||
) (err error) {
|
) error {
|
||||||
response.QueryStateAfterEventsRequest = *request
|
response.QueryStateAfterEventsRequest = *request
|
||||||
roomNID, err := r.DB.RoomNID(request.RoomID)
|
roomNID, err := r.DB.RoomNID(request.RoomID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -115,12 +118,41 @@ func (r *RoomserverQueryAPI) QueryStateAfterEvents(
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QueryEventsByID implements api.RoomserverQueryAPI
|
||||||
|
func (r *RoomserverQueryAPI) QueryEventsByID(
|
||||||
|
request *api.QueryEventsByIDRequest,
|
||||||
|
response *api.QueryEventsByIDResponse,
|
||||||
|
) error {
|
||||||
|
response.QueryEventsByIDRequest = *request
|
||||||
|
|
||||||
|
eventNIDMap, err := r.DB.EventNIDs(request.EventIDs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var eventNIDs []types.EventNID
|
||||||
|
for _, nid := range eventNIDMap {
|
||||||
|
eventNIDs = append(eventNIDs, nid)
|
||||||
|
}
|
||||||
|
|
||||||
|
events, err := r.loadEvents(eventNIDs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
response.Events = events
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (r *RoomserverQueryAPI) loadStateEvents(stateEntries []types.StateEntry) ([]gomatrixserverlib.Event, error) {
|
func (r *RoomserverQueryAPI) loadStateEvents(stateEntries []types.StateEntry) ([]gomatrixserverlib.Event, error) {
|
||||||
eventNIDs := make([]types.EventNID, len(stateEntries))
|
eventNIDs := make([]types.EventNID, len(stateEntries))
|
||||||
for i := range stateEntries {
|
for i := range stateEntries {
|
||||||
eventNIDs[i] = stateEntries[i].EventNID
|
eventNIDs[i] = stateEntries[i].EventNID
|
||||||
}
|
}
|
||||||
|
return r.loadEvents(eventNIDs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RoomserverQueryAPI) loadEvents(eventNIDs []types.EventNID) ([]gomatrixserverlib.Event, error) {
|
||||||
stateEvents, err := r.DB.Events(eventNIDs)
|
stateEvents, err := r.DB.Events(eventNIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -163,4 +195,18 @@ func (r *RoomserverQueryAPI) SetupHTTP(servMux *http.ServeMux) {
|
||||||
return util.JSONResponse{Code: 200, JSON: &response}
|
return util.JSONResponse{Code: 200, JSON: &response}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
servMux.Handle(
|
||||||
|
api.RoomserverQueryEventsByIDPath,
|
||||||
|
common.MakeAPI("query_events_by_id", func(req *http.Request) util.JSONResponse {
|
||||||
|
var request api.QueryEventsByIDRequest
|
||||||
|
var response api.QueryEventsByIDResponse
|
||||||
|
if err := json.NewDecoder(req.Body).Decode(&request); err != nil {
|
||||||
|
return util.ErrorResponse(err)
|
||||||
|
}
|
||||||
|
if err := r.QueryEventsByID(&request, &response); err != nil {
|
||||||
|
return util.ErrorResponse(err)
|
||||||
|
}
|
||||||
|
return util.JSONResponse{Code: 200, JSON: &response}
|
||||||
|
}),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,9 @@ const bulkSelectEventReferenceSQL = "" +
|
||||||
const bulkSelectEventIDSQL = "" +
|
const bulkSelectEventIDSQL = "" +
|
||||||
"SELECT event_nid, event_id FROM events WHERE event_nid = ANY($1)"
|
"SELECT event_nid, event_id FROM events WHERE event_nid = ANY($1)"
|
||||||
|
|
||||||
|
const bulkSelectEventNIDSQL = "" +
|
||||||
|
"SELECT event_id, event_nid FROM events WHERE event_id = ANY($1)"
|
||||||
|
|
||||||
type eventStatements struct {
|
type eventStatements struct {
|
||||||
insertEventStmt *sql.Stmt
|
insertEventStmt *sql.Stmt
|
||||||
selectEventStmt *sql.Stmt
|
selectEventStmt *sql.Stmt
|
||||||
|
@ -116,6 +119,7 @@ type eventStatements struct {
|
||||||
bulkSelectStateAtEventAndReferenceStmt *sql.Stmt
|
bulkSelectStateAtEventAndReferenceStmt *sql.Stmt
|
||||||
bulkSelectEventReferenceStmt *sql.Stmt
|
bulkSelectEventReferenceStmt *sql.Stmt
|
||||||
bulkSelectEventIDStmt *sql.Stmt
|
bulkSelectEventIDStmt *sql.Stmt
|
||||||
|
bulkSelectEventNIDStmt *sql.Stmt
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *eventStatements) prepare(db *sql.DB) (err error) {
|
func (s *eventStatements) prepare(db *sql.DB) (err error) {
|
||||||
|
@ -136,6 +140,7 @@ func (s *eventStatements) prepare(db *sql.DB) (err error) {
|
||||||
{&s.bulkSelectStateAtEventAndReferenceStmt, bulkSelectStateAtEventAndReferenceSQL},
|
{&s.bulkSelectStateAtEventAndReferenceStmt, bulkSelectStateAtEventAndReferenceSQL},
|
||||||
{&s.bulkSelectEventReferenceStmt, bulkSelectEventReferenceSQL},
|
{&s.bulkSelectEventReferenceStmt, bulkSelectEventReferenceSQL},
|
||||||
{&s.bulkSelectEventIDStmt, bulkSelectEventIDSQL},
|
{&s.bulkSelectEventIDStmt, bulkSelectEventIDSQL},
|
||||||
|
{&s.bulkSelectEventNIDStmt, bulkSelectEventNIDSQL},
|
||||||
}.prepare(db)
|
}.prepare(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -321,6 +326,26 @@ func (s *eventStatements) bulkSelectEventID(eventNIDs []types.EventNID) (map[typ
|
||||||
return results, nil
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bulkSelectEventNIDs returns a map from string event ID to numeric event ID.
|
||||||
|
// If an event ID is not in the database then it is omitted from the map.
|
||||||
|
func (s *eventStatements) bulkSelectEventNID(eventIDs []string) (map[string]types.EventNID, error) {
|
||||||
|
rows, err := s.bulkSelectEventNIDStmt.Query(pq.StringArray(eventIDs))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
results := make(map[string]types.EventNID, len(eventIDs))
|
||||||
|
for rows.Next() {
|
||||||
|
var eventID string
|
||||||
|
var eventNID int64
|
||||||
|
if err = rows.Scan(&eventID, &eventNID); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
results[eventID] = types.EventNID(eventNID)
|
||||||
|
}
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
func eventNIDsAsArray(eventNIDs []types.EventNID) pq.Int64Array {
|
func eventNIDsAsArray(eventNIDs []types.EventNID) pq.Int64Array {
|
||||||
nids := make([]int64, len(eventNIDs))
|
nids := make([]int64, len(eventNIDs))
|
||||||
for i := range eventNIDs {
|
for i := range eventNIDs {
|
||||||
|
|
|
@ -170,6 +170,11 @@ func (d *Database) EventStateKeyNIDs(eventStateKeys []string) (map[string]types.
|
||||||
return d.statements.bulkSelectEventStateKeyNID(eventStateKeys)
|
return d.statements.bulkSelectEventStateKeyNID(eventStateKeys)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EventNIDs implements query.RoomQueryDatabase
|
||||||
|
func (d *Database) EventNIDs(eventIDs []string) (map[string]types.EventNID, error) {
|
||||||
|
return d.statements.bulkSelectEventNID(eventIDs)
|
||||||
|
}
|
||||||
|
|
||||||
// Events implements input.EventDatabase
|
// Events implements input.EventDatabase
|
||||||
func (d *Database) Events(eventNIDs []types.EventNID) ([]types.Event, error) {
|
func (d *Database) Events(eventNIDs []types.EventNID) ([]types.Event, error) {
|
||||||
eventJSONs, err := d.statements.bulkSelectEventJSON(eventNIDs)
|
eventJSONs, err := d.statements.bulkSelectEventJSON(eventNIDs)
|
||||||
|
|
Loading…
Reference in New Issue