feat: push notifications for DMs

- DM handler now sends push notifications to other conversation members
- Cleared stale push subscriptions (old broken VAPID keys)
- Auto-subscribe will re-create them on next page load
This commit is contained in:
2026-07-02 14:56:58 -04:00
parent a593f04d7f
commit a502cd8fd4
2 changed files with 28 additions and 6 deletions
+1 -1
View File
@@ -212,7 +212,7 @@ func main() {
}) })
// Direct messages // Direct messages
dmHandler := dm.NewHandler(database.DB, hub, logger) dmHandler := dm.NewHandler(database.DB, hub, pushHandler, logger)
r.Route("/conversations", func(r chi.Router) { r.Route("/conversations", func(r chi.Router) {
dmHandler.RegisterRoutes(r) dmHandler.RegisterRoutes(r)
}) })
+27 -5
View File
@@ -12,19 +12,21 @@ import (
"git.dustin.coffee/hobokenchicken/dumpsterChat/internal/gateway" "git.dustin.coffee/hobokenchicken/dumpsterChat/internal/gateway"
"git.dustin.coffee/hobokenchicken/dumpsterChat/internal/middleware" "git.dustin.coffee/hobokenchicken/dumpsterChat/internal/middleware"
"git.dustin.coffee/hobokenchicken/dumpsterChat/internal/push"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
) )
// Handler handles direct-message conversations. // Handler handles direct-message conversations.
type Handler struct { type Handler struct {
db *sql.DB db *sql.DB
hub *gateway.Hub hub *gateway.Hub
logger *slog.Logger pushHandler *push.Handler
logger *slog.Logger
} }
// NewHandler creates a new DM handler. // NewHandler creates a new DM handler.
func NewHandler(db *sql.DB, hub *gateway.Hub, logger *slog.Logger) *Handler { func NewHandler(db *sql.DB, hub *gateway.Hub, pushHandler *push.Handler, logger *slog.Logger) *Handler {
return &Handler{db: db, hub: hub, logger: logger} return &Handler{db: db, hub: hub, pushHandler: pushHandler, logger: logger}
} }
// RegisterRoutes registers conversation routes. // RegisterRoutes registers conversation routes.
@@ -408,6 +410,26 @@ func (h *Handler) SendMessage(w http.ResponseWriter, r *http.Request) {
}) })
} }
// Push notifications for DM participants
if h.pushHandler != nil {
go func() {
members, err := h.MemberIDs(context.Background(), convID)
if err != nil {
return
}
payload := map[string]interface{}{
"title": msg.AuthorName,
"body": req.Content,
"url": "/conversations/" + convID,
}
for _, memberID := range members {
if memberID != userID {
h.pushHandler.SendPush(context.Background(), memberID, payload)
}
}
}()
}
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated) w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(msg) json.NewEncoder(w).Encode(msg)