diff --git a/clientapi/routing/presence.go b/clientapi/routing/presence.go index 77bf35aa8..9176e542a 100644 --- a/clientapi/routing/presence.go +++ b/clientapi/routing/presence.go @@ -104,6 +104,13 @@ func SetPresence(req *http.Request, } } +type presenceResponse struct { + Presence string `json:"presence"` + StatusMsg string `json:"status_msg,omitempty"` + LastActiveAgo int64 `json:"last_active_ago,omitempty"` + CurrentlyActive bool `json:"currently_active,omitempty"` +} + // GetPresence returns the presence status of a given user. // If the requesting user doesn't share a room with this user, the request is denied. func GetPresence(req *http.Request, @@ -146,17 +153,17 @@ func GetPresence(req *http.Request, } } + resp := presenceResponse{} lastActive := time.Since(presence.LastActiveTS.Time()) - presence.LastActiveAgo = lastActive.Milliseconds() + resp.LastActiveAgo = lastActive.Milliseconds() - presence.CurrentlyActive = lastActive <= time.Minute*5 - if !presence.CurrentlyActive { + resp.CurrentlyActive = lastActive <= time.Minute*5 + if !resp.CurrentlyActive { presence.PresenceStatus = types.Unavailable } - presence.Presence = presence.PresenceStatus.String() - + resp.Presence = presence.PresenceStatus.String() return util.JSONResponse{ Code: http.StatusOK, - JSON: presence, + JSON: resp, } } diff --git a/userapi/api/api.go b/userapi/api/api.go index d16505b1e..34d7a4508 100644 --- a/userapi/api/api.go +++ b/userapi/api/api.go @@ -352,12 +352,12 @@ type QueryPresenceForUserRequest struct { // QueryPresenceForUserResponse is the response for QueryPresenceForUserRequest type QueryPresenceForUserResponse struct { - PresenceStatus types.PresenceStatus `json:"-"` - Presence string `json:"presence"` - StatusMsg string `json:"status_msg,omitempty"` - LastActiveTS gomatrixserverlib.Timestamp `json:"-"` - LastActiveAgo int64 `json:"last_active_ago,omitempty"` - CurrentlyActive bool `json:"currently_active,omitempty"` + PresenceStatus types.PresenceStatus + Presence string + StatusMsg string + LastActiveTS gomatrixserverlib.Timestamp + LastActiveAgo int64 + CurrentlyActive bool } // Device represents a client's device (mobile, web, etc) diff --git a/userapi/internal/api.go b/userapi/internal/api.go index adc30b0b9..88dbe5804 100644 --- a/userapi/internal/api.go +++ b/userapi/internal/api.go @@ -480,7 +480,7 @@ func (a *UserInternalAPI) QueryPresenceForUser(ctx context.Context, req *api.Que res.StatusMsg = p.StatusMsg res.LastActiveTS = p.LastActiveTS if maxLastSeen > p.LastActiveTS.Time().Unix() { - res.LastActiveAgo = maxLastSeen + res.LastActiveTS = gomatrixserverlib.Timestamp(maxLastSeen) } return nil } diff --git a/userapi/inthttp/server.go b/userapi/inthttp/server.go index 51e3aad38..69a343dd5 100644 --- a/userapi/inthttp/server.go +++ b/userapi/inthttp/server.go @@ -247,4 +247,17 @@ func AddRoutes(internalAPIMux *mux.Router, s api.UserInternalAPI) { return util.JSONResponse{Code: http.StatusOK, JSON: &response} }), ) + internalAPIMux.Handle(QueryPresenceForUserPath, + httputil.MakeInternalAPI("queryPresenceForUser", func(req *http.Request) util.JSONResponse { + request := api.QueryPresenceForUserRequest{} + response := api.QueryPresenceForUserResponse{} + if err := json.NewDecoder(req.Body).Decode(&request); err != nil { + return util.MessageResponse(http.StatusBadRequest, err.Error()) + } + if err := s.QueryPresenceForUser(req.Context(), &request, &response); err != nil { + return util.ErrorResponse(err) + } + return util.JSONResponse{Code: http.StatusOK, JSON: &response} + }), + ) } diff --git a/userapi/storage/presence/postgres/presence_table.go b/userapi/storage/presence/postgres/presence_table.go index 00a398324..33976d9e6 100644 --- a/userapi/storage/presence/postgres/presence_table.go +++ b/userapi/storage/presence/postgres/presence_table.go @@ -48,8 +48,8 @@ const upsertPresenceSQL = "" + " (user_id, presence, status_msg, last_active_ts)" + " VALUES ($1, $2, $3, $4)" + " ON CONFLICT (user_id)" + - " DO UPDATE SET id = nextval('presence_presences_user_id')," + - " presence = $2, status_msg = $3, last_active_ts = $4" + + " DO UPDATE SET id = currval('presence_presence_id')," + + " presence = $2, status_msg = COALESCE($3, p.status_msg), last_active_ts = $4" + " RETURNING id" const selectPresenceForUserSQL = "" + @@ -86,7 +86,13 @@ func (p *presenceStatements) UpsertPresence( lastActiveTS int64, ) (pos int64, err error) { stmt := sqlutil.TxStmt(txn, p.upsertPresenceStmt) - err = stmt.QueryRowContext(ctx, userID, presence, statusMsg, lastActiveTS).Scan(&pos) + msg := &statusMsg + // avoid clearing status_msg when going idle + // makes it impossible to delete status_msg, though.. + if statusMsg == "" { + msg = nil + } + err = stmt.QueryRowContext(ctx, userID, presence, msg, lastActiveTS).Scan(&pos) return } diff --git a/userapi/storage/presence/storage.go b/userapi/storage/presence/storage.go index dc869f0a4..e5d784756 100644 --- a/userapi/storage/presence/storage.go +++ b/userapi/storage/presence/storage.go @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build !wasm + package presence import ( diff --git a/userapi/storage/presence/storage_wasm.go b/userapi/storage/presence/storage_wasm.go index 0763b5217..54c9eea2d 100644 --- a/userapi/storage/presence/storage_wasm.go +++ b/userapi/storage/presence/storage_wasm.go @@ -12,20 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -package devices +package presence import ( "fmt" "github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/userapi/storage/presence/sqlite3" - "github.com/matrix-org/gomatrixserverlib" ) -func NewDatabase( - dbProperties *config.DatabaseOptions, - serverName gomatrixserverlib.ServerName, -) (Database, error) { +func NewDatabase(dbProperties *config.DatabaseOptions) (Database, error) { switch { case dbProperties.ConnectionString.IsSQLite(): return sqlite3.NewDatabase(dbProperties)