mirror of
https://gitlab.com/comunic/comunicapiv2
synced 2025-03-13 01:22:38 +00:00
236 lines
6.0 KiB
TypeScript
236 lines
6.0 KiB
TypeScript
import { RequestHandler } from "../entities/RequestHandler";
|
|
import { UserWebSocketRequestsHandler } from "../entities/WebSocketRequestHandler";
|
|
import { ActiveClient, UserWebSocketController } from "./UserWebSocketController";
|
|
import { EventsHelper, CallSignalFromRTCRelayEvent } from "../helpers/EventsHelper";
|
|
import * as ws from 'ws'
|
|
import { WsMessage } from "../entities/WsMessage";
|
|
import { conf } from "../helpers/ConfigHelper";
|
|
import { RTCRelayController } from "./RTCRelayController";
|
|
|
|
/**
|
|
* Legacy calls controller
|
|
*
|
|
* @author Pierre HUBERT
|
|
*/
|
|
|
|
export class CallsController {
|
|
|
|
/**
|
|
* Legacy calls config
|
|
*/
|
|
public static GetLegacyConfig(h: RequestHandler) {
|
|
h.send({
|
|
enabled: false
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get call configuration
|
|
*
|
|
* @param h Request handler
|
|
*/
|
|
public static async GetConfig(h: UserWebSocketRequestsHandler) {
|
|
|
|
// Check if user is member of at least one call
|
|
if(h.wsClient.activeCalls.size == 0)
|
|
h.error(401, "You do not belong to any call for now!")
|
|
|
|
h.send({
|
|
iceServers: conf().rtc_relay.iceServers
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Join a call
|
|
*
|
|
* @param h Request handler
|
|
*/
|
|
public static async JoinCall(h: UserWebSocketRequestsHandler) {
|
|
const convID = await h.postConversationId("convID");
|
|
|
|
// If the user was active in any other calls, remove him
|
|
for(const c of UserWebSocketController.active_clients.filter((f) => f.userID == h.getUserId() && f.activeCalls.has(convID)))
|
|
await this.MakeUserLeaveCall(convID, c)
|
|
|
|
|
|
h.wsClient.activeCalls.set(convID, {
|
|
ready: false
|
|
});
|
|
|
|
// Notify all other users
|
|
await UserWebSocketController.SendToSpecifcClients(
|
|
(c) => c.activeCalls.has(convID) && c.userID != h.getUserId(),
|
|
() => WsMessage.NoIDMessage("user_joined_call", {
|
|
callID: convID,
|
|
userID: h.getUserId()
|
|
})
|
|
)
|
|
|
|
h.success();
|
|
}
|
|
|
|
/**
|
|
* Leave a call
|
|
*
|
|
* @param h Request handler
|
|
*/
|
|
public static async LeaveCall(h: UserWebSocketRequestsHandler) {
|
|
// Warning ! For some technical reasons, we do not check if the user
|
|
// really belongs to the conversation, so be careful when manipulating
|
|
// conversation ID here
|
|
const convID = h.postInt("convID");
|
|
|
|
// Check if user is already in the conversation
|
|
if(!h.wsClient.activeCalls.has(convID)) {
|
|
h.success();
|
|
return;
|
|
}
|
|
|
|
// Make the user leave the call
|
|
await this.MakeUserLeaveCall(convID, h.wsClient);
|
|
|
|
h.success();
|
|
}
|
|
|
|
/**
|
|
* Get the list of members for a call
|
|
*
|
|
* The user must have joined the call to get this information
|
|
*
|
|
* @param h Request handler
|
|
*/
|
|
public static async GetMembersList(h: UserWebSocketRequestsHandler) {
|
|
const convID = h.postCallId("callID");
|
|
|
|
h.send(UserWebSocketController.active_clients.filter(
|
|
(f) => f.activeCalls.has(convID)
|
|
).map(f => {return {
|
|
userID: f.userID,
|
|
ready: f.activeCalls.get(convID).ready
|
|
}}))
|
|
}
|
|
|
|
/**
|
|
* Handles client signal
|
|
*
|
|
* @param h Request handler
|
|
*/
|
|
public static async OnClientSignal(h: UserWebSocketRequestsHandler) {
|
|
const callID = h.postCallId("callID");
|
|
const peerID = h.postCallPeerID(callID, "peerID"); // The ID of the user we stream the audio / video from
|
|
const type = h.postString("type");
|
|
const data = h.postJSON("data");
|
|
|
|
if(type !== "SDP" && type !== "CANDIDATE")
|
|
h.error(401, "Invalid candidate type");
|
|
|
|
if(type == "SDP" && (!data.hasOwnProperty("type") || data.type !== "offer" || !data.hasOwnProperty("sdp")))
|
|
h.error(401, "Invalid SDP signal!")
|
|
|
|
if(type == "CANDIDATE" && (!data.hasOwnProperty("candidate") || !data.hasOwnProperty("sdpMLineIndex") || !data.hasOwnProperty("sdpMid")))
|
|
h.error(401, "Invalid candidate signal!")
|
|
|
|
await RTCRelayController.SendMessage({
|
|
title: "signal",
|
|
callHash: callID+"-"+peerID,
|
|
peerId: String(peerID === h.getUserId() ? 0 : peerID),
|
|
data: {
|
|
type: type,
|
|
data: data
|
|
}
|
|
});
|
|
|
|
h.success()
|
|
}
|
|
|
|
/**
|
|
* Handles proxy signals
|
|
*
|
|
* @param e Event information
|
|
*/
|
|
public static async OnProxySignal(e: CallSignalFromRTCRelayEvent) {
|
|
|
|
// Extract information
|
|
const callID = Number(e.callHash.split("-")[0])
|
|
const peerID = Number(e.callHash.split("-")[1])
|
|
|
|
let targetUser = Number(e.peerID)
|
|
if(targetUser == 0)
|
|
targetUser = peerID;
|
|
|
|
// Send the message
|
|
await UserWebSocketController.SendToSpecifcClients(
|
|
(c) => c.userID == targetUser && c.activeCalls.has(callID),
|
|
() => WsMessage.NoIDMessage("new_call_signal", {
|
|
callID: callID,
|
|
peerID: peerID,
|
|
data: e.data
|
|
})
|
|
)
|
|
|
|
}
|
|
|
|
/**
|
|
* Mark a user as ready to share its streams
|
|
*
|
|
* @param h Request handler
|
|
*/
|
|
public static async MarkUserReady(h: UserWebSocketRequestsHandler) {
|
|
const callID = h.postCallId("callID");
|
|
|
|
h.wsClient.activeCalls.get(callID).ready = true;
|
|
|
|
// Notify all other users
|
|
await UserWebSocketController.SendToSpecifcClients(
|
|
(c) => c.activeCalls.has(callID) && c.userID != h.getUserId(),
|
|
() => WsMessage.NoIDMessage("user_ready", {
|
|
callID: callID,
|
|
userID: h.getUserId()
|
|
})
|
|
)
|
|
|
|
h.success();
|
|
}
|
|
|
|
/**
|
|
* Make the client leave the call
|
|
*
|
|
* @param c Client information
|
|
*/
|
|
public static async MakeUserLeaveCall(convID: number, c: ActiveClient) {
|
|
c.activeCalls.delete(convID)
|
|
|
|
// Notify user (if possible)
|
|
if(c.ws.readyState == ws.OPEN)
|
|
UserWebSocketController.SendToClient(c, WsMessage.NoIDMessage("call_closed",convID));
|
|
|
|
// Notify all other users
|
|
await UserWebSocketController.SendToSpecifcClients(
|
|
(c) => c.activeCalls.has(convID),
|
|
() => WsMessage.NoIDMessage("user_left_call", {
|
|
callID: convID,
|
|
userID: c.userID
|
|
})
|
|
)
|
|
}
|
|
}
|
|
|
|
// Listen for websocket closed
|
|
EventsHelper.Listen("user_ws_closed", async w => {
|
|
for(const convID of w.client.activeCalls)
|
|
await CallsController.MakeUserLeaveCall(convID[0], w.client)
|
|
});
|
|
|
|
// Listen to signal from RTC proxy
|
|
EventsHelper.Listen("rtc_relay_signal", async msg => {
|
|
await CallsController.OnProxySignal(msg)
|
|
})
|
|
|
|
// Close all call when RTC WS is closed
|
|
EventsHelper.Listen("rtc_relay_ws_closed", async () => {
|
|
for(const client of UserWebSocketController.active_clients) {
|
|
for(const convID of client.activeCalls)
|
|
await CallsController.MakeUserLeaveCall(convID[0], client);
|
|
}
|
|
})
|