mirror of
https://github.com/lone-cloud/prism
synced 2026-06-03 08:43:10 -07:00
255 lines
6.3 KiB
Go
255 lines
6.3 KiB
Go
package subscription
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
)
|
|
|
|
type Store struct {
|
|
DB *sql.DB
|
|
}
|
|
|
|
func NewStore(db *sql.DB) (*Store, error) {
|
|
store := &Store{DB: db}
|
|
if err := store.createTables(); err != nil {
|
|
return nil, err
|
|
}
|
|
return store, nil
|
|
}
|
|
|
|
func (s *Store) createTables() error {
|
|
queries := []string{
|
|
`CREATE TABLE IF NOT EXISTS apps (
|
|
appName TEXT PRIMARY KEY
|
|
)`,
|
|
`CREATE TABLE IF NOT EXISTS subscriptions (
|
|
id TEXT PRIMARY KEY DEFAULT (hex(randomblob(16))),
|
|
appName TEXT NOT NULL,
|
|
channel TEXT NOT NULL,
|
|
signalGroupId TEXT,
|
|
signalAccount TEXT,
|
|
telegramChatId TEXT,
|
|
pushEndpoint TEXT,
|
|
p256dh TEXT,
|
|
auth TEXT,
|
|
vapidPrivateKey TEXT,
|
|
FOREIGN KEY(appName) REFERENCES apps(appName) ON DELETE CASCADE
|
|
)`,
|
|
`CREATE INDEX IF NOT EXISTS idx_subscriptions_appName ON subscriptions(appName)`,
|
|
}
|
|
|
|
for _, query := range queries {
|
|
if _, err := s.DB.Exec(query); err != nil {
|
|
return fmt.Errorf("failed to create tables: %w", err)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *Store) RegisterApp(appName string) error {
|
|
_, err := s.DB.Exec(`INSERT INTO apps (appName) VALUES (?) ON CONFLICT(appName) DO NOTHING`, appName)
|
|
return err
|
|
}
|
|
|
|
func (s *Store) AddSubscription(sub Subscription) (string, error) {
|
|
if err := s.RegisterApp(sub.AppName); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
var signalGroupID, signalAccount, telegramChatID, pushEndpoint, p256dh, auth, vapidPrivateKey *string
|
|
|
|
if sub.Signal != nil {
|
|
signalGroupID = &sub.Signal.GroupID
|
|
signalAccount = &sub.Signal.Account
|
|
}
|
|
if sub.Telegram != nil {
|
|
telegramChatID = &sub.Telegram.ChatID
|
|
}
|
|
if sub.WebPush != nil {
|
|
pushEndpoint = &sub.WebPush.Endpoint
|
|
p256dh = &sub.WebPush.P256dh
|
|
auth = &sub.WebPush.Auth
|
|
vapidPrivateKey = &sub.WebPush.VapidPrivateKey
|
|
}
|
|
|
|
var id string
|
|
err := s.DB.QueryRow(`
|
|
INSERT INTO subscriptions (appName, channel, signalGroupId, signalAccount, telegramChatId, pushEndpoint, p256dh, auth, vapidPrivateKey)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING id
|
|
`, sub.AppName, sub.Channel, signalGroupID, signalAccount, telegramChatID, pushEndpoint, p256dh, auth, vapidPrivateKey).Scan(&id)
|
|
|
|
return id, err
|
|
}
|
|
|
|
func (s *Store) GetApp(appName string) (*App, error) {
|
|
row := s.DB.QueryRow(`SELECT appName FROM apps WHERE appName = ?`, appName)
|
|
|
|
var app App
|
|
if err := row.Scan(&app.AppName); err == sql.ErrNoRows {
|
|
return nil, nil
|
|
} else if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
subs, err := s.GetSubscriptions(appName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
app.Subscriptions = subs
|
|
|
|
return &app, nil
|
|
}
|
|
|
|
func (s *Store) GetSubscriptions(appName string) ([]Subscription, error) {
|
|
rows, err := s.DB.Query(`
|
|
SELECT id, appName, channel, signalGroupId, signalAccount, telegramChatId, pushEndpoint, p256dh, auth, vapidPrivateKey
|
|
FROM subscriptions
|
|
WHERE appName = ?
|
|
`, appName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var subscriptions []Subscription
|
|
for rows.Next() {
|
|
var sub Subscription
|
|
var signalGroupID, signalAccount, telegramChatID, pushEndpoint, p256dh, auth, vapidPrivateKey sql.NullString
|
|
|
|
if err := rows.Scan(&sub.ID, &sub.AppName, &sub.Channel, &signalGroupID, &signalAccount, &telegramChatID, &pushEndpoint, &p256dh, &auth, &vapidPrivateKey); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if signalGroupID.Valid && signalAccount.Valid {
|
|
sub.Signal = &SignalSubscription{
|
|
GroupID: signalGroupID.String,
|
|
Account: signalAccount.String,
|
|
}
|
|
}
|
|
if telegramChatID.Valid {
|
|
sub.Telegram = &TelegramSubscription{
|
|
ChatID: telegramChatID.String,
|
|
}
|
|
}
|
|
if pushEndpoint.Valid {
|
|
sub.WebPush = &WebPushSubscription{
|
|
Endpoint: pushEndpoint.String,
|
|
}
|
|
if p256dh.Valid {
|
|
sub.WebPush.P256dh = p256dh.String
|
|
}
|
|
if auth.Valid {
|
|
sub.WebPush.Auth = auth.String
|
|
}
|
|
if vapidPrivateKey.Valid {
|
|
sub.WebPush.VapidPrivateKey = vapidPrivateKey.String
|
|
}
|
|
}
|
|
|
|
subscriptions = append(subscriptions, sub)
|
|
}
|
|
|
|
return subscriptions, rows.Err()
|
|
}
|
|
|
|
func (s *Store) GetAllApps() ([]App, error) {
|
|
rows, err := s.DB.Query(`SELECT appName FROM apps ORDER BY appName`)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
appNames := make([]string, 0)
|
|
for rows.Next() {
|
|
var appName string
|
|
if err := rows.Scan(&appName); err != nil {
|
|
_ = rows.Close()
|
|
return nil, err
|
|
}
|
|
appNames = append(appNames, appName)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
_ = rows.Close()
|
|
return nil, err
|
|
}
|
|
if err := rows.Close(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
apps := make([]App, 0, len(appNames))
|
|
for _, appName := range appNames {
|
|
app := App{AppName: appName}
|
|
|
|
subs, err := s.GetSubscriptions(appName)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
app.Subscriptions = subs
|
|
|
|
apps = append(apps, app)
|
|
}
|
|
|
|
return apps, nil
|
|
}
|
|
|
|
func (s *Store) DeleteSubscription(subscriptionID string) error {
|
|
_, err := s.DB.Exec(`DELETE FROM subscriptions WHERE id = ?`, subscriptionID)
|
|
return err
|
|
}
|
|
|
|
func (s *Store) DeleteSubscriptionsByChannel(channel Channel) error {
|
|
_, err := s.DB.Exec(`DELETE FROM subscriptions WHERE channel = ?`, channel)
|
|
return err
|
|
}
|
|
|
|
func (s *Store) GetSubscription(subscriptionID string) (*Subscription, error) {
|
|
row := s.DB.QueryRow(`
|
|
SELECT id, appName, channel, signalGroupId, signalAccount, telegramChatId, pushEndpoint, p256dh, auth, vapidPrivateKey
|
|
FROM subscriptions
|
|
WHERE id = ?
|
|
`, subscriptionID)
|
|
|
|
var sub Subscription
|
|
var signalGroupID, signalAccount, telegramChatID, pushEndpoint, p256dh, auth, vapidPrivateKey sql.NullString
|
|
|
|
err := row.Scan(&sub.ID, &sub.AppName, &sub.Channel, &signalGroupID, &signalAccount, &telegramChatID, &pushEndpoint, &p256dh, &auth, &vapidPrivateKey)
|
|
if err == sql.ErrNoRows {
|
|
return nil, nil
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if signalGroupID.Valid && signalAccount.Valid {
|
|
sub.Signal = &SignalSubscription{
|
|
GroupID: signalGroupID.String,
|
|
Account: signalAccount.String,
|
|
}
|
|
}
|
|
if telegramChatID.Valid {
|
|
sub.Telegram = &TelegramSubscription{
|
|
ChatID: telegramChatID.String,
|
|
}
|
|
}
|
|
if pushEndpoint.Valid {
|
|
sub.WebPush = &WebPushSubscription{
|
|
Endpoint: pushEndpoint.String,
|
|
}
|
|
if p256dh.Valid {
|
|
sub.WebPush.P256dh = p256dh.String
|
|
}
|
|
if auth.Valid {
|
|
sub.WebPush.Auth = auth.String
|
|
}
|
|
if vapidPrivateKey.Valid {
|
|
sub.WebPush.VapidPrivateKey = vapidPrivateKey.String
|
|
}
|
|
}
|
|
|
|
return &sub, nil
|
|
}
|
|
|
|
func (s *Store) RemoveApp(appName string) error {
|
|
_, err := s.DB.Exec(`DELETE FROM apps WHERE appName = ?`, appName)
|
|
return err
|
|
}
|