- Avoid clearing status_msg when going idle

- Fix issue with last_active_ago not beeing set
- Add missing internal server api
- Use currval (the actual next free) for the new id
- Fix copy&paste error
This commit is contained in:
Till Faelligen 2021-07-28 17:27:57 +02:00
parent 6f6a1d32c3
commit 62295ecd70
7 changed files with 46 additions and 22 deletions

View file

@ -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. // 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. // If the requesting user doesn't share a room with this user, the request is denied.
func GetPresence(req *http.Request, func GetPresence(req *http.Request,
@ -146,17 +153,17 @@ func GetPresence(req *http.Request,
} }
} }
resp := presenceResponse{}
lastActive := time.Since(presence.LastActiveTS.Time()) lastActive := time.Since(presence.LastActiveTS.Time())
presence.LastActiveAgo = lastActive.Milliseconds() resp.LastActiveAgo = lastActive.Milliseconds()
presence.CurrentlyActive = lastActive <= time.Minute*5 resp.CurrentlyActive = lastActive <= time.Minute*5
if !presence.CurrentlyActive { if !resp.CurrentlyActive {
presence.PresenceStatus = types.Unavailable presence.PresenceStatus = types.Unavailable
} }
presence.Presence = presence.PresenceStatus.String() resp.Presence = presence.PresenceStatus.String()
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusOK, Code: http.StatusOK,
JSON: presence, JSON: resp,
} }
} }

View file

@ -352,12 +352,12 @@ type QueryPresenceForUserRequest struct {
// QueryPresenceForUserResponse is the response for QueryPresenceForUserRequest // QueryPresenceForUserResponse is the response for QueryPresenceForUserRequest
type QueryPresenceForUserResponse struct { type QueryPresenceForUserResponse struct {
PresenceStatus types.PresenceStatus `json:"-"` PresenceStatus types.PresenceStatus
Presence string `json:"presence"` Presence string
StatusMsg string `json:"status_msg,omitempty"` StatusMsg string
LastActiveTS gomatrixserverlib.Timestamp `json:"-"` LastActiveTS gomatrixserverlib.Timestamp
LastActiveAgo int64 `json:"last_active_ago,omitempty"` LastActiveAgo int64
CurrentlyActive bool `json:"currently_active,omitempty"` CurrentlyActive bool
} }
// Device represents a client's device (mobile, web, etc) // Device represents a client's device (mobile, web, etc)

View file

@ -480,7 +480,7 @@ func (a *UserInternalAPI) QueryPresenceForUser(ctx context.Context, req *api.Que
res.StatusMsg = p.StatusMsg res.StatusMsg = p.StatusMsg
res.LastActiveTS = p.LastActiveTS res.LastActiveTS = p.LastActiveTS
if maxLastSeen > p.LastActiveTS.Time().Unix() { if maxLastSeen > p.LastActiveTS.Time().Unix() {
res.LastActiveAgo = maxLastSeen res.LastActiveTS = gomatrixserverlib.Timestamp(maxLastSeen)
} }
return nil return nil
} }

View file

@ -247,4 +247,17 @@ func AddRoutes(internalAPIMux *mux.Router, s api.UserInternalAPI) {
return util.JSONResponse{Code: http.StatusOK, JSON: &response} 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}
}),
)
} }

View file

@ -48,8 +48,8 @@ const upsertPresenceSQL = "" +
" (user_id, presence, status_msg, last_active_ts)" + " (user_id, presence, status_msg, last_active_ts)" +
" VALUES ($1, $2, $3, $4)" + " VALUES ($1, $2, $3, $4)" +
" ON CONFLICT (user_id)" + " ON CONFLICT (user_id)" +
" DO UPDATE SET id = nextval('presence_presences_user_id')," + " DO UPDATE SET id = currval('presence_presence_id')," +
" presence = $2, status_msg = $3, last_active_ts = $4" + " presence = $2, status_msg = COALESCE($3, p.status_msg), last_active_ts = $4" +
" RETURNING id" " RETURNING id"
const selectPresenceForUserSQL = "" + const selectPresenceForUserSQL = "" +
@ -86,7 +86,13 @@ func (p *presenceStatements) UpsertPresence(
lastActiveTS int64, lastActiveTS int64,
) (pos int64, err error) { ) (pos int64, err error) {
stmt := sqlutil.TxStmt(txn, p.upsertPresenceStmt) 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 return
} }

View file

@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
// +build !wasm
package presence package presence
import ( import (

View file

@ -12,20 +12,16 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package devices package presence
import ( import (
"fmt" "fmt"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/dendrite/userapi/storage/presence/sqlite3" "github.com/matrix-org/dendrite/userapi/storage/presence/sqlite3"
"github.com/matrix-org/gomatrixserverlib"
) )
func NewDatabase( func NewDatabase(dbProperties *config.DatabaseOptions) (Database, error) {
dbProperties *config.DatabaseOptions,
serverName gomatrixserverlib.ServerName,
) (Database, error) {
switch { switch {
case dbProperties.ConnectionString.IsSQLite(): case dbProperties.ConnectionString.IsSQLite():
return sqlite3.NewDatabase(dbProperties) return sqlite3.NewDatabase(dbProperties)