initiating call sequence to contact

This commit is contained in:
Roland Osborne 2023-03-24 00:37:06 -07:00
parent 11407b0cc6
commit 7a36d4843d
12 changed files with 174 additions and 28 deletions

View File

@ -2,6 +2,7 @@ package databag
import (
"net/http"
"github.com/gorilla/mux"
)
//KeepCall keeps call and signaling alive
@ -13,11 +14,8 @@ func KeepCall(w http.ResponseWriter, r *http.Request) {
return
}
var callId string
if err := ParseRequest(r, w, &callId); err != nil {
ErrResponse(w, http.StatusBadRequest, err)
return
}
params := mux.Vars(r)
callId := params["callId"]
bridgeRelay.KeepAlive(account.ID, callId);
WriteResponse(w, nil);

View File

@ -3,16 +3,14 @@ package databag
import (
"net/http"
"errors"
"github.com/gorilla/mux"
)
//RemoveCall adds an active call with ice signal and relay
func RemoveCall(w http.ResponseWriter, r *http.Request) {
var callId string
if err := ParseRequest(r, w, &callId); err != nil {
ErrResponse(w, http.StatusBadRequest, err)
return
}
params := mux.Vars(r)
callId := params["callId"]
tokenType := ParamTokenType(r)
if tokenType == APPTokenAgent {

View File

@ -8,7 +8,7 @@ import (
)
var bridgeRelay BridgeRelay;
const BridgeKeepAlive = 6
const BridgeKeepAlive = 15
type BridgeStatus struct {
status string

View File

@ -800,28 +800,28 @@ var endpoints = routes{
route{
"AddCall",
strings.ToUpper("Post"),
"/talk/call",
"/talk/calls",
AddCall,
},
route{
"KeepCall",
strings.ToUpper("Put"),
"/talk/call/{callId}",
"/talk/calls/{callId}",
KeepCall,
},
route{
"EndCall",
strings.ToUpper("Delete"),
"/talk/call/{callId}",
"/talk/calls/{callId}",
EndCall,
},
route{
"AddRing",
strings.ToUpper("Post"),
"/talk/ring",
"/talk/rings",
AddRing,
},

View File

@ -0,0 +1,10 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function addCall(token, cardId) {
let param = "?agent=" + token
let call = await fetchWithTimeout('/talk/calls' + param, { method: 'POST', body: JSON.stringify(cardId) });
checkResponse(call)
let ret = await call.json()
return ret;
}

View File

@ -6,7 +6,7 @@ export async function addContactRing(server, token, call) {
host = `https://${server}`
}
let ring = await fetchWithTimeout(`${host}/talk/ring?contact=${token}`, { method: 'POST', body: JSON.stringify(call) });
let ring = await fetchWithTimeout(`${host}/talk/rings?contact=${token}`, { method: 'POST', body: JSON.stringify(call) });
checkResponse(ring);
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function keepCall(token, callId) {
let param = "?agent=" + token
let call = await fetchWithTimeout(`/talk/calls/${callId}` + param, { method: 'PUT' });
checkResponse(call)
}

View File

@ -0,0 +1,8 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function removeCall(token, callId) {
let param = "?agent=" + token
let call = await fetchWithTimeout(`/talk/calls/${callId}` + param, { method: 'DELETE' });
checkResponse(call)
}

View File

@ -0,0 +1,12 @@
import { checkResponse, fetchWithTimeout } from './fetchUtil';
export async function removeContactCall(server, token, callId) {
let host = "";
if (server) {
host = `https://${server}`
}
const call = await fetchWithTimeout(`${host}/talk/calls/${callId}?contact=${token}`, { method: 'DELETE' });
checkResponse(call);
}

View File

@ -45,12 +45,14 @@ export function useAppContext(websocket) {
profileContext.actions.setToken(token);
cardContext.actions.setToken(token);
channelContext.actions.setToken(token);
ringContext.actions.setToken(token);
}
catch (err) {
accountContext.actions.clearToken();
profileContext.actions.clearToken();
cardContext.actions.clearToken();
channelContext.actions.clearToken();
ringContext.actions.clearToken();
throw err;
}
setWebsocket(token);
@ -59,8 +61,8 @@ export function useAppContext(websocket) {
const clearSession = () => {
uploadContext.actions.clear();
storeContext.actions.clear();
ringContext.actions.clear();
ringContext.actions.clearToken();
accountContext.actions.clearToken();
profileContext.actions.clearToken();
cardContext.actions.clearToken();
@ -176,11 +178,9 @@ export function useAppContext(websocket) {
let activity = JSON.parse(ev.data);
updateState({ status: 'connected' });
if (activity.revision) {
console.log("GOR REVISION");
setAppRevision(activity.revision);
}
if (activity.ring) {
console.log("GOT PHONE!");
const { cardId, callId, calleeToken } = activity.ring;
ringContext.actions.ring(cardId, callId, calleeToken);
}

View File

@ -1,22 +1,39 @@
import { useEffect, useContext, useState, useRef } from 'react';
import { createWebsocket } from 'api/fetchUtil';
import { addContactRing } from 'api/addContactRing';
import { addCall } from 'api/addCall';
import { keepCall } from 'api/keepCall';
import { removeCall } from 'api/removeCall';
import { removeContactCall } from 'api/removeContactCall';
export function useRingContext() {
const [state, setState] = useState({
ringing: new Map(),
callStatus: null,
});
const access = useRef(null);
const EXPIRE = 3000000
const ringing = useRef(new Map());
const calling = useRef(null);
const ws = useRef(null);
const updateState = (value) => {
setState((s) => ({ ...s, ...value }))
}
const actions = {
clear: () => {
setToken: (token) => {
if (access.current) {
throw new Error("invalid ring state");
}
access.current = token;
ringing.current = new Map();
updateState({ ringing: ringing.current });
calling.current = null;
updateState({ callStatus: null, ringing: ringing.current });
},
clearToken: () => {
access.current = null;
},
ring: (cardId, callId, calleeToken) => {
const key = `${cardId}:${callId}`
@ -30,14 +47,11 @@ export function useRingContext() {
},
ignore: (cardId, callId) => {
const key = `${cardId}:${callId}`
console.log("IGNORE", key);
const call = ringing.current.get(key);
if (call) {
call.status = 'ignored'
ringing.current.set(key, call);
updateState({ ringing: ringing.current });
console.log(ringing.current);
}
},
decline: (cardId, callId) => {
@ -49,13 +63,109 @@ console.log(ringing.current);
updateState({ ringing: ringing.current });
}
},
accept: (cardId, callId) => {
accept: async (cardId, callId, contactNode, contactToken, calleeToken) => {
if (calling.current) {
throw new Error("active session");
}
const key = `${cardId}:${callId}`
const call = ringing.current.get(key);
if (call) {
call.status = 'accepted'
ringing.current.set(key, call);
updateState({ ringing: ringing.current });
// connect signal socket
calling.current = { state: "connecting", callId, contactNode, contactToken, host: false };
updateState({ callStatus: "connecting" });
ws.current = createWebsocket(`wss://${contactNode}/signal`);
ws.current.onmessage = (ev) => {
// handle messages [impolite]
console.log(ev);
}
ws.current.onclose = (e) => {
// update state to disconnected
calling.current = null;
updateState({ calling: null });
}
ws.current.onopen = () => {
calling.current.state = "connected"
updateState({ callStatus: "connected" });
ws.current.send(JSON.stringify({ AppToken: calleeToken }))
}
ws.current.error = (e) => {
console.log(e)
ws.current.close();
}
}
},
end: async () => {
if (!calling.current) {
throw new Error('inactive session');
}
try {
const { host, callId, contactNode, contactToken } = calling.current;
if (host) {
await removeCall(access.current, callId);
}
else {
await removeContactCall(contactNode, contactToken, callId);
}
}
catch (err) {
console.log(err);
}
ws.current.close();
},
call: async (cardId, contactNode, contactToken) => {
if (calling.current) {
throw new Error("active session");
}
// create call
const call = await addCall(access.current, cardId);
const { callId, keepAlive, callerToken, calleeToken } = call;
const aliveInterval = setInterval(async () => {
try {
await keepCall(access.current, call.callId);
}
catch (err) {
console.log(err);
}
}, keepAlive * 1000);
let index = 0;
const ringInterval = setInterval(async () => {
try {
await addContactRing(contactNode, contactToken, { index, callId, calleeToken });
index += 1;
}
catch (err) {
console.log(err);
}
}, 3000);
calling.current = { state: "connecting", callId, host: true };
updateState({ callStatus: "connecting" });
const protocol = window.location.protocol === 'http:' ? 'ws://' : 'wss://';
ws.current = createWebsocket(`${protocol}${window.location.host}/signal`);
ws.current.onmessage = (ev) => {
// handle messages [polite]
// on connected stop ringing
console.log(ev);
}
ws.current.onclose = (e) => {
clearInterval(ringInterval);
clearInterval(aliveInterval);
calling.current = null;
updateState({ callStatus: null });
}
ws.current.onopen = () => {
calling.current.state = "ringing";
updateState({ callStatus: "ringing" });
ws.current.send(JSON.stringify({ AppToken: callerToken }))
}
ws.current.error = (e) => {
console.log(e)
ws.current.close();
}
},
}

View File

@ -1,5 +1,6 @@
import { useContext, useState, useEffect } from 'react';
import { CardContext } from 'context/CardContext';
import { RingContext } from 'context/RingContext';
import { ViewportContext } from 'context/ViewportContext';
import { getListingMessage } from 'api/getListingMessage';
import { getCardByGuid } from 'context/cardUtil';
@ -21,6 +22,7 @@ export function useContact(guid, listing, close) {
});
const card = useContext(CardContext);
const ring = useContext(RingContext);
const viewport = useContext(ViewportContext);
const updateState = (value) => {
@ -157,12 +159,12 @@ export function useContact(guid, listing, close) {
});
},
ring: async () => {
console.log("ringing!!");
console.log("calling!!");
const contact = card.state.cards.get(state.cardId);
const { node, guid } = contact.data.cardProfile;
const { token } = contact.data.cardDetail;
await addContactRing(node, `${guid}.${token}`, { index: 0, callId: 'abc', calleeToken: '123' });
console.log(contact);
await ring.actions.call(state.cardId, node, `${guid}.${token}`);
//await addContactRing(node, `${guid}.${token}`, { index: 0, callId: 'abc', calleeToken: '123' });
},
};