72ca99b58d
- Added @Summary/@Router/@Param/@Success/@Security annotations to all API handlers - Regenerated docs/swagger.json, docs/swagger.yaml, docs/docs.go with full endpoint definitions - Fixed generated docs.go to remove unsupported LeftDelim/RightDelim fields
151 lines
3.8 KiB
Go
151 lines
3.8 KiB
Go
package voice
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
"git.dustin.coffee/hobokenchicken/dumpsterChat/internal/gateway"
|
|
"git.dustin.coffee/hobokenchicken/dumpsterChat/internal/middleware"
|
|
"github.com/go-chi/chi/v5"
|
|
"github.com/livekit/protocol/livekit"
|
|
)
|
|
|
|
type Handler struct {
|
|
db *sql.DB
|
|
client *Client
|
|
hub *gateway.Hub
|
|
}
|
|
|
|
func NewHandler(db *sql.DB, client *Client, hub *gateway.Hub) *Handler {
|
|
return &Handler{
|
|
db: db,
|
|
client: client,
|
|
hub: hub,
|
|
}
|
|
}
|
|
|
|
func (h *Handler) RegisterRoutes(r chi.Router) {
|
|
r.Post("/token", h.GetToken)
|
|
r.Get("/rooms/{roomID}/participants", h.GetParticipants)
|
|
}
|
|
|
|
type tokenRequest struct {
|
|
RoomName string `json:"room_name"`
|
|
}
|
|
|
|
type tokenResponse struct {
|
|
Token string `json:"token"`
|
|
LiveKitURL string `json:"livekit_url"`
|
|
}
|
|
|
|
// @Summary Get voice token
|
|
// @Description Get a LiveKit access token for a voice room
|
|
// @Tags voice
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Security SessionAuth
|
|
// @Param body body tokenRequest true "Room data"
|
|
// @Success 200 {object} tokenResponse
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 401 {object} map[string]string
|
|
// @Failure 404 {object} map[string]string
|
|
// @Router /voice/token [post]
|
|
func (h *Handler) GetToken(w http.ResponseWriter, r *http.Request) {
|
|
userID, ok := middleware.UserIDFromContext(r.Context())
|
|
if !ok {
|
|
http.Error(w, `{"error":"unauthorized"}`, http.StatusUnauthorized)
|
|
return
|
|
}
|
|
|
|
var req tokenRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, `{"error":"invalid request"}`, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if req.RoomName == "" {
|
|
http.Error(w, `{"error":"missing room_name"}`, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// Get username for the identity
|
|
var username string
|
|
err := h.db.QueryRowContext(r.Context(), `SELECT username FROM users WHERE id = $1`, userID).Scan(&username)
|
|
if err != nil {
|
|
http.Error(w, `{"error":"user not found"}`, http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
// Create room if it doesn't exist
|
|
_, err = h.client.CreateRoom(req.RoomName)
|
|
if err != nil {
|
|
// Room might already exist, that's fine
|
|
}
|
|
|
|
token, err := h.client.GenerateToken(req.RoomName, userID, username)
|
|
if err != nil {
|
|
http.Error(w, `{"error":"token generation failed"}`, http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
// Broadcast voice join event
|
|
h.hub.BroadcastEvent(gateway.Event{
|
|
Type: "VOICE_JOIN",
|
|
Data: map[string]interface{}{
|
|
"room_name": req.RoomName,
|
|
"user_id": userID,
|
|
"username": username,
|
|
},
|
|
})
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(tokenResponse{
|
|
Token: token,
|
|
LiveKitURL: h.client.url,
|
|
})
|
|
}
|
|
|
|
// @Summary Get voice room participants
|
|
// @Description Get participants in a voice room
|
|
// @Tags voice
|
|
// @Produce json
|
|
// @Param roomID path string true "Room ID"
|
|
// @Success 200 {array} object
|
|
// @Failure 400 {object} map[string]string
|
|
// @Failure 500 {object} map[string]string
|
|
// @Router /voice/rooms/{roomID}/participants [get]
|
|
func (h *Handler) GetParticipants(w http.ResponseWriter, r *http.Request) {
|
|
roomID := chi.URLParam(r, "roomID")
|
|
if roomID == "" {
|
|
http.Error(w, `{"error":"missing room ID"}`, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
participants, err := h.client.ListParticipants(roomID)
|
|
if err != nil {
|
|
http.Error(w, `{"error":"failed to list participants"}`, http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
type participantInfo struct {
|
|
Identity string `json:"identity"`
|
|
State string `json:"state"`
|
|
}
|
|
|
|
result := make([]participantInfo, 0, len(participants))
|
|
for _, p := range participants {
|
|
state := "connected"
|
|
if p.State == livekit.ParticipantInfo_DISCONNECTED {
|
|
state = "disconnected"
|
|
}
|
|
result = append(result, participantInfo{
|
|
Identity: p.Identity,
|
|
State: state,
|
|
})
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(result)
|
|
}
|