Skip to content

Commit d3470cf

Browse files
committed
Add webpush extension
References: ircv3/ircv3-specifications#471
1 parent 9376c88 commit d3470cf

File tree

9 files changed

+509
-0
lines changed

9 files changed

+509
-0
lines changed

db.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ type Database interface {
3131

3232
GetReadReceipt(ctx context.Context, networkID int64, name string) (*ReadReceipt, error)
3333
StoreReadReceipt(ctx context.Context, networkID int64, receipt *ReadReceipt) error
34+
35+
ListWebPushConfigs(ctx context.Context) ([]WebPushConfig, error)
36+
StoreWebPushConfig(ctx context.Context, config *WebPushConfig) error
37+
38+
ListWebPushSubscriptions(ctx context.Context, networkID int64) ([]WebPushSubscription, error)
39+
StoreWebPushSubscription(ctx context.Context, networkID int64, sub *WebPushSubscription) error
40+
DeleteWebPushSubscription(ctx context.Context, id int64) error
3441
}
3542

3643
type MetricsCollectorDatabase interface {
@@ -189,3 +196,20 @@ type ReadReceipt struct {
189196
Target string // channel or nick
190197
Timestamp time.Time
191198
}
199+
200+
type WebPushConfig struct {
201+
ID int64
202+
VAPIDKeys struct {
203+
Public, Private string
204+
}
205+
}
206+
207+
type WebPushSubscription struct {
208+
ID int64
209+
Endpoint string
210+
Keys struct {
211+
Auth string
212+
P256DH string
213+
VAPID string
214+
}
215+
}

db_postgres.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,26 @@ func (db *PostgresDB) listTopNetworkAddrs(ctx context.Context) (map[string]int,
592592
return addrs, rows.Err()
593593
}
594594

595+
func (db *PostgresDB) ListWebPushConfigs(ctx context.Context) ([]WebPushConfig, error) {
596+
return nil, fmt.Errorf("TODO")
597+
}
598+
599+
func (db *PostgresDB) StoreWebPushConfig(ctx context.Context, config *WebPushConfig) error {
600+
return fmt.Errorf("TODO")
601+
}
602+
603+
func (db *PostgresDB) ListWebPushSubscriptions(ctx context.Context, networkID int64) ([]WebPushSubscription, error) {
604+
return nil, fmt.Errorf("TODO")
605+
}
606+
607+
func (db *PostgresDB) StoreWebPushSubscription(ctx context.Context, networkID int64, sub *WebPushSubscription) error {
608+
return fmt.Errorf("TODO")
609+
}
610+
611+
func (db *PostgresDB) DeleteWebPushSubscription(ctx context.Context, id int64) error {
612+
return fmt.Errorf("TODO")
613+
}
614+
595615
var postgresNetworksTotalDesc = prometheus.NewDesc("soju_networks_total", "Number of networks", []string{"hostname"}, nil)
596616

597617
type postgresMetricsCollector struct {

db_sqlite.go

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,27 @@ CREATE TABLE ReadReceipt (
7979
FOREIGN KEY(network) REFERENCES Network(id),
8080
UNIQUE(network, target)
8181
);
82+
83+
CREATE TABLE WebPushConfig (
84+
id INTEGER PRIMARY KEY,
85+
created_at TEXT NOT NULL,
86+
vapid_key_public TEXT NOT NULL,
87+
vapid_key_private TEXT NOT NULL,
88+
UNIQUE(vapid_key_public)
89+
);
90+
91+
CREATE TABLE WebPushSubscription (
92+
id INTEGER PRIMARY KEY,
93+
created_at TEXT NOT NULL,
94+
updated_at TEXT NOT NULL,
95+
network INTEGER NOT NULL,
96+
endpoint TEXT NOT NULL,
97+
key_vapid TEXT,
98+
key_auth TEXT,
99+
key_p256dh TEXT,
100+
FOREIGN KEY(network) REFERENCES Network(id),
101+
UNIQUE(network, endpoint)
102+
);
82103
`
83104

84105
var sqliteMigrations = []string{
@@ -189,6 +210,28 @@ var sqliteMigrations = []string{
189210
UNIQUE(network, target)
190211
);
191212
`,
213+
`
214+
CREATE TABLE WebPushConfig (
215+
id INTEGER PRIMARY KEY,
216+
created_at TEXT NOT NULL,
217+
vapid_key_public TEXT NOT NULL,
218+
vapid_key_private TEXT NOT NULL,
219+
UNIQUE(vapid_key_public)
220+
);
221+
222+
CREATE TABLE WebPushSubscription (
223+
id INTEGER PRIMARY KEY,
224+
created_at TEXT NOT NULL,
225+
updated_at TEXT NOT NULL,
226+
network INTEGER NOT NULL,
227+
endpoint TEXT NOT NULL,
228+
key_vapid TEXT,
229+
key_auth TEXT,
230+
key_p256dh TEXT,
231+
FOREIGN KEY(network) REFERENCES Network(id),
232+
UNIQUE(network, endpoint)
233+
);
234+
`,
192235
}
193236

194237
type SqliteDB struct {
@@ -570,6 +613,11 @@ func (db *SqliteDB) DeleteNetwork(ctx context.Context, id int64) error {
570613
}
571614
defer tx.Rollback()
572615

616+
_, err = tx.ExecContext(ctx, "DELETE FROM WebPushSubscription WHERE network = ?", id)
617+
if err != nil {
618+
return err
619+
}
620+
573621
_, err = tx.ExecContext(ctx, "DELETE FROM DeliveryReceipt WHERE network = ?", id)
574622
if err != nil {
575623
return err
@@ -820,3 +868,147 @@ func (db *SqliteDB) StoreReadReceipt(ctx context.Context, networkID int64, recei
820868

821869
return err
822870
}
871+
872+
func (db *SqliteDB) ListWebPushConfigs(ctx context.Context) ([]WebPushConfig, error) {
873+
db.lock.RLock()
874+
defer db.lock.RUnlock()
875+
876+
ctx, cancel := context.WithTimeout(ctx, sqliteQueryTimeout)
877+
defer cancel()
878+
879+
rows, err := db.db.QueryContext(ctx, `
880+
SELECT id, vapid_key_public, vapid_key_private
881+
FROM WebPushConfig`)
882+
if err != nil {
883+
return nil, err
884+
}
885+
defer rows.Close()
886+
887+
var configs []WebPushConfig
888+
for rows.Next() {
889+
var config WebPushConfig
890+
if err := rows.Scan(&config.ID, &config.VAPIDKeys.Public, &config.VAPIDKeys.Private); err != nil {
891+
return nil, err
892+
}
893+
configs = append(configs, config)
894+
}
895+
if err := rows.Err(); err != nil {
896+
return nil, err
897+
}
898+
899+
return configs, nil
900+
}
901+
902+
func (db *SqliteDB) StoreWebPushConfig(ctx context.Context, config *WebPushConfig) error {
903+
db.lock.Lock()
904+
defer db.lock.Unlock()
905+
906+
ctx, cancel := context.WithTimeout(ctx, sqliteQueryTimeout)
907+
defer cancel()
908+
909+
if config.ID != 0 {
910+
return fmt.Errorf("cannot update a WebPushConfig")
911+
}
912+
913+
args := []interface{}{
914+
sql.Named("vapid_key_public", config.VAPIDKeys.Public),
915+
sql.Named("vapid_key_private", config.VAPIDKeys.Private),
916+
sql.Named("now", formatServerTime(time.Now())),
917+
}
918+
919+
res, err := db.db.ExecContext(ctx, `
920+
INSERT INTO
921+
WebPushConfig(created_at, vapid_key_public, vapid_key_private)
922+
VALUES (:now, :vapid_key_public, :vapid_key_private)`,
923+
args...)
924+
if err != nil {
925+
return err
926+
}
927+
config.ID, err = res.LastInsertId()
928+
return err
929+
}
930+
931+
func (db *SqliteDB) ListWebPushSubscriptions(ctx context.Context, networkID int64) ([]WebPushSubscription, error) {
932+
db.lock.RLock()
933+
defer db.lock.RUnlock()
934+
935+
ctx, cancel := context.WithTimeout(ctx, sqliteQueryTimeout)
936+
defer cancel()
937+
938+
rows, err := db.db.QueryContext(ctx, `
939+
SELECT id, endpoint, key_auth, key_p256dh, key_vapid
940+
FROM WebPushSubscription
941+
WHERE network = ?`, networkID)
942+
if err != nil {
943+
return nil, err
944+
}
945+
defer rows.Close()
946+
947+
var subs []WebPushSubscription
948+
for rows.Next() {
949+
var sub WebPushSubscription
950+
if err := rows.Scan(&sub.ID, &sub.Endpoint, &sub.Keys.Auth, &sub.Keys.P256DH, &sub.Keys.VAPID); err != nil {
951+
return nil, err
952+
}
953+
subs = append(subs, sub)
954+
}
955+
if err := rows.Err(); err != nil {
956+
return nil, err
957+
}
958+
959+
return subs, nil
960+
}
961+
962+
func (db *SqliteDB) StoreWebPushSubscription(ctx context.Context, networkID int64, sub *WebPushSubscription) error {
963+
db.lock.Lock()
964+
defer db.lock.Unlock()
965+
966+
ctx, cancel := context.WithTimeout(ctx, sqliteQueryTimeout)
967+
defer cancel()
968+
969+
args := []interface{}{
970+
sql.Named("id", sub.ID),
971+
sql.Named("network", networkID),
972+
sql.Named("now", formatServerTime(time.Now())),
973+
sql.Named("endpoint", sub.Endpoint),
974+
sql.Named("key_auth", sub.Keys.Auth),
975+
sql.Named("key_p256dh", sub.Keys.P256DH),
976+
sql.Named("key_vapid", sub.Keys.VAPID),
977+
}
978+
979+
var err error
980+
if sub.ID != 0 {
981+
_, err = db.db.ExecContext(ctx, `
982+
UPDATE WebPushSubscription
983+
SET updated_at = :now, key_auth = :key_auth, key_p256dh = :key_p256dh,
984+
key_vapid = :key_vapid
985+
WHERE id = :id`,
986+
args...)
987+
} else {
988+
var res sql.Result
989+
res, err = db.db.ExecContext(ctx, `
990+
INSERT INTO
991+
WebPushSubscription(created_at, updated_at, network, endpoint,
992+
key_auth, key_p256dh, key_vapid)
993+
VALUES (:now, :now, :network, :endpoint, :key_auth, :key_p256dh,
994+
:key_vapid)`,
995+
args...)
996+
if err != nil {
997+
return err
998+
}
999+
sub.ID, err = res.LastInsertId()
1000+
}
1001+
1002+
return err
1003+
}
1004+
1005+
func (db *SqliteDB) DeleteWebPushSubscription(ctx context.Context, id int64) error {
1006+
db.lock.Lock()
1007+
defer db.lock.Unlock()
1008+
1009+
ctx, cancel := context.WithTimeout(ctx, sqliteQueryTimeout)
1010+
defer cancel()
1011+
1012+
_, err := db.db.ExecContext(ctx, "DELETE FROM WebPushSubscription WHERE id = ?", id)
1013+
return err
1014+
}

0 commit comments

Comments
 (0)