|
|
|
@@ -5,12 +5,15 @@ import (
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"log/slog"
|
|
|
|
|
"net/http"
|
|
|
|
|
"strings"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"github.com/flowy-live/llink/internal/utils/flog"
|
|
|
|
|
|
|
|
|
|
"cloud.google.com/go/firestore"
|
|
|
|
|
"github.com/livekit/protocol/webhook"
|
|
|
|
|
|
|
|
|
|
"github.com/flowy-live/llink/internal/auth"
|
|
|
|
|
"github.com/flowy-live/llink/internal/billing"
|
|
|
|
|
"github.com/flowy-live/llink/internal/depot"
|
|
|
|
@@ -22,7 +25,6 @@ import (
|
|
|
|
|
"github.com/flowy-live/llink/internal/particle"
|
|
|
|
|
"github.com/flowy-live/llink/internal/utils"
|
|
|
|
|
"github.com/flowy-live/llink/internal/waitlist"
|
|
|
|
|
"github.com/livekit/protocol/webhook"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Handler struct {
|
|
|
|
@@ -187,13 +189,13 @@ func (h *Handler) RequestSignInCode(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
_, err := h.humanSvc.GetOrCreateByEmail(r.Context(), req.Email)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("failed to get or create human", "error", err, "email", req.Email)
|
|
|
|
|
flog.Error("failed to get or create human", "error", err, "email", req.Email)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := h.authSvc.RequestSignInCode(r.Context(), req.Email); err != nil {
|
|
|
|
|
slog.Error("failed to request sign-in code", "error", err, "email", req.Email)
|
|
|
|
|
flog.Error("failed to request sign-in code", "error", err, "email", req.Email)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -220,7 +222,7 @@ func (h *Handler) SignIn(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
http.Error(w, "human not found", http.StatusNotFound)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
slog.Error("failed to get human for sign-in", "error", err, "email", req.Email)
|
|
|
|
|
flog.Error("failed to get human for sign-in", "error", err, "email", req.Email)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -231,7 +233,7 @@ func (h *Handler) SignIn(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
http.Error(w, "invalid code", http.StatusUnauthorized)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
slog.Error("failed to verify sign-in code", "error", err, "email", req.Email)
|
|
|
|
|
flog.Error("failed to verify sign-in code", "error", err, "email", req.Email)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -256,7 +258,7 @@ func (h *Handler) FirebaseToken(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
token, err := h.authSvc.MintFirebaseCustomToken(r.Context(), humanId)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("failed to mint Firebase custom token", "error", err, "humanId", humanId)
|
|
|
|
|
flog.Error("failed to mint Firebase custom token", "error", err, "humanId", humanId)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -273,7 +275,7 @@ func (h *Handler) SignOut(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := h.authSvc.SignOut(r.Context(), token); err != nil {
|
|
|
|
|
slog.Error("failed to sign out", "error", err)
|
|
|
|
|
flog.Error("failed to sign out", "error", err)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -294,7 +296,7 @@ func (h *Handler) GetCurrentHuman(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
http.Error(w, "human not found", http.StatusNotFound)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
slog.Error("failed to get current human", "error", err, "email", email)
|
|
|
|
|
flog.Error("failed to get current human", "error", err, "email", email)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -323,7 +325,7 @@ func (h *Handler) UpdateSettings(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
if req.EmailNotificationsEnabled != nil {
|
|
|
|
|
if err := h.humanSvc.UpdateEmailNotificationsEnabled(r.Context(), humanId, *req.EmailNotificationsEnabled); err != nil {
|
|
|
|
|
slog.Error("failed to update email notifications setting", "error", err, "humanId", humanId)
|
|
|
|
|
flog.Error("failed to update email notifications setting", "error", err, "humanId", humanId)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -355,14 +357,14 @@ func (h *Handler) CreateNetwork(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
http.Error(w, "name cannot be empty", http.StatusBadRequest)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
slog.Error("failed to create network", "error", err, "humanId", humanId, "name", req.Name)
|
|
|
|
|
flog.Error("failed to create network", "error", err, "humanId", humanId, "name", req.Name)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resp, err := h.networkToDTO(r.Context(), net)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("failed to convert network to DTO", "error", err, "network_id", net.ID)
|
|
|
|
|
flog.Error("failed to convert network to DTO", "error", err, "network_id", net.ID)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -381,7 +383,7 @@ func (h *Handler) ListNetworks(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
networks, err := h.networkSvc.ListForHuman(r.Context(), humanId)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("failed to list networks", "error", err, "humanId", humanId)
|
|
|
|
|
flog.Error("failed to list networks", "error", err, "humanId", humanId)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -390,7 +392,7 @@ func (h *Handler) ListNetworks(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
for _, net := range networks {
|
|
|
|
|
dto, err := h.networkToDTO(r.Context(), net)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Warn("failed to convert network to DTO in list", "error", err, "network_id", net.ID)
|
|
|
|
|
flog.Warn("failed to convert network to DTO in list", "error", err, "network_id", net.ID)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
resp = append(resp, dto)
|
|
|
|
@@ -415,7 +417,7 @@ func (h *Handler) GetNetwork(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
isMember, err := h.networkSvc.IsMember(r.Context(), networkID, humanId)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("failed to check network membership", "error", err, "network_id", networkID, "humanId", humanId)
|
|
|
|
|
flog.Error("failed to check network membership", "error", err, "network_id", networkID, "humanId", humanId)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -430,14 +432,14 @@ func (h *Handler) GetNetwork(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
http.Error(w, "network not found", http.StatusNotFound)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
slog.Error("failed to get network", "error", err, "network_id", networkID)
|
|
|
|
|
flog.Error("failed to get network", "error", err, "network_id", networkID)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resp, err := h.networkToDTO(r.Context(), net)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("failed to convert network to DTO", "error", err, "network_id", networkID)
|
|
|
|
|
flog.Error("failed to convert network to DTO", "error", err, "network_id", networkID)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -463,7 +465,7 @@ func (h *Handler) AddMembersToNetwork(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
isMember, err := h.networkSvc.IsMember(r.Context(), networkID, humanId)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("failed to check network membership", "error", err, "network_id", networkID, "humanId", humanId)
|
|
|
|
|
flog.Error("failed to check network membership", "error", err, "network_id", networkID, "humanId", humanId)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -497,7 +499,7 @@ func (h *Handler) AddMembersToNetwork(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
inviteEmails = append(inviteEmails, normalized)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
slog.Error("failed to look up human by email", "error", err, "email", normalized)
|
|
|
|
|
flog.Error("failed to look up human by email", "error", err, "email", normalized)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -506,7 +508,7 @@ func (h *Handler) AddMembersToNetwork(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
if len(memberHumanIds) > 0 {
|
|
|
|
|
if err := h.networkSvc.AddMembers(r.Context(), networkID, memberHumanIds); err != nil {
|
|
|
|
|
slog.Error("failed to add members to network", "error", err, "network_id", networkID)
|
|
|
|
|
flog.Error("failed to add members to network", "error", err, "network_id", networkID)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -514,7 +516,7 @@ func (h *Handler) AddMembersToNetwork(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
if len(inviteEmails) > 0 {
|
|
|
|
|
if err := h.networkSvc.InviteByEmail(r.Context(), networkID, inviteEmails); err != nil {
|
|
|
|
|
slog.Error("failed to invite members to network", "error", err, "network_id", networkID)
|
|
|
|
|
flog.Error("failed to invite members to network", "error", err, "network_id", networkID)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -522,14 +524,14 @@ func (h *Handler) AddMembersToNetwork(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
net, err := h.networkSvc.GetByID(r.Context(), networkID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("failed to get network after adding members", "error", err, "network_id", networkID)
|
|
|
|
|
flog.Error("failed to get network after adding members", "error", err, "network_id", networkID)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resp, err := h.networkToDTO(r.Context(), net)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("failed to convert network to DTO", "error", err, "network_id", networkID)
|
|
|
|
|
flog.Error("failed to convert network to DTO", "error", err, "network_id", networkID)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -558,7 +560,7 @@ func (h *Handler) RemoveMemberFromNetwork(w http.ResponseWriter, r *http.Request
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := h.networkSvc.RemoveMember(r.Context(), net.ID, memberHumanId); err != nil {
|
|
|
|
|
slog.Error("failed to remove member from network", "error", err, "network_id", net.ID, "memberHumanId", memberHumanId)
|
|
|
|
|
flog.Error("failed to remove member from network", "error", err, "network_id", net.ID, "memberHumanId", memberHumanId)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -581,7 +583,7 @@ func (h *Handler) ListInvitationsForNetwork(w http.ResponseWriter, r *http.Reque
|
|
|
|
|
|
|
|
|
|
isMember, err := h.networkSvc.IsMember(r.Context(), networkID, humanId)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("failed to check network membership", "error", err, "network_id", networkID, "humanId", humanId)
|
|
|
|
|
flog.Error("failed to check network membership", "error", err, "network_id", networkID, "humanId", humanId)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -592,7 +594,7 @@ func (h *Handler) ListInvitationsForNetwork(w http.ResponseWriter, r *http.Reque
|
|
|
|
|
|
|
|
|
|
invitations, err := h.networkSvc.ListInvitationsForNetwork(r.Context(), networkID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("failed to list invitations", "error", err, "network_id", networkID)
|
|
|
|
|
flog.Error("failed to list invitations", "error", err, "network_id", networkID)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -620,7 +622,7 @@ func (h *Handler) ListMyInvitations(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
invitations, err := h.networkSvc.ListInvitationsForEmail(r.Context(), email)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("failed to list invitations for email", "error", err, "email", email)
|
|
|
|
|
flog.Error("failed to list invitations for email", "error", err, "email", email)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -663,7 +665,7 @@ func (h *Handler) AcceptInvitation(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := h.networkSvc.AcceptInvitation(r.Context(), req.NetworkId, email, humanId); err != nil {
|
|
|
|
|
slog.Error("failed to accept invitation", "error", err, "network_id", req.NetworkId, "email", email)
|
|
|
|
|
flog.Error("failed to accept invitation", "error", err, "network_id", req.NetworkId, "email", email)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -686,7 +688,7 @@ func (h *Handler) RevokeInvitation(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
isMember, err := h.networkSvc.IsMember(r.Context(), networkID, humanId)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("failed to check network membership", "error", err, "network_id", networkID, "humanId", humanId)
|
|
|
|
|
flog.Error("failed to check network membership", "error", err, "network_id", networkID, "humanId", humanId)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -707,7 +709,7 @@ func (h *Handler) RevokeInvitation(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := h.networkSvc.RevokeInvitation(r.Context(), networkID, req.Email); err != nil {
|
|
|
|
|
slog.Error("failed to revoke invitation", "error", err, "network_id", networkID, "email", req.Email)
|
|
|
|
|
flog.Error("failed to revoke invitation", "error", err, "network_id", networkID, "email", req.Email)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -729,7 +731,7 @@ func (h *Handler) DownloadParticleMedia(w http.ResponseWriter, r *http.Request)
|
|
|
|
|
|
|
|
|
|
downloadURL, err := h.depotSvc.GetDownloadURL(r.Context(), objectID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("failed to get download URL", "error", err, "object_id", objectID)
|
|
|
|
|
flog.Error("failed to get download URL", "error", err, "object_id", objectID)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -763,7 +765,7 @@ func (h *Handler) PrepareUpload(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
isMember, err := h.networkSvc.IsMember(r.Context(), req.NetworkId, humanId)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("failed to check network membership", "error", err, "network_id", req.NetworkId, "humanId", humanId)
|
|
|
|
|
flog.Error("failed to check network membership", "error", err, "network_id", req.NetworkId, "humanId", humanId)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -785,7 +787,7 @@ func (h *Handler) PrepareUpload(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
slog.Error("failed to prepare upload", "error", err, "network_id", req.NetworkId, "name", req.Name)
|
|
|
|
|
flog.Error("failed to prepare upload", "error", err, "network_id", req.NetworkId, "name", req.Name)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -823,7 +825,7 @@ func (h *Handler) ConfirmUpload(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
slog.Error("failed to confirm upload", "error", err, "object_id", objectID)
|
|
|
|
|
flog.Error("failed to confirm upload", "error", err, "object_id", objectID)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -886,7 +888,7 @@ func (h *Handler) AddToWaitlist(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
http.Error(w, "already in the waitlist", http.StatusConflict)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
slog.Error("failed to add to waitlist", "error", err, "email", req.Email)
|
|
|
|
|
flog.Error("failed to add to waitlist", "error", err, "email", req.Email)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -912,7 +914,7 @@ func (h *Handler) GetWaitlist(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
entries, err := h.waitlistSvc.GetWaitlist(r.Context(), filter)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("failed to get waitlist", "error", err)
|
|
|
|
|
flog.Error("failed to get waitlist", "error", err)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -945,7 +947,7 @@ func (h *Handler) GetWaitlistEntry(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
http.Error(w, "entry not found", http.StatusNotFound)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
slog.Error("failed to get waitlist entry", "error", err, "email", email)
|
|
|
|
|
flog.Error("failed to get waitlist entry", "error", err, "email", email)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -977,7 +979,7 @@ func (h *Handler) InviteWaitlistEntrant(w http.ResponseWriter, r *http.Request)
|
|
|
|
|
http.Error(w, "entry not found", http.StatusNotFound)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
slog.Error("failed to invite waitlist entrant", "error", err, "email", req.Email)
|
|
|
|
|
flog.Error("failed to invite waitlist entrant", "error", err, "email", req.Email)
|
|
|
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -1019,7 +1021,7 @@ func (h *Handler) networkToDTO(ctx context.Context, n *network.Network) (Network
|
|
|
|
|
for _, memberHumanId := range n.MemberHumanIds {
|
|
|
|
|
hum, err := h.humanSvc.GetByID(ctx, memberHumanId)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Warn("failed to look up network member", "humanId", memberHumanId, "error", err)
|
|
|
|
|
flog.Warn("failed to look up network member", "humanId", memberHumanId, "error", err)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
humans = append(humans, humanToDTO(hum))
|
|
|
|
@@ -1070,7 +1072,7 @@ func (h *Handler) GetLivekitToken(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
token, err := h.livekitClient.GetJoinToken(roomName, humanId, humanEmail)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("failed to generate livekit token", "error", err, "humanId", humanId, "roomName", roomName)
|
|
|
|
|
flog.Error("failed to generate livekit token", "error", err, "humanId", humanId, "roomName", roomName)
|
|
|
|
|
http.Error(w, "failed to generate token", http.StatusInternalServerError)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -1084,13 +1086,13 @@ func (h *Handler) GetLivekitToken(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
func (h *Handler) HandleLivekitWebhook(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
event, err := webhook.ReceiveWebhookEvent(r, h.livekitClient.KeyProvider())
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("failed to verify livekit webhook", "error", err)
|
|
|
|
|
flog.Error("failed to verify livekit webhook", "error", err)
|
|
|
|
|
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
eventType := event.GetEvent()
|
|
|
|
|
slog.Info("received livekit webhook", "event", eventType, "room", event.GetRoom().GetName())
|
|
|
|
|
flog.Info("received livekit webhook", "event", eventType, "room", event.GetRoom().GetName())
|
|
|
|
|
|
|
|
|
|
switch eventType {
|
|
|
|
|
case "participant_joined", "participant_left", "room_finished":
|
|
|
|
@@ -1103,7 +1105,7 @@ func (h *Handler) HandleLivekitWebhook(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
roomName := event.GetRoom().GetName()
|
|
|
|
|
parts := strings.SplitN(roomName, "/", 2)
|
|
|
|
|
if len(parts) != 2 {
|
|
|
|
|
slog.Error("invalid room name format", "room", roomName)
|
|
|
|
|
flog.Error("invalid room name format", "room", roomName)
|
|
|
|
|
http.Error(w, "invalid room name", http.StatusBadRequest)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
@@ -1120,7 +1122,7 @@ func (h *Handler) HandleLivekitWebhook(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
// Authoritative list avoids drift from missed/out-of-order webhooks.
|
|
|
|
|
participants, err := h.livekitClient.ListParticipants(ctx, roomName)
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("failed to list participants", "error", err, "room", roomName)
|
|
|
|
|
flog.Error("failed to list participants", "error", err, "room", roomName)
|
|
|
|
|
// 200 to suppress LiveKit retries.
|
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
|
return
|
|
|
|
@@ -1136,7 +1138,7 @@ func (h *Handler) HandleLivekitWebhook(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
{Path: "huddle_active_participants", Value: participantIds},
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
slog.Error("failed to update huddle participants in firestore", "error", err, "path", docPath)
|
|
|
|
|
flog.Error("failed to update huddle participants in firestore", "error", err, "path", docPath)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
|