mirror of
https://github.com/Kornstalx/5etools-mirror-2.github.io.git
synced 2025-10-28 20:45:35 -05:00
562 lines
20 KiB
JavaScript
562 lines
20 KiB
JavaScript
|
|
class _InitiativeTrackerNetworkingP2pMetaV1 {
|
|
constructor () {
|
|
this.rows = [];
|
|
this.serverInfo = null;
|
|
this.serverPeer = null;
|
|
}
|
|
}
|
|
|
|
class _InitiativeTrackerNetworkingP2pMetaV0 {
|
|
constructor () {
|
|
this.rows = [];
|
|
this.serverInfo = null;
|
|
}
|
|
}
|
|
|
|
export class InitiativeTrackerNetworking {
|
|
constructor ({board}) {
|
|
this._board = board;
|
|
|
|
this._p2pMetaV1 = new _InitiativeTrackerNetworkingP2pMetaV1();
|
|
this._p2pMetaV0 = new _InitiativeTrackerNetworkingP2pMetaV0();
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
sendStateToClients ({fnGetToSend}) {
|
|
return this._sendMessageToClients({fnGetToSend});
|
|
}
|
|
|
|
sendShowImageMessageToClients ({imageHref}) {
|
|
return this._sendMessageToClients({
|
|
fnGetToSend: () => ({
|
|
type: "showImage",
|
|
payload: {
|
|
imageHref,
|
|
},
|
|
}),
|
|
});
|
|
}
|
|
|
|
_sendMessageToClients ({fnGetToSend}) {
|
|
let toSend = null;
|
|
|
|
// region V1
|
|
if (this._p2pMetaV1.serverPeer) {
|
|
if (!this._p2pMetaV1.serverPeer.hasConnections()) return;
|
|
|
|
toSend ||= fnGetToSend();
|
|
this._p2pMetaV1.serverPeer.sendMessage(toSend);
|
|
}
|
|
// endregion
|
|
|
|
// region V0
|
|
if (this._p2pMetaV0.serverInfo) {
|
|
this._p2pMetaV0.rows = this._p2pMetaV0.rows.filter(row => !row.isDeleted);
|
|
this._p2pMetaV0.serverInfo = this._p2pMetaV0.serverInfo.filter(row => {
|
|
if (row.isDeleted) {
|
|
row.server.close();
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
|
|
toSend ||= fnGetToSend();
|
|
try {
|
|
this._p2pMetaV0.serverInfo.filter(info => info.server.isActive).forEach(info => info.server.sendMessage(toSend));
|
|
} catch (e) { setTimeout(() => { throw e; }); }
|
|
}
|
|
// endregion
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
/**
|
|
* @param opts
|
|
* @param opts.doUpdateExternalStates
|
|
* @param [opts.$btnStartServer]
|
|
* @param [opts.$btnGetToken]
|
|
* @param [opts.$btnGetLink]
|
|
* @param [opts.fnDispServerStoppedState]
|
|
* @param [opts.fnDispServerRunningState]
|
|
*/
|
|
async startServerV1 (opts) {
|
|
opts = opts || {};
|
|
|
|
if (this._p2pMetaV1.serverPeer) {
|
|
await this._p2pMetaV1.serverPeer.pInit();
|
|
return {
|
|
isRunning: true,
|
|
token: this._p2pMetaV1.serverPeer?.token,
|
|
};
|
|
}
|
|
|
|
try {
|
|
if (opts.$btnStartServer) opts.$btnStartServer.prop("disabled", true);
|
|
this._p2pMetaV1.serverPeer = new PeerVeServer();
|
|
await this._p2pMetaV1.serverPeer.pInit();
|
|
if (opts.$btnGetToken) opts.$btnGetToken.prop("disabled", false);
|
|
if (opts.$btnGetLink) opts.$btnGetLink.prop("disabled", false);
|
|
|
|
this._p2pMetaV1.serverPeer.on("connection", connection => {
|
|
const pConnected = new Promise(resolve => {
|
|
connection.on("open", () => {
|
|
resolve(true);
|
|
opts.doUpdateExternalStates();
|
|
});
|
|
});
|
|
const pTimeout = MiscUtil.pDelay(5 * 1000, false);
|
|
Promise.race([pConnected, pTimeout])
|
|
.then(didConnect => {
|
|
if (!didConnect) {
|
|
JqueryUtil.doToast({content: `Connecting to "${connection.label.escapeQuotes()}" has taken more than 5 seconds! The connection may need to be re-attempted.`, type: "warning"});
|
|
}
|
|
});
|
|
});
|
|
|
|
$(window).on("beforeunload", evt => {
|
|
const message = `The connection will be closed`;
|
|
(evt || window.event).message = message;
|
|
return message;
|
|
});
|
|
|
|
if (opts.fnDispServerRunningState) opts.fnDispServerRunningState();
|
|
|
|
return {
|
|
isRunning: true,
|
|
token: this._p2pMetaV1.serverPeer?.token,
|
|
};
|
|
} catch (e) {
|
|
if (opts.fnDispServerStoppedState) opts.fnDispServerStoppedState();
|
|
if (opts.$btnStartServer) opts.$btnStartServer.prop("disabled", false);
|
|
this._p2pMetaV1.serverPeer = null;
|
|
JqueryUtil.doToast({content: `Failed to start server! ${VeCt.STR_SEE_CONSOLE}`, type: "danger"});
|
|
setTimeout(() => { throw e; });
|
|
}
|
|
|
|
return {
|
|
isRunning: false,
|
|
token: this._p2pMetaV1.serverPeer?.token,
|
|
};
|
|
}
|
|
|
|
handleClick_playerWindowV1 ({doUpdateExternalStates}) {
|
|
const {$modalInner} = UiUtil.getShowModal({
|
|
title: "Configure Player View",
|
|
isUncappedHeight: true,
|
|
isHeight100: true,
|
|
cbClose: () => {
|
|
if (this._p2pMetaV1.rows.length) this._p2pMetaV1.rows.forEach(row => row.$row.detach());
|
|
if (this._p2pMetaV1.serverPeer) this._p2pMetaV1.serverPeer.offTemp("connection");
|
|
},
|
|
});
|
|
|
|
const $wrpHelp = UiUtil.$getAddModalRow($modalInner, "div");
|
|
|
|
const fnDispServerStoppedState = () => {
|
|
$btnStartServer.html(`<span class="glyphicon glyphicon-play"></span> Start Server`).prop("disabled", false);
|
|
$btnGetToken.prop("disabled", true);
|
|
$btnGetLink.prop("disabled", true);
|
|
};
|
|
|
|
const fnDispServerRunningState = () => {
|
|
$btnStartServer.html(`<span class="glyphicon glyphicon-play"></span> Server Running`).prop("disabled", true);
|
|
$btnGetToken.prop("disabled", false);
|
|
$btnGetLink.prop("disabled", false);
|
|
};
|
|
|
|
const $btnStartServer = $(`<button class="btn btn-default mr-2"></button>`)
|
|
.click(async () => {
|
|
const {isRunning} = await this.startServerV1({doUpdateExternalStates, $btnStartServer, $btnGetToken, $btnGetLink, fnDispServerStoppedState, fnDispServerRunningState});
|
|
if (!isRunning) return;
|
|
|
|
this._p2pMetaV1.serverPeer.onTemp("connection", showConnected);
|
|
showConnected();
|
|
});
|
|
|
|
const $btnGetToken = $(`<button class="btn btn-default mr-2" disabled><span class="glyphicon glyphicon-copy"></span> Copy Token</button>`).appendTo($wrpHelp)
|
|
.click(async () => {
|
|
await MiscUtil.pCopyTextToClipboard(this._p2pMetaV1.serverPeer.token);
|
|
JqueryUtil.showCopiedEffect($btnGetToken);
|
|
});
|
|
|
|
const $btnGetLink = $(`<button class="btn btn-default" disabled><span class="glyphicon glyphicon-link"></span> Copy Link</button>`).appendTo($wrpHelp)
|
|
.click(async () => {
|
|
const cleanOrigin = window.location.origin.replace(/\/+$/, "");
|
|
const url = `${cleanOrigin}/inittrackerplayerview.html#v1:${this._p2pMetaV1.serverPeer.token}`;
|
|
await MiscUtil.pCopyTextToClipboard(url);
|
|
JqueryUtil.showCopiedEffect($btnGetLink);
|
|
});
|
|
|
|
if (this._p2pMetaV1.serverPeer) fnDispServerRunningState();
|
|
else fnDispServerStoppedState();
|
|
|
|
$$`<div class="row w-100">
|
|
<div class="ve-col-12">
|
|
<p>
|
|
The Player View is part of a peer-to-peer system to allow players to connect to a DM's initiative tracker. Players should use the <a href="inittrackerplayerview.html">Initiative Tracker Player View</a> page to connect to the DM's instance. As a DM, the usage is as follows:
|
|
<ol>
|
|
<li>Start the server.</li>
|
|
<li>Copy your link/token and share it with your players.</li>
|
|
<li>Wait for them to connect!</li>
|
|
</ol>
|
|
</p>
|
|
<p>${$btnStartServer}${$btnGetLink}${$btnGetToken}</p>
|
|
<p><i>Please note that this system is highly experimental. Your experience may vary.</i></p>
|
|
</div>
|
|
</div>`.appendTo($wrpHelp);
|
|
|
|
UiUtil.addModalSep($modalInner);
|
|
|
|
const $wrpConnected = UiUtil.$getAddModalRow($modalInner, "div").addClass("flx-col");
|
|
|
|
const showConnected = () => {
|
|
if (!this._p2pMetaV1.serverPeer) return $wrpConnected.html(`<div class="w-100 ve-flex-vh-center"><i>No clients connected.</i></div>`);
|
|
|
|
let stack = `<div class="w-100"><h5>Connected Clients:</h5><ul>`;
|
|
this._p2pMetaV1.serverPeer.getActiveConnections()
|
|
.map(it => it.label || "(Unknown)")
|
|
.sort(SortUtil.ascSortLower)
|
|
.forEach(it => stack += `<li>${it.escapeQuotes()}</li>`);
|
|
stack += "</ul></div>";
|
|
$wrpConnected.html(stack);
|
|
};
|
|
|
|
if (this._p2pMetaV1.serverPeer) this._p2pMetaV1.serverPeer.onTemp("connection", showConnected);
|
|
|
|
showConnected();
|
|
}
|
|
|
|
// nop on receiving a message; we want to send only
|
|
// TODO expand this, to allow e.g. players to set statuses or assign damage/healing (at DM approval?)
|
|
_playerWindowV0_DM_MESSAGE_RECEIVER = function () {};
|
|
|
|
_playerWindowV0_DM_ERROR_HANDLER = function (err) {
|
|
if (!this.isClosed) {
|
|
// TODO: this could be better at handling `err.error == "RTCError: User-Initiated Abort, reason=Close called"`
|
|
JqueryUtil.doToast({
|
|
content: `Server error:\n${err ? (err.message || err.error || err) : "(Unknown error)"}`,
|
|
type: "danger",
|
|
});
|
|
}
|
|
};
|
|
|
|
async _playerWindowV0_pGetServerTokens ({rowMetas}) {
|
|
const targetRows = rowMetas.filter(it => !it.isDeleted).filter(it => !it.isActive);
|
|
if (targetRows.every(it => it.isActive)) {
|
|
return JqueryUtil.doToast({
|
|
content: "No rows require Server Token generation!",
|
|
type: "warning",
|
|
});
|
|
}
|
|
|
|
let anyInvalidNames = false;
|
|
targetRows.forEach(row => {
|
|
row.$iptName.removeClass("error-background");
|
|
if (!row.$iptName.val().trim()) {
|
|
anyInvalidNames = true;
|
|
row.$iptName.addClass("error-background");
|
|
}
|
|
});
|
|
if (anyInvalidNames) return;
|
|
|
|
const names = targetRows.map(row => {
|
|
row.isActive = true;
|
|
|
|
row.$iptName.attr("disabled", true);
|
|
row.$btnGenServerToken.attr("disabled", true);
|
|
|
|
return row.$iptName.val();
|
|
});
|
|
|
|
if (this._p2pMetaV0.serverInfo) {
|
|
await this._p2pMetaV0.serverInfo;
|
|
|
|
const serverInfo = await PeerUtilV0.pInitialiseServersAddToExisting(
|
|
names,
|
|
this._p2pMetaV0.serverInfo,
|
|
this._playerWindowV0_DM_MESSAGE_RECEIVER,
|
|
this._playerWindowV0_DM_ERROR_HANDLER,
|
|
);
|
|
|
|
return targetRows.map((row, i) => {
|
|
row.name = serverInfo[i].name;
|
|
row.serverInfo = serverInfo[i];
|
|
row.$iptTokenServer.val(serverInfo[i].textifiedSdp).attr("disabled", false);
|
|
|
|
serverInfo[i].rowMeta = row;
|
|
|
|
row.$iptTokenClient.attr("disabled", false);
|
|
row.$btnAcceptClientToken.attr("disabled", false);
|
|
|
|
return serverInfo[i].textifiedSdp;
|
|
});
|
|
} else {
|
|
this._p2pMetaV0.serverInfo = (async () => {
|
|
this._p2pMetaV0.serverInfo = await PeerUtilV0.pInitialiseServers(names, this._playerWindowV0_DM_MESSAGE_RECEIVER, this._playerWindowV0_DM_ERROR_HANDLER);
|
|
|
|
targetRows.forEach((row, i) => {
|
|
row.name = this._p2pMetaV0.serverInfo[i].name;
|
|
row.serverInfo = this._p2pMetaV0.serverInfo[i];
|
|
row.$iptTokenServer.val(this._p2pMetaV0.serverInfo[i].textifiedSdp).attr("disabled", false);
|
|
|
|
this._p2pMetaV0.serverInfo[i].rowMeta = row;
|
|
|
|
row.$iptTokenClient.attr("disabled", false);
|
|
row.$btnAcceptClientToken.attr("disabled", false);
|
|
});
|
|
})();
|
|
|
|
await this._p2pMetaV0.serverInfo;
|
|
return targetRows.map(row => row.serverInfo.textifiedSdp);
|
|
}
|
|
}
|
|
|
|
handleClick_playerWindowV0 ({doUpdateExternalStates}) {
|
|
const {$modalInner} = UiUtil.getShowModal({
|
|
title: "Configure Player View",
|
|
isUncappedHeight: true,
|
|
isHeight100: true,
|
|
cbClose: () => {
|
|
if (this._p2pMetaV0.rows.length) this._p2pMetaV0.rows.forEach(row => row.$row.detach());
|
|
},
|
|
});
|
|
|
|
const $wrpHelp = UiUtil.$getAddModalRow($modalInner, "div");
|
|
const $btnAltGenAll = $(`<button class="btn btn-primary btn-text-insert">Generate All</button>`).click(() => $btnGenServerTokens.click());
|
|
const $btnAltCopyAll = $(`<button class="btn btn-primary btn-text-insert">Copy Server Tokens</button>`).click(() => $btnCopyServers.click());
|
|
$$`<div class="ve-flex w-100">
|
|
<div class="ve-col-12">
|
|
<p>
|
|
The Player View is part of a peer-to-peer (i.e., serverless) system to allow players to connect to a DM's initiative tracker. Players should use the <a href="inittrackerplayerview.html">Initiative Tracker Player View</a> page to connect to the DM's instance. As a DM, the usage is as follows:
|
|
<ol>
|
|
<li>Add the required number of players, and input (preferably unique) player names.</li>
|
|
<li>Click "${$btnAltGenAll}," which will generate a "server token" per player. You can click "${$btnAltCopyAll}" to copy them all as a single block of text, or click on the "Server Token" values to copy them individually. Distribute these tokens to your players (via a messaging service of your choice; we recommend <a href="https://discordapp.com/">Discord</a>). Each player should paste their token into the <a href="inittrackerplayerview.html">Initiative Tracker Player View</a>, following the instructions provided therein.</li>
|
|
<li>
|
|
Get a resulting "client token" from each player via a messaging service of your choice. Then, either:
|
|
<ol type="a">
|
|
<li>Click the "Accept Multiple Clients" button, and paste in text containing multiple client tokens. <b>This will try to find tokens in <i>any</i> text, ignoring everything else.</b> Pasting a chatroom log (containing, for example, usernames and timestamps mixed with tokens) is the expected usage.</li>
|
|
<li>Paste each token into the appropriate "Client Token" field and "Accept Client" on each. A token can be identified by the slugified player name in the first few characters.</li>
|
|
</ol>
|
|
</li>
|
|
</ol>
|
|
</p>
|
|
<p>Once a player's client has been "accepted," it will receive updates from the DM's tracker. <i>Please note that this system is highly experimental. Your experience may vary.</i></p>
|
|
</div>
|
|
</div>`.appendTo($wrpHelp);
|
|
|
|
UiUtil.addModalSep($modalInner);
|
|
|
|
const $wrpTop = UiUtil.$getAddModalRow($modalInner, "div");
|
|
|
|
const $btnAddClient = $(`<button class="btn btn-xs btn-primary" title="Add Client">Add Player</button>`).click(() => addClientRow());
|
|
|
|
const $btnCopyServers = $(`<button class="btn btn-xs btn-primary" title="Copy any available server tokens to the clipboard">Copy Server Tokens</button>`)
|
|
.click(async () => {
|
|
const targetRows = this._p2pMetaV0.rows.filter(it => !it.isDeleted && !it.$iptTokenClient.attr("disabled"));
|
|
if (!targetRows.length) {
|
|
JqueryUtil.doToast({
|
|
content: `No free server tokens to copy. Generate some!`,
|
|
type: "warning",
|
|
});
|
|
} else {
|
|
await MiscUtil.pCopyTextToClipboard(targetRows.map(it => it.$iptTokenServer.val()).join("\n\n"));
|
|
JqueryUtil.showCopiedEffect($btnGenServerTokens);
|
|
}
|
|
});
|
|
|
|
const $btnAcceptClients = $(`<button class="btn btn-xs btn-primary" title="Open a prompt into which text containing client tokens can be pasted">Accept Multiple Clients</button>`)
|
|
.click(() => {
|
|
const {$modalInner, doClose} = UiUtil.getShowModal({title: "Accept Multiple Clients"});
|
|
|
|
const $iptText = $(`<textarea class="form-control dm-init-pl__textarea block mb-2"></textarea>`)
|
|
.keydown(() => $iptText.removeClass("error-background"));
|
|
|
|
const $btnAccept = $(`<button class="btn btn-xs btn-primary block ve-text-center" title="Add Client">Accept Multiple Clients</button>`)
|
|
.click(async () => {
|
|
$iptText.removeClass("error-background");
|
|
const txt = $iptText.val();
|
|
if (!txt.trim() || !PeerUtilV0.containsAnyTokens(txt)) {
|
|
$iptText.addClass("error-background");
|
|
} else {
|
|
const connected = await PeerUtilV0.pConnectClientsToServers(this._p2pMetaV0.serverInfo, txt);
|
|
this._board.doBindAlertOnNavigation();
|
|
connected.forEach(serverInfo => {
|
|
serverInfo.rowMeta.$iptTokenClient.val(serverInfo._tempTokenToDisplay || "").attr("disabled", true);
|
|
serverInfo.rowMeta.$btnAcceptClientToken.attr("disabled", true);
|
|
delete serverInfo._tempTokenToDisplay;
|
|
});
|
|
doClose();
|
|
doUpdateExternalStates();
|
|
}
|
|
});
|
|
|
|
$$`<div>
|
|
<p>Paste text containing one or more client tokens, and click "Accept Multiple Clients"</p>
|
|
${$iptText}
|
|
<div class="ve-flex-vh-center">${$btnAccept}</div>
|
|
</div>`.appendTo($modalInner);
|
|
});
|
|
|
|
$$`
|
|
<div class="ve-flex w-100">
|
|
<div class="ve-col-12">
|
|
<div class="ve-flex-inline-v-center mr-2">
|
|
<span class="mr-1">Add a player (client):</span>
|
|
${$btnAddClient}
|
|
</div>
|
|
<div class="ve-flex-inline-v-center mr-2">
|
|
<span class="mr-1">Copy all un-paired server tokens:</span>
|
|
${$btnCopyServers}
|
|
</div>
|
|
<div class="ve-flex-inline-v-center mr-2">
|
|
<span class="mr-1">Mass-accept clients:</span>
|
|
${$btnAcceptClients}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
`.appendTo($wrpTop);
|
|
|
|
UiUtil.addModalSep($modalInner);
|
|
|
|
const $btnGenServerTokens = $(`<button class="btn btn-primary btn-xs">Generate All</button>`)
|
|
.click(() => this._playerWindowV0_pGetServerTokens({rowMetas: this._p2pMetaV0.rows}));
|
|
|
|
UiUtil.$getAddModalRow($modalInner, "div")
|
|
.append($$`
|
|
<div class="ve-flex w-100">
|
|
<div class="ve-col-2 bold">Player Name</div>
|
|
<div class="ve-col-3-5 bold">Server Token</div>
|
|
<div class="ve-col-1 ve-text-center">${$btnGenServerTokens}</div>
|
|
<div class="ve-col-3-5 bold">Client Token</div>
|
|
</div>
|
|
`);
|
|
|
|
const _get$rowTemplate = (
|
|
$iptName,
|
|
$iptTokenServer,
|
|
$btnGenServerToken,
|
|
$iptTokenClient,
|
|
$btnAcceptClientToken,
|
|
$btnDeleteClient,
|
|
) => $$`<div class="w-100 mb-2 ve-flex">
|
|
<div class="ve-col-2 pr-1">${$iptName}</div>
|
|
<div class="ve-col-3-5 px-1">${$iptTokenServer}</div>
|
|
<div class="ve-col-1 px-1 ve-flex-vh-center">${$btnGenServerToken}</div>
|
|
<div class="ve-col-3-5 px-1">${$iptTokenClient}</div>
|
|
<div class="ve-col-1-5 px-1 ve-flex-vh-center">${$btnAcceptClientToken}</div>
|
|
<div class="ve-col-0-5 pl-1 ve-flex-vh-center">${$btnDeleteClient}</div>
|
|
</div>`;
|
|
|
|
const clientRowMetas = [];
|
|
const addClientRow = () => {
|
|
const rowMeta = {id: CryptUtil.uid()};
|
|
clientRowMetas.push(rowMeta);
|
|
|
|
const $iptName = $(`<input class="form-control input-sm">`)
|
|
.keydown(evt => {
|
|
$iptName.removeClass("error-background");
|
|
if (evt.key === "Enter") $btnGenServerToken.click();
|
|
});
|
|
|
|
const $iptTokenServer = $(`<input class="form-control input-sm copyable code" readonly disabled>`)
|
|
.click(async () => {
|
|
await MiscUtil.pCopyTextToClipboard($iptTokenServer.val());
|
|
JqueryUtil.showCopiedEffect($iptTokenServer);
|
|
}).disableSpellcheck();
|
|
|
|
const $btnGenServerToken = $(`<button class="btn btn-xs btn-primary" title="Generate Server Token">Generate</button>`)
|
|
.click(() => this._playerWindowV0_pGetServerTokens({rowMetas: [rowMeta]}));
|
|
|
|
const $iptTokenClient = $(`<input class="form-control input-sm code" disabled>`)
|
|
.keydown(evt => {
|
|
$iptTokenClient.removeClass("error-background");
|
|
if (evt.key === "Enter") $btnAcceptClientToken.click();
|
|
}).disableSpellcheck();
|
|
|
|
const $btnAcceptClientToken = $(`<button class="btn btn-xs btn-primary" title="Accept Client Token" disabled>Accept Client</button>`)
|
|
.click(async () => {
|
|
const token = $iptTokenClient.val();
|
|
if (PeerUtilV0.isValidToken(token)) {
|
|
try {
|
|
await PeerUtilV0.pConnectClientsToServers([rowMeta.serverInfo], token);
|
|
this._board.doBindAlertOnNavigation();
|
|
$iptTokenClient.prop("disabled", true);
|
|
$btnAcceptClientToken.prop("disabled", true);
|
|
doUpdateExternalStates();
|
|
} catch (e) {
|
|
JqueryUtil.doToast({
|
|
content: `Failed to accept client token! Are you sure it was valid? (See the log for more details.)`,
|
|
type: "danger",
|
|
});
|
|
setTimeout(() => { throw e; });
|
|
}
|
|
} else $iptTokenClient.addClass("error-background");
|
|
});
|
|
|
|
const $btnDeleteClient = $(`<button class="btn btn-xs btn-danger"><span class="glyphicon glyphicon-trash"></span></button>`)
|
|
.click(() => {
|
|
rowMeta.$row.remove();
|
|
rowMeta.isDeleted = true;
|
|
if (rowMeta.serverInfo) {
|
|
rowMeta.serverInfo.server.close();
|
|
rowMeta.serverInfo.isDeleted = true;
|
|
}
|
|
const ix = clientRowMetas.indexOf(rowMeta);
|
|
if (~ix) clientRowMetas.splice(ix, 1);
|
|
|
|
if (!clientRowMetas.length) addClientRow();
|
|
});
|
|
|
|
rowMeta.$row = _get$rowTemplate(
|
|
$iptName,
|
|
$iptTokenServer,
|
|
$btnGenServerToken,
|
|
$iptTokenClient,
|
|
$btnAcceptClientToken,
|
|
$btnDeleteClient,
|
|
).appendTo($wrpRowsInner);
|
|
|
|
rowMeta.$iptName = $iptName;
|
|
rowMeta.$iptTokenServer = $iptTokenServer;
|
|
rowMeta.$btnGenServerToken = $btnGenServerToken;
|
|
rowMeta.$iptTokenClient = $iptTokenClient;
|
|
rowMeta.$btnAcceptClientToken = $btnAcceptClientToken;
|
|
this._p2pMetaV0.rows.push(rowMeta);
|
|
|
|
return rowMeta;
|
|
};
|
|
|
|
const $wrpRows = UiUtil.$getAddModalRow($modalInner, "div");
|
|
const $wrpRowsInner = $(`<div class="w-100"></div>`).appendTo($wrpRows);
|
|
|
|
if (this._p2pMetaV0.rows.length) this._p2pMetaV0.rows.forEach(row => row.$row.appendTo($wrpRowsInner));
|
|
else addClientRow();
|
|
}
|
|
|
|
async pHandleDoConnectLocalV0 ({clientView}) {
|
|
// generate a stub/fake row meta
|
|
const rowMeta = {
|
|
id: CryptUtil.uid(),
|
|
$row: $(),
|
|
$iptName: $(`<input value="local">`),
|
|
$iptTokenServer: $(),
|
|
$btnGenServerToken: $(),
|
|
$iptTokenClient: $(),
|
|
$btnAcceptClientToken: $(),
|
|
};
|
|
|
|
this._p2pMetaV0.rows.push(rowMeta);
|
|
|
|
const serverTokens = await this._playerWindowV0_pGetServerTokens({rowMetas: [rowMeta]});
|
|
const clientData = await PeerUtilV0.pInitialiseClient(
|
|
serverTokens[0],
|
|
msg => clientView.handleMessage(msg),
|
|
() => {}, // ignore local errors
|
|
);
|
|
clientView.clientData = clientData;
|
|
await PeerUtilV0.pConnectClientsToServers([rowMeta.serverInfo], clientData.textifiedSdp);
|
|
}
|
|
}
|