💩 Switch to use livekit (Non-tested)
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"git.solsynth.dev/hydrogen/messaging/pkg/external"
|
||||
"git.solsynth.dev/hydrogen/messaging/pkg/services"
|
||||
"github.com/robfig/cron/v3"
|
||||
"os"
|
||||
@ -42,11 +43,10 @@ func main() {
|
||||
}
|
||||
|
||||
// Connect other services
|
||||
go func() {
|
||||
if err := grpc.ConnectPassport(); err != nil {
|
||||
log.Fatal().Err(err).Msg("An error occurred when connecting to identity grpc endpoint...")
|
||||
}
|
||||
}()
|
||||
external.SetupLiveKit()
|
||||
if err := grpc.ConnectPassport(); err != nil {
|
||||
log.Fatal().Err(err).Msg("An error occurred when connecting to identity grpc endpoint...")
|
||||
}
|
||||
|
||||
// Server
|
||||
server.NewServer()
|
||||
|
18
pkg/external/livekit.go
vendored
Normal file
18
pkg/external/livekit.go
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
package external
|
||||
|
||||
import (
|
||||
lksdk "github.com/livekit/server-sdk-go"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var Lk *lksdk.RoomServiceClient
|
||||
|
||||
func SetupLiveKit() {
|
||||
host := "https://" + viper.GetString("calling.endpoint")
|
||||
|
||||
Lk = lksdk.NewRoomServiceClient(
|
||||
host,
|
||||
viper.GetString("calling.api_key"),
|
||||
viper.GetString("calling.api_secret"),
|
||||
)
|
||||
}
|
@ -2,17 +2,10 @@ package models
|
||||
|
||||
import "time"
|
||||
|
||||
type CallProvider = string
|
||||
|
||||
const (
|
||||
CallProviderJitsi = "jitsi"
|
||||
)
|
||||
|
||||
type Call struct {
|
||||
BaseModel
|
||||
|
||||
Provider string `json:"provider"`
|
||||
EndedAt *time.Time `json:"ended_at"`
|
||||
EndedAt *time.Time `json:"ended_at"`
|
||||
|
||||
ExternalID string `json:"external_id"`
|
||||
FounderID uint `json:"founder_id"`
|
||||
|
@ -136,10 +136,10 @@ func exchangeCallToken(c *fiber.Ctx) error {
|
||||
} else {
|
||||
return c.JSON(fiber.Map{
|
||||
"token": tk,
|
||||
"endpoint": viper.GetString("meeting.endpoint"),
|
||||
"endpoint": viper.GetString("calling.endpoint"),
|
||||
"full_url": fmt.Sprintf(
|
||||
"%s/%s?jwt=%s",
|
||||
viper.GetString("meeting.endpoint"),
|
||||
viper.GetString("calling.endpoint"),
|
||||
call.ExternalID,
|
||||
url.QueryEscape(tk),
|
||||
),
|
||||
|
@ -53,13 +53,15 @@ func createChannel(c *fiber.Ctx) error {
|
||||
user := c.Locals("principal").(models.Account)
|
||||
|
||||
var data struct {
|
||||
Alias string `json:"alias" validate:"required,min=4,max=32"`
|
||||
Alias string `json:"alias" validate:"required,lowercase,min=4,max=32"`
|
||||
Name string `json:"name" validate:"required"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
if err := BindAndValidate(c, &data); err != nil {
|
||||
return err
|
||||
} else if err = services.GetChannelAliasAvailability(data.Alias); err != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
|
||||
channel, err := services.NewChannel(user, data.Alias, data.Name, data.Description)
|
||||
|
@ -1,11 +1,14 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"git.solsynth.dev/hydrogen/messaging/pkg/database"
|
||||
"git.solsynth.dev/hydrogen/messaging/pkg/external"
|
||||
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/livekit/protocol/auth"
|
||||
"github.com/livekit/protocol/livekit"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/samber/lo"
|
||||
"github.com/spf13/viper"
|
||||
@ -65,8 +68,7 @@ func GetOngoingCall(channel models.Channel) (models.Call, error) {
|
||||
|
||||
func NewCall(channel models.Channel, founder models.ChannelMember) (models.Call, error) {
|
||||
call := models.Call{
|
||||
Provider: models.CallProviderJitsi,
|
||||
ExternalID: channel.Name,
|
||||
ExternalID: channel.Alias,
|
||||
FounderID: founder.ID,
|
||||
ChannelID: channel.ID,
|
||||
Founder: founder,
|
||||
@ -77,6 +79,15 @@ func NewCall(channel models.Channel, founder models.ChannelMember) (models.Call,
|
||||
return call, fmt.Errorf("this channel already has an ongoing call")
|
||||
}
|
||||
|
||||
_, err := external.Lk.CreateRoom(context.Background(), &livekit.CreateRoomRequest{
|
||||
Name: call.ExternalID,
|
||||
EmptyTimeout: viper.GetUint32("calling.empty_timeout_duration"),
|
||||
MaxParticipants: viper.GetUint32("calling.max_participants"),
|
||||
})
|
||||
if err != nil {
|
||||
return call, fmt.Errorf("remote livekit error: %v", err)
|
||||
}
|
||||
|
||||
var members []models.ChannelMember
|
||||
if err := database.C.Save(&call).Error; err != nil {
|
||||
return call, err
|
||||
@ -111,6 +122,12 @@ func NewCall(channel models.Channel, founder models.ChannelMember) (models.Call,
|
||||
func EndCall(call models.Call) (models.Call, error) {
|
||||
call.EndedAt = lo.ToPtr(time.Now())
|
||||
|
||||
if _, err := external.Lk.DeleteRoom(context.Background(), &livekit.DeleteRoomRequest{
|
||||
Room: call.ExternalID,
|
||||
}); err != nil {
|
||||
log.Error().Err(err).Msg("Unable to delete room at livekit side")
|
||||
}
|
||||
|
||||
var members []models.ChannelMember
|
||||
if err := database.C.Save(&call).Error; err != nil {
|
||||
return call, err
|
||||
@ -129,20 +146,22 @@ func EndCall(call models.Call) (models.Call, error) {
|
||||
return call, nil
|
||||
}
|
||||
|
||||
func EncodeCallToken(user models.Account) (string, error) {
|
||||
// Jitsi requires HS256 as algorithm, so we cannot use HS512
|
||||
tk := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
|
||||
"context": jwt.MapClaims{
|
||||
"user": jwt.MapClaims{
|
||||
"avatar": user.Avatar,
|
||||
"name": user.Name,
|
||||
},
|
||||
},
|
||||
"aud": viper.GetString("meeting.client_id"),
|
||||
"iss": viper.GetString("domain"),
|
||||
"sub": "meet.jitsi",
|
||||
"room": "*",
|
||||
})
|
||||
func EncodeCallToken(user models.Account, call models.Call) (string, error) {
|
||||
isAdmin := false
|
||||
if user.ID == call.FounderID || user.ID == call.Channel.AccountID {
|
||||
isAdmin = true
|
||||
}
|
||||
|
||||
return tk.SignedString([]byte(viper.GetString("meeting.client_secret")))
|
||||
identity := fmt.Sprintf("%d", user.ID)
|
||||
grant := &auth.VideoGrant{
|
||||
Room: call.ExternalID,
|
||||
RoomJoin: true,
|
||||
RoomAdmin: isAdmin,
|
||||
}
|
||||
|
||||
duration := time.Second * time.Duration(viper.GetInt("calling.token_duration"))
|
||||
tk := auth.NewAccessToken(viper.GetString("calling.api_key"), viper.GetString("calling.api_secret"))
|
||||
tk.AddGrant(grant).SetIdentity(identity).SetValidFor(duration)
|
||||
|
||||
return tk.ToJWT()
|
||||
}
|
||||
|
@ -2,12 +2,20 @@ package services
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"git.solsynth.dev/hydrogen/messaging/pkg/database"
|
||||
"git.solsynth.dev/hydrogen/messaging/pkg/models"
|
||||
"github.com/samber/lo"
|
||||
)
|
||||
|
||||
func GetChannelAliasAvailability(alias string) error {
|
||||
if !regexp.MustCompile("^[a-z0-9-]+$").MatchString(alias) {
|
||||
return fmt.Errorf("channel alias should only contains lowercase letters, numbers, and hyphens")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetChannel(id uint) (models.Channel, error) {
|
||||
var channel models.Channel
|
||||
if err := database.C.Where(models.Channel{
|
||||
|
Reference in New Issue
Block a user