mirror of https://github.com/matrix-org/go-neb.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
497 lines
13 KiB
497 lines
13 KiB
package database
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/matrix-org/go-neb/api"
|
|
"github.com/matrix-org/go-neb/types"
|
|
"maunium.net/go/mautrix/id"
|
|
)
|
|
|
|
const schemaSQL = `
|
|
CREATE TABLE IF NOT EXISTS services (
|
|
service_id TEXT NOT NULL,
|
|
service_type TEXT NOT NULL,
|
|
service_user_id TEXT NOT NULL,
|
|
service_json TEXT NOT NULL,
|
|
time_added_ms BIGINT NOT NULL,
|
|
time_updated_ms BIGINT NOT NULL,
|
|
UNIQUE(service_id)
|
|
);
|
|
CREATE UNIQUE INDEX IF NOT EXISTS service_id_and_user_idx ON services(service_user_id, service_id);
|
|
|
|
CREATE TABLE IF NOT EXISTS matrix_clients (
|
|
user_id TEXT NOT NULL,
|
|
client_json TEXT NOT NULL,
|
|
next_batch TEXT NOT NULL,
|
|
time_added_ms BIGINT NOT NULL,
|
|
time_updated_ms BIGINT NOT NULL,
|
|
UNIQUE(user_id)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS auth_realms (
|
|
realm_id TEXT NOT NULL,
|
|
realm_type TEXT NOT NULL,
|
|
realm_json TEXT NOT NULL,
|
|
time_added_ms BIGINT NOT NULL,
|
|
time_updated_ms BIGINT NOT NULL,
|
|
UNIQUE(realm_id)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS auth_sessions (
|
|
session_id TEXT NOT NULL,
|
|
realm_id TEXT NOT NULL,
|
|
user_id TEXT NOT NULL,
|
|
session_json TEXT NOT NULL,
|
|
time_added_ms BIGINT NOT NULL,
|
|
time_updated_ms BIGINT NOT NULL,
|
|
UNIQUE(realm_id, user_id),
|
|
UNIQUE(realm_id, session_id)
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS bot_options (
|
|
user_id TEXT NOT NULL,
|
|
room_id TEXT NOT NULL,
|
|
set_by_user_id TEXT NOT NULL,
|
|
bot_options_json TEXT NOT NULL,
|
|
time_added_ms BIGINT NOT NULL,
|
|
time_updated_ms BIGINT NOT NULL,
|
|
UNIQUE(user_id, room_id)
|
|
);
|
|
`
|
|
|
|
const selectMatrixClientConfigSQL = `
|
|
SELECT client_json FROM matrix_clients WHERE user_id = $1
|
|
`
|
|
|
|
func selectMatrixClientConfigTxn(txn *sql.Tx, userID id.UserID) (config api.ClientConfig, err error) {
|
|
var configJSON []byte
|
|
err = txn.QueryRow(selectMatrixClientConfigSQL, userID).Scan(&configJSON)
|
|
if err != nil {
|
|
return
|
|
}
|
|
err = json.Unmarshal(configJSON, &config)
|
|
return
|
|
}
|
|
|
|
const selectMatrixClientConfigsSQL = `
|
|
SELECT client_json FROM matrix_clients
|
|
`
|
|
|
|
func selectMatrixClientConfigsTxn(txn *sql.Tx) (configs []api.ClientConfig, err error) {
|
|
rows, err := txn.Query(selectMatrixClientConfigsSQL)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer rows.Close()
|
|
for rows.Next() {
|
|
var config api.ClientConfig
|
|
var configJSON []byte
|
|
if err = rows.Scan(&configJSON); err != nil {
|
|
return
|
|
}
|
|
if err = json.Unmarshal(configJSON, &config); err != nil {
|
|
return
|
|
}
|
|
configs = append(configs, config)
|
|
}
|
|
return
|
|
}
|
|
|
|
const insertMatrixClientConfigSQL = `
|
|
INSERT INTO matrix_clients(
|
|
user_id, client_json, next_batch, time_added_ms, time_updated_ms
|
|
) VALUES ($1, $2, '', $3, $4)
|
|
`
|
|
|
|
func insertMatrixClientConfigTxn(txn *sql.Tx, now time.Time, config api.ClientConfig) error {
|
|
t := now.UnixNano() / 1000000
|
|
configJSON, err := json.Marshal(&config)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = txn.Exec(insertMatrixClientConfigSQL, config.UserID, configJSON, t, t)
|
|
return err
|
|
}
|
|
|
|
const updateMatrixClientConfigSQL = `
|
|
UPDATE matrix_clients SET client_json = $1, time_updated_ms = $2
|
|
WHERE user_id = $3
|
|
`
|
|
|
|
func updateMatrixClientConfigTxn(txn *sql.Tx, now time.Time, config api.ClientConfig) error {
|
|
t := now.UnixNano() / 1000000
|
|
configJSON, err := json.Marshal(&config)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = txn.Exec(updateMatrixClientConfigSQL, configJSON, t, config.UserID)
|
|
return err
|
|
}
|
|
|
|
const updateNextBatchSQL = `
|
|
UPDATE matrix_clients SET next_batch = $1 WHERE user_id = $2
|
|
`
|
|
|
|
func updateNextBatchTxn(txn *sql.Tx, userID id.UserID, nextBatch string) error {
|
|
_, err := txn.Exec(updateNextBatchSQL, nextBatch, userID)
|
|
return err
|
|
}
|
|
|
|
const selectNextBatchSQL = `
|
|
SELECT next_batch FROM matrix_clients WHERE user_id = $1
|
|
`
|
|
|
|
func selectNextBatchTxn(txn *sql.Tx, userID id.UserID) (string, error) {
|
|
var nextBatch string
|
|
row := txn.QueryRow(selectNextBatchSQL, userID)
|
|
if err := row.Scan(&nextBatch); err != nil {
|
|
return "", err
|
|
}
|
|
return nextBatch, nil
|
|
}
|
|
|
|
const selectServiceSQL = `
|
|
SELECT service_type, service_user_id, service_json FROM services
|
|
WHERE service_id = $1
|
|
`
|
|
|
|
func selectServiceTxn(txn *sql.Tx, serviceID string) (types.Service, error) {
|
|
var serviceType string
|
|
var serviceUserID id.UserID
|
|
var serviceJSON []byte
|
|
row := txn.QueryRow(selectServiceSQL, serviceID)
|
|
if err := row.Scan(&serviceType, &serviceUserID, &serviceJSON); err != nil {
|
|
return nil, err
|
|
}
|
|
return types.CreateService(serviceID, serviceType, serviceUserID, serviceJSON)
|
|
}
|
|
|
|
const updateServiceSQL = `
|
|
UPDATE services SET service_type=$1, service_user_id=$2, service_json=$3, time_updated_ms=$4
|
|
WHERE service_id=$5
|
|
`
|
|
|
|
func updateServiceTxn(txn *sql.Tx, now time.Time, service types.Service) error {
|
|
serviceJSON, err := json.Marshal(service)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
t := now.UnixNano() / 1000000
|
|
_, err = txn.Exec(
|
|
updateServiceSQL, service.ServiceType(), service.ServiceUserID(), serviceJSON, t,
|
|
service.ServiceID(),
|
|
)
|
|
return err
|
|
}
|
|
|
|
const insertServiceSQL = `
|
|
INSERT INTO services(
|
|
service_id, service_type, service_user_id, service_json, time_added_ms, time_updated_ms
|
|
) VALUES ($1, $2, $3, $4, $5, $6)
|
|
`
|
|
|
|
func insertServiceTxn(txn *sql.Tx, now time.Time, service types.Service) error {
|
|
serviceJSON, err := json.Marshal(service)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
t := now.UnixNano() / 1000000
|
|
_, err = txn.Exec(
|
|
insertServiceSQL,
|
|
service.ServiceID(), service.ServiceType(), service.ServiceUserID(), serviceJSON, t, t,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const selectServicesForUserSQL = `
|
|
SELECT service_id, service_type, service_json FROM services WHERE service_user_id=$1 ORDER BY service_id
|
|
`
|
|
|
|
func selectServicesForUserTxn(txn *sql.Tx, userID id.UserID) (srvs []types.Service, err error) {
|
|
rows, err := txn.Query(selectServicesForUserSQL, userID)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer rows.Close()
|
|
for rows.Next() {
|
|
var s types.Service
|
|
var serviceID string
|
|
var serviceType string
|
|
var serviceJSON []byte
|
|
if err = rows.Scan(&serviceID, &serviceType, &serviceJSON); err != nil {
|
|
return
|
|
}
|
|
s, err = types.CreateService(serviceID, serviceType, userID, serviceJSON)
|
|
if err != nil {
|
|
return
|
|
}
|
|
srvs = append(srvs, s)
|
|
}
|
|
return
|
|
}
|
|
|
|
const selectServicesByTypeSQL = `
|
|
SELECT service_id, service_user_id, service_json FROM services WHERE service_type=$1 ORDER BY service_id
|
|
`
|
|
|
|
func selectServicesByTypeTxn(txn *sql.Tx, serviceType string) (srvs []types.Service, err error) {
|
|
rows, err := txn.Query(selectServicesByTypeSQL, serviceType)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer rows.Close()
|
|
for rows.Next() {
|
|
var s types.Service
|
|
var serviceID string
|
|
var serviceUserID id.UserID
|
|
var serviceJSON []byte
|
|
if err = rows.Scan(&serviceID, &serviceUserID, &serviceJSON); err != nil {
|
|
return
|
|
}
|
|
s, err = types.CreateService(serviceID, serviceType, serviceUserID, serviceJSON)
|
|
if err != nil {
|
|
return
|
|
}
|
|
srvs = append(srvs, s)
|
|
}
|
|
return
|
|
}
|
|
|
|
const deleteServiceSQL = `
|
|
DELETE FROM services WHERE service_id = $1
|
|
`
|
|
|
|
func deleteServiceTxn(txn *sql.Tx, serviceID string) error {
|
|
_, err := txn.Exec(deleteServiceSQL, serviceID)
|
|
return err
|
|
}
|
|
|
|
const insertRealmSQL = `
|
|
INSERT INTO auth_realms(
|
|
realm_id, realm_type, realm_json, time_added_ms, time_updated_ms
|
|
) VALUES ($1, $2, $3, $4, $5)
|
|
`
|
|
|
|
func insertRealmTxn(txn *sql.Tx, now time.Time, realm types.AuthRealm) error {
|
|
realmJSON, err := json.Marshal(realm)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
t := now.UnixNano() / 1000000
|
|
_, err = txn.Exec(
|
|
insertRealmSQL,
|
|
realm.ID(), realm.Type(), realmJSON, t, t,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const selectRealmSQL = `
|
|
SELECT realm_type, realm_json FROM auth_realms WHERE realm_id = $1
|
|
`
|
|
|
|
func selectRealmTxn(txn *sql.Tx, realmID string) (types.AuthRealm, error) {
|
|
var realmType string
|
|
var realmJSON []byte
|
|
row := txn.QueryRow(selectRealmSQL, realmID)
|
|
if err := row.Scan(&realmType, &realmJSON); err != nil {
|
|
return nil, err
|
|
}
|
|
return types.CreateAuthRealm(realmID, realmType, realmJSON)
|
|
}
|
|
|
|
const selectRealmsByTypeSQL = `
|
|
SELECT realm_id, realm_json FROM auth_realms WHERE realm_type = $1 ORDER BY realm_id
|
|
`
|
|
|
|
func selectRealmsByTypeTxn(txn *sql.Tx, realmType string) (realms []types.AuthRealm, err error) {
|
|
rows, err := txn.Query(selectRealmsByTypeSQL, realmType)
|
|
if err != nil {
|
|
return
|
|
}
|
|
defer rows.Close()
|
|
for rows.Next() {
|
|
var realm types.AuthRealm
|
|
var realmID string
|
|
var realmJSON []byte
|
|
if err = rows.Scan(&realmID, &realmJSON); err != nil {
|
|
return
|
|
}
|
|
realm, err = types.CreateAuthRealm(realmID, realmType, realmJSON)
|
|
if err != nil {
|
|
return
|
|
}
|
|
realms = append(realms, realm)
|
|
}
|
|
return
|
|
}
|
|
|
|
const updateRealmSQL = `
|
|
UPDATE auth_realms SET realm_type=$1, realm_json=$2, time_updated_ms=$3
|
|
WHERE realm_id=$4
|
|
`
|
|
|
|
func updateRealmTxn(txn *sql.Tx, now time.Time, realm types.AuthRealm) error {
|
|
realmJSON, err := json.Marshal(realm)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
t := now.UnixNano() / 1000000
|
|
_, err = txn.Exec(
|
|
updateRealmSQL, realm.Type(), realmJSON, t,
|
|
realm.ID(),
|
|
)
|
|
return err
|
|
}
|
|
|
|
const insertAuthSessionSQL = `
|
|
INSERT INTO auth_sessions(
|
|
session_id, realm_id, user_id, session_json, time_added_ms, time_updated_ms
|
|
) VALUES ($1, $2, $3, $4, $5, $6)
|
|
`
|
|
|
|
func insertAuthSessionTxn(txn *sql.Tx, now time.Time, session types.AuthSession) error {
|
|
sessionJSON, err := json.Marshal(session)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
t := now.UnixNano() / 1000000
|
|
_, err = txn.Exec(
|
|
insertAuthSessionSQL,
|
|
session.ID(), session.RealmID(), session.UserID(), sessionJSON, t, t,
|
|
)
|
|
return err
|
|
}
|
|
|
|
const deleteAuthSessionSQL = `
|
|
DELETE FROM auth_sessions WHERE realm_id=$1 AND user_id=$2
|
|
`
|
|
|
|
func deleteAuthSessionTxn(txn *sql.Tx, realmID string, userID id.UserID) error {
|
|
_, err := txn.Exec(deleteAuthSessionSQL, realmID, userID)
|
|
return err
|
|
}
|
|
|
|
const selectAuthSessionByUserSQL = `
|
|
SELECT session_id, realm_type, realm_json, session_json FROM auth_sessions
|
|
JOIN auth_realms ON auth_sessions.realm_id = auth_realms.realm_id
|
|
WHERE auth_sessions.realm_id = $1 AND auth_sessions.user_id = $2
|
|
`
|
|
|
|
func selectAuthSessionByUserTxn(txn *sql.Tx, realmID string, userID id.UserID) (types.AuthSession, error) {
|
|
var id string
|
|
var realmType string
|
|
var realmJSON []byte
|
|
var sessionJSON []byte
|
|
row := txn.QueryRow(selectAuthSessionByUserSQL, realmID, userID)
|
|
if err := row.Scan(&id, &realmType, &realmJSON, &sessionJSON); err != nil {
|
|
return nil, err
|
|
}
|
|
realm, err := types.CreateAuthRealm(realmID, realmType, realmJSON)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
session := realm.AuthSession(id, userID, realmID)
|
|
if session == nil {
|
|
return nil, fmt.Errorf("Cannot create session for given realm")
|
|
}
|
|
if err := json.Unmarshal(sessionJSON, session); err != nil {
|
|
return nil, err
|
|
}
|
|
return session, nil
|
|
}
|
|
|
|
const selectAuthSessionByIDSQL = `
|
|
SELECT user_id, realm_type, realm_json, session_json FROM auth_sessions
|
|
JOIN auth_realms ON auth_sessions.realm_id = auth_realms.realm_id
|
|
WHERE auth_sessions.realm_id = $1 AND auth_sessions.session_id = $2
|
|
`
|
|
|
|
func selectAuthSessionByIDTxn(txn *sql.Tx, realmID, sid string) (types.AuthSession, error) {
|
|
var userID id.UserID
|
|
var realmType string
|
|
var realmJSON []byte
|
|
var sessionJSON []byte
|
|
row := txn.QueryRow(selectAuthSessionByIDSQL, realmID, sid)
|
|
if err := row.Scan(&userID, &realmType, &realmJSON, &sessionJSON); err != nil {
|
|
return nil, err
|
|
}
|
|
realm, err := types.CreateAuthRealm(realmID, realmType, realmJSON)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
session := realm.AuthSession(sid, userID, realmID)
|
|
if session == nil {
|
|
return nil, fmt.Errorf("Cannot create session for given realm")
|
|
}
|
|
if err := json.Unmarshal(sessionJSON, session); err != nil {
|
|
return nil, err
|
|
}
|
|
return session, nil
|
|
}
|
|
|
|
const updateAuthSessionSQL = `
|
|
UPDATE auth_sessions SET session_id=$1, session_json=$2, time_updated_ms=$3
|
|
WHERE realm_id=$4 AND user_id=$5
|
|
`
|
|
|
|
func updateAuthSessionTxn(txn *sql.Tx, now time.Time, session types.AuthSession) error {
|
|
sessionJSON, err := json.Marshal(session)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
t := now.UnixNano() / 1000000
|
|
_, err = txn.Exec(
|
|
updateAuthSessionSQL, session.ID(), sessionJSON, t,
|
|
session.RealmID(), session.UserID(),
|
|
)
|
|
return err
|
|
}
|
|
|
|
const selectBotOptionsSQL = `
|
|
SELECT bot_options_json, set_by_user_id FROM bot_options WHERE user_id = $1 AND room_id = $2
|
|
`
|
|
|
|
func selectBotOptionsTxn(txn *sql.Tx, userID id.UserID, roomID id.RoomID) (opts types.BotOptions, err error) {
|
|
var optionsJSON []byte
|
|
err = txn.QueryRow(selectBotOptionsSQL, userID, roomID).Scan(&optionsJSON, &opts.SetByUserID)
|
|
if err != nil {
|
|
return
|
|
}
|
|
err = json.Unmarshal(optionsJSON, &opts.Options)
|
|
return
|
|
}
|
|
|
|
const insertBotOptionsSQL = `
|
|
INSERT INTO bot_options(
|
|
user_id, room_id, bot_options_json, set_by_user_id, time_added_ms, time_updated_ms
|
|
) VALUES ($1, $2, $3, $4, $5, $6)
|
|
`
|
|
|
|
func insertBotOptionsTxn(txn *sql.Tx, now time.Time, opts types.BotOptions) error {
|
|
t := now.UnixNano() / 1000000
|
|
optsJSON, err := json.Marshal(&opts.Options)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = txn.Exec(insertBotOptionsSQL, opts.UserID, opts.RoomID, optsJSON, opts.SetByUserID, t, t)
|
|
return err
|
|
}
|
|
|
|
const updateBotOptionsSQL = `
|
|
UPDATE bot_options SET bot_options_json = $1, set_by_user_id = $2, time_updated_ms = $3
|
|
WHERE user_id = $4 AND room_id = $5
|
|
`
|
|
|
|
func updateBotOptionsTxn(txn *sql.Tx, now time.Time, opts types.BotOptions) error {
|
|
t := now.UnixNano() / 1000000
|
|
optsJSON, err := json.Marshal(&opts.Options)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = txn.Exec(updateBotOptionsSQL, optsJSON, opts.SetByUserID, t, opts.UserID, opts.RoomID)
|
|
return err
|
|
}
|