@skylineos/clsp-player
Version:
Skyline Technology Solutions' CLSP Video Player. Stream video in near-real-time in modern browsers.
207 lines (164 loc) • 4.95 kB
JavaScript
import URL from 'url';
import utils from '../utils/utils';
export default class StreamConfiguration {
static factory (
streamName, host, port, useSSL, tokenConfig,
) {
return new StreamConfiguration(
streamName, host, port, useSSL, tokenConfig,
);
}
static fromObject (config) {
if (!config || !(typeof config === 'object')) {
throw new Error('config must be an object to create a streamConfiguration');
}
return StreamConfiguration.factory(
config.streamName,
config.host,
config.port,
config.useSSL,
{
...config.tokenConfig,
},
);
}
static isStreamConfiguration (target) {
return target instanceof StreamConfiguration;
}
static generateConfigFromUrl (url) {
if (!url) {
throw new Error('No source was given to be parsed!');
}
/* eslint-disable-next-line n/no-deprecated-api */
const parsed = URL.parse(url);
let useSSL;
let defaultPort;
let b64HashAccessUrl = '';
let jwt = '';
parsed.protocol = parsed.protocol.toLowerCase();
// Chrome is the only browser that allows non-http protocols in
// the anchor tag's href, so change them all to http here so we
// get the benefits of the anchor tag's parsing
if (parsed.protocol === 'clsps:') {
useSSL = true;
defaultPort = utils.getDefaultStreamPort('clsps');
}
else if (parsed.protocol === 'clsp:') {
useSSL = false;
defaultPort = utils.getDefaultStreamPort('clsp');
}
else {
throw new Error('The given source is not a clsp url, and therefore cannot be parsed.');
}
const paths = parsed.pathname.split('/');
const streamName = paths[paths.length - 1];
let host = parsed.hostname;
let port = parsed.port;
if (!port || port.length === 0) {
port = defaultPort;
}
port = parseInt(port);
// @ is a special address meaning the server that loaded the web page.
if (host === '@') {
host = window.location.hostname;
}
// URL: clsp[s]://<sfs-addr>[:<port>]/<stream>?token=...
const qpOffset = url.indexOf(parsed.pathname) + parsed.pathname.length;
const qrArgs = url.substr(qpOffset).split('?')[1] || '';
const query = {};
const pairs = qrArgs.split('&');
for (let i = 0; i < pairs.length; i++) {
const pair = pairs[i].split('=');
query[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1] || '');
}
// set the jwt token if it's present in the query path
if (typeof query.token !== 'undefined' && query.token.length > 0) {
const jwtUrl = `${parsed.protocol}://${host}:${port}/${streamName}?token=${query.token}`;
b64HashAccessUrl = window.btoa(jwtUrl);
jwt = query.token;
}
return {
streamName,
host,
port,
useSSL,
tokenConfig: {
b64HashAccessUrl,
jwt,
},
};
}
static fromUrl (url) {
const config = StreamConfiguration.generateConfigFromUrl(url);
return StreamConfiguration.fromObject(config);
}
constructor (
streamName,
host,
port,
useSSL,
tokenConfig = {},
) {
if (!streamName) {
throw new Error('streamName is required to create a stream configuration.');
}
if (!host) {
throw new Error('host is required to create a stream configuration.');
}
if (!port) {
throw new Error('port is required to create a stream configuration.');
}
if (!useSSL && useSSL !== false) {
throw new Error('useSSL is required to create a stream configuration.');
}
if (!tokenConfig || typeof tokenConfig !== 'object') {
throw new Error('tokenConfig is required to create a stream configuration.');
}
this.streamName = streamName;
this.host = host;
this.port = port;
this.useSSL = useSSL;
this.tokenConfig = tokenConfig;
this.isDestroyed = false;
this.isDestroyComplete = false;
}
clone (streamConfiguration) {
if (!StreamConfiguration.isStreamConfiguration(streamConfiguration)) {
throw new Error('Cannot clone with invalid streamConfiguration');
}
const clone = StreamConfiguration.factory(...streamConfiguration.toObject());
return clone;
}
toObject () {
return {
streamName: this.streamName,
host: this.host,
port: this.port,
useSSL: this.useSSL,
tokenConfig: {
...this.tokenConfig,
},
};
}
get protocol () {
return this.useSSL
? 'clsps'
: 'clsp';
}
get url () {
return `${this.protocol}://${this.host}:${this.port}/${this.streamName}`;
}
destroy () {
if (this.isDestroyed) {
return;
}
this.isDestroyed = true;
this.streamName = null;
this.host = null;
this.port = null;
this.useSSL = null;
this.tokenConfig = null;
this.isDestroyComplete = false;
this.logger.info('destroy complete');
}
}