diff --git a/net/server/internal/api_addCall.go b/net/server/internal/api_addCall.go index 1cfa5641..34c3f1f2 100644 --- a/net/server/internal/api_addCall.go +++ b/net/server/internal/api_addCall.go @@ -40,6 +40,17 @@ func AddCall(w http.ResponseWriter, r *http.Request) { return } + iceService := getBoolConfigValue(CNFIceService, false); + iceURL := getStrConfigValue(CNFIceUrl, "") + iceUsername := getStrConfigValue(CNFIceUsername, "") + icePassword := getStrConfigValue(CNFIcePassword, "") + + ice, err := getIce(iceService, iceURL, iceUsername, icePassword); + if err != nil || len(ice) == 0 { + ErrResponse(w, http.StatusServiceUnavailable, err) + return + } + // generate call params callerBin, callerErr := securerandom.Bytes(APPTokenSize) if callerErr != nil { @@ -51,20 +62,11 @@ func AddCall(w http.ResponseWriter, r *http.Request) { ErrResponse(w, http.StatusInternalServerError, calleeErr) return } - //turnBin, turnErr := securerandom.Bytes(APPTokenSize) - //if turnErr != nil { - // ErrResponse(w, http.StatusInternalServerError, turnErr) - // return - //} callId := uuid.New().String() // allocate bridge callerToken := hex.EncodeToString(callerBin); calleeToken := hex.EncodeToString(calleeBin); - iceService := getBoolConfigValue(CNFIceService, false); - iceUrl := getStrConfigValue(CNFIceUrl, "") - iceUsername := getStrConfigValue(CNFIceUsername, "") - icePassword := getStrConfigValue(CNFIcePassword, "") bridgeRelay.AddBridge(account.ID, callId, cardId, callerToken, calleeToken); // create response @@ -73,10 +75,11 @@ func AddCall(w http.ResponseWriter, r *http.Request) { CardId: cardId, CallerToken: callerToken, CalleeToken: calleeToken, + Ice: ice, IceService: iceService, - IceUrl: iceUrl, - IceUsername: iceUsername, - IcePassword: icePassword, + IceURL: ice[len(ice)-1].URLs, + IceUsername: ice[len(ice)-1].Username, + IcePassword: ice[len(ice)-1].Credential, KeepAlive: BridgeKeepAlive, } WriteResponse(w, call); diff --git a/net/server/internal/api_getNodeConfig.go b/net/server/internal/api_getNodeConfig.go index e9f4b817..795310b4 100644 --- a/net/server/internal/api_getNodeConfig.go +++ b/net/server/internal/api_getNodeConfig.go @@ -26,7 +26,7 @@ func GetNodeConfig(w http.ResponseWriter, r *http.Request) { config.PushSupported = getBoolConfigValue(CNFPushSupported, true) config.EnableIce = getBoolConfigValue(CNFEnableIce, false) config.IceService = getBoolConfigValue(CNFIceService, false) - config.IceUrl = getStrConfigValue(CNFIceUrl, "") + config.IceURL = getStrConfigValue(CNFIceUrl, "") config.IceUsername = getStrConfigValue(CNFIceUsername, "") config.IcePassword = getStrConfigValue(CNFIcePassword, "") config.EnableOpenAccess = getBoolConfigValue(CNFEnableOpenAccess, false); diff --git a/net/server/internal/api_setNodeConfig.go b/net/server/internal/api_setNodeConfig.go index 1d15286d..e9b02b34 100644 --- a/net/server/internal/api_setNodeConfig.go +++ b/net/server/internal/api_setNodeConfig.go @@ -121,7 +121,7 @@ func SetNodeConfig(w http.ResponseWriter, r *http.Request) { if res := tx.Clauses(clause.OnConflict{ Columns: []clause.Column{{Name: "config_id"}}, DoUpdates: clause.AssignmentColumns([]string{"str_value"}), - }).Create(&store.Config{ConfigID: CNFIceUrl, StrValue: config.IceUrl}).Error; res != nil { + }).Create(&store.Config{ConfigID: CNFIceUrl, StrValue: config.IceURL}).Error; res != nil { return res } diff --git a/net/server/internal/api_status.go b/net/server/internal/api_status.go index 6f31979e..730769e6 100644 --- a/net/server/internal/api_status.go +++ b/net/server/internal/api_status.go @@ -156,7 +156,7 @@ func SetRing(card *store.Card, ring Ring) { phone.CallID = ring.CallID phone.CalleeToken = ring.CalleeToken phone.Ice = ring.Ice - phone.IceUrl = ring.IceUrl + phone.IceURL = ring.IceURL phone.IceUsername = ring.IceUsername phone.IcePassword = ring.IcePassword phone.CardID = card.CardSlot.CardSlotID diff --git a/net/server/internal/iceUtil.go b/net/server/internal/iceUtil.go new file mode 100644 index 00000000..e54a056a --- /dev/null +++ b/net/server/internal/iceUtil.go @@ -0,0 +1,47 @@ +package databag + +import ( + "encoding/json" + "net/http" + "errors" + "bytes" +) + +func getIce(service bool, urls string, username string, credential string) ([]IceURL, error) { + + if service { + gen := "https://rtc.live.cloudflare.com/v1/turn/keys/" + username + "/credentials/generate" + req, err := http.NewRequest(http.MethodPost, gen, bytes.NewBuffer([]byte("{\"ttl\": 86400}"))) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json; charset=utf-8") + req.Header.Set("Authorization", "Bearer " + credential) + client := &http.Client{} + resp, err := client.Do(req) + if err != nil || resp == nil || resp.StatusCode != 201 { + return nil, errors.New("invalid ice service response") + } + + var r IceService + err = json.NewDecoder(resp.Body).Decode(&r) + if err != nil { + return nil, errors.New("invalid ice service response") + } + + ice := []IceURL{} + for _, url := range r.Servers.URLs { + ice = append(ice, IceURL{ URLs: url, Username: r.Servers.Username, Credential: r.Servers.Credential }); + } + return ice, nil + } + + return []IceURL { + IceURL { + URLs: urls, + Username: username, + Credential: credential, + }, + }, nil +} + diff --git a/net/server/internal/models.go b/net/server/internal/models.go index e1a20fc4..265212b2 100644 --- a/net/server/internal/models.go +++ b/net/server/internal/models.go @@ -377,7 +377,7 @@ type NodeConfig struct { IceService bool `json:"iceService"` - IceUrl string `json:"iceUrl"` + IceURL string `json:"iceUrl"` IceUsername string `json:"iceUsername"` @@ -460,9 +460,9 @@ type Phone struct { CalleeToken string `json:"calleeToken"` - Ice []IceUrl `json:"ice,omitEmpty"` + Ice []IceURL `json:"ice,omitEmpty"` - IceUrl string `json:"iceUrl"` + IceURL string `json:"iceUrl"` IceUsername string `json:"iceUsername"` @@ -569,14 +569,30 @@ type Call struct { IceService bool `json:"iceService"` - IceUrl string `json:"iceUrl"` + Ice []IceURL `json:"ice,omitEmpty"` + + IceURL string `json:"iceUrl"` IceUsername string `json:"iceUsername"` IcePassword string `json:"icePassword"` } -type IceUrl struct { +type IceServers struct { + + URLs []string `json:"urls"` + + Username string `json:"username"` + + Credential string `json:"credential"` +} + +type IceService struct { + + Servers IceServers `json:"iceServers"` +} + +type IceURL struct { URLs string `json:"urls"` @@ -593,9 +609,9 @@ type Ring struct { Index int32 `json:"index"` - Ice []IceUrl `json:"ice,omitEmpty"` + Ice []IceURL `json:"ice,omitEmpty"` - IceUrl string `json:"iceUrl"` + IceURL string `json:"iceUrl"` IceUsername string `json:"iceUsername"` diff --git a/net/web/src/context/useRingContext.hook.js b/net/web/src/context/useRingContext.hook.js index 0300a180..1a4a5761 100644 --- a/net/web/src/context/useRingContext.hook.js +++ b/net/web/src/context/useRingContext.hook.js @@ -134,28 +134,6 @@ export function useRingContext() { processing.current = false; } - const getIce = async (service, urls, username, credential) => { - if (!service) { - return [{ urls, username, credential }]; - } - - const params = await fetch(urls.replace('%%TURN_KEY_ID%%', username), { - method: 'POST', - body: '{"ttl": 86400}', - headers: new Headers({ - 'Authorization': `Bearer ${credential}`, - 'Content-Type': 'application/json' - }) - }); - const server = await params.json(); - const ice = []; - server.iceServers.urls.forEach(urls => { - const { username, credential } = server.iceServers; - ice.push({ urls, username, credential }); - }); - return ice; - } - const getAudioStream = async (audioId) => { try { if (audioId) { @@ -357,6 +335,8 @@ export function useRingContext() { } }, accept: async (cardId, callId, contactNode, contactToken, calleeToken, ice, audioId) => { +console.log("ACCEPT", ice); + if (calling.current) { throw new Error("active session"); } @@ -409,7 +389,6 @@ export function useRingContext() { // create call let call; - let ice; try { call = await addCall(access.current, cardId); } @@ -419,10 +398,9 @@ export function useRingContext() { } let index = 0; - const { id, keepAlive, callerToken, calleeToken, iceService, iceUrl, iceUsername, icePassword } = call; + const { id, keepAlive, callerToken, calleeToken, ice } = call; try { - ice = await getIce(iceService, iceUrl, iceUsername, icePassword); - const turn = ice[ice.length - 1]; + const turn = ice[ice.length - 1]; //backwards compatibility await addContactRing(contactNode, contactToken, { index, callId: id, calleeToken, ice, iceUrl: turn.urls, iceUsername: turn.username, icePassword: turn.credential }); } catch (err) {