web_push.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. package server
  2. import (
  3. "database/sql"
  4. _ "github.com/mattn/go-sqlite3" // SQLite driver
  5. )
  6. const (
  7. createWebPushSubscriptionsTableQuery = `
  8. BEGIN;
  9. CREATE TABLE IF NOT EXISTS subscriptions (
  10. id INTEGER PRIMARY KEY AUTOINCREMENT,
  11. topic TEXT NOT NULL,
  12. user_id TEXT,
  13. endpoint TEXT NOT NULL,
  14. key_auth TEXT NOT NULL,
  15. key_p256dh TEXT NOT NULL,
  16. updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
  17. );
  18. CREATE INDEX IF NOT EXISTS idx_topic ON subscriptions (topic);
  19. CREATE INDEX IF NOT EXISTS idx_endpoint ON subscriptions (endpoint);
  20. CREATE UNIQUE INDEX IF NOT EXISTS idx_topic_endpoint ON subscriptions (topic, endpoint);
  21. COMMIT;
  22. `
  23. insertWebPushSubscriptionQuery = `
  24. INSERT OR REPLACE INTO subscriptions (topic, user_id, endpoint, key_auth, key_p256dh)
  25. VALUES (?, ?, ?, ?, ?)
  26. `
  27. deleteWebPushSubscriptionByEndpointQuery = `DELETE FROM subscriptions WHERE endpoint = ?`
  28. deleteWebPushSubscriptionByUserIDQuery = `DELETE FROM subscriptions WHERE user_id = ?`
  29. deleteWebPushSubscriptionByTopicAndEndpointQuery = `DELETE FROM subscriptions WHERE topic = ? AND endpoint = ?`
  30. selectWebPushSubscriptionsForTopicQuery = `SELECT endpoint, key_auth, key_p256dh, user_id FROM subscriptions WHERE topic = ?`
  31. selectWebPushSubscriptionsCountQuery = `SELECT COUNT(*) FROM subscriptions`
  32. )
  33. type webPushStore struct {
  34. db *sql.DB
  35. }
  36. func newWebPushStore(filename string) (*webPushStore, error) {
  37. db, err := sql.Open("sqlite3", filename)
  38. if err != nil {
  39. return nil, err
  40. }
  41. if err := setupSubscriptionsDB(db); err != nil {
  42. return nil, err
  43. }
  44. return &webPushStore{
  45. db: db,
  46. }, nil
  47. }
  48. func setupSubscriptionsDB(db *sql.DB) error {
  49. // If 'subscriptions' table does not exist, this must be a new database
  50. rowsMC, err := db.Query(selectWebPushSubscriptionsCountQuery)
  51. if err != nil {
  52. return setupNewSubscriptionsDB(db)
  53. }
  54. return rowsMC.Close()
  55. }
  56. func setupNewSubscriptionsDB(db *sql.DB) error {
  57. if _, err := db.Exec(createWebPushSubscriptionsTableQuery); err != nil {
  58. return err
  59. }
  60. return nil
  61. }
  62. func (c *webPushStore) AddSubscription(topic string, userID string, subscription webPushSubscribePayload) error {
  63. _, err := c.db.Exec(
  64. insertWebPushSubscriptionQuery,
  65. topic,
  66. userID,
  67. subscription.BrowserSubscription.Endpoint,
  68. subscription.BrowserSubscription.Keys.Auth,
  69. subscription.BrowserSubscription.Keys.P256dh,
  70. )
  71. return err
  72. }
  73. func (c *webPushStore) RemoveSubscription(topic string, endpoint string) error {
  74. _, err := c.db.Exec(
  75. deleteWebPushSubscriptionByTopicAndEndpointQuery,
  76. topic,
  77. endpoint,
  78. )
  79. return err
  80. }
  81. func (c *webPushStore) SubscriptionsForTopic(topic string) (subscriptions []webPushSubscription, err error) {
  82. rows, err := c.db.Query(selectWebPushSubscriptionsForTopicQuery, topic)
  83. if err != nil {
  84. return nil, err
  85. }
  86. defer rows.Close()
  87. var data []webPushSubscription
  88. for rows.Next() {
  89. i := webPushSubscription{}
  90. err = rows.Scan(&i.BrowserSubscription.Endpoint, &i.BrowserSubscription.Keys.Auth, &i.BrowserSubscription.Keys.P256dh, &i.UserID)
  91. if err != nil {
  92. return nil, err
  93. }
  94. data = append(data, i)
  95. }
  96. return data, nil
  97. }
  98. func (c *webPushStore) RemoveByEndpoint(endpoint string) error {
  99. _, err := c.db.Exec(
  100. deleteWebPushSubscriptionByEndpointQuery,
  101. endpoint,
  102. )
  103. return err
  104. }
  105. func (c *webPushStore) RemoveByUserID(userID string) error {
  106. _, err := c.db.Exec(
  107. deleteWebPushSubscriptionByUserIDQuery,
  108. userID,
  109. )
  110. return err
  111. }
  112. func (c *webPushStore) Close() error {
  113. return c.db.Close()
  114. }