package jitsi import ( "context" "fmt" "log/slog" "time" "goAuth/internal/user" "github.com/golang-jwt/jwt/v5" ) type Service struct { r *Repository Secret string AppID string AppName string Domain string } type claims struct { jwt.RegisteredClaims Room string `json:"room,omitempty"` Context *roomContext `json:"context,omitempty"` } type roomContext struct { User *jitsiUser `json:"user,omitempty"` } type jitsiUser struct { Id string `json:"id"` Name string `json:"name"` Email string `json:"email,omitempty"` Avatar string `json:"avatar,omitempty"` Moderator bool `json:"moderator"` } func NewService(r *Repository, secret, appId, appName, domain string) (*Service, error) { return &Service{r: r, Secret: secret, AppID: appId, AppName: appName, Domain: domain}, nil } func (s *Service) MeetUrl(room, jwtToken string) string { domain := s.Domain if domain == "" { domain = "meet.jit.si" } return fmt.Sprintf("https://%s/%s?jwt=%s", domain, room, jwtToken) } func (s *Service) GenerateToken(userID, userName, room string, moderator bool, avatar string) (string, error) { if s.Secret == "" { return "", ErrSecretNotConfigured } if s.AppID == "" { return "", ErrAppIDNotConfigured } now := time.Now().UTC() claims := claims{ RegisteredClaims: jwt.RegisteredClaims{ Issuer: s.AppID, Subject: userID, Audience: jwt.ClaimStrings{s.AppID}, IssuedAt: jwt.NewNumericDate(now), NotBefore: jwt.NewNumericDate(now), ExpiresAt: jwt.NewNumericDate(now.Add(1 * time.Hour)), ID: fmt.Sprintf("%s-%d", userID, now.Unix()), }, Room: room, Context: &roomContext{ User: &jitsiUser{ Id: userID, Name: userName, Avatar: avatar, Moderator: moderator, }, }, } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) signed, err := token.SignedString([]byte(s.Secret)) if err != nil { slog.Error("sign jitsi token", slog.String("op", "service.GenerateToken"), slog.String("user_id", userID), slog.String("room", room), slog.Any("error", err)) return "", fmt.Errorf("sign jitsi token: %w", err) } return signed, nil } func (s *Service) RecordRoomJoin(ctx context.Context, u *user.User, room string) error { if u == nil { slog.Error("nil user", slog.String("op", "service.RecordRoomJoin"), slog.String("room", room)) return ErrInternal } return s.r.RecordJoin(ctx, u.Id, room, time.Now().UTC()) } func (s *Service) RoomHistory(ctx context.Context, u *user.User, limit, offset int64) ([]*RoomHistory, error) { if u == nil { slog.Error("nil user", slog.String("op", "service.RoomHistory")) return nil, ErrInternal } return s.r.List(ctx, u.Id, limit, offset) } func (s *Service) DeleteRoom(ctx context.Context, u *user.User, room string) error { if u == nil { slog.Error("nil user", slog.String("op", "service.DeleteRoom"), slog.String("room", room)) return ErrInternal } return s.r.DeleteRoom(ctx, u.Id, room) } func (s *Service) ClearHistory(ctx context.Context, u *user.User) error { if u == nil { slog.Error("nil user", slog.String("op", "service.ClearHistory")) return ErrInternal } return s.r.DeleteAll(ctx, u.Id) }