mirror of
https://github.com/matrix-org/dendrite.git
synced 2025-12-13 09:53:10 -06:00
send to device (STD) done, cooperate with key centre encryptoapi
This commit is contained in:
parent
7770664878
commit
57e6eb73dc
|
|
@ -60,7 +60,9 @@ const selectDeviceByIDSQL = "" +
|
||||||
"SELECT display_name FROM device_devices WHERE localpart = $1 and device_id = $2"
|
"SELECT display_name FROM device_devices WHERE localpart = $1 and device_id = $2"
|
||||||
|
|
||||||
const selectDevicesByLocalpartSQL = "" +
|
const selectDevicesByLocalpartSQL = "" +
|
||||||
"SELECT device_id, display_name FROM device_devices WHERE localpart = $1"
|
// todo : display name still has a problem when value is null
|
||||||
|
//"SELECT device_id, display_name FROM device_devices WHERE localpart = $1"
|
||||||
|
"SELECT device_id FROM device_devices WHERE localpart = $1"
|
||||||
|
|
||||||
const updateDeviceNameSQL = "" +
|
const updateDeviceNameSQL = "" +
|
||||||
"UPDATE device_devices SET display_name = $1 WHERE localpart = $2 AND device_id = $3"
|
"UPDATE device_devices SET display_name = $1 WHERE localpart = $2 AND device_id = $3"
|
||||||
|
|
@ -197,6 +199,8 @@ func (s *devicesStatements) selectDevicesByLocalpart(
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var dev authtypes.Device
|
var dev authtypes.Device
|
||||||
err = rows.Scan(&dev.ID)
|
err = rows.Scan(&dev.ID)
|
||||||
|
// todo: display name still has a problem when value is null
|
||||||
|
//err = rows.Scan(&dev.ID, &dev.DisplayName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return devices, err
|
return devices, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -167,20 +167,37 @@ func (s *keyStatements) selectInKeys(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
userID string,
|
userID string,
|
||||||
arr []string,
|
arr []string,
|
||||||
) (holders []types.KeyHolder, err error) {
|
) ([]types.KeyHolder, error) {
|
||||||
rows := sql.Rows{}
|
holders := []types.KeyHolder{}
|
||||||
rowsP := &rows
|
|
||||||
stmt := s.selectAllKeyStmt
|
stmt := s.selectAllKeyStmt
|
||||||
if len(arr) == 0 {
|
if len(arr) == 0 {
|
||||||
rowsP, err = stmt.QueryContext(ctx, userID, "device_key")
|
// mapping for all device keys
|
||||||
} else {
|
rowsP, err := stmt.QueryContext(ctx, userID, "device_key")
|
||||||
stmt = s.selectInKeysStmt
|
if err != nil {
|
||||||
list := pq.Array(arr)
|
return nil, err
|
||||||
rowsP, err = stmt.QueryContext(ctx, userID, list)
|
}
|
||||||
|
holders, err = injectKeyHolder(rowsP, holders)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = rowsP.Close()
|
||||||
|
return holders, err
|
||||||
}
|
}
|
||||||
|
stmt = s.selectInKeysStmt
|
||||||
|
list := pq.Array(arr)
|
||||||
|
rowsP, err := stmt.QueryContext(ctx, userID, list)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
holders, err = injectKeyHolder(rowsP, holders)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = rowsP.Close()
|
||||||
|
return holders, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func injectKeyHolder(rows *sql.Rows, keyHolder []types.KeyHolder) (holders []types.KeyHolder, err error) {
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
single := &types.KeyHolder{}
|
single := &types.KeyHolder{}
|
||||||
if err = rows.Scan(
|
if err = rows.Scan(
|
||||||
|
|
@ -194,8 +211,8 @@ func (s *keyStatements) selectInKeys(
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
holders = append(holders, *single)
|
keyHolder = append(keyHolder, *single)
|
||||||
}
|
}
|
||||||
err = rowsP.Close()
|
holders = keyHolder
|
||||||
return holders, err
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const pathPrefixR0 = "/_matrix/client/r0"
|
const pathPrefixR0 = "/_matrix/client/r0"
|
||||||
|
const pathPrefixUnstable = "/_matrix/client/unstable"
|
||||||
|
|
||||||
// Setup configures the given mux with sync-server listeners
|
// Setup configures the given mux with sync-server listeners
|
||||||
func Setup(apiMux *mux.Router, srp *sync.RequestPool, syncDB *storage.SyncServerDatabase, deviceDB *devices.Database) {
|
func Setup(apiMux *mux.Router, srp *sync.RequestPool, syncDB *storage.SyncServerDatabase, deviceDB *devices.Database, notifier *sync.Notifier) {
|
||||||
r0mux := apiMux.PathPrefix(pathPrefixR0).Subrouter()
|
r0mux := apiMux.PathPrefix(pathPrefixR0).Subrouter()
|
||||||
|
unstablemux := apiMux.PathPrefix(pathPrefixUnstable).Subrouter()
|
||||||
|
|
||||||
r0mux.Handle("/sync", common.MakeAuthAPI("sync", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse {
|
r0mux.Handle("/sync", common.MakeAuthAPI("sync", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse {
|
||||||
return srp.OnIncomingSyncRequest(req, device)
|
return srp.OnIncomingSyncRequest(req, device)
|
||||||
|
|
@ -50,4 +52,13 @@ func Setup(apiMux *mux.Router, srp *sync.RequestPool, syncDB *storage.SyncServer
|
||||||
vars := mux.Vars(req)
|
vars := mux.Vars(req)
|
||||||
return OnIncomingStateTypeRequest(req, syncDB, vars["roomID"], vars["type"], vars["stateKey"])
|
return OnIncomingStateTypeRequest(req, syncDB, vars["roomID"], vars["type"], vars["stateKey"])
|
||||||
})).Methods(http.MethodGet, http.MethodOptions)
|
})).Methods(http.MethodGet, http.MethodOptions)
|
||||||
|
|
||||||
|
unstablemux.Handle("/sendToDevice/{eventType}/{txnId}",
|
||||||
|
common.MakeAuthAPI("look up changes", deviceDB, func(req *http.Request, device *authtypes.Device) util.JSONResponse {
|
||||||
|
vars := mux.Vars(req)
|
||||||
|
eventType := vars["eventType"]
|
||||||
|
txnID := vars["txnId"]
|
||||||
|
return SendToDevice(req, device.UserID, syncDB, deviceDB, eventType, txnID, notifier)
|
||||||
|
}),
|
||||||
|
).Methods(http.MethodPut, http.MethodOptions)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
89
src/github.com/matrix-org/dendrite/syncapi/routing/std.go
Normal file
89
src/github.com/matrix-org/dendrite/syncapi/routing/std.go
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
package routing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||||
|
"github.com/matrix-org/dendrite/clientapi/auth/storage/devices"
|
||||||
|
"github.com/matrix-org/dendrite/clientapi/httputil"
|
||||||
|
"github.com/matrix-org/dendrite/syncapi/storage"
|
||||||
|
"github.com/matrix-org/dendrite/syncapi/sync"
|
||||||
|
"github.com/matrix-org/dendrite/syncapi/types"
|
||||||
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/util"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SendToDevice this is a function for calling process of send-to-device messages those bypassed DAG
|
||||||
|
func SendToDevice(
|
||||||
|
req *http.Request,
|
||||||
|
sender string,
|
||||||
|
syncDB *storage.SyncServerDatabase,
|
||||||
|
deviceDB *devices.Database,
|
||||||
|
eventType, txnID string,
|
||||||
|
notifier *sync.Notifier,
|
||||||
|
) util.JSONResponse {
|
||||||
|
ctx := req.Context()
|
||||||
|
stdRq := types.StdRequest{}
|
||||||
|
httputil.UnmarshalJSONRequest(req, &stdRq)
|
||||||
|
for uid, deviceMap := range stdRq.Sender {
|
||||||
|
|
||||||
|
// federation consideration todo:
|
||||||
|
// if uid is remote domain a fed process should go
|
||||||
|
if false {
|
||||||
|
// federation process
|
||||||
|
return util.JSONResponse{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// uid is local domain
|
||||||
|
for device, cont := range deviceMap {
|
||||||
|
jsonBuffer, err := json.Marshal(cont)
|
||||||
|
if err != nil {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusForbidden,
|
||||||
|
JSON: struct{}{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ev := types.StdHolder{
|
||||||
|
Sender: sender,
|
||||||
|
Event: jsonBuffer,
|
||||||
|
EventTyp: eventType,
|
||||||
|
}
|
||||||
|
var pos int64
|
||||||
|
|
||||||
|
// wildcard all devices
|
||||||
|
if device == "*" {
|
||||||
|
var deviceCollection []authtypes.Device
|
||||||
|
var localpart string
|
||||||
|
localpart, _, _ = gomatrixserverlib.SplitID('@', uid)
|
||||||
|
deviceCollection, err = deviceDB.GetDevicesByLocalpart(ctx, localpart)
|
||||||
|
for _, val := range deviceCollection {
|
||||||
|
pos, err = syncDB.InsertStdMessage(ctx, ev, txnID, uid, val.ID)
|
||||||
|
notifier.OnNewEvent(nil, uid, types.StreamPosition(pos))
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusForbidden,
|
||||||
|
JSON: struct{}{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusOK,
|
||||||
|
JSON: struct{}{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos, err = syncDB.InsertStdMessage(ctx, ev, txnID, uid, device)
|
||||||
|
if err != nil {
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusForbidden,
|
||||||
|
JSON: struct{}{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
notifier.OnNewEvent(nil, uid, types.StreamPosition(pos))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return util.JSONResponse{
|
||||||
|
Code: http.StatusOK,
|
||||||
|
JSON: struct{}{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,162 @@
|
||||||
|
package storage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
|
||||||
|
"github.com/lib/pq"
|
||||||
|
"github.com/matrix-org/dendrite/common"
|
||||||
|
"github.com/matrix-org/dendrite/syncapi/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// we treat send to device as abbrev as STD in the context below.
|
||||||
|
|
||||||
|
const sendToDeviceSchema = `
|
||||||
|
CREATE TABLE IF NOT EXISTS syncapi_send_to_device (
|
||||||
|
id BIGINT PRIMARY KEY DEFAULT nextval('syncapi_stream_id'),
|
||||||
|
txn_id TEXT NOT NULL,
|
||||||
|
sender TEXT NOT NULL,
|
||||||
|
event_type TEXT NOT NULL,
|
||||||
|
target_device_id TEXT NOT NULL,
|
||||||
|
target_user_id TEXT NOT NULL,
|
||||||
|
event_json TEXT NOT NULL,
|
||||||
|
del_read INTEGER DEFAULT 0,
|
||||||
|
max_read BIGINT DEFAULT currval('syncapi_stream_id') ,
|
||||||
|
CONSTRAINT syncapi_send_to_device_unique UNIQUE (txn_id, target_device_id, target_user_id)
|
||||||
|
);
|
||||||
|
`
|
||||||
|
|
||||||
|
const insertSTDSQL = "" +
|
||||||
|
"INSERT INTO syncapi_send_to_device (" +
|
||||||
|
" sender, event_type, target_user_id, target_device_id, txn_id, event_json" +
|
||||||
|
") VALUES ($1, $2, $3, $4, $5, $6) RETURNING id"
|
||||||
|
|
||||||
|
const deleteSTDSQL = "" +
|
||||||
|
"DELETE FROM syncapi_send_to_device WHERE target_user_id = $1 AND target_device_id = $2 AND max_read < $3 AND del_read = 1"
|
||||||
|
|
||||||
|
const selectSTDEventsInRangeSQL = "" +
|
||||||
|
"SELECT id, sender, event_type, event_json FROM syncapi_send_to_device" +
|
||||||
|
" WHERE target_user_id = $1 AND target_device_id = $2 AND id <= $3" +
|
||||||
|
" ORDER BY id LIMIT 100 "
|
||||||
|
|
||||||
|
const updateSTDEventSQL = "" +
|
||||||
|
"UPDATE syncapi_send_to_device SET del_read = 1 , max_read = $1 WHERE id = ANY($2)"
|
||||||
|
|
||||||
|
const selectMaxSTDIDSQL = "" +
|
||||||
|
"SELECT MAX(id) FROM syncapi_send_to_device"
|
||||||
|
|
||||||
|
type stdEventsStatements struct {
|
||||||
|
insertStdEventStmt *sql.Stmt
|
||||||
|
selectStdEventsInRangeStmt *sql.Stmt
|
||||||
|
deleteStdEventStmt *sql.Stmt
|
||||||
|
selectStdIDStmt *sql.Stmt
|
||||||
|
updateStdStmt *sql.Stmt
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stdEventsStatements) prepare(db *sql.DB) (err error) {
|
||||||
|
_, err = db.Exec(sendToDeviceSchema)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if s.insertStdEventStmt, err = db.Prepare(insertSTDSQL); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if s.selectStdEventsInRangeStmt, err = db.Prepare(selectSTDEventsInRangeSQL); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if s.deleteStdEventStmt, err = db.Prepare(deleteSTDSQL); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if s.selectStdIDStmt, err = db.Prepare(selectMaxSTDIDSQL); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if s.updateStdStmt, err = db.Prepare(updateSTDEventSQL); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stdEventsStatements) insertStdEvent(
|
||||||
|
ctx context.Context, stdEvent types.StdHolder,
|
||||||
|
transactionID string, targetUID, targetDevice string,
|
||||||
|
) (streamPos int64, err error) {
|
||||||
|
err = s.insertStdEventStmt.QueryRowContext(
|
||||||
|
ctx,
|
||||||
|
stdEvent.Sender,
|
||||||
|
stdEvent.EventTyp,
|
||||||
|
targetUID,
|
||||||
|
targetDevice,
|
||||||
|
transactionID,
|
||||||
|
stdEvent.Event,
|
||||||
|
).Scan(&streamPos)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stdEventsStatements) deleteStdEvent(
|
||||||
|
ctx context.Context, userID, deviceID string,
|
||||||
|
idUpBound int64,
|
||||||
|
) error {
|
||||||
|
_, err := s.deleteStdEventStmt.ExecContext(ctx, userID, deviceID, idUpBound)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stdEventsStatements) selectStdEventsInRange(
|
||||||
|
ctx context.Context, txn *sql.Tx,
|
||||||
|
targetUserID, targetDeviceID string,
|
||||||
|
endPos int64,
|
||||||
|
) ([]types.StdHolder, error) {
|
||||||
|
stdHolder := []types.StdHolder{}
|
||||||
|
stmt := common.TxStmt(txn, s.selectStdEventsInRangeStmt)
|
||||||
|
rows, err := stmt.QueryContext(ctx, targetUserID, targetDeviceID, endPos)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for rows.Next() {
|
||||||
|
holder := types.StdHolder{}
|
||||||
|
var (
|
||||||
|
id int64
|
||||||
|
sender string
|
||||||
|
eventType string
|
||||||
|
eventJSON []byte
|
||||||
|
)
|
||||||
|
if err = rows.Scan(&id, &sender, &eventType, &eventJSON); err != nil {
|
||||||
|
closeErr := rows.Close()
|
||||||
|
if closeErr != nil {
|
||||||
|
return nil, closeErr
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
holder.StreamID = id
|
||||||
|
holder.Sender = sender
|
||||||
|
holder.Event = eventJSON
|
||||||
|
holder.EventTyp = eventType
|
||||||
|
stdHolder = append(stdHolder, holder)
|
||||||
|
}
|
||||||
|
err = rows.Close()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
// update events with read mark
|
||||||
|
update := []int64{}
|
||||||
|
for _, val := range stdHolder {
|
||||||
|
update = append(update, val.StreamID)
|
||||||
|
}
|
||||||
|
updateStmt := common.TxStmt(txn, s.updateStdStmt)
|
||||||
|
_, err = updateStmt.ExecContext(ctx, endPos, pq.Array(update))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return stdHolder, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *stdEventsStatements) selectMaxStdID(
|
||||||
|
ctx context.Context, txn *sql.Tx,
|
||||||
|
) (id int64, err error) {
|
||||||
|
var nullableID sql.NullInt64
|
||||||
|
stmt := common.TxStmt(txn, s.selectStdIDStmt)
|
||||||
|
err = stmt.QueryRowContext(ctx).Scan(&nullableID)
|
||||||
|
if nullableID.Valid {
|
||||||
|
id = nullableID.Int64
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
@ -23,8 +23,8 @@ import (
|
||||||
|
|
||||||
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
"github.com/matrix-org/dendrite/clientapi/auth/authtypes"
|
||||||
"github.com/matrix-org/dendrite/roomserver/api"
|
"github.com/matrix-org/dendrite/roomserver/api"
|
||||||
// Import the postgres database driver.
|
|
||||||
_ "github.com/lib/pq"
|
"encoding/json"
|
||||||
"github.com/matrix-org/dendrite/common"
|
"github.com/matrix-org/dendrite/common"
|
||||||
"github.com/matrix-org/dendrite/syncapi/types"
|
"github.com/matrix-org/dendrite/syncapi/types"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
|
@ -54,6 +54,7 @@ type SyncServerDatabase struct {
|
||||||
events outputRoomEventsStatements
|
events outputRoomEventsStatements
|
||||||
roomstate currentRoomStateStatements
|
roomstate currentRoomStateStatements
|
||||||
invites inviteEventsStatements
|
invites inviteEventsStatements
|
||||||
|
stdMsg stdEventsStatements
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSyncServerDatabase creates a new sync server database
|
// NewSyncServerDatabase creates a new sync server database
|
||||||
|
|
@ -78,6 +79,9 @@ func NewSyncServerDatabase(dataSourceName string) (*SyncServerDatabase, error) {
|
||||||
if err := d.invites.prepare(d.db); err != nil {
|
if err := d.invites.prepare(d.db); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if err := d.stdMsg.prepare(d.db); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return &d, nil
|
return &d, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -212,6 +216,13 @@ func (d *SyncServerDatabase) syncStreamPositionTx(
|
||||||
if maxInviteID > maxID {
|
if maxInviteID > maxID {
|
||||||
maxID = maxInviteID
|
maxID = maxInviteID
|
||||||
}
|
}
|
||||||
|
maxStdID, err := d.stdMsg.selectMaxStdID(ctx, txn)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
if maxStdID > maxID {
|
||||||
|
maxID = maxStdID
|
||||||
|
}
|
||||||
return types.StreamPosition(maxID), nil
|
return types.StreamPosition(maxID), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -678,3 +689,94 @@ func getMembershipFromEvent(ev *gomatrixserverlib.Event, userID string) string {
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
send to device messaging implementation
|
||||||
|
del / maxID / select in range / insert
|
||||||
|
*/
|
||||||
|
|
||||||
|
// DelStdMessage delete message for a given maxID, those below would be deleted
|
||||||
|
func (d *SyncServerDatabase) DelStdMessage(
|
||||||
|
ctx context.Context, targetUID, targetDevice string, maxID int64,
|
||||||
|
) (err error) {
|
||||||
|
err = common.WithTransaction(d.db, func(txn *sql.Tx) error {
|
||||||
|
err := d.stdMsg.deleteStdEvent(ctx, targetUID, targetDevice, maxID)
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// InsertStdMessage insert std message
|
||||||
|
func (d *SyncServerDatabase) InsertStdMessage(
|
||||||
|
ctx context.Context, stdEvent types.StdHolder, transactionID, targetUID, targetDevice string,
|
||||||
|
) (pos int64, err error) {
|
||||||
|
err = common.WithTransaction(d.db, func(txn *sql.Tx) error {
|
||||||
|
curPos, err := d.stdMsg.insertStdEvent(ctx, stdEvent, transactionID, targetUID, targetDevice)
|
||||||
|
pos = curPos
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectMaxStdID select maximum id in std stream
|
||||||
|
func (d *SyncServerDatabase) SelectMaxStdID(
|
||||||
|
ctx context.Context,
|
||||||
|
) (maxID int64, err error) {
|
||||||
|
err = common.WithTransaction(d.db, func(txn *sql.Tx) error {
|
||||||
|
max, err := d.stdMsg.selectMaxStdID(ctx, txn)
|
||||||
|
maxID = max
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectRangedStd select a range of std messages
|
||||||
|
func (d *SyncServerDatabase) SelectRangedStd(
|
||||||
|
ctx context.Context,
|
||||||
|
targetUserID, targetDeviceID string,
|
||||||
|
endPos int64,
|
||||||
|
) (holder []types.StdHolder, err error) {
|
||||||
|
err = common.WithTransaction(d.db, func(txn *sql.Tx) error {
|
||||||
|
list, err := d.stdMsg.selectStdEventsInRange(ctx, txn, targetUserID, targetDeviceID, endPos)
|
||||||
|
holder = list
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// StdEXT : send to device extension process
|
||||||
|
func StdEXT(
|
||||||
|
ctx context.Context,
|
||||||
|
syncDB *SyncServerDatabase,
|
||||||
|
respIn types.Response,
|
||||||
|
userID, deviceID string,
|
||||||
|
since int64,
|
||||||
|
) (respOut *types.Response) {
|
||||||
|
respOut = &respIn
|
||||||
|
// when extension works at the very beginning
|
||||||
|
err := syncDB.stdMsg.deleteStdEvent(ctx, userID, deviceID, since)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// when err is nil, these before res should be tagged omitted,
|
||||||
|
// when next /sync is coming , and err is nil , all those omitted.
|
||||||
|
res, err := syncDB.SelectRangedStd(ctx, userID, deviceID, since)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
//toDevice := &types.ToDevice{}
|
||||||
|
mid := []types.StdEvent{}
|
||||||
|
//toDevice.StdEvent = mid
|
||||||
|
for _, val := range res {
|
||||||
|
ev := types.StdEvent{}
|
||||||
|
ev.Sender = val.Sender
|
||||||
|
ev.Type = val.EventTyp
|
||||||
|
err := json.Unmarshal(val.Event, &ev.Content)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mid = append(mid, ev)
|
||||||
|
}
|
||||||
|
respOut.ToDevice.StdEvent = mid
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -106,6 +106,10 @@ func (rp *RequestPool) OnIncomingSyncRequest(req *http.Request, device *authtype
|
||||||
// can respond
|
// can respond
|
||||||
|
|
||||||
syncData, err := rp.currentSyncForUser(*syncReq, currPos)
|
syncData, err := rp.currentSyncForUser(*syncReq, currPos)
|
||||||
|
|
||||||
|
// std extension consideration
|
||||||
|
syncData = storage.StdEXT(syncReq.ctx, rp.db, *syncData, syncReq.device.UserID, syncReq.device.ID, int64(currPos))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return httputil.LogThenError(req, err)
|
return httputil.LogThenError(req, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,5 +71,5 @@ func SetupSyncAPIComponent(
|
||||||
logrus.WithError(err).Panicf("failed to start client data consumer")
|
logrus.WithError(err).Panicf("failed to start client data consumer")
|
||||||
}
|
}
|
||||||
|
|
||||||
routing.Setup(base.APIMux, requestPool, syncDB, deviceDB)
|
routing.Setup(base.APIMux, requestPool, syncDB, deviceDB, notifier)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,32 @@ type Response struct {
|
||||||
Invite map[string]InviteResponse `json:"invite"`
|
Invite map[string]InviteResponse `json:"invite"`
|
||||||
Leave map[string]LeaveResponse `json:"leave"`
|
Leave map[string]LeaveResponse `json:"leave"`
|
||||||
} `json:"rooms"`
|
} `json:"rooms"`
|
||||||
|
ToDevice ToDevice `json:"to_device"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StdHolder represents send to device response from db
|
||||||
|
type StdHolder struct {
|
||||||
|
StreamID int64
|
||||||
|
Sender string
|
||||||
|
EventTyp string
|
||||||
|
Event []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// StdRequest represents send to device request format
|
||||||
|
type StdRequest struct {
|
||||||
|
Sender map[string]map[string]interface{} `json:"messages"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToDevice represents a middleware for response send to device
|
||||||
|
type ToDevice struct {
|
||||||
|
StdEvent []StdEvent `json:"events"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// StdEvent represents send to device event format
|
||||||
|
type StdEvent struct {
|
||||||
|
Sender string `json:"sender"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Content interface{} `json:"content"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewResponse creates an empty response with initialised maps.
|
// NewResponse creates an empty response with initialised maps.
|
||||||
|
|
@ -81,7 +107,8 @@ func (r *Response) IsEmpty() bool {
|
||||||
len(r.Rooms.Invite) == 0 &&
|
len(r.Rooms.Invite) == 0 &&
|
||||||
len(r.Rooms.Leave) == 0 &&
|
len(r.Rooms.Leave) == 0 &&
|
||||||
len(r.AccountData.Events) == 0 &&
|
len(r.AccountData.Events) == 0 &&
|
||||||
len(r.Presence.Events) == 0
|
len(r.Presence.Events) == 0 &&
|
||||||
|
len(r.ToDevice.StdEvent) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// JoinResponse represents a /sync response for a room which is under the 'join' key.
|
// JoinResponse represents a /sync response for a room which is under the 'join' key.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue