diff --git a/clientapi/routing/presence.go b/clientapi/routing/presence.go index 236ca1cde..e9049aaff 100644 --- a/clientapi/routing/presence.go +++ b/clientapi/routing/presence.go @@ -32,8 +32,8 @@ import ( ) type presenceRequest struct { - Presence string `json:"presence"` - StatusMsg string `json:"status_msg"` + Presence string `json:"presence"` + StatusMsg *string `json:"status_msg"` } // SetPresence updates the users presence status @@ -145,7 +145,7 @@ func GetPresence(req *http.Request, resp := presenceResponse{} lastActive := time.Since(presence.LastActiveTS.Time()) resp.LastActiveAgo = lastActive.Milliseconds() - resp.StatusMsg = presence.StatusMsg + resp.StatusMsg = *presence.StatusMsg resp.CurrentlyActive = lastActive <= time.Minute*5 if !resp.CurrentlyActive { presence.PresenceStatus = types.Unavailable diff --git a/eduserver/api/input.go b/eduserver/api/input.go index cff1be9bc..465f11ad4 100644 --- a/eduserver/api/input.go +++ b/eduserver/api/input.go @@ -81,7 +81,7 @@ type InputReceiptEventResponse struct{} type InputPresenceRequest struct { UserID string `json:"user_id"` Presence types.PresenceStatus `json:"status"` - StatusMsg string `json:"status_msg"` + StatusMsg *string `json:"status_msg"` LastActiveTS gomatrixserverlib.Timestamp `json:"last_active_ts"` StreamPos types2.StreamPosition `json:"stream_pos"` } diff --git a/eduserver/api/output.go b/eduserver/api/output.go index 3d35f29b9..239ac25c6 100644 --- a/eduserver/api/output.go +++ b/eduserver/api/output.go @@ -62,18 +62,18 @@ type OutputCrossSigningKeyUpdate struct { type OutputPresenceData struct { UserID string `json:"user_id"` Presence types.PresenceStatus `json:"presence"` - StatusMsg string `json:"status_msg,omitempty"` + StatusMsg *string `json:"status_msg,omitempty"` LastActiveTS gomatrixserverlib.Timestamp `json:"last_active_ts"` LastActiveAgo int64 `json:"last_active_ago,omitempty"` StreamPos types2.StreamPosition `json:"stream_pos"` } type FederationPresenceSingle struct { - CurrentlyActive bool `json:"currently_active"` - LastActiveAgo int `json:"last_active_ago"` - Presence string `json:"presence"` - UserID string `json:"user_id"` - StatusMsg string `json:"status_msg"` + CurrentlyActive bool `json:"currently_active"` + LastActiveAgo int `json:"last_active_ago"` + Presence string `json:"presence"` + UserID string `json:"user_id"` + StatusMsg *string `json:"status_msg"` } type FederationPresenceData struct { diff --git a/eduserver/api/wrapper.go b/eduserver/api/wrapper.go index 8940dfdf4..436351618 100644 --- a/eduserver/api/wrapper.go +++ b/eduserver/api/wrapper.go @@ -95,7 +95,7 @@ func SetPresence( ctx context.Context, eduAPI EDUServerInputAPI, userAPI userapi.UserInternalAPI, - userID, statusMsg string, + userID string, statusMsg *string, presence types.PresenceStatus, lastActiveTS gomatrixserverlib.Timestamp, ) error { diff --git a/syncapi/streams/streams_presence.go b/syncapi/streams/streams_presence.go index acc27cb13..4db542d11 100644 --- a/syncapi/streams/streams_presence.go +++ b/syncapi/streams/streams_presence.go @@ -30,11 +30,11 @@ func (p *PresenceStreamProvider) CompleteSync(ctx context.Context, req *types.Sy } type outputPresence struct { - AvatarUrl string `json:"avatar_url,omitempty"` - CurrentlyActive bool `json:"currently_active,omitempty"` - LastActiveAgo int64 `json:"last_active_ago,omitempty"` - Presence string `json:"presence,omitempty"` - StatusMsg string `json:"status_msg,omitempty"` + AvatarUrl string `json:"avatar_url,omitempty"` + CurrentlyActive bool `json:"currently_active,omitempty"` + LastActiveAgo int64 `json:"last_active_ago,omitempty"` + Presence string `json:"presence,omitempty"` + StatusMsg *string `json:"status_msg,omitempty"` } func (p *PresenceStreamProvider) IncrementalSync(ctx context.Context, req *types.SyncRequest, from, to types.StreamPosition) types.StreamPosition { diff --git a/syncapi/sync/requestpool.go b/syncapi/sync/requestpool.go index 5de7d3de7..eee453e5c 100644 --- a/syncapi/sync/requestpool.go +++ b/syncapi/sync/requestpool.go @@ -33,6 +33,7 @@ import ( "github.com/matrix-org/dendrite/syncapi/streams" "github.com/matrix-org/dendrite/syncapi/types" userapi "github.com/matrix-org/dendrite/userapi/api" + types2 "github.com/matrix-org/dendrite/userapi/types" "github.com/matrix-org/util" "github.com/prometheus/client_golang/prometheus" ) @@ -149,6 +150,7 @@ func (rp *RequestPool) OnIncomingSyncRequest(req *http.Request, device *userapi. activeSyncRequests.Inc() defer activeSyncRequests.Dec() + rp.updatePresence(req, device) rp.updateLastSeen(req, device) waitingSyncRequests.Inc() @@ -258,6 +260,23 @@ func (rp *RequestPool) OnIncomingSyncRequest(req *http.Request, device *userapi. } } +// updatePresence updates/sets the presence if user asks for it +func (rp *RequestPool) updatePresence(req *http.Request, device *userapi.Device) { + presence := req.URL.Query().Get("set_presence") + + // If this parameter is omitted then the client is automatically marked as online when it uses this API. + if presence == "" { + presence = "online" + } + pReq := &userapi.InputPresenceRequest{ + UserID: device.UserID, + Presence: types2.ToPresenceStatus(presence), + LastActiveTS: time.Now().Unix(), + } + go rp.userAPI.InputPresenceData(req.Context(), pReq, &userapi.InputPresenceResponse{}) // nolint:errcheck + +} + func (rp *RequestPool) OnIncomingKeyChangeRequest(req *http.Request, device *userapi.Device) util.JSONResponse { from := req.URL.Query().Get("from") to := req.URL.Query().Get("to") diff --git a/userapi/api/api.go b/userapi/api/api.go index cf119a959..d180d16f5 100644 --- a/userapi/api/api.go +++ b/userapi/api/api.go @@ -340,7 +340,7 @@ type InputPresenceRequest struct { DisplayName string AvatarURL string Presence types.PresenceStatus - StatusMsg string + StatusMsg *string LastActiveTS int64 } @@ -359,7 +359,7 @@ type QueryPresenceForUserResponse struct { UserID string `json:"user_id"` PresenceStatus types.PresenceStatus `json:"presence_status"` Presence string `json:"presence"` - StatusMsg string `json:"status_msg"` + StatusMsg *string `json:"status_msg"` LastActiveTS gomatrixserverlib.Timestamp `json:"last_active_ts"` LastActiveAgo int64 `json:"last_active_ago"` CurrentlyActive bool `json:"currently_active"` diff --git a/userapi/storage/presence/interface.go b/userapi/storage/presence/interface.go index 2883a5191..04a752d32 100644 --- a/userapi/storage/presence/interface.go +++ b/userapi/storage/presence/interface.go @@ -25,7 +25,8 @@ type Database interface { // UpsertPresence creates/updates the presence status of a user. UpsertPresence( ctx context.Context, - userID, statusMsg string, + userID string, + statusMsg *string, presence types.PresenceStatus, lastActiveTS int64, ) (pos int64, err error) diff --git a/userapi/storage/presence/postgres/presence_table.go b/userapi/storage/presence/postgres/presence_table.go index 010578103..102730ab8 100644 --- a/userapi/storage/presence/postgres/presence_table.go +++ b/userapi/storage/presence/postgres/presence_table.go @@ -35,7 +35,7 @@ CREATE TABLE IF NOT EXISTS presence_presences ( -- The actual presence presence INT NOT NULL, -- The status message - status_msg TEXT NOT NULL, + status_msg TEXT, -- The last time an action was received by this user last_active_ts BIGINT NOT NULL, CONSTRAINT presence_presences_unique UNIQUE (user_id) @@ -96,8 +96,9 @@ func (p *presenceStatements) prepare(db *sql.DB) (err error) { // UpsertPresence creates/updates a presence status. func (p *presenceStatements) UpsertPresence( ctx context.Context, - txn *sql.Tx, userID, - statusMsg string, + txn *sql.Tx, + userID string, + statusMsg *string, presence types.PresenceStatus, lastActiveTS int64, ) (pos int64, err error) { diff --git a/userapi/storage/presence/postgres/storage.go b/userapi/storage/presence/postgres/storage.go index 9932b74d6..c3575b515 100644 --- a/userapi/storage/presence/postgres/storage.go +++ b/userapi/storage/presence/postgres/storage.go @@ -42,7 +42,8 @@ func NewDatabase(dbProperties *config.DatabaseOptions) (*Database, error) { func (d *Database) UpsertPresence( ctx context.Context, - userID, statusMsg string, + userID string, + statusMsg *string, presence types.PresenceStatus, lastActiveTS int64, ) (pos int64, err error) { diff --git a/userapi/storage/presence/sqlite3/presence_table.go b/userapi/storage/presence/sqlite3/presence_table.go index 4b67fda71..8f545a796 100644 --- a/userapi/storage/presence/sqlite3/presence_table.go +++ b/userapi/storage/presence/sqlite3/presence_table.go @@ -43,12 +43,12 @@ CREATE INDEX IF NOT EXISTS presence_presences_user_id ON presence_presences(user ` const upsertPresenceSQL = "" + - "INSERT INTO presence_presences" + + "INSERT INTO presence_presences AS p" + " (user_id, presence, status_msg, last_active_ts)" + " VALUES ($1, $2, $3, $4)" + " ON CONFLICT (user_id)" + " DO UPDATE SET id = (select max(id) from presence_presences)+1," + - " presence = $5, status_msg = $6, last_active_ts = $7" + + " presence = $5, status_msg = COALESCE($6, p.status_msg), last_active_ts = $7" + " RETURNING id" const selectPresenceForUserSQL = "" + @@ -95,8 +95,9 @@ func (p *presenceStatements) prepare(db *sql.DB) (err error) { // UpsertPresence creates/updates a presence status. func (p *presenceStatements) UpsertPresence( ctx context.Context, - txn *sql.Tx, userID, - statusMsg string, + txn *sql.Tx, + userID string, + statusMsg *string, presence types.PresenceStatus, lastActiveTS int64, ) (pos int64, err error) { diff --git a/userapi/storage/presence/sqlite3/storage.go b/userapi/storage/presence/sqlite3/storage.go index 7a969c3c2..74b4d17da 100644 --- a/userapi/storage/presence/sqlite3/storage.go +++ b/userapi/storage/presence/sqlite3/storage.go @@ -56,7 +56,8 @@ func NewDatabase(dbProperties *config.DatabaseOptions) (*Database, error) { func (d *Database) UpsertPresence( ctx context.Context, - userID, statusMsg string, + userID string, + statusMsg *string, presence types.PresenceStatus, lastActiveTS int64, ) (pos int64, err error) {