diff --git a/syncapi/storage/postgres/stats.go b/syncapi/storage/postgres/stats.go new file mode 100644 index 000000000..a18b776da --- /dev/null +++ b/syncapi/storage/postgres/stats.go @@ -0,0 +1,105 @@ +// Copyright 2022 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package postgres + +import ( + "context" + "database/sql" + "fmt" + + "github.com/matrix-org/dendrite/internal/sqlutil" + "github.com/matrix-org/dendrite/syncapi/storage/tables" +) + +const countEventTypesSQL = ""+ + "SELECT COUNT(*) FROM syncapi_output_room_events"+ + " WHERE type = $1 AND id > $2 AND sender like $3" + +const countActiveRoomsSQL = ""+ + "SELECT COUNT(DISTINCT room_id) FROM syncapi_output_room_events"+ + " WHERE type = $1 AND id > $2" + +type statsStatements struct { + serverName string + countTypesStmt *sql.Stmt + countActiveRoomsStmt *sql.Stmt +} + +func PrepareStats(db *sql.DB, serverName string) (tables.Stats, error) { + s := &statsStatements{ + serverName: serverName, + } + return s, sqlutil.StatementList{ + {&s.countTypesStmt, countEventTypesSQL}, + {&s.countActiveRoomsStmt, countActiveRoomsSQL}, + }.Prepare(db) +} + +func (s *statsStatements) DailyE2EEMessages(ctx context.Context, txn *sql.Tx, prevID int64) (result int64, err error) { + stmt := sqlutil.TxStmt(txn, s.countTypesStmt) + err = stmt.QueryRowContext(ctx, + "m.room.encrypted", + prevID, "%", + ).Scan(&result) + return +} + +func (s *statsStatements) DailySentE2EEMessages(ctx context.Context, txn *sql.Tx, prevID int64) (result int64, err error) { + stmt := sqlutil.TxStmt(txn, s.countTypesStmt) + err = stmt.QueryRowContext(ctx, + "m.room.encrypted", + prevID, + fmt.Sprintf("%%:%s", s.serverName), + ).Scan(&result) + return +} + +func (s *statsStatements) DailyMessages(ctx context.Context, txn *sql.Tx, prevID int64) (result int64, err error) { + stmt := sqlutil.TxStmt(txn, s.countTypesStmt) + err = stmt.QueryRowContext(ctx, + "m.room.message", + prevID, + "%", + ).Scan(&result) + return +} + +func (s *statsStatements) DailySentMessages(ctx context.Context, txn *sql.Tx, prevID int64) (result int64, err error) { + stmt := sqlutil.TxStmt(txn, s.countTypesStmt) + err = stmt.QueryRowContext(ctx, + prevID, + "m.room.message", + fmt.Sprintf("%%:%s", s.serverName), + ).Scan(&result) + return +} + +func (s *statsStatements) DailyActiveE2EERooms(ctx context.Context, txn *sql.Tx, prevID int64) (result int64, err error) { + stmt := sqlutil.TxStmt(txn, s.countActiveRoomsStmt) + err = stmt.QueryRowContext(ctx, + "m.room.encrypted", + prevID, + ).Scan(&result) + return +} + +func (s *statsStatements) DailyActiveRooms(ctx context.Context, txn *sql.Tx, prevID int64) (result int64, err error) { + stmt := sqlutil.TxStmt(txn, s.countActiveRoomsStmt) + err = stmt.QueryRowContext(ctx, + "m.room.message", + prevID, + ).Scan(&result) + return +} \ No newline at end of file diff --git a/syncapi/storage/tables/interface.go b/syncapi/storage/tables/interface.go index 1d807ee6b..2c3cbf82f 100644 --- a/syncapi/storage/tables/interface.go +++ b/syncapi/storage/tables/interface.go @@ -171,3 +171,6 @@ type Memberships interface { UpsertMembership(ctx context.Context, txn *sql.Tx, event *gomatrixserverlib.HeaderedEvent, streamPos, topologicalPos types.StreamPosition) error SelectMembership(ctx context.Context, txn *sql.Tx, roomID, userID, memberships []string) (eventID string, streamPos, topologyPos types.StreamPosition, err error) } + +type Stats interface { +} \ No newline at end of file diff --git a/userapi/storage/postgres/stats.go b/userapi/storage/postgres/stats.go new file mode 100644 index 000000000..d9f20d60b --- /dev/null +++ b/userapi/storage/postgres/stats.go @@ -0,0 +1,69 @@ +// Copyright 2022 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package postgres + +import ( + "context" + "database/sql" + "time" + + "github.com/matrix-org/dendrite/internal/sqlutil" + "github.com/matrix-org/dendrite/syncapi/storage/tables" + "github.com/matrix-org/gomatrixserverlib" +) + +const countUsersLastSeenAfterSQL = ""+ + "SELECT COUNT(*) FROM ("+ + " SELECT user_id FROM device_devices WHERE last_seen > $1 "+ + " GROUP BY user_id"+ + " )" + +const countActiveRoomsSQL = ""+ + "SELECT COUNT(DISTINCT room_id) FROM syncapi_output_room_events"+ + " WHERE type = $1 AND id > $2" + +type statsStatements struct { + serverName string + countUsersLastSeenAfterStmt *sql.Stmt + countActiveRoomsStmt *sql.Stmt +} + +func PrepareStats(db *sql.DB, serverName string) (tables.Stats, error) { + s := &statsStatements{ + serverName: serverName, + } + return s, sqlutil.StatementList{ + {&s.countUsersLastSeenAfterStmt, countUsersLastSeenAfterSQL}, + {&s.countActiveRoomsStmt, countActiveRoomsSQL}, + }.Prepare(db) +} + +func (s *statsStatements) DailyUsers(ctx context.Context, txn *sql.Tx) (result int64, err error) { + stmt := sqlutil.TxStmt(txn, s.countUsersLastSeenAfterStmt) + lastSeenAfter := time.Now().AddDate(0, 0, 1) + err = stmt.QueryRowContext(ctx, + gomatrixserverlib.AsTimestamp(lastSeenAfter), + ).Scan(&result) + return +} + +func (s *statsStatements) MonthlyUsers(ctx context.Context, txn *sql.Tx) (result int64, err error) { + stmt := sqlutil.TxStmt(txn, s.countUsersLastSeenAfterStmt) + lastSeenAfter := time.Now().AddDate(0, 0, 30) + err = stmt.QueryRowContext(ctx, + gomatrixserverlib.AsTimestamp(lastSeenAfter), + ).Scan(&result) + return +} \ No newline at end of file diff --git a/userapi/storage/tables/interface.go b/userapi/storage/tables/interface.go index 12939ced5..186b388ef 100644 --- a/userapi/storage/tables/interface.go +++ b/userapi/storage/tables/interface.go @@ -93,3 +93,5 @@ type ThreePIDTable interface { InsertThreePID(ctx context.Context, txn *sql.Tx, threepid, medium, localpart string) (err error) DeleteThreePID(ctx context.Context, txn *sql.Tx, threepid string, medium string) (err error) } + +type Stats interface{} \ No newline at end of file