@geckos.io/client
Advanced tools
Comparing version 2.0.0-dev.4 to 2.0.0
@@ -1,3 +0,3 @@ | ||
import client from './geckos/channel'; | ||
import client from './geckos/channel.js'; | ||
export default client; | ||
//# sourceMappingURL=bundle.d.ts.map |
@@ -1,8 +0,3 @@ | ||
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var channel_1 = __importDefault(require("./geckos/channel")); | ||
exports.default = channel_1.default; | ||
import client from './geckos/channel.js'; | ||
export default client; | ||
//# sourceMappingURL=bundle.js.map |
@@ -1,2 +0,2 @@ | ||
import * as Types from '@geckos.io/common/lib/types'; | ||
import * as Types from '@geckos.io/common/lib/types.js'; | ||
export declare class ClientChannel { | ||
@@ -3,0 +3,0 @@ maxMessageSize: number | undefined; |
@@ -1,84 +0,36 @@ | ||
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __generator = (this && this.__generator) || function (thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
} | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ClientChannel = void 0; | ||
var connectionsManager_1 = __importDefault(require("../wrtc/connectionsManager")); | ||
var constants_1 = require("@geckos.io/common/lib/constants"); | ||
var peerConnection_1 = __importDefault(require("../wrtc/peerConnection")); | ||
var reliableMessage_1 = require("@geckos.io/common/lib/reliableMessage"); | ||
var ClientChannel = /** @class */ (function () { | ||
function ClientChannel(url, authorization, port, label, rtcConfiguration // eslint-disable-line no-undef | ||
import ConnectionsManagerClient from '../wrtc/connectionsManager.js'; | ||
import { EVENTS } from '@geckos.io/common/lib/constants.js'; | ||
import PeerConnection from '../wrtc/peerConnection.js'; | ||
import { makeReliable } from '@geckos.io/common/lib/reliableMessage.js'; | ||
export class ClientChannel { | ||
constructor(url, authorization, port, label, rtcConfiguration // eslint-disable-line no-undef | ||
) { | ||
var _this = this; | ||
this.userData = {}; | ||
// stores all reliable messages for about 15 seconds | ||
this.receivedReliableMessages = []; | ||
this.url = port ? url + ":" + port : url; | ||
this.connectionsManager = new connectionsManager_1.default(this.url, authorization, label, rtcConfiguration); | ||
this.url = port ? `${url}:${port}` : url; | ||
this.connectionsManager = new ConnectionsManagerClient(this.url, authorization, label, rtcConfiguration); | ||
this.bridge = this.connectionsManager.bridge; | ||
// remove all event listeners on disconnect | ||
this.bridge.on(constants_1.EVENTS.DISCONNECTED, function () { return _this.bridge.removeAllListeners(); }); | ||
this.bridge.on(EVENTS.DISCONNECTED, () => this.bridge.removeAllListeners()); | ||
} | ||
ClientChannel.prototype.onconnectionstatechange = function () { | ||
var _this = this; | ||
var lpc = this.peerConnection.localPeerConnection; | ||
lpc.onconnectionstatechange = function () { | ||
onconnectionstatechange() { | ||
const lpc = this.peerConnection.localPeerConnection; | ||
lpc.onconnectionstatechange = () => { | ||
if (lpc.connectionState === 'disconnected' || lpc.connectionState === 'closed') | ||
_this.bridge.emit(constants_1.EVENTS.DISCONNECTED); | ||
this.bridge.emit(EVENTS.DISCONNECTED); | ||
}; | ||
}; | ||
Object.defineProperty(ClientChannel.prototype, "id", { | ||
/** Get the channel's id. */ | ||
get: function () { | ||
return this.peerConnection.id; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
} | ||
/** Get the channel's id. */ | ||
get id() { | ||
return this.peerConnection.id; | ||
} | ||
/** Close the WebRTC connection */ | ||
ClientChannel.prototype.close = function () { | ||
close() { | ||
this.peerConnection.localPeerConnection.close(); | ||
// fire the DISCONNECTED event manually | ||
this.bridge.emit(constants_1.EVENTS.DISCONNECTED); | ||
this.bridge.emit(EVENTS.DISCONNECTED); | ||
try { | ||
var host = this.url + "/.wrtc/v2"; | ||
fetch(host + "/connections/" + this.id + "/close", { | ||
const host = `${this.url}/.wrtc/v2`; | ||
fetch(`${host}/connections/${this.id}/close`, { | ||
method: 'POST', | ||
@@ -93,15 +45,11 @@ headers: { | ||
} | ||
}; | ||
} | ||
/** Emit a message to the server. */ | ||
ClientChannel.prototype.emit = function (eventName, data, options) { | ||
var _this = this; | ||
if (data === void 0) { data = null; } | ||
emit(eventName, data = null, options) { | ||
if (options && options.reliable) { | ||
reliableMessage_1.makeReliable(options, function (id) { | ||
return _this.connectionsManager.emit(eventName, { | ||
MESSAGE: data, | ||
RELIABLE: 1, | ||
ID: id | ||
}); | ||
}); | ||
makeReliable(options, (id) => this.connectionsManager.emit(eventName, { | ||
MESSAGE: data, | ||
RELIABLE: 1, | ||
ID: id | ||
})); | ||
} | ||
@@ -111,18 +59,13 @@ else { | ||
} | ||
}; | ||
Object.defineProperty(ClientChannel.prototype, "raw", { | ||
/** Emit a raw message to the server */ | ||
get: function () { | ||
var _this = this; | ||
return { | ||
/** | ||
* Emit a raw message. | ||
* @param rawMessage The raw message. Can be of type 'USVString | ArrayBuffer | ArrayBufferView' | ||
*/ | ||
emit: function (rawMessage) { return _this.emit(constants_1.EVENTS.RAW_MESSAGE, rawMessage); } | ||
}; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
} | ||
/** Emit a raw message to the server */ | ||
get raw() { | ||
return { | ||
/** | ||
* Emit a raw message. | ||
* @param rawMessage The raw message. Can be of type 'USVString | ArrayBuffer | ArrayBufferView' | ||
*/ | ||
emit: (rawMessage) => this.emit(EVENTS.RAW_MESSAGE, rawMessage) | ||
}; | ||
} | ||
/** | ||
@@ -132,8 +75,8 @@ * Listen for a raw message from the server. | ||
*/ | ||
ClientChannel.prototype.onRaw = function (callback) { | ||
this.bridge.on(constants_1.EVENTS.RAW_MESSAGE, function (rawMessage) { | ||
var cb = function (rawMessage) { return callback(rawMessage); }; | ||
onRaw(callback) { | ||
this.bridge.on(EVENTS.RAW_MESSAGE, (rawMessage) => { | ||
const cb = (rawMessage) => callback(rawMessage); | ||
cb(rawMessage); | ||
}); | ||
}; | ||
} | ||
/** | ||
@@ -143,31 +86,21 @@ * Listen for the connect event. | ||
*/ | ||
ClientChannel.prototype.onConnect = function (callback) { | ||
async onConnect(callback) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function () { | ||
var response; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
this.peerConnection = new peerConnection_1.default(); | ||
return [4 /*yield*/, this.peerConnection.connect(this.connectionsManager)]; | ||
case 1: | ||
response = _b.sent(); | ||
if (response.error) | ||
callback(response.error); | ||
else { | ||
// set the userData | ||
if (response.userData) | ||
this.userData = response.userData; | ||
// keep track of the maxMessageSize | ||
this.maxMessageSize = this.connectionsManager.maxMessageSize = (_a = this.peerConnection.localPeerConnection.sctp) === null || _a === void 0 ? void 0 : _a.maxMessageSize; | ||
// init onConnectionStateChange event | ||
this.onconnectionstatechange(); | ||
// we are now ready | ||
callback(); | ||
} | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
}; | ||
this.peerConnection = new PeerConnection(); | ||
const response = await this.peerConnection.connect(this.connectionsManager); | ||
if (response.error) | ||
callback(response.error); | ||
else { | ||
// set the userData | ||
if (response.userData) | ||
this.userData = response.userData; | ||
// keep track of the maxMessageSize | ||
this.maxMessageSize = this.connectionsManager.maxMessageSize = | ||
(_a = this.peerConnection.localPeerConnection.sctp) === null || _a === void 0 ? void 0 : _a.maxMessageSize; | ||
// init onConnectionStateChange event | ||
this.onconnectionstatechange(); | ||
// we are now ready | ||
callback(); | ||
} | ||
} | ||
/** | ||
@@ -177,5 +110,5 @@ * Listen for the disconnect event. | ||
*/ | ||
ClientChannel.prototype.onDisconnect = function (callback) { | ||
this.bridge.on(constants_1.EVENTS.DISCONNECTED, callback); | ||
}; | ||
onDisconnect(callback) { | ||
this.bridge.on(EVENTS.DISCONNECTED, callback); | ||
} | ||
/** | ||
@@ -186,12 +119,11 @@ * Listen for a message from the server. | ||
*/ | ||
ClientChannel.prototype.on = function (eventName, callback) { | ||
var _this = this; | ||
this.bridge.on(eventName, function (data) { | ||
on(eventName, callback) { | ||
this.bridge.on(eventName, (data) => { | ||
// check if message is reliable | ||
// and reject it if it has already been submitted | ||
var isReliableMessage = data && data.RELIABLE === 1 && data.ID !== 'undefined'; | ||
var expireTime = 15000; // 15 seconds | ||
var deleteExpiredReliableMessages = function () { | ||
var currentTime = new Date().getTime(); | ||
_this.receivedReliableMessages.forEach(function (msg, index, object) { | ||
const isReliableMessage = data && data.RELIABLE === 1 && data.ID !== 'undefined'; | ||
const expireTime = 15000; // 15 seconds | ||
const deleteExpiredReliableMessages = () => { | ||
const currentTime = new Date().getTime(); | ||
this.receivedReliableMessages.forEach((msg, index, object) => { | ||
if (msg.expire <= currentTime) { | ||
@@ -204,4 +136,4 @@ object.splice(index, 1); | ||
deleteExpiredReliableMessages(); | ||
if (_this.receivedReliableMessages.filter(function (obj) { return obj.id === data.ID; }).length === 0) { | ||
_this.receivedReliableMessages.push({ | ||
if (this.receivedReliableMessages.filter(obj => obj.id === data.ID).length === 0) { | ||
this.receivedReliableMessages.push({ | ||
id: data.ID, | ||
@@ -221,6 +153,4 @@ timestamp: new Date(), | ||
}); | ||
}; | ||
return ClientChannel; | ||
}()); | ||
exports.ClientChannel = ClientChannel; | ||
} | ||
} | ||
/** | ||
@@ -234,8 +164,7 @@ * The geckos.io client library. | ||
*/ | ||
var geckosClient = function (options) { | ||
if (options === void 0) { options = {}; } | ||
var _a = options.authorization, authorization = _a === void 0 ? undefined : _a, _b = options.iceServers, iceServers = _b === void 0 ? [] : _b, _c = options.iceTransportPolicy, iceTransportPolicy = _c === void 0 ? 'all' : _c, _d = options.label, label = _d === void 0 ? 'geckos.io' : _d, _e = options.port, port = _e === void 0 ? 9208 : _e, _f = options.url, url = _f === void 0 ? location.protocol + "//" + location.hostname : _f; | ||
return new ClientChannel(url, authorization, port, label, { iceServers: iceServers, iceTransportPolicy: iceTransportPolicy }); | ||
const geckosClient = (options = {}) => { | ||
const { authorization = undefined, iceServers = [], iceTransportPolicy = 'all', label = 'geckos.io', port = 9208, url = `${location.protocol}//${location.hostname}` } = options; | ||
return new ClientChannel(url, authorization, port, label, { iceServers, iceTransportPolicy }); | ||
}; | ||
exports.default = geckosClient; | ||
export default geckosClient; | ||
//# sourceMappingURL=channel.js.map |
@@ -1,3 +0,3 @@ | ||
import { ChannelId, Data, RawMessage } from '@geckos.io/common/lib/types'; | ||
import client, { ClientChannel } from './geckos/channel'; | ||
import { ChannelId, Data, RawMessage } from '@geckos.io/common/lib/types.js'; | ||
import client, { ClientChannel } from './geckos/channel.js'; | ||
export default client; | ||
@@ -4,0 +4,0 @@ export { client as geckos }; |
@@ -1,26 +0,4 @@ | ||
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||
Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||
}) : function(o, v) { | ||
o["default"] = v; | ||
}); | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
__setModuleDefault(result, mod); | ||
return result; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.geckos = void 0; | ||
var channel_1 = __importStar(require("./geckos/channel")); | ||
exports.geckos = channel_1.default; | ||
exports.default = channel_1.default; | ||
import client, { ClientChannel } from './geckos/channel.js'; | ||
export default client; | ||
export { client as geckos }; | ||
//# sourceMappingURL=index.js.map |
@@ -1,3 +0,3 @@ | ||
import { ChannelId, Data, EventName, RawMessage } from '@geckos.io/common/lib/types'; | ||
import { Bridge } from '@geckos.io/common/lib/bridge'; | ||
import { ChannelId, Data, EventName, RawMessage } from '@geckos.io/common/lib/types.js'; | ||
import { Bridge } from '@geckos.io/common/lib/bridge.js'; | ||
interface RTCRemotePeerConnection { | ||
@@ -4,0 +4,0 @@ id: ChannelId; |
@@ -1,60 +0,7 @@ | ||
"use strict"; | ||
var __assign = (this && this.__assign) || function () { | ||
__assign = Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __generator = (this && this.__generator) || function (thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
} | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var bridge_1 = require("@geckos.io/common/lib/bridge"); | ||
var parseMessage_1 = __importDefault(require("@geckos.io/common/lib/parseMessage")); | ||
var sendMessage_1 = __importDefault(require("@geckos.io/common/lib/sendMessage")); | ||
var ConnectionsManagerClient = /** @class */ (function () { | ||
function ConnectionsManagerClient(url, authorization, label, rtcConfiguration // eslint-disable-line no-undef | ||
import { Bridge } from '@geckos.io/common/lib/bridge.js'; | ||
import ParseMessage from '@geckos.io/common/lib/parseMessage.js'; | ||
import SendMessage from '@geckos.io/common/lib/sendMessage.js'; | ||
export default class ConnectionsManagerClient { | ||
constructor(url, authorization, label, rtcConfiguration // eslint-disable-line no-undef | ||
) { | ||
var _this = this; | ||
this.url = url; | ||
@@ -64,182 +11,155 @@ this.authorization = authorization; | ||
this.rtcConfiguration = rtcConfiguration; | ||
this.bridge = new bridge_1.Bridge(); | ||
this.onDataChannel = function (ev) { | ||
var channel = ev.channel; | ||
if (channel.label !== _this.label) | ||
this.bridge = new Bridge(); | ||
this.onDataChannel = (ev) => { | ||
const { channel } = ev; | ||
if (channel.label !== this.label) | ||
return; | ||
_this.dataChannel = channel; | ||
this.dataChannel = channel; | ||
// set default binaryType to arraybuffer | ||
// https://github.com/node-webrtc/node-webrtc/issues/441 | ||
_this.dataChannel.binaryType = 'arraybuffer'; | ||
_this.dataChannel.onmessage = function (ev) { | ||
var _a = parseMessage_1.default(ev), key = _a.key, data = _a.data; | ||
_this.bridge.emit(key, data); | ||
this.dataChannel.binaryType = 'arraybuffer'; | ||
this.dataChannel.onmessage = (ev) => { | ||
const { key, data } = ParseMessage(ev); | ||
this.bridge.emit(key, data); | ||
}; | ||
}; | ||
} | ||
ConnectionsManagerClient.prototype.emit = function (eventName, data) { | ||
if (data === void 0) { data = null; } | ||
sendMessage_1.default(this.dataChannel, this.maxMessageSize, eventName, data); | ||
}; | ||
emit(eventName, data = null) { | ||
SendMessage(this.dataChannel, this.maxMessageSize, eventName, data); | ||
} | ||
// fetch additional candidates | ||
ConnectionsManagerClient.prototype.fetchAdditionalCandidates = function (host, id) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var res, candidates; | ||
var _this = this; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, fetch(host + "/connections/" + id + "/additional-candidates", { | ||
method: 'GET', | ||
headers: { | ||
'Content-Type': 'application/json' | ||
} | ||
})]; | ||
case 1: | ||
res = _a.sent(); | ||
if (!res.ok) return [3 /*break*/, 3]; | ||
return [4 /*yield*/, res.json() | ||
// eslint-disable-next-line no-undef | ||
]; | ||
case 2: | ||
candidates = _a.sent(); | ||
// eslint-disable-next-line no-undef | ||
candidates.forEach(function (c) { | ||
// eslint-disable-line no-undef | ||
_this.localPeerConnection.addIceCandidate(c); | ||
}); | ||
_a.label = 3; | ||
case 3: return [2 /*return*/]; | ||
} | ||
async fetchAdditionalCandidates(host, id) { | ||
const res = await fetch(`${host}/connections/${id}/additional-candidates`, { | ||
method: 'GET', | ||
headers: { | ||
'Content-Type': 'application/json' | ||
} | ||
}); | ||
if (res.ok) { | ||
const candidates = await res.json(); | ||
// eslint-disable-next-line no-undef | ||
candidates.forEach((c) => { | ||
// eslint-disable-line no-undef | ||
this.localPeerConnection.addIceCandidate(c); | ||
}); | ||
} | ||
} | ||
async connect() { | ||
const host = `${this.url}/.wrtc/v2`; | ||
let headers = { 'Content-Type': 'application/json' }; | ||
if (this.authorization) | ||
headers = { ...headers, ['Authorization']: this.authorization }; | ||
let userData = {}; | ||
try { | ||
const res = await fetch(`${host}/connections`, { | ||
method: 'POST', | ||
headers | ||
}); | ||
if (res.status >= 300) { | ||
throw { | ||
name: 'Error', | ||
message: `Connection failed with status code ${res.status}.`, | ||
status: res.status, | ||
statusText: res.statusText | ||
}; | ||
} | ||
const json = await res.json(); | ||
userData = json.userData; | ||
this.remotePeerConnection = json; | ||
} | ||
catch (error) { | ||
console.error(error.message); | ||
return { error }; | ||
} | ||
const { id, localDescription } = this.remotePeerConnection; | ||
/** | ||
* testing | ||
*/ | ||
// console.log(localDescription.sdp?.split('\n')) | ||
// remove all host type candidates (for testing) | ||
// let removedHostCandidates: any[] = [] | ||
// localDescription.sdp = localDescription.sdp | ||
// ?.split('\n') | ||
// .filter(line => { | ||
// if (/typ host/.test(line)) { | ||
// console.log('removing', line) | ||
// removedHostCandidates.push(line.replace('a=', '').trim()) | ||
// } | ||
// return !/typ host/.test(line) | ||
// }) | ||
// .join('\n') | ||
// console.log(localDescription.sdp) | ||
// add all (host) candidates manually | ||
// setTimeout(() => { | ||
// removedHostCandidates.forEach(candidate => { | ||
// console.log('try to add candidate: ', candidate) | ||
// this.localPeerConnection.addIceCandidate({ candidate, sdpMid: '0', sdpMLineIndex: 0 }) | ||
// }) | ||
// }, 2000) | ||
// eslint-disable-next-line no-undef | ||
const configuration = { | ||
// @ts-ignore | ||
sdpSemantics: 'unified-plan', | ||
...this.rtcConfiguration | ||
}; | ||
const RTCPc = RTCPeerConnection || webkitRTCPeerConnection; // eslint-disable-line no-undef | ||
// create rtc peer connection | ||
this.localPeerConnection = new RTCPc(configuration); | ||
// get additional ice candidates | ||
// we do still continue to gather candidates even if the connection is established, | ||
// maybe we get a better connection. | ||
// So the server is still gathering candidates and we ask for them frequently. | ||
const showBackOffIntervals = (attempts = 10, initial = 50, factor = 1.8, jitter = 20) => Array(attempts) | ||
.fill(0) | ||
.map((_, index) => parseInt((initial * factor ** index).toString()) + parseInt((Math.random() * jitter).toString())); | ||
showBackOffIntervals().forEach(ms => { | ||
setTimeout(() => { | ||
this.fetchAdditionalCandidates(host, id); | ||
}, ms); | ||
}); | ||
}; | ||
ConnectionsManagerClient.prototype.connect = function () { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var host, headers, userData, res, json, error_1, _a, id, localDescription, configuration, RTCPc, showBackOffIntervals, originalAnswer, updatedAnswer, error_2, waitForDataChannel, error_3; | ||
var _b; | ||
var _this = this; | ||
return __generator(this, function (_c) { | ||
switch (_c.label) { | ||
case 0: | ||
host = this.url + "/.wrtc/v2"; | ||
headers = { 'Content-Type': 'application/json' }; | ||
if (this.authorization) | ||
headers = __assign(__assign({}, headers), (_b = {}, _b['Authorization'] = this.authorization, _b)); | ||
userData = {}; | ||
_c.label = 1; | ||
case 1: | ||
_c.trys.push([1, 4, , 5]); | ||
return [4 /*yield*/, fetch(host + "/connections", { | ||
method: 'POST', | ||
headers: headers | ||
})]; | ||
case 2: | ||
res = _c.sent(); | ||
if (res.status >= 300) { | ||
throw { | ||
name: 'Error', | ||
message: "Connection failed with status code " + res.status + ".", | ||
status: res.status, | ||
statusText: res.statusText | ||
}; | ||
} | ||
return [4 /*yield*/, res.json()]; | ||
case 3: | ||
json = _c.sent(); | ||
userData = json.userData; | ||
this.remotePeerConnection = json; | ||
return [3 /*break*/, 5]; | ||
case 4: | ||
error_1 = _c.sent(); | ||
console.error(error_1.message); | ||
return [2 /*return*/, { error: error_1 }]; | ||
case 5: | ||
_a = this.remotePeerConnection, id = _a.id, localDescription = _a.localDescription; | ||
configuration = __assign({ | ||
// @ts-ignore | ||
sdpSemantics: 'unified-plan' }, this.rtcConfiguration); | ||
RTCPc = RTCPeerConnection || webkitRTCPeerConnection // eslint-disable-line no-undef | ||
; | ||
// create rtc peer connection | ||
this.localPeerConnection = new RTCPc(configuration); | ||
showBackOffIntervals = function (attempts, initial, factor, jitter) { | ||
if (attempts === void 0) { attempts = 10; } | ||
if (initial === void 0) { initial = 50; } | ||
if (factor === void 0) { factor = 1.8; } | ||
if (jitter === void 0) { jitter = 20; } | ||
return Array(attempts) | ||
.fill(0) | ||
.map(function (_, index) { return parseInt((initial * Math.pow(factor, index)).toString()) + parseInt((Math.random() * jitter).toString()); }); | ||
}; | ||
showBackOffIntervals().forEach(function (ms) { | ||
setTimeout(function () { | ||
_this.fetchAdditionalCandidates(host, id); | ||
}, ms); | ||
}); | ||
_c.label = 6; | ||
case 6: | ||
_c.trys.push([6, 16, , 17]); | ||
return [4 /*yield*/, this.localPeerConnection.setRemoteDescription(localDescription)]; | ||
case 7: | ||
_c.sent(); | ||
this.localPeerConnection.addEventListener('datachannel', this.onDataChannel, { once: true }); | ||
return [4 /*yield*/, this.localPeerConnection.createAnswer()]; | ||
case 8: | ||
originalAnswer = _c.sent(); | ||
updatedAnswer = new RTCSessionDescription({ | ||
type: 'answer', | ||
sdp: originalAnswer.sdp | ||
}); | ||
return [4 /*yield*/, this.localPeerConnection.setLocalDescription(updatedAnswer)]; | ||
case 9: | ||
_c.sent(); | ||
_c.label = 10; | ||
case 10: | ||
_c.trys.push([10, 12, , 13]); | ||
return [4 /*yield*/, fetch(host + "/connections/" + id + "/remote-description", { | ||
method: 'POST', | ||
body: JSON.stringify(this.localPeerConnection.localDescription), | ||
headers: { | ||
'Content-Type': 'application/json' | ||
} | ||
})]; | ||
case 11: | ||
_c.sent(); | ||
return [3 /*break*/, 13]; | ||
case 12: | ||
error_2 = _c.sent(); | ||
console.error(error_2.message); | ||
return [2 /*return*/, { error: error_2 }]; | ||
case 13: | ||
waitForDataChannel = function () { | ||
return new Promise(function (resolve) { | ||
_this.localPeerConnection.addEventListener('datachannel', function () { | ||
resolve(); | ||
}, { once: true }); | ||
}); | ||
}; | ||
if (!!this.dataChannel) return [3 /*break*/, 15]; | ||
return [4 /*yield*/, waitForDataChannel()]; | ||
case 14: | ||
_c.sent(); | ||
_c.label = 15; | ||
case 15: return [2 /*return*/, { | ||
userData: userData, | ||
localPeerConnection: this.localPeerConnection, | ||
dataChannel: this.dataChannel, | ||
id: id | ||
}]; | ||
case 16: | ||
error_3 = _c.sent(); | ||
console.error(error_3.message); | ||
this.localPeerConnection.close(); | ||
return [2 /*return*/, { error: error_3 }]; | ||
case 17: return [2 /*return*/]; | ||
} | ||
try { | ||
await this.localPeerConnection.setRemoteDescription(localDescription); | ||
this.localPeerConnection.addEventListener('datachannel', this.onDataChannel, { once: true }); | ||
const originalAnswer = await this.localPeerConnection.createAnswer(); | ||
const updatedAnswer = new RTCSessionDescription({ | ||
type: 'answer', | ||
sdp: originalAnswer.sdp | ||
}); | ||
}); | ||
}; | ||
return ConnectionsManagerClient; | ||
}()); | ||
exports.default = ConnectionsManagerClient; | ||
await this.localPeerConnection.setLocalDescription(updatedAnswer); | ||
try { | ||
await fetch(`${host}/connections/${id}/remote-description`, { | ||
method: 'POST', | ||
body: JSON.stringify(this.localPeerConnection.localDescription), | ||
headers: { | ||
'Content-Type': 'application/json' | ||
} | ||
}); | ||
} | ||
catch (error) { | ||
console.error(error.message); | ||
return { error }; | ||
} | ||
const waitForDataChannel = () => { | ||
return new Promise(resolve => { | ||
this.localPeerConnection.addEventListener('datachannel', () => { | ||
resolve(); | ||
}, { once: true }); | ||
}); | ||
}; | ||
if (!this.dataChannel) | ||
await waitForDataChannel(); | ||
return { | ||
userData, | ||
localPeerConnection: this.localPeerConnection, | ||
dataChannel: this.dataChannel, | ||
id: id | ||
}; | ||
} | ||
catch (error) { | ||
console.error(error.message); | ||
this.localPeerConnection.close(); | ||
return { error }; | ||
} | ||
} | ||
} | ||
//# sourceMappingURL=connectionsManager.js.map |
@@ -1,3 +0,3 @@ | ||
import { ChannelId } from '@geckos.io/common/lib/types'; | ||
import ConnectionsManagerClient from './connectionsManager'; | ||
import { ChannelId } from '@geckos.io/common/lib/types.js'; | ||
import ConnectionsManagerClient from './connectionsManager.js'; | ||
export default class PeerConnection { | ||
@@ -4,0 +4,0 @@ dataChannel: RTCDataChannel; |
@@ -1,74 +0,23 @@ | ||
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __generator = (this && this.__generator) || function (thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
import { ERRORS } from '@geckos.io/common/lib/constants.js'; | ||
export default class PeerConnection { | ||
async connect(connectionsManager) { | ||
const webRTCPcSupported = RTCPeerConnection || webkitRTCPeerConnection; // eslint-disable-line no-undef | ||
if (webRTCPcSupported) { | ||
const { localPeerConnection, dataChannel, id, userData, error } = await connectionsManager.connect(); | ||
if (error) | ||
return { error }; | ||
if (!localPeerConnection || !dataChannel || !id || !userData) | ||
return { error: new Error('Something went wrong in "await connectionsManager.connect()"') }; | ||
this.localPeerConnection = localPeerConnection; | ||
this.dataChannel = dataChannel; | ||
this.id = id; | ||
return { userData }; | ||
} | ||
else { | ||
const error = new Error(ERRORS.BROWSER_NOT_SUPPORTED); | ||
console.error(error.message); | ||
return { error }; | ||
} | ||
} | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var constants_1 = require("@geckos.io/common/lib/constants"); | ||
var PeerConnection = /** @class */ (function () { | ||
function PeerConnection() { | ||
} | ||
PeerConnection.prototype.connect = function (connectionsManager) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var webRTCPcSupported, _a, localPeerConnection, dataChannel, id, userData, error, error; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
webRTCPcSupported = RTCPeerConnection || webkitRTCPeerConnection // eslint-disable-line no-undef | ||
; | ||
if (!webRTCPcSupported) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, connectionsManager.connect()]; | ||
case 1: | ||
_a = _b.sent(), localPeerConnection = _a.localPeerConnection, dataChannel = _a.dataChannel, id = _a.id, userData = _a.userData, error = _a.error; | ||
if (error) | ||
return [2 /*return*/, { error: error }]; | ||
if (!localPeerConnection || !dataChannel || !id || !userData) | ||
return [2 /*return*/, { error: new Error('Something went wrong in "await connectionsManager.connect()"') }]; | ||
this.localPeerConnection = localPeerConnection; | ||
this.dataChannel = dataChannel; | ||
this.id = id; | ||
return [2 /*return*/, { userData: userData }]; | ||
case 2: | ||
error = new Error(constants_1.ERRORS.BROWSER_NOT_SUPPORTED); | ||
console.error(error.message); | ||
return [2 /*return*/, { error: error }]; | ||
} | ||
}); | ||
}); | ||
}; | ||
return PeerConnection; | ||
}()); | ||
exports.default = PeerConnection; | ||
} | ||
//# sourceMappingURL=peerConnection.js.map |
{ | ||
"name": "@geckos.io/client", | ||
"version": "2.0.0-dev.4", | ||
"version": "2.0.0", | ||
"description": "Real-time client/server communication over UDP using WebRTC and Node.js", | ||
"main": "./lib/index.js", | ||
"types": "./lib/index.d.ts", | ||
"type": "module", | ||
"author": "Yannick Deubel (https://github.com/yandeu)", | ||
@@ -37,5 +38,8 @@ "license": "BSD-3-Clause", | ||
}, | ||
"engines": { | ||
"node": "^14.15 || >=16" | ||
}, | ||
"scripts": { | ||
"bundle": "npm run bundle:version", | ||
"bundle:version": "cross-env-shell ../../node_modules/.bin/webpack --config webpack/webpack.prod.js --env path=../../../bundles --env packageVersion=${npm_package_version}", | ||
"bundle:version": "cross-env-shell ../../node_modules/.bin/webpack --config webpack/webpack.prod.cjs --env path=../../../bundles --env packageVersion=${npm_package_version}", | ||
"build": "tsc --build tsconfig.json", | ||
@@ -45,3 +49,3 @@ "prepublishOnly": "npm run build" | ||
"dependencies": { | ||
"@geckos.io/common": "^2.0.0-dev.4" | ||
"@geckos.io/common": "^2.0.0" | ||
}, | ||
@@ -48,0 +52,0 @@ "funding": { |
@@ -14,2 +14,3 @@ <a href="http://geckos.io"> | ||
![NPM](https://img.shields.io/npm/l/@geckos.io/client.svg?style=flat-square) | ||
[![ES Modules Badge](https://img.shields.io/badge/Node.js-ES%20Modules-F7DF1E?style=flat-square)](https://github.com/yandeu/yandeu/blob/main/posts/2020-05-28-esm-for-nodejs.md) | ||
@@ -16,0 +17,0 @@ Real-time client/server communication over UDP using **WebRTC** and **Node.js**. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
0
51
Yes
36611
464
5
Updated@geckos.io/common@^2.0.0