Compare commits

...

12 Commits

36 changed files with 1581 additions and 323 deletions
+2 -2
View File
@@ -11,7 +11,7 @@ for(let arg of process.argv){
}
const config = {
signallingURL: "ws://localhost:8889",
signallingURL: "ws://localhost:0000",
mediasoup: {
worker: {
@@ -25,7 +25,7 @@ const config = {
"rtp",
"srtp",
"rtcp",
"sctp"
"sctp",
// 'rtx',
// 'bwe',
// 'score',
+15
View File
@@ -10,6 +10,7 @@
"dependencies": {
"mediasoup_prebuilt": "^3.8.4",
"mediasoup-sdp-bridge": "file:mediasoup-sdp-bridge",
"run-script-os": "^1.1.6",
"ws": "^7.1.2"
}
},
@@ -176,6 +177,15 @@
"resolved": "https://registry.npmjs.org/random-number/-/random-number-0.0.9.tgz",
"integrity": "sha512-ipG3kRCREi/YQpi2A5QGcvDz1KemohovWmH6qGfboVyyGdR2t/7zQz0vFxrfxpbHQgPPdtVlUDaks3aikD1Ljw=="
},
"node_modules/run-script-os": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/run-script-os/-/run-script-os-1.1.6.tgz",
"integrity": "sha512-ql6P2LzhBTTDfzKts+Qo4H94VUKpxKDFz6QxxwaUZN0mwvi7L3lpOI7BqPCq7lgDh3XLl0dpeXwfcVIitlrYrw==",
"bin": {
"run-os": "index.js",
"run-script-os": "index.js"
}
},
"node_modules/sdp-transform": {
"version": "2.14.1",
"resolved": "https://registry.npmjs.org/sdp-transform/-/sdp-transform-2.14.1.tgz",
@@ -346,6 +356,11 @@
"resolved": "https://registry.npmjs.org/random-number/-/random-number-0.0.9.tgz",
"integrity": "sha512-ipG3kRCREi/YQpi2A5QGcvDz1KemohovWmH6qGfboVyyGdR2t/7zQz0vFxrfxpbHQgPPdtVlUDaks3aikD1Ljw=="
},
"run-script-os": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/run-script-os/-/run-script-os-1.1.6.tgz",
"integrity": "sha512-ql6P2LzhBTTDfzKts+Qo4H94VUKpxKDFz6QxxwaUZN0mwvi7L3lpOI7BqPCq7lgDh3XLl0dpeXwfcVIitlrYrw=="
},
"sdp-transform": {
"version": "2.14.1",
"resolved": "https://registry.npmjs.org/sdp-transform/-/sdp-transform-2.14.1.tgz",
+18 -1
View File
@@ -1,4 +1,17 @@
var server_settings = process.argv.slice(2)
if (!server_settings) {
process.exit(1)
}
try {
server_settings = JSON.parse(server_settings)
} catch (err) {
console.log('can not process arguments')
process.exit(1)
}
const config = require('./config');
config.signallingURL = 'ws://localhost:' + server_settings.sfu_port
const WebSocket = require('ws');
const mediasoup = require('mediasoup_prebuilt');
const mediasoupSdp = require('mediasoup-sdp-bridge');
@@ -12,13 +25,17 @@ function connectSignalling(server) {
console.log("Connecting to Signalling Server at %s", server);
signalServer = new WebSocket(server);
signalServer.addEventListener("open", _ => { console.log(`Connected to signalling server`); });
signalServer.addEventListener("error", result => { console.log(`Error: ${result.message}`); });
signalServer.addEventListener("error", result => { console.log(`Error: ${result.message}`); process.exit()});
signalServer.addEventListener("message", result => onSignallingMessage(result.data));
signalServer.addEventListener("close", result => {
console.log(`Disconnected from signalling server: ${result.code} ${result.reason}`);
console.log("Attempting reconnect to signalling server...");
process.exit()
let death_count = 0
setTimeout(()=> {
connectSignalling(server);
if ((++death_count) > 2)
process.exit()
}, 2000);
});
}
@@ -0,0 +1,3 @@
<svg width="72" height="72" viewBox="0 0 72 72" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M54 35.9999L27.0001 53.9999L27.0001 18L54 35.9999Z" fill="white" stroke="white" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 241 B

@@ -0,0 +1,3 @@
<svg width="106" height="106" viewBox="0 0 106 106" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="53" cy="53" r="53" fill="#454545"/>
</svg>

After

Width:  |  Height:  |  Size: 155 B

+299 -128
View File
@@ -1,20 +1,69 @@
/*Copyright Epic Games, Inc. All Rights Reserved.*/
@import url(./fonts/fonts.css);
:root {
/*Using colour scheme https://color.adobe.com/TD-Colors---Option-3-color-theme-10394433/*/
--colour1:#000000;
--colour2:#FFFFFF;
--colour3:#0585fe;
--colour4:#35b350;
--colour5:#ffab00;
--colour6:#1e1d22;
--colour7:#3c3b40;
--colour1: #151619;
;
--colour2: #FFFFFF;
--colour3: #0585fe;
--colour4: #35b350;
--colour5: #ffab00;
--colour6: #1e1d22;
--colour7: #3c3b40;
}
body{
margin: 0px;
background-color: black;
#loader {
width: 106px;
height: 106px;
border-radius: 50%;
display: inline-block;
position: relative;
background: conic-gradient(from 135deg at 50% 50%,
rgba(255, 255, 255, 0) -6.26deg,
#ffffff 314.83deg,
rgba(255, 255, 255, 0) 353.74deg,
#ffffff 674.83deg);
box-sizing: border-box;
animation: rotation 1s linear infinite;
}
@keyframes rotation {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
#loader::after {
content: "";
box-sizing: border-box;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 100px;
height: 100px;
border-radius: 50%;
background: #151619;
}
body {
margin: 0px;
background-color: #151619;
font-family: 'Montserrat', sans-serif;
}
}
h2 {
font-family: "GilroyWebRegular";
}
#playerUI {
width: 100%;
@@ -22,8 +71,8 @@ body{
}
canvas {
image-rendering: crisp-edges;
position: absolute;
image-rendering: crisp-edges;
position: absolute;
}
video {
@@ -32,14 +81,13 @@ video {
height: 100%;
}
#player{
#player {
width: 100%;
height: 100%;
position: absolute;
background-color: #000;
}
#videoPlayOverlay{
#videoPlayOverlay {
position: absolute;
font-size: 1.8em;
width: 100%;
@@ -48,15 +96,14 @@ video {
}
/* State for element to be clickable */
.clickableState{
.clickableState {
align-items: center;
justify-content: center;
display: flex;
cursor: pointer;
}
/* State for element to show text, this is for informational use*/
.textDisplayState{
.textDisplayState {
align-items: center;
justify-content: center;
display: flex;
@@ -64,21 +111,108 @@ video {
}
/* State to hide overlay, WebRTC communication is in progress and or is playing */
.hiddenState{
.hiddenState {
display: none;
}
#playButton{
display: inline-block;
height: auto;
#playButton {
display: block;
width: 88px;
height: 88px;
z-index: 30;
backdrop-filter: blur(10px);
border-radius: 112px;
cursor: pointer;
}
img#playButton{
max-width: 241px;
width: 10%;
#container {
width: 400px;
height: 100%;
justify-content: center;
/* Background */
background: transparent;
/* Button_1 */
border-width: 0px 2px;
border-style: solid;
border-color: #23242A;
display: flex;
flex-direction: column;
align-items: center;
gap: 40px;
padding: 40px 56px;
box-sizing: border-box;
}
@media screen and (max-width: 500px) {
#container {
width: 100%;
border: none;
}
}
#playButton:hover {
background: linear-gradient(180deg, #BC75FF 0%, #798FFF 100%);
backdrop-filter: blur(10px)
}
#title {
font-style: normal;
font-weight: 400;
font-size: 38px;
line-height: 100%;
/* or 38px */
/* White */
color: #F2F2F2;
margin: 0 0 16px 0;
}
#caption {
font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-size: 16px;
line-height: 140%;
/* or 22px */
text-align: center;
/* Inactive */
color: #C5C7CE;
margin: 0;
text-align: left;
}
#link {
font-family: 'Inter';
cursor: pointer;
background: #1C1D21;
border-radius: 4px;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
text-decoration: none;
padding: 8px 16px;
box-sizing: border-box;
font-weight: 400;
font-size: 12px;
line-height: 130%;
/* identical to box height, or 16px */
/* Inactive */
color: #C5C7CE;
}
#link:hover {
background: #23242A;
}
#freezeFrameOverlay {
background-color: transparent;
}
@@ -117,14 +251,14 @@ img#playButton{
border: 3px solid var(--colour3);
transition: 0.25s ease;
padding-left: 0.55rem;
padding-top: 0.55rem;
padding-top: 0.55rem;
}
#overlay button:active {
border: 3px solid var(--colour3);
background-color: var(--colour7);
padding-left: 0.55rem;
padding-top: 0.55rem;
padding-top: 0.55rem;
}
#overlay img {
@@ -146,7 +280,7 @@ img#playButton{
position: absolute;
top: 0;
transform: translateY(25%);
left: 125%;
left: 125%;
z-index: 20;
}
@@ -158,19 +292,19 @@ img#playButton{
#connection .tooltiptext {
top: 125%;
transform: translateX(-25%);
left: 0;
left: 0;
z-index: 20;
padding: 5px 10px;
}
#settings-panel .tooltiptext {
display: block;
top: 125%;
transform: translateX(-50%);
left: 0;
z-index: 20;
padding: 5px 10px;
border: 3px solid var(--colour5);
top: 125%;
transform: translateX(-50%);
left: 0;
z-index: 20;
padding: 5px 10px;
border: 3px solid var(--colour5);
width: max-content;
}
@@ -180,10 +314,10 @@ img#playButton{
left: 1%;
font-family: 'Michroma', sans-serif;
pointer-events: all;
display: block;
display: none;
}
#controls > * {
#controls>* {
margin-bottom: 0.5rem;
border-radius: 50%;
display: block;
@@ -203,6 +337,7 @@ img#playButton{
right: 10%;
font-family: 'Michroma', sans-serif;
pointer-events: all;
visibility: hidden;
width: min-content;
}
@@ -218,16 +353,23 @@ img#playButton{
font-family: 'Michroma', sans-serif;
height: 3rem;
width: 3rem;
pointer-events: all;
pointer-events: none;
visibility: hidden;
}
.noselect {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
-webkit-touch-callout: none;
/* iOS Safari */
-webkit-user-select: none;
/* Safari */
-khtml-user-select: none;
/* Konqueror HTML */
-moz-user-select: none;
/* Old versions of Firefox */
-ms-user-select: none;
/* Internet Explorer/Edge */
user-select: none;
/* Non-prefixed version, currently
supported by Chrome, Edge, Opera and Firefox */
}
@@ -261,10 +403,10 @@ img#playButton{
#heading {
display: inline-block;
font-size: 2em;
margin-block-start: 0.67em;
margin-block-end: 0.67em;
margin-inline-start: 0px;
margin-inline-end: 0px;
margin-block-start: 0.67em;
margin-block-end: 0.67em;
margin-inline-start: 0px;
margin-inline-end: 0px;
position: relative;
padding: 0 0 0 2rem;
}
@@ -281,7 +423,8 @@ img#playButton{
#close:after {
padding-left: 0.5rem;
display: inline-block;
content: "\00d7"; /* This will render the 'X' */
content: "\00d7";
/* This will render the 'X' */
}
#close:hover {
@@ -301,7 +444,7 @@ img#playButton{
margin: 0.5rem 0;
}
.settings-text{
.settings-text {
margin-right: 2rem;
display: flex;
}
@@ -310,24 +453,44 @@ img#playButton{
.tgl-switch {
vertical-align: middle;
display: inline-block;
}
.tgl-switch .tgl {
display:none;
}
.tgl, .tgl:after, .tgl:before, .tgl *, .tgl *:after, .tgl *:before, .tgl + .tgl-slider {
}
.tgl-switch .tgl {
display: none;
}
.tgl,
.tgl:after,
.tgl:before,
.tgl *,
.tgl *:after,
.tgl *:before,
.tgl+.tgl-slider {
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.tgl::-moz-selection, .tgl:after::-moz-selection, .tgl:before::-moz-selection, .tgl *::-moz-selection, .tgl *:after::-moz-selection, .tgl *:before::-moz-selection, .tgl + .tgl-slider::-moz-selection {
box-sizing: border-box;
}
.tgl::-moz-selection,
.tgl:after::-moz-selection,
.tgl:before::-moz-selection,
.tgl *::-moz-selection,
.tgl *:after::-moz-selection,
.tgl *:before::-moz-selection,
.tgl+.tgl-slider::-moz-selection {
background: none;
}
.tgl::selection, .tgl:after::selection, .tgl:before::selection, .tgl *::selection, .tgl *:after::selection, .tgl *:before::selection, .tgl + .tgl-slider::selection {
}
.tgl::selection,
.tgl:after::selection,
.tgl:before::selection,
.tgl *::selection,
.tgl *:after::selection,
.tgl *:before::selection,
.tgl+.tgl-slider::selection {
background: none;
}
.tgl + .tgl-slider {
}
.tgl+.tgl-slider {
outline: 0;
display: block;
width: 40px;
@@ -335,50 +498,53 @@ img#playButton{
position: relative;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.tgl + .tgl-slider:after, .tgl + .tgl-slider:before {
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.tgl+.tgl-slider:after,
.tgl+.tgl-slider:before {
position: relative;
display: block;
content: "";
width: 50%;
height: 100%;
}
.tgl + .tgl-slider:after {
}
.tgl+.tgl-slider:after {
left: 0;
}
.tgl + .tgl-slider:before {
}
.tgl+.tgl-slider:before {
display: none;
}
.tgl-flat + .tgl-slider {
}
.tgl-flat+.tgl-slider {
padding: 2px;
-webkit-transition: all .2s ease;
transition: all .2s ease;
background: var(--colour6);
border: 3px solid var(--colour7);
border-radius: 2em;
}
.tgl-flat + .tgl-slider:after {
}
.tgl-flat+.tgl-slider:after {
-webkit-transition: all .2s ease;
transition: all .2s ease;
background: var(--colour7);
content: "";
border-radius: 1em;
}
.tgl-flat:checked + .tgl-slider {
}
.tgl-flat:checked+.tgl-slider {
border: 3px solid var(--colour3);
}
.tgl-flat:checked + .tgl-slider:after {
}
.tgl-flat:checked+.tgl-slider:after {
left: 50%;
background: var(--colour3);
}
}
.subtitle-text {
margin: 0 0 0 1rem;
@@ -411,7 +577,8 @@ img#playButton{
#hiddenInput {
position: absolute;
left: -10%; /* Although invisible, push off-screen to prevent user interaction. */
left: -10%;
/* Although invisible, push off-screen to prevent user interaction. */
width: 0px;
opacity: 0;
}
@@ -428,47 +595,50 @@ img#playButton{
}
input {
text-align: right;
text-align: right;
}
.warning {
box-sizing: border-box;
position: relative;
transform: scale(var(--ggs,1));
width: 20px;
height: 20px;
border: 2px solid;
border-radius: 40px;
box-sizing: border-box;
position: relative;
transform: scale(var(--ggs, 1));
width: 20px;
height: 20px;
border: 2px solid;
border-radius: 40px;
display: none;
}
.warning::after,
.warning::before {
content: "";
display: block;
box-sizing: border-box;
position: absolute;
border-radius: 3px;
width: 2px;
background: currentColor;
left: 7px
content: "";
display: block;
box-sizing: border-box;
position: absolute;
border-radius: 3px;
width: 2px;
background: currentColor;
left: 7px
}
.warning::after {
top: 2px;
height: 8px
top: 2px;
height: 8px
}
.warning::before {
height: 2px;
bottom: 2px
height: 2px;
bottom: 2px
}
/* Flat buttons */
input[type="button"] {
background-color: transparent;
color: var(--colour2);
font-family: 'Montserrat';
border: 3px solid var(--colour3);
border-radius: 1rem;
font-size: 0.75rem;
color: var(--colour2);
font-family: 'Montserrat';
border: 3px solid var(--colour3);
border-radius: 1rem;
font-size: 0.75rem;
padding-left: 0.5rem;
padding-right: 0.5rem;
}
@@ -477,6 +647,7 @@ input[type="button"]:hover {
background-color: var(--colour3);
transition: ease 0.3s;
}
input[type="button"]:active {
background-color: transparent;
}
@@ -489,11 +660,11 @@ input[type="button"]:active {
select,
input[type="number"] {
background-color: var(--colour7);
color: var(--colour2);
border: 1px solid var(--colour6);
padding: 0.25rem;
font-family: 'Montserrat';
border-radius: 0.25rem;
color: var(--colour2);
border: 1px solid var(--colour6);
padding: 0.25rem;
font-family: 'Montserrat';
border-radius: 0.25rem;
}
input[type=number]::-webkit-inner-spin-button {
@@ -543,17 +714,17 @@ object {
#afkOverlay {
z-index: 999;
background-color: rgba(30, 29, 34, 0.5);
display: inline-block;
height: 100vh;
width: 100vw;
line-height: 100vh;
text-align: center;
background-color: rgba(30, 29, 34, 0.5);
display: inline-block;
height: 100vh;
width: 100vw;
line-height: 100vh;
text-align: center;
overflow: hidden;
}
#afkOverlay center {
display: inline-block;
line-height: 1.5;
height: 100vh;
line-height: 1.5;
height: 100vh;
}
@@ -9,7 +9,7 @@
<link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16.png">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Michroma&family=Montserrat:wght@600&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Inter&display=swap" rel="stylesheet">
<link type="text/css" rel="stylesheet" href="player.css">
<script type="text/javascript">
// This horrible hack is to make Fippo's adapter-latest.js work with Firefox when not on https
@@ -27,6 +27,10 @@
<script type="text/javascript" src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script type="text/javascript" src="scripts/webRtcPlayer.js"></script>
<script type="text/javascript" src="scripts/app.js"></script>
<script>
inputOptions.controlScheme = ControlSchemeType.HoveringMouse;
inputOptions.fakeMouseWithTouches = true;
</script>
</head>
<body onload="load()">
@@ -47,35 +51,39 @@
<object data="images/Info.svg" type="image/svg+xml"></object>
<span class="tooltiptext">Information</span>
</button>
</div>
<div id="unrealengine">
<p></p>
<svg viewBox="0 0 1204.105 74.011" xmlns="http://www.w3.org/2000/svg">
<g id="svgGroup" stroke-linecap="round" fill-rule="evenodd" font-size="9pt" stroke="#ffffff" stroke-width="0.25mm" fill="#ffffff" style="stroke:#ffffff;stroke-width:0.25mm;fill:#ffffff">
<path d="M 894.605 74.006 L 921.305 74.006 C 942.427 74.006 953.413 73.292 956.313 60.527 A 37.848 37.848 0 0 0 957.105 52.206 L 957.105 31.606 L 907.305 31.606 L 907.305 46.606 L 934.905 46.606 L 934.905 48.706 C 934.905 53.442 932.251 55.385 928.738 56.147 A 26.156 26.156 0 0 1 923.305 56.606 L 899.605 56.606 A 39.408 39.408 0 0 1 894.638 56.344 C 888.593 55.565 886.231 52.853 885.654 45.747 A 52.88 52.88 0 0 1 885.505 41.506 L 885.505 32.506 A 48.028 48.028 0 0 1 885.738 27.377 C 886.556 19.865 889.695 17.689 897.793 17.433 A 57.321 57.321 0 0 1 899.605 17.406 L 923.705 17.406 A 38.323 38.323 0 0 1 927.889 17.588 C 932.328 18.085 934.835 19.818 934.904 25.273 A 18.461 18.461 0 0 1 934.905 25.506 L 956.705 25.506 L 956.705 23.206 A 36.235 36.235 0 0 0 955.47 12.587 C 953.178 5.214 946.987 0.624 931.363 0.064 A 93.813 93.813 0 0 0 928.005 0.006 L 894.605 0.006 C 874.839 0.006 862.985 4.89 862.71 25.469 A 55.259 55.259 0 0 0 862.705 26.206 L 862.705 47.806 A 39.6 39.6 0 0 0 863.741 57.358 C 866.906 70.059 877.192 73.722 892.685 73.99 A 111.289 111.289 0 0 0 894.605 74.006 Z M 323.405 73.206 L 403.905 73.206 L 403.905 55.806 L 345.605 55.806 L 345.605 44.206 L 399.605 44.206 L 399.605 29.206 L 345.605 29.206 L 345.605 17.606 L 402.605 17.606 L 402.605 0.806 L 323.405 0.806 L 323.405 73.206 Z M 656.905 73.206 L 737.405 73.206 L 737.405 55.806 L 679.105 55.806 L 679.105 44.206 L 733.105 44.206 L 733.105 29.206 L 679.105 29.206 L 679.105 17.606 L 736.105 17.606 L 736.105 0.806 L 656.905 0.806 L 656.905 73.206 Z M 1123.605 73.206 L 1204.105 73.206 L 1204.105 55.806 L 1145.805 55.806 L 1145.805 44.206 L 1199.805 44.206 L 1199.805 29.206 L 1145.805 29.206 L 1145.805 17.606 L 1202.805 17.606 L 1202.805 0.806 L 1123.605 0.806 L 1123.605 73.206 Z M 106.205 73.206 L 128.405 73.206 L 128.405 20.606 L 128.605 20.606 L 170.305 73.206 L 204.705 73.206 L 204.705 0.806 L 182.505 0.806 L 182.505 53.406 L 182.305 53.406 L 140.605 0.806 L 106.205 0.806 L 106.205 73.206 Z M 750.805 73.206 L 773.005 73.206 L 773.005 20.606 L 773.205 20.606 L 814.905 73.206 L 849.305 73.206 L 849.305 0.806 L 827.105 0.806 L 827.105 53.406 L 826.905 53.406 L 785.205 0.806 L 750.805 0.806 L 750.805 73.206 Z M 1010.105 73.206 L 1032.305 73.206 L 1032.305 20.606 L 1032.505 20.606 L 1074.205 73.206 L 1108.605 73.206 L 1108.605 0.806 L 1086.405 0.806 L 1086.405 53.406 L 1086.205 53.406 L 1044.505 0.806 L 1010.105 0.806 L 1010.105 73.206 Z M 29.705 74.006 L 61.505 74.006 A 51.732 51.732 0 0 0 72.484 72.955 C 82.691 70.728 88.531 64.939 90.473 55.381 A 40.134 40.134 0 0 0 91.205 47.406 L 91.205 0.806 L 69.005 0.806 L 69.005 42.606 C 69.005 51.405 65.987 55.082 57.762 55.385 A 31.364 31.364 0 0 1 56.605 55.406 L 34.605 55.406 A 22.943 22.943 0 0 1 30.082 55.013 C 24.736 53.93 22.488 50.538 22.231 43.95 A 34.441 34.441 0 0 1 22.205 42.606 L 22.205 0.806 L 0.005 0.806 L 0.005 47.406 C 0.005 64.841 8.73 73.457 27.816 73.981 A 68.853 68.853 0 0 0 29.705 74.006 Z M 219.705 73.206 L 241.905 73.206 L 241.905 54.406 L 276.805 54.406 A 18.122 18.122 0 0 1 280.084 54.663 C 284.425 55.469 285.905 58.272 285.905 64.506 L 285.905 73.206 L 308.105 73.206 L 308.105 60.906 C 308.105 49.006 302.605 46.106 296.005 44.906 L 296.005 44.706 A 22.978 22.978 0 0 0 300.937 43.003 C 305.503 40.745 307.44 37.183 308.108 32.151 A 40.124 40.124 0 0 0 308.405 26.906 L 308.405 22.306 A 33.46 33.46 0 0 0 307.248 12.853 C 305.018 5.341 299.196 0.806 286.705 0.806 L 219.705 0.806 L 219.705 73.206 Z M 410.205 73.206 L 435.005 73.206 L 441.505 60.406 L 486.505 60.406 L 493.405 73.206 L 518.105 73.206 L 478.305 0.806 L 449.405 0.806 L 410.205 73.206 Z M 526.005 73.206 L 598.105 73.206 L 598.105 54.606 L 548.205 54.606 L 548.205 0.806 L 526.005 0.806 L 526.005 73.206 Z M 971.705 73.206 L 993.905 73.206 L 993.905 0.806 L 971.705 0.806 L 971.705 73.206 Z M 241.905 18.806 L 276.605 18.806 A 34.237 34.237 0 0 1 280.146 18.959 C 283.795 19.344 285.876 20.558 286.556 23.711 A 12.861 12.861 0 0 1 286.805 26.406 L 286.805 28.806 A 12.128 12.128 0 0 1 286.485 31.774 C 285.685 34.926 283.316 36.406 278.605 36.406 L 241.905 36.406 L 241.905 18.806 Z M 463.805 17.606 L 478.205 44.806 L 449.805 44.806 L 463.805 17.606 Z"/>
<g id="svgGroup" stroke-linecap="round" fill-rule="evenodd" font-size="9pt" stroke="#ffffff"
stroke-width="0.25mm" fill="#ffffff" style="stroke:#ffffff;stroke-width:0.25mm;fill:#ffffff">
<path
d="M 894.605 74.006 L 921.305 74.006 C 942.427 74.006 953.413 73.292 956.313 60.527 A 37.848 37.848 0 0 0 957.105 52.206 L 957.105 31.606 L 907.305 31.606 L 907.305 46.606 L 934.905 46.606 L 934.905 48.706 C 934.905 53.442 932.251 55.385 928.738 56.147 A 26.156 26.156 0 0 1 923.305 56.606 L 899.605 56.606 A 39.408 39.408 0 0 1 894.638 56.344 C 888.593 55.565 886.231 52.853 885.654 45.747 A 52.88 52.88 0 0 1 885.505 41.506 L 885.505 32.506 A 48.028 48.028 0 0 1 885.738 27.377 C 886.556 19.865 889.695 17.689 897.793 17.433 A 57.321 57.321 0 0 1 899.605 17.406 L 923.705 17.406 A 38.323 38.323 0 0 1 927.889 17.588 C 932.328 18.085 934.835 19.818 934.904 25.273 A 18.461 18.461 0 0 1 934.905 25.506 L 956.705 25.506 L 956.705 23.206 A 36.235 36.235 0 0 0 955.47 12.587 C 953.178 5.214 946.987 0.624 931.363 0.064 A 93.813 93.813 0 0 0 928.005 0.006 L 894.605 0.006 C 874.839 0.006 862.985 4.89 862.71 25.469 A 55.259 55.259 0 0 0 862.705 26.206 L 862.705 47.806 A 39.6 39.6 0 0 0 863.741 57.358 C 866.906 70.059 877.192 73.722 892.685 73.99 A 111.289 111.289 0 0 0 894.605 74.006 Z M 323.405 73.206 L 403.905 73.206 L 403.905 55.806 L 345.605 55.806 L 345.605 44.206 L 399.605 44.206 L 399.605 29.206 L 345.605 29.206 L 345.605 17.606 L 402.605 17.606 L 402.605 0.806 L 323.405 0.806 L 323.405 73.206 Z M 656.905 73.206 L 737.405 73.206 L 737.405 55.806 L 679.105 55.806 L 679.105 44.206 L 733.105 44.206 L 733.105 29.206 L 679.105 29.206 L 679.105 17.606 L 736.105 17.606 L 736.105 0.806 L 656.905 0.806 L 656.905 73.206 Z M 1123.605 73.206 L 1204.105 73.206 L 1204.105 55.806 L 1145.805 55.806 L 1145.805 44.206 L 1199.805 44.206 L 1199.805 29.206 L 1145.805 29.206 L 1145.805 17.606 L 1202.805 17.606 L 1202.805 0.806 L 1123.605 0.806 L 1123.605 73.206 Z M 106.205 73.206 L 128.405 73.206 L 128.405 20.606 L 128.605 20.606 L 170.305 73.206 L 204.705 73.206 L 204.705 0.806 L 182.505 0.806 L 182.505 53.406 L 182.305 53.406 L 140.605 0.806 L 106.205 0.806 L 106.205 73.206 Z M 750.805 73.206 L 773.005 73.206 L 773.005 20.606 L 773.205 20.606 L 814.905 73.206 L 849.305 73.206 L 849.305 0.806 L 827.105 0.806 L 827.105 53.406 L 826.905 53.406 L 785.205 0.806 L 750.805 0.806 L 750.805 73.206 Z M 1010.105 73.206 L 1032.305 73.206 L 1032.305 20.606 L 1032.505 20.606 L 1074.205 73.206 L 1108.605 73.206 L 1108.605 0.806 L 1086.405 0.806 L 1086.405 53.406 L 1086.205 53.406 L 1044.505 0.806 L 1010.105 0.806 L 1010.105 73.206 Z M 29.705 74.006 L 61.505 74.006 A 51.732 51.732 0 0 0 72.484 72.955 C 82.691 70.728 88.531 64.939 90.473 55.381 A 40.134 40.134 0 0 0 91.205 47.406 L 91.205 0.806 L 69.005 0.806 L 69.005 42.606 C 69.005 51.405 65.987 55.082 57.762 55.385 A 31.364 31.364 0 0 1 56.605 55.406 L 34.605 55.406 A 22.943 22.943 0 0 1 30.082 55.013 C 24.736 53.93 22.488 50.538 22.231 43.95 A 34.441 34.441 0 0 1 22.205 42.606 L 22.205 0.806 L 0.005 0.806 L 0.005 47.406 C 0.005 64.841 8.73 73.457 27.816 73.981 A 68.853 68.853 0 0 0 29.705 74.006 Z M 219.705 73.206 L 241.905 73.206 L 241.905 54.406 L 276.805 54.406 A 18.122 18.122 0 0 1 280.084 54.663 C 284.425 55.469 285.905 58.272 285.905 64.506 L 285.905 73.206 L 308.105 73.206 L 308.105 60.906 C 308.105 49.006 302.605 46.106 296.005 44.906 L 296.005 44.706 A 22.978 22.978 0 0 0 300.937 43.003 C 305.503 40.745 307.44 37.183 308.108 32.151 A 40.124 40.124 0 0 0 308.405 26.906 L 308.405 22.306 A 33.46 33.46 0 0 0 307.248 12.853 C 305.018 5.341 299.196 0.806 286.705 0.806 L 219.705 0.806 L 219.705 73.206 Z M 410.205 73.206 L 435.005 73.206 L 441.505 60.406 L 486.505 60.406 L 493.405 73.206 L 518.105 73.206 L 478.305 0.806 L 449.405 0.806 L 410.205 73.206 Z M 526.005 73.206 L 598.105 73.206 L 598.105 54.606 L 548.205 54.606 L 548.205 0.806 L 526.005 0.806 L 526.005 73.206 Z M 971.705 73.206 L 993.905 73.206 L 993.905 0.806 L 971.705 0.806 L 971.705 73.206 Z M 241.905 18.806 L 276.605 18.806 A 34.237 34.237 0 0 1 280.146 18.959 C 283.795 19.344 285.876 20.558 286.556 23.711 A 12.861 12.861 0 0 1 286.805 26.406 L 286.805 28.806 A 12.128 12.128 0 0 1 286.485 31.774 C 285.685 34.926 283.316 36.406 278.605 36.406 L 241.905 36.406 L 241.905 18.806 Z M 463.805 17.606 L 478.205 44.806 L 449.805 44.806 L 463.805 17.606 Z" />
</g>
</svg>
</div>
<div id="connection" class="tooltip">
<svg version="1.1" id="connectionStrength" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 494.45 494.45" style="enable-background:new 0 0 494.45 494.45;" xml:space="preserve">
<circle id="dot" cx="247.125" cy="398.925" r="35.3"/>
<svg version="1.1" id="connectionStrength" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 494.45 494.45"
style="enable-background:new 0 0 494.45 494.45;" xml:space="preserve">
<circle id="dot" cx="247.125" cy="398.925" r="35.3" />
<path id="middle" d="M395.225,277.325c-6.8,0-13.5-2.6-18.7-7.8c-71.4-71.3-187.4-71.3-258.8,0c-10.3,10.3-27.1,10.3-37.4,0
s-10.3-27.1,0-37.4c92-92,241.6-92,333.6,0c10.3,10.3,10.3,27.1,0,37.4C408.725,274.725,401.925,277.325,395.225,277.325z"/>
<path id="middle"
d="M395.225,277.325c-6.8,0-13.5-2.6-18.7-7.8c-71.4-71.3-187.4-71.3-258.8,0c-10.3,10.3-27.1,10.3-37.4,0
s-10.3-27.1,0-37.4c92-92,241.6-92,333.6,0c10.3,10.3,10.3,27.1,0,37.4C408.725,274.725,401.925,277.325,395.225,277.325z" />
<path id="outer" d="M467.925,204.625c-6.8,0-13.5-2.6-18.7-7.8c-111.5-111.4-292.7-111.4-404.1,0c-10.3,10.3-27.1,10.3-37.4,0
s-10.3-27.1,0-37.4c64-64,149-99.2,239.5-99.2s175.5,35.2,239.5,99.2c10.3,10.3,10.3,27.1,0,37.4
C481.425,202.025,474.625,204.625,467.925,204.625z"/>
C481.425,202.025,474.625,204.625,467.925,204.625z" />
<path id="inner" d="M323.625,348.825c-6.8,0-13.5-2.6-18.7-7.8c-15.4-15.4-36-23.9-57.8-23.9s-42.4,8.5-57.8,23.9
c-10.3,10.3-27.1,10.3-37.4,0c-10.3-10.3-10.3-27.1,0-37.4c25.4-25.4,59.2-39.4,95.2-39.4s69.8,14,95.2,39.5
c10.3,10.3,10.3,27.1,0,37.4C337.225,346.225,330.425,348.825,323.625,348.825z"/>
c10.3,10.3,10.3,27.1,0,37.4C337.225,346.225,330.425,348.825,323.625,348.825z" />
</svg>
<span class="tooltiptext" id="qualityText">Not connected</span>
</div>
@@ -158,19 +166,19 @@
<div class="tgl-slider"></div>
</label>
</label>
</div>
</div>
<div id="showFPS" class="setting">
<div class="settings-text">Show FPS</div>
<label class="btn-overlay">
<input type="button" id="show-fps-button" class="overlay-button btn-flat" value="Toggle">
</label>
</div>
</div>
<div id="keyframeRequest" class="setting">
<div class="settings-text">Request KeyFrame</div>
<label class="btn-overlay">
<input type="button" id="request-keyframe-button" class="overlay-button btn-flat" value="Request">
</label>
</div>
</div>
<section id="encoderSettings">
<div id="encoderSettingsHeader" class="settings-text">
<div>Encoder Settings</div>
@@ -189,7 +197,7 @@
</div>
</div>
</section>
<section id="webRTCSettings">
<div id="webRTCSettingsHeader" class="settings-text">
<div>WebRTC Settings</div>
@@ -211,7 +219,7 @@
</div>
</div>
</section>
<section id="streamSettings">
<div id="streamSettingsHeader" class="settings-text">
<div>Stream Settings</div>
@@ -238,7 +246,7 @@
</label>
</div>
</div>
</section>
</section>
</div>
</div>
</div>
@@ -246,7 +254,7 @@
<div class="panel">
<div id="heading">Information</div>
<div id="close" onclick="statsClicked()"></div>
<div id="content">
<div id="content">
<section id="statsPanel">
<div class="setting settings-text">
<div>Session Stats</div>
+122 -7
View File
@@ -1,7 +1,5 @@
// Copyright Epic Games, Inc. All Rights Reserved.
//-- Server side logic. Serves pixel streaming WebRTC-based page, proxies data back to Streamer --//
var server_settings = process.argv.slice(2)
if (!server_settings) {
@@ -18,11 +16,13 @@ try {
var express = require('express');
var app = express();
const {fork} = require('node:child_process')
const fs = require('fs');
const path = require('path');
const querystring = require('querystring');
const bodyParser = require('body-parser');
const logging = require('./modules/logging.js');
var request = require('request')
logging.RegisterConsoleLogger();
// Command line argument --configFile needs to be checked before loading the config, all other command line arguments are dealt with through the config object
@@ -54,7 +54,33 @@ const config = require('./modules/config.js').init(configFile, defaultConfig);
config.StreamerPort = server_settings.app_port
config.HttpPort = server_settings.webrtc_port
config.SFUPort = 0
config.SFUPort = server_settings.sfu_port
const session_server_url = server_settings.session_server_url
const session_id = server_settings.session_id
const useSFU = true
console.log('useSFU: ', useSFU)
function runSFU() {
const sfu_file_path = __dirname + '/../SFU/sfu_server.js'
if (!fs.existsSync(sfu_file_path)) {
console.logColor(logging.Red, 'can not run sfu: sfu file not exists!')
return
}
try {
var sfu_proc_args = JSON.stringify({sfu_port:config.SFUPort})
fork(sfu_file_path, [sfu_proc_args], {
detached: true
})
} catch (err) {
console.error(err)
return null
}
}
if (useSFU) {
runSFU()
}
if (config.LogToFile) {
logging.RegisterFileLogger('./logs/');
@@ -275,9 +301,13 @@ if(config.EnableWebserver) {
}
//Setup http and https servers
http.listen(httpPort, function () {
console.logColor(logging.Green, 'Http listening on *: ' + httpPort);
});
var isHttpWorking = false
// http listen moved to streamer connection because webrtc server starts liten after application running
// http.listen(httpPort, function () {
// console.logColor(logging.Green, 'Http listening on *: ' + httpPort);
// });
if (config.UseHTTPS) {
https.listen(httpsPort, function () {
@@ -343,6 +373,7 @@ function sendMessageToPlayer(playerId, msg) {
let WebSocket = require('ws');
const { URL } = require('url');
const { exit } = require('process')
console.logColor(logging.Green, `WebSocket listening for Streamer connections on :${streamerPort}`)
let streamerServer = new WebSocket.Server({ port: streamerPort, backlog: 1 });
@@ -359,9 +390,17 @@ streamerServer.on('connection', function (ws, req) {
console.logColor(logging.Green, `Streamer connected: ${req.connection.remoteAddress}`);
sendStreamerConnectedToMatchmaker();
if (!isHttpWorking) {
isHttpWorking = true
http.listen(httpPort, function () {
console.logColor(logging.Green, 'Http listening on *: ' + httpPort);
});
}
ws.on('message', (msgRaw) => {
var msg;
try {
msg = JSON.parse(msgRaw);
} catch(err) {
@@ -526,9 +565,75 @@ sfuServer.on('connection', function (ws, req) {
let playerCount = 0;
const get_time_in_seconds = () => {
return new Date().getTime() / 1000;
}
var session_start_time = get_time_in_seconds()
// timeouts
const first_connection_timeout = 40
const player_reconnection_timeout = 30
// players connection detection
var has_player_ever_connected = false
var last_player_connection_time
const check_players = () => {
// update player count on session server
try {
request.post(
session_server_url + '/cirrus/update_users_count',
{ json: { session_id: session_id, users_count: playerCount } },
function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
}
}
)
} catch (e) {
console.log(e)
}
// if first player connection timeout reached destory session
if (!has_player_ever_connected) {
has_player_ever_connected = playerCount > 0
// if player never connected and timeout reached destroy session by exit
console.log('first connection time: ', (get_time_in_seconds() - session_start_time))
if ((get_time_in_seconds() - session_start_time) > first_connection_timeout) {
exit()
}
// if player never connected skip everything
return
}
// if player not connected in reconnection timeout destory session
if (playerCount) {
last_player_connection_time = get_time_in_seconds()
} else {
if (!last_player_connection_time) {
last_player_connection_time = get_time_in_seconds()
}
console.log('reconnection time: ', (get_time_in_seconds() - last_player_connection_time))
if ((get_time_in_seconds() - last_player_connection_time) > player_reconnection_timeout) {
//console.log('should exit, but wont for debug')
exit()
}
}
}
const start_players_check = () => {
check_players()
setTimeout(() => start_players_check(), 1000)
}
start_players_check()
console.logColor(logging.Green, `WebSocket listening for Players connections on :${httpPort}`);
let playerServer = new WebSocket.Server({ server: config.UseHTTPS ? https : http});
playerServer.on('connection', function (ws, req) {
// Reject connection if streamer is not connected
if (!streamer || streamer.readyState != 1 /* OPEN */) {
ws.close(1013 /* Try again later */, 'Streamer is not connected');
@@ -538,7 +643,7 @@ playerServer.on('connection', function (ws, req) {
var url = require('url');
const parsedUrl = url.parse(req.url);
const urlParams = new URLSearchParams(parsedUrl.search);
const preferSFU = urlParams.has('preferSFU') && urlParams.get('preferSFU') !== 'false';
const preferSFU = useSFU//urlParams.has('preferSFU') && urlParams.get('preferSFU') !== 'false';
const skipSFU = !preferSFU;
const skipStreamer = preferSFU && sfu;
@@ -564,6 +669,13 @@ playerServer.on('connection', function (ws, req) {
p.ws.send(playerCountMsg);
}
}
function sendPlayersLastInputTime() {
let playerCountMsg = JSON.stringify({ type: 'lastOtherPlayerInput'});
for (let p of players.values()) {
p.ws.send(playerCountMsg);
}
}
ws.on('message', (msgRaw) =>{
@@ -601,6 +713,9 @@ playerServer.on('connection', function (ws, req) {
} else if (msg.type == "peerDataChannelsReady") {
msg.playerId = playerId;
sendMessageToController(msg, skipSFU, true);
} else if (msg.type == "playerInput") {
//msg.playerId = playerId;
sendPlayersLastInputTime();
}
else {
console.error(`player ${playerId}: unsupported message type: ${msg.type}`);
+2 -1
View File
@@ -16,5 +16,6 @@
"StreamerPort": 8888,
"SFUPort": 8889,
"MaxPlayerCount": -1,
"peerConnectionOptions": "{ \"iceServers\": [{\"urls\": [\"stun:stun1.l.google.com:19302\",\"stun:stun1.l.google.com:19302\"]}] }"
"peerConnectionOptions": "{\"iceServers\": [{\"urls\": [\"stun:stun1.l.google.com:19302\",\"stun:stun2.l.google.com:19302\",\"stun:stun3.l.google.com:19302\",\"stun:stun4.l.google.com:19302\"]},{\"urls\":[\"turn:13.250.13.83:3478?transport=udp\"],\"username\":\"YzYNCouZM1mhqhmseWk6\",\"credential\":\"YzYNCouZM1mhqhmseWk6\"},{\"urls\": [\"turn:192.158.29.39:3478?transport=tcp\"],\"credential\": \"JZEOEt2V3Qb0y27GRntt2u2PAYA=\",\"username\": \"28224511:1379330808\"}]}"
}
@@ -0,0 +1,54 @@
@font-face {
font-family: 'Inter';
src:
url('./inter-v12-latin_cyrillic-regular.woff2') format('woff2'),
url('./inter-v12-latin_cyrillic-regular.woff') format('woff');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Inter';
src:
url('./inter-v12-latin_cyrillic-300.woff2') format('woff2'),
url('./inter-v12-latin_cyrillic-300.woff') format('woff');
font-weight: 300;
font-style: normal;
}
@font-face {
font-family: 'Inter';
src:
url('./inter-v12-latin_cyrillic-500.woff2') format('woff2'),
url('./inter-v12-latin_cyrillic-500.woff') format('woff');
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: 'Inter';
src:
url('./inter-v12-latin_cyrillic-600.woff2') format('woff2'),
url('./inter-v12-latin_cyrillic-600.woff') format('woff');
font-weight: 600;
font-style: normal;
}
@font-face {
font-family: 'Inter';
src:
url('./inter-v12-latin_cyrillic-700.woff2') format('woff2'),
url('./inter-v12-latin_cyrillic-700.woff') format('woff');
font-weight: 700;
font-style: normal;
}
@font-face {
font-family: 'GilroyWebRegular';
src: url('./Gilroy_Regular.woff'),
url('./Gilroy_Regular.woff2');
font-weight: 400;
font-style: normal;
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

+23 -9
View File
@@ -12,8 +12,9 @@
"express": "^4.16.2",
"express-session": "^1.15.6",
"helmet": "^3.21.3",
"passport": "^0.6.0",
"passport": "^0.4.0",
"passport-local": "^1.0.0",
"run-script-os": "^1.1.6",
"ws": "^7.1.2",
"y18n": "^5.0.5",
"yargs": "^15.3.0"
@@ -676,13 +677,12 @@
}
},
"node_modules/passport": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/passport/-/passport-0.6.0.tgz",
"integrity": "sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==",
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/passport/-/passport-0.4.1.tgz",
"integrity": "sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg==",
"dependencies": {
"passport-strategy": "1.x.x",
"pause": "0.0.1",
"utils-merge": "^1.0.1"
"pause": "0.0.1"
},
"engines": {
"node": ">= 0.4.0"
@@ -796,6 +796,15 @@
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
},
"node_modules/run-script-os": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/run-script-os/-/run-script-os-1.1.6.tgz",
"integrity": "sha512-ql6P2LzhBTTDfzKts+Qo4H94VUKpxKDFz6QxxwaUZN0mwvi7L3lpOI7BqPCq7lgDh3XLl0dpeXwfcVIitlrYrw==",
"bin": {
"run-os": "index.js",
"run-script-os": "index.js"
}
},
"node_modules/safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -1526,9 +1535,9 @@
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
},
"passport": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/passport/-/passport-0.6.0.tgz",
"integrity": "sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==",
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/passport/-/passport-0.4.1.tgz",
"integrity": "sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg==",
"requires": {
"passport-strategy": "1.x.x",
"pause": "0.0.1"
@@ -1612,6 +1621,11 @@
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
},
"run-script-os": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/run-script-os/-/run-script-os-1.1.6.tgz",
"integrity": "sha512-ql6P2LzhBTTDfzKts+Qo4H94VUKpxKDFz6QxxwaUZN0mwvi7L3lpOI7BqPCq7lgDh3XLl0dpeXwfcVIitlrYrw=="
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+233 -154
View File
@@ -4,11 +4,13 @@
* Class definitions
* TODO: Move these to seperate files once we introduce a bundler
*/
class TwoWayMap {
constructor(map = {}) {
this.map = map;
this.reverseMap = new Map();
for(const key in map) {
for (const key in map) {
const value = map[key];
this.reverseMap[value] = key;
}
@@ -27,6 +29,51 @@ class TwoWayMap {
delete this.reverseMap[value];
}
}
// afk
const get_time_in_seconds = () => {
return new Date().getTime() / 1000;
}
let lastInputTime
let lastInputSendTime = 0
let inputSendTimeout = 3
let cirrusWebsocket = null
let lastOtherPlayerInput = get_time_in_seconds()
function getOveralLastPlayerInput() {
return lastOtherPlayerInput
}
function updateLastInputTime() {
lastInputTime = get_time_in_seconds()
}
updateLastInputTime()
function updateLastOtherPlayerInput() {
//console.log('last player input')
lastOtherPlayerInput = get_time_in_seconds()
}
const check_input = () => {
//console.log('time from last input: ', get_time_in_seconds() - getOveralLastPlayerInput())
if (!cirrusWebsocket)
return
if (lastInputSendTime == lastInputTime) {
return
}
if ((get_time_in_seconds() - lastInputSendTime) > inputSendTimeout) {
lastInputSendTime = lastInputTime
cirrusWebsocket.send(JSON.stringify({type:"playerInput"}))
}
}
const start_check_input = () => {
check_input()
setTimeout(() => start_check_input(), 1000)
}
start_check_input()
/**
* Frontend logic
@@ -76,7 +123,7 @@ let freezeFrame = {
let file = {
mimetype: "",
extension: "",
receiving: false,
receiving: false,
size: 0,
data: [],
valid: false,
@@ -85,7 +132,7 @@ let file = {
// Optionally detect if the user is not interacting (AFK) and disconnect them.
let afk = {
enabled: false, // Set to true to enable the AFK system.
enabled: true, // Set to true to enable the AFK system.
warnTimeout: 120, // The time to elapse before warning the user they are inactive.
closeTimeout: 10, // The time after the warning when we disconnect the user.
@@ -329,7 +376,7 @@ function registerMessageHandlers() {
registerMessageHandler(MessageDirection.ToStreamer, "StopStreaming", sendMessageToStreamer);
registerMessageHandler(MessageDirection.ToStreamer, "LatencyTest", sendMessageToStreamer);
registerMessageHandler(MessageDirection.ToStreamer, "RequestInitialSettings", sendMessageToStreamer);
registerMessageHandler(MessageDirection.ToStreamer, "TestEcho", () => { /* Do nothing */});
registerMessageHandler(MessageDirection.ToStreamer, "TestEcho", () => { /* Do nothing */ });
registerMessageHandler(MessageDirection.ToStreamer, "UIInteraction", emitUIInteraction);
registerMessageHandler(MessageDirection.ToStreamer, "Command", emitCommand);
registerMessageHandler(MessageDirection.ToStreamer, "KeyDown", sendMessageToStreamer);
@@ -470,7 +517,7 @@ function onProtocolMessage(data) {
}
let direction = protocolJSON.Direction;
delete protocolJSON.Direction;
console.log(`Received new ${ direction == MessageDirection.FromStreamer ? "FromStreamer" : "ToStreamer" } protocol. Updating existing protocol...`);
console.log(`Received new ${direction == MessageDirection.FromStreamer ? "FromStreamer" : "ToStreamer"} protocol. Updating existing protocol...`);
Object.keys(protocolJSON).forEach((messageType) => {
let message = protocolJSON[messageType];
switch (direction) {
@@ -482,7 +529,7 @@ function onProtocolMessage(data) {
// return in a forEach is equivalent to a continue in a normal for loop
return;
}
if(message.byteLength > 0 && !message.hasOwnProperty("structure")) {
if (message.byteLength > 0 && !message.hasOwnProperty("structure")) {
// If we specify a bytelength, will must have a corresponding structure
console.error(`ToStreamer->${messageType} protocol definition was malformed as it specified a byteLength but no accompanying structure`);
// return in a forEach is equivalent to a continue in a normal for loop
@@ -632,72 +679,72 @@ function gamepadDisconnectHandler(e) {
function fullscreen() {
// if already full screen; exit
// else go fullscreen
if (
document.fullscreenElement ||
document.webkitFullscreenElement ||
document.mozFullScreenElement ||
document.msFullscreenElement
) {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
} else {
let element;
//HTML elements controls
if(!(document.fullscreenEnabled || document.webkitFullscreenEnabled)) {
// Chrome and FireFox on iOS can only fullscreen a <video>
element = document.getElementById("streamingVideo");
// else go fullscreen
if (
document.fullscreenElement ||
document.webkitFullscreenElement ||
document.mozFullScreenElement ||
document.msFullscreenElement
) {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
} else {
// Everywhere else can fullscreen a <div>
element = document.getElementById("playerUI");
let element;
//HTML elements controls
if (!(document.fullscreenEnabled || document.webkitFullscreenEnabled)) {
// Chrome and FireFox on iOS can only fullscreen a <video>
element = document.getElementById("streamingVideo");
} else {
// Everywhere else can fullscreen a <div>
element = document.getElementById("playerUI");
}
if (!element) {
return;
}
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen();
} else if (element.webkitRequestFullscreen) {
element.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
} else if (element.msRequestFullscreen) {
element.msRequestFullscreen();
} else if (element.webkitEnterFullscreen) {
element.webkitEnterFullscreen(); //for iphone this code worked
}
}
if(!element) {
return;
}
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen();
} else if (element.webkitRequestFullscreen) {
element.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
} else if (element.msRequestFullscreen) {
element.msRequestFullscreen();
} else if (element.webkitEnterFullscreen) {
element.webkitEnterFullscreen(); //for iphone this code worked
}
}
onFullscreenChange()
onFullscreenChange()
}
function onFullscreenChange() {
isFullscreen = (document.webkitIsFullScreen
|| document.mozFullScreen
|| (document.msFullscreenElement && document.msFullscreenElement !== null)
|| (document.fullscreenElement && document.fullscreenElement !== null));
isFullscreen = (document.webkitIsFullScreen
|| document.mozFullScreen
|| (document.msFullscreenElement && document.msFullscreenElement !== null)
|| (document.fullscreenElement && document.fullscreenElement !== null));
let minimize = document.getElementById('minimize');
let minimize = document.getElementById('minimize');
let maximize = document.getElementById('maximize');
if(minimize && maximize){
if(isFullscreen) {
if (minimize && maximize) {
if (isFullscreen) {
minimize.style.display = 'inline';
maximize.style.display = 'none';
} else {
minimize.style.display = 'none';
maximize.style.display = 'inline';
}
}
}
}
function parseURLParams() {
let urlParams = new URLSearchParams(window.location.search);
inputOptions.controlScheme = (urlParams.has('hoveringMouse') ? ControlSchemeType.HoveringMouse : ControlSchemeType.LockedMouse);
inputOptions.controlScheme = (urlParams.has('hoveringMouse') ? ControlSchemeType.HoveringMouse : ControlSchemeType.HoveringMouse);
let schemeToggle = document.getElementById("control-scheme-text");
switch (inputOptions.controlScheme) {
case ControlSchemeType.HoveringMouse:
@@ -712,12 +759,12 @@ function parseURLParams() {
break;
}
if(urlParams.has('noWatermark')) {
if (urlParams.has('noWatermark')) {
let watermark = document.getElementById("unrealengine");
watermark.style.display = 'none';
}
inputOptions.hideBrowserCursor = (urlParams.has('hideBrowserCursor') ? true : false);
inputOptions.hideBrowserCursor = (urlParams.has('hideBrowserCursor') ? true : false);
}
@@ -754,21 +801,21 @@ function setupHtmlEvents() {
let resizeCheckBox = document.getElementById('enlarge-display-to-fill-window-tgl');
if (resizeCheckBox !== null) {
resizeCheckBox.onchange = function(event) {
resizeCheckBox.onchange = function (event) {
resizePlayerStyle();
};
}
qualityControlOwnershipCheckBox = document.getElementById('quality-control-ownership-tgl');
if (qualityControlOwnershipCheckBox !== null) {
qualityControlOwnershipCheckBox.onchange = function(event) {
qualityControlOwnershipCheckBox.onchange = function (event) {
requestQualityControl();
};
}
let encoderParamsSubmit = document.getElementById('encoder-params-submit');
if (encoderParamsSubmit !== null) {
encoderParamsSubmit.onclick = function(event) {
encoderParamsSubmit.onclick = function (event) {
let minQP = document.getElementById('encoder-min-qp-text').value;
let maxQP = document.getElementById('encoder-max-qp-text').value;
@@ -780,7 +827,7 @@ function setupHtmlEvents() {
let webrtcParamsSubmit = document.getElementById('webrtc-params-submit');
if (webrtcParamsSubmit !== null) {
webrtcParamsSubmit.onclick = function(event) {
webrtcParamsSubmit.onclick = function (event) {
let FPS = document.getElementById('webrtc-fps-text').value;
let minBitrate = document.getElementById('webrtc-min-bitrate-text').value * 1000;
let maxBitrate = document.getElementById('webrtc-max-bitrate-text').value * 1000;
@@ -822,7 +869,7 @@ function setupHtmlEvents() {
let statsCheckBox = document.getElementById('show-stats-tgl');
if (statsCheckBox !== null) {
statsCheckBox.onchange = function(event) {
statsCheckBox.onchange = function (event) {
let stats = document.getElementById('statsContainer');
stats.style.display = event.target.checked ? "block" : "none";
};
@@ -836,19 +883,22 @@ function setupHtmlEvents() {
}
// Setup toggle and pair with some URL query string param.
setupToggleWithUrlParams("prefer-sfu-tgl", "preferSFU");
//setupToggleWithUrlParams("prefer-sfu-tgl", "preferSFU");
setupToggleWithUrlParams("use-mic-tgl", "useMic");
setupToggleWithUrlParams("force-turn-tgl", "ForceTURN");
setupToggleWithUrlParams("force-mono-tgl", "ForceMonoAudio");
setupToggleWithUrlParams("control-tgl", "hoveringMouse");
setupToggleWithUrlParams("cursor-tgl", "hideBrowserCursor");
setupToggleWithUrlParams("control-tgl", "hoveringMouse");
setupToggleWithUrlParams("offer-receive-tgl", "offerToReceive");
setupToggleWithUrlParams("cursor-tgl", "hideBrowserCursor");
var streamSelector = document.getElementById('stream-select');
var trackSelector = document.getElementById('track-select');
if (streamSelector) {
streamSelector.onchange = function(event) {
streamSelector.onchange = function (event) {
const stream = webRtcPlayerObj.availableVideoStreams.get(streamSelector.value);
webRtcPlayerObj.video.srcObject = stream;
streamTrackSource = stream;
@@ -857,7 +907,7 @@ function setupHtmlEvents() {
}
if (trackSelector) {
trackSelector.onchange = function(event) {
trackSelector.onchange = function (event) {
if (!streamTrackSource) {
streamTrackSource = webRtcPlayerObj.availableVideoStreams.get(streamSelector.value);
}
@@ -876,9 +926,9 @@ function setupHtmlEvents() {
}
}
function setupToggleWithUrlParams(toggleId, urlParameterKey){
function setupToggleWithUrlParams(toggleId, urlParameterKey) {
let toggleElem = document.getElementById(toggleId);
if(toggleElem) {
if (toggleElem) {
toggleElem.checked = new URLSearchParams(window.location.search).has(urlParameterKey);
toggleElem.addEventListener('change', (event) => {
const urlParams = new URLSearchParams(window.location.search);
@@ -942,7 +992,7 @@ function sendStartLatencyTest() {
return;
}
let onTestStarted = function(StartTimeMs) {
let onTestStarted = function (StartTimeMs) {
let descriptor = {
StartTime: StartTimeMs
};
@@ -987,8 +1037,28 @@ function setOverlay(htmlClass, htmlElement, onClickFunction) {
function showConnectOverlay() {
let startText = document.createElement('div');
startText.id = 'playButton';
startText.innerHTML = 'Click to start'.toUpperCase();
startText.id = 'container'
let title = document.createElement('h2')
title.id = "title"
title.innerHTML = 'Демонстрация начата'
let caption = document.createElement('p')
caption.id = 'caption'
caption.innerHTML = 'Нажмите, чтобы продолжить'
let headerContainer = document.createElement('div')
headerContainer.appendChild(title)
headerContainer.appendChild(caption)
startText.appendChild(headerContainer)
let playButton = document.createElement('img')
playButton.id = 'playButton'
playButton.src = './images/Play.png'
startText.appendChild(playButton)
let buttonBack = document.createElement('a')
let captionBack = document.createElement('div')
captionBack.innerHTML = 'Выбор жилого комплекса'
buttonBack.appendChild(captionBack)
buttonBack.id = 'link'
buttonBack.href = 'https://stream.graff.tech/'
startText.appendChild(buttonBack)
setOverlay('clickableState', startText, event => {
connect();
@@ -996,6 +1066,13 @@ function showConnectOverlay() {
});
}
function showLoader() {
let loader = document.createElement('span')
loader.id = 'loader'
setOverlay('textDisplayState', loader)
}
function showTextOverlay(text) {
let textOverlay = document.createElement('div');
textOverlay.id = 'messageOverlay';
@@ -1004,8 +1081,8 @@ function showTextOverlay(text) {
}
function playStream() {
if(webRtcPlayerObj && webRtcPlayerObj.video) {
if(webRtcPlayerObj.audio.srcObject && autoPlayAudio) {
if (webRtcPlayerObj && webRtcPlayerObj.video) {
if (webRtcPlayerObj.audio.srcObject && autoPlayAudio) {
// Video and Audio are seperate tracks
webRtcPlayerObj.audio.play().then(() => {
// audio play has succeeded, start playing video
@@ -1026,7 +1103,7 @@ function playStream() {
function playVideo() {
webRtcPlayerObj.video.play().catch((onRejectedReason) => {
if(webRtcPlayerObj.audio.srcObject) {
if (webRtcPlayerObj.audio.srcObject) {
webRtcPlayerObj.audio.stop();
}
console.error(onRejectedReason);
@@ -1038,7 +1115,7 @@ function playVideo() {
function showPlayOverlay() {
let img = document.createElement('img');
img.id = 'playButton';
img.src = '/images/Play.png';
img.src = './images/Play.png';
img.alt = 'Start Streaming';
setOverlay('clickableState', img, event => {
playStream();
@@ -1071,7 +1148,7 @@ function showAfkOverlay() {
document.exitPointerLock();
}
afk.countdownTimer = setInterval(function() {
afk.countdownTimer = setInterval(function () {
afk.countdown--;
if (afk.countdown == 0) {
// The user failed to click so disconnect them.
@@ -1110,9 +1187,10 @@ function resetAfkWarningTimer() {
}
function createWebRtcOffer() {
console.log('loaderLOADER')
if (webRtcPlayerObj) {
console.log('Creating offer');
showTextOverlay('Starting connection to server, please wait');
showLoader();
webRtcPlayerObj.createOffer();
} else {
console.log('WebRTC player not setup, cannot create offer');
@@ -1122,6 +1200,7 @@ function createWebRtcOffer() {
function sendInputData(data) {
if (webRtcPlayerObj) {
updateLastInputTime();
resetAfkWarningTimer();
webRtcPlayerObj.send(data);
}
@@ -1290,7 +1369,7 @@ function setupWebRtcPlayer(htmlElement, config) {
htmlElement.appendChild(webRtcPlayerObj.audio);
htmlElement.appendChild(freezeFrameOverlay);
webRtcPlayerObj.onWebRtcOffer = function(offer) {
webRtcPlayerObj.onWebRtcOffer = function (offer) {
if (ws && ws.readyState === WS_OPEN_STATE) {
let offerStr = JSON.stringify(offer);
console.log("%c[Outbound SS message (offer)]", "background: lightgreen; color: black", offer);
@@ -1298,7 +1377,7 @@ function setupWebRtcPlayer(htmlElement, config) {
}
};
webRtcPlayerObj.onWebRtcCandidate = function(candidate) {
webRtcPlayerObj.onWebRtcCandidate = function (candidate) {
if (ws && ws.readyState === WS_OPEN_STATE) {
ws.send(JSON.stringify({
type: 'iceCandidate',
@@ -1322,7 +1401,7 @@ function setupWebRtcPlayer(htmlElement, config) {
}
};
webRtcPlayerObj.onSFURecvDataChannelReady = function() {
webRtcPlayerObj.onSFURecvDataChannelReady = function () {
if (webRtcPlayerObj.sfu) {
// Send SFU a message to let it know browser data channels are ready
const requestMsg = { type: "peerDataChannelsReady" };
@@ -1331,7 +1410,7 @@ function setupWebRtcPlayer(htmlElement, config) {
}
}
webRtcPlayerObj.onVideoInitialised = function() {
webRtcPlayerObj.onVideoInitialised = function () {
if (ws && ws.readyState === WS_OPEN_STATE) {
if (shouldShowPlayOverlay) {
showPlayOverlay();
@@ -1351,7 +1430,7 @@ function setupWebRtcPlayer(htmlElement, config) {
updateStreamList();
}
webRtcPlayerObj.onDataChannelMessage = function(data) {
webRtcPlayerObj.onDataChannelMessage = function (data) {
let view = new Uint8Array(data);
try {
let messageType = fromStreamerMessages.getFromValue(view[0]);
@@ -1375,8 +1454,8 @@ function setupWebRtcPlayer(htmlElement, config) {
return webRtcPlayerObj.video;
}
function setupStats(){
webRtcPlayerObj.aggregateStats(1 * 1000 /*Check every 1 second*/ );
function setupStats() {
webRtcPlayerObj.aggregateStats(1 * 1000 /*Check every 1 second*/);
let printInterval = 5 * 60 * 1000; /*Print every 5 minutes*/
let nextPrintDuration = printInterval;
@@ -1416,14 +1495,14 @@ function setupStats(){
let qualityStatus = document.getElementById("connectionStrength");
// "blinks" quality status element for 1 sec by making it transparent, speed = number of blinks
let blinkQualityStatus = function(speed) {
let blinkQualityStatus = function (speed) {
let iter = speed;
let opacity = 1; // [0..1]
let tickId = setInterval(
function() {
function () {
opacity -= 0.1;
// map `opacity` to [-0.5..0.5] range, decrement by 0.2 per step and take `abs` to make it blink: 1 -> 0 -> 1
qualityStatus.style.opacity = `${Math.abs((opacity - 0.5) * 2)}`;
qualityStatus.style.opacity = `${Math.abs((opacity - 0.5) * 2)}`;
if (opacity <= 0.1) {
if (--iter == 0) {
clearInterval(tickId);
@@ -1479,11 +1558,10 @@ function setupStats(){
statsText += `<div>Duration: ${timeFormat.format(runTimeHours)}:${timeFormat.format(runTimeMinutes)}:${timeFormat.format(runTimeSeconds)}</div>`;
statsText += `<div>Controls stream input: ${inputController === null ? "Not sent yet" : (inputController ? "true" : "false")}</div>`;
statsText += `<div>Audio codec: ${aggregatedStats.hasOwnProperty('audioCodec') ? aggregatedStats.audioCodec : "Not set" }</div>`;
statsText += `<div>Video codec: ${aggregatedStats.hasOwnProperty('videoCodec') ? aggregatedStats.videoCodec : "Not set" }</div>`;
statsText += `<div>Video Resolution: ${
aggregatedStats.hasOwnProperty('frameWidth') && aggregatedStats.frameWidth && aggregatedStats.hasOwnProperty('frameHeight') && aggregatedStats.frameHeight ?
aggregatedStats.frameWidth + 'x' + aggregatedStats.frameHeight : 'Chrome only'
statsText += `<div>Audio codec: ${aggregatedStats.hasOwnProperty('audioCodec') ? aggregatedStats.audioCodec : "Not set"}</div>`;
statsText += `<div>Video codec: ${aggregatedStats.hasOwnProperty('videoCodec') ? aggregatedStats.videoCodec : "Not set"}</div>`;
statsText += `<div>Video Resolution: ${aggregatedStats.hasOwnProperty('frameWidth') && aggregatedStats.frameWidth && aggregatedStats.hasOwnProperty('frameHeight') && aggregatedStats.frameHeight ?
aggregatedStats.frameWidth + 'x' + aggregatedStats.frameHeight : 'Chrome only'
}</div>`;
statsText += `<div>Received (${receivedBytesMeasurement}): ${numberFormat.format(receivedBytes)}</div>`;
statsText += `<div>Frames Decoded: ${aggregatedStats.hasOwnProperty('framesDecoded') ? numberFormat.format(aggregatedStats.framesDecoded) : 'Chrome only'}</div>`;
@@ -1515,7 +1593,7 @@ function setupStats(){
}
};
webRtcPlayerObj.latencyTestTimings.OnAllLatencyTimingsReady = function(timings) {
webRtcPlayerObj.latencyTestTimings.OnAllLatencyTimingsReady = function (timings) {
if (!timings.BrowserReceiptTimeMs) {
return;
@@ -1550,6 +1628,7 @@ function setupStats(){
function onWebRtcOffer(webRTCData) {
webRtcPlayerObj.receiveOffer(webRTCData);
showLoader
setupStats();
}
@@ -1563,7 +1642,7 @@ function onWebRtcSFUPeerDatachannels(webRTCData) {
}
function onWebRtcIce(iceCandidate) {
if (webRtcPlayerObj){
if (webRtcPlayerObj) {
webRtcPlayerObj.handleCandidateFromServer(iceCandidate);
}
}
@@ -1600,7 +1679,7 @@ let inputOptions = {
// user drags with their mouse. We may perform the reverse; a single finger
// touch may be converted into a mouse drag UE side. This allows a
// non-touch application to be controlled partially via a touch device.
fakeMouseWithTouches: false,
fakeMouseWithTouches: true,
// Hiding the browser cursor enables the use of UE's inbuilt software cursor,
// without having the browser cursor display on top
@@ -1689,7 +1768,7 @@ function invalidateFreezeFrameOverlay() {
freezeFrame.valid = false;
freezeFrameOverlay.classList.remove("freezeframeBackground");
}, freezeFrameDelay);
if (webRtcPlayerObj) {
webRtcPlayerObj.setVideoEnabled(true);
}
@@ -1796,7 +1875,7 @@ function updateVideoStreamSize() {
return;
let descriptor = {
"Resolution.Width": playerElement.clientWidth,
"Resolution.Width": playerElement.clientWidth,
"Resolution.Height": playerElement.clientHeight
};
emitCommand(descriptor);
@@ -1815,14 +1894,14 @@ let _orientationChangeTimeout;
function onOrientationChange(event) {
clearTimeout(_orientationChangeTimeout);
_orientationChangeTimeout = setTimeout(function() {
_orientationChangeTimeout = setTimeout(function () {
resizePlayerStyle();
}, 500);
}
function sendMessageToStreamer(messageType, indata = []) {
messageFormat = toStreamerMessages.getFromKey(messageType);
if(messageFormat === undefined) {
if (messageFormat === undefined) {
console.error(`Attempted to send a message to the streamer with message type: ${messageType}, but the frontend hasn't been configured to send such a message. Check you've added the message type in your cpp`);
return;
}
@@ -1864,7 +1943,7 @@ function emitDescriptor(messageType, descriptor) {
// Convert the descriptor object into a JSON string.
let descriptorAsString = JSON.stringify(descriptor);
let messageFormat = toStreamerMessages.getFromKey(messageType);
if(messageFormat === undefined) {
if (messageFormat === undefined) {
console.error(`Attempted to emit descriptor with message type: ${messageType}, but the frontend hasn't been configured to send such a message. Check you've added the message type in your cpp`);
}
// Add the UTF-16 JSON string to the array byte buffer, going two bytes at
@@ -2102,7 +2181,7 @@ function createOnScreenKeyboardHelpers(htmlElement) {
// Hide the 'edit text' button.
editTextButton.classList.add('hiddenState');
editTextButton.addEventListener('click', function() {
editTextButton.addEventListener('click', function () {
// Show the on-screen keyboard.
hiddenInput.focus();
});
@@ -2126,7 +2205,7 @@ function showOnScreenKeyboard(command) {
}
function registerMouseEnterAndLeaveEvents(playerElement) {
playerElement.onmouseenter = function(e) {
playerElement.onmouseenter = function (e) {
if (print_inputs) {
console.log('mouse enter');
}
@@ -2134,7 +2213,7 @@ function registerMouseEnterAndLeaveEvents(playerElement) {
playerElement.pressMouseButtons(e);
};
playerElement.onmouseleave = function(e) {
playerElement.onmouseleave = function (e) {
if (print_inputs) {
console.log('mouse leave');
}
@@ -2155,7 +2234,7 @@ function registerLockedMouseEvents(playerElement) {
playerElement.requestPointerLock = playerElement.requestPointerLock || playerElement.mozRequestPointerLock;
document.exitPointerLock = document.exitPointerLock || document.mozExitPointerLock;
playerElement.onclick = function() {
playerElement.onclick = function () {
playerElement.requestPointerLock();
};
@@ -2221,11 +2300,11 @@ function registerLockedMouseEvents(playerElement) {
toStreamerHandlers.MouseDown("MouseDouble", [e.button, coord.x, coord.y]);
};
playerElement.pressMouseButtons = function(e) {
playerElement.pressMouseButtons = function (e) {
pressMouseButtons(e.buttons, x, y);
};
playerElement.releaseMouseButtons = function(e) {
playerElement.releaseMouseButtons = function (e) {
releaseMouseButtons(e.buttons, x, y);
};
}
@@ -2277,11 +2356,11 @@ function registerHoveringMouseEvents(playerElement) {
toStreamerHandlers.MouseDown("MouseDouble", [e.button, coord.x, coord.y]);
};
playerElement.pressMouseButtons = function(e) {
playerElement.pressMouseButtons = function (e) {
pressMouseButtons(e.buttons, e.offsetX, e.offsetY);
};
playerElement.releaseMouseButtons = function(e) {
playerElement.releaseMouseButtons = function (e) {
releaseMouseButtons(e.buttons, e.offsetX, e.offsetY);
};
}
@@ -2303,7 +2382,7 @@ function registerTouchEvents(playerElement) {
function forgetTouch(touch) {
fingers.push(fingerIds[touch.identifier]);
// Sort array back into descending order. This means if finger '1' were to lift after finger '0', we would ensure that 0 will be the first index to pop
fingers.sort(function(a, b){return b - a});
fingers.sort(function (a, b) { return b - a });
delete fingerIds[touch.identifier];
}
@@ -2317,8 +2396,8 @@ function registerTouchEvents(playerElement) {
console.log(`F${fingerIds[touch.identifier]}=(${x}, ${y})`);
}
let coord = normalizeAndQuantizeUnsigned(x, y);
switch(type) {
switch (type) {
case "TouchStart":
toStreamerHandlers.TouchStart("TouchStart", [numTouches, coord.x, coord.y, fingerIds[touch.identifier], MaxByteValue * touch.force, coord.inRange ? 1 : 0]);
break;
@@ -2336,7 +2415,7 @@ function registerTouchEvents(playerElement) {
let finger = undefined;
playerElement.ontouchstart = function(e) {
playerElement.ontouchstart = function (e) {
if (finger === undefined) {
let firstTouch = e.changedTouches[0];
finger = {
@@ -2354,7 +2433,7 @@ function registerTouchEvents(playerElement) {
e.preventDefault();
};
playerElement.ontouchend = function(e) {
playerElement.ontouchend = function (e) {
for (let t = 0; t < e.changedTouches.length; t++) {
let touch = e.changedTouches[t];
if (touch.identifier === finger.id) {
@@ -2371,7 +2450,7 @@ function registerTouchEvents(playerElement) {
e.preventDefault();
};
playerElement.ontouchmove = function(e) {
playerElement.ontouchmove = function (e) {
for (let t = 0; t < e.touches.length; t++) {
let touch = e.touches[t];
if (touch.identifier === finger.id) {
@@ -2388,7 +2467,7 @@ function registerTouchEvents(playerElement) {
e.preventDefault();
};
} else {
playerElement.ontouchstart = function(e) {
playerElement.ontouchstart = function (e) {
// Assign a unique identifier to each touch.
for (let t = 0; t < e.changedTouches.length; t++) {
rememberTouch(e.changedTouches[t]);
@@ -2401,7 +2480,7 @@ function registerTouchEvents(playerElement) {
e.preventDefault();
};
playerElement.ontouchend = function(e) {
playerElement.ontouchend = function (e) {
if (print_inputs) {
console.log('touch end');
}
@@ -2414,7 +2493,7 @@ function registerTouchEvents(playerElement) {
e.preventDefault();
};
playerElement.ontouchmove = function(e) {
playerElement.ontouchmove = function (e) {
if (print_inputs) {
console.log('touch move');
}
@@ -2556,9 +2635,9 @@ function getKeyCode(e) {
// If we don't have keyCode property because browser API is deprecated then use KeyboardEvent.code instead.
// See: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode#constants_for_keycode_value
if(!("keyCode" in e)) {
if (!("keyCode" in e)) {
// Convert KeyboardEvent.code string into integer-based key code for backwards compatibility reasons.
if(e.code in CodeToKeyCode) {
if (e.code in CodeToKeyCode) {
return CodeToKeyCode[e.code];
} else {
console.warn(`Keyboard code of ${e.code} is not supported in our mapping, ignoring this key.`);
@@ -2577,10 +2656,10 @@ function getKeyCode(e) {
function registerKeyboardEvents() {
document.onkeydown = function(e) {
document.onkeydown = function (e) {
const keyCode = getKeyCode(e);
if(!keyCode) { return; }
if (!keyCode) { return; }
if (print_inputs) {
console.log(`key down ${keyCode}, repeat = ${e.repeat}`);
@@ -2602,10 +2681,10 @@ function registerKeyboardEvents() {
};
document.onkeyup = function(e) {
document.onkeyup = function (e) {
const keyCode = getKeyCode(e);
if(!keyCode) { return; }
if (!keyCode) { return; }
if (print_inputs) {
console.log(`key up ${keyCode}`);
@@ -2618,8 +2697,8 @@ function registerKeyboardEvents() {
}
};
document.onkeypress = function(e){
if(!("charCode" in e)){
document.onkeypress = function (e) {
if (!("charCode" in e)) {
console.warn("KeyboardEvent.charCode is deprecated in this browser, cannot send key press.");
return;
}
@@ -2632,30 +2711,28 @@ function registerKeyboardEvents() {
};
}
function settingsClicked( /* e */ ) {
function settingsClicked( /* e */) {
/**
* Toggle settings panel. If stats panel is already open, close it and then open settings
*/
let settings = document.getElementById('settings-panel');
let stats = document.getElementById('stats-panel');
if(stats.classList.contains("panel-wrap-visible"))
{
if (stats.classList.contains("panel-wrap-visible")) {
stats.classList.toggle("panel-wrap-visible");
}
settings.classList.toggle("panel-wrap-visible");
}
function statsClicked( /* e */ ) {
function statsClicked( /* e */) {
/**
* Toggle stats panel. If settings panel is already open, close it and then open stats
*/
let settings = document.getElementById('settings-panel');
let stats = document.getElementById('stats-panel');
if(settings.classList.contains("panel-wrap-visible"))
{
if (settings.classList.contains("panel-wrap-visible")) {
settings.classList.toggle("panel-wrap-visible");
}
@@ -2703,21 +2780,22 @@ function connect() {
ws = new WebSocket(connectionUrl);
ws.attemptStreamReconnection = true;
ws.onmessagebinary = function(event) {
if(!event || !event.data) { return; }
ws.onmessagebinary = function (event) {
if (!event || !event.data) { return; }
event.data.text().then(function(messageString){
event.data.text().then(function (messageString) {
// send the new stringified event back into `onmessage`
ws.onmessage({ data: messageString });
}).catch(function(error){
}).catch(function (error) {
console.error(`Failed to parse binary blob from websocket, reason: ${error}`);
});
}
ws.onmessage = function(event) {
ws.onmessage = function (event) {
cirrusWebsocket = ws
// Check if websocket message is binary, if so, stringify it.
if(event.data && event.data instanceof Blob) {
if (event.data && event.data instanceof Blob) {
ws.onmessagebinary(event);
return;
}
@@ -2738,36 +2816,38 @@ function connect() {
onWebRtcAnswer(msg);
} else if (msg.type === 'iceCandidate') {
onWebRtcIce(msg.candidate);
} else if(msg.type === 'warning' && msg.warning) {
} else if (msg.type === 'warning' && msg.warning) {
console.warn(msg.warning);
} else if (msg.type === 'peerDataChannels') {
onWebRtcSFUPeerDatachannels(msg);
} else if (msg.type === 'lastOtherPlayerInput') {
updateLastOtherPlayerInput();
} else {
console.error("Invalid SS message type", msg.type);
}
};
ws.onerror = function(event) {
ws.onerror = function (event) {
console.log(`WS error: ${JSON.stringify(event)}`);
cirrusWebsocket = null
};
ws.onclose = function(event) {
ws.onclose = function (event) {
cirrusWebsocket = null
closeStream();
if(ws.attemptStreamReconnection === true){
if (ws.attemptStreamReconnection === true) {
console.log(`WS closed: ${JSON.stringify(event.code)} - ${event.reason}`);
if(event.reason !== "")
{
if (event.reason !== "") {
showTextOverlay(`DISCONNECTED: ${event.reason.toUpperCase()}`);
}
else
{
else {
showTextOverlay(`DISCONNECTED`);
}
let reclickToStart = setTimeout(function(){
let reclickToStart = setTimeout(function () {
start(true)
}, 4000);
}
@@ -2815,7 +2895,7 @@ function clearMouseEvents(playerElement) {
function toggleControlScheme() {
let schemeToggle = document.getElementById("control-scheme-text");
switch (inputOptions.controlScheme) {
case ControlSchemeType.HoveringMouse:
inputOptions.controlScheme = ControlSchemeType.LockedMouse;
@@ -2833,8 +2913,7 @@ function toggleControlScheme() {
}
console.log(`Updating control scheme to: ${inputOptions.controlScheme ? "Hovering Mouse" : "Locked Mouse"}`)
if(webRtcPlayerObj && webRtcPlayerObj.video)
{
if (webRtcPlayerObj && webRtcPlayerObj.video) {
registerMouse(webRtcPlayerObj.video);
}
}
@@ -2847,14 +2926,14 @@ function toggleBrowserCursorVisibility() {
}
function restartStream() {
if(!ws){
if (!ws) {
return;
}
ws.attemptStreamReconnection = false;
let existingOnClose = ws.onclose;
ws.onclose = function(event) {
ws.onclose = function (event) {
existingOnClose(event);
// this is how we restart
connect_on_load = true;
@@ -2870,7 +2949,7 @@ function closeStream() {
if (webRtcPlayerObj) {
// Remove video element from the page.
let playerDiv = document.getElementById('player');
if(playerDiv){
if (playerDiv) {
playerDiv.removeChild(webRtcPlayerObj.video);
}
let outer = document.getElementById("outer");
@@ -2895,6 +2974,6 @@ function load() {
setupFreezeFrameOverlay();
registerKeyboardEvents();
// Example response event listener that logs to console
addResponseEventListener('logListener', (response) => {console.log(`Received response message from streamer: "${response}"`)})
addResponseEventListener('logListener', (response) => { console.log(`Received response message from streamer: "${response}"`) })
start(false);
}
@@ -75,7 +75,8 @@ function webRtcPlayer(parOptions) {
}
// Prefer SFU or P2P connection
this.preferSFU = urlParams.has('preferSFU');
this.preferSFU = true//urlParams.has('preferSFU');
console.log('USING SFU: ', this.preferSFU)
console.log(this.preferSFU ?
"The browser will signal it would prefer an SFU connection. Remove ?preferSFU from the url to signal for P2P usage." :
"The browser will signal for a P2P connection. Pass ?preferSFU in the url to signal for SFU usage.");
+772
View File
@@ -0,0 +1,772 @@
{
"name": "WebServers",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"dependencies": {
"request": "^2.88.2"
}
},
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/epoberezkin"
}
},
"node_modules/asn1": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
"integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
"dependencies": {
"safer-buffer": "~2.1.0"
}
},
"node_modules/assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==",
"engines": {
"node": ">=0.8"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
"integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==",
"engines": {
"node": "*"
}
},
"node_modules/aws4": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz",
"integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg=="
},
"node_modules/bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
"dependencies": {
"tweetnacl": "^0.14.3"
}
},
"node_modules/caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="
},
"node_modules/dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==",
"dependencies": {
"assert-plus": "^1.0.0"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
"integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==",
"dependencies": {
"jsbn": "~0.1.0",
"safer-buffer": "^2.1.0"
}
},
"node_modules/extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
"node_modules/extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==",
"engines": [
"node >=0.6.0"
]
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"node_modules/forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==",
"engines": {
"node": "*"
}
},
"node_modules/form-data": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 0.12"
}
},
"node_modules/getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==",
"dependencies": {
"assert-plus": "^1.0.0"
}
},
"node_modules/har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
"integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==",
"engines": {
"node": ">=4"
}
},
"node_modules/har-validator": {
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
"integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
"deprecated": "this library is no longer supported",
"dependencies": {
"ajv": "^6.12.3",
"har-schema": "^2.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
"integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==",
"dependencies": {
"assert-plus": "^1.0.0",
"jsprim": "^1.2.2",
"sshpk": "^1.7.0"
},
"engines": {
"node": ">=0.8",
"npm": ">=1.3.7"
}
},
"node_modules/is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
},
"node_modules/isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g=="
},
"node_modules/jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg=="
},
"node_modules/json-schema": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
"integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
},
"node_modules/json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
},
"node_modules/json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="
},
"node_modules/jsprim": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
"integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
"dependencies": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
"json-schema": "0.4.0",
"verror": "1.10.0"
},
"engines": {
"node": ">=0.6.0"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/oauth-sign": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
"engines": {
"node": "*"
}
},
"node_modules/performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
},
"node_modules/psl": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
"integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag=="
},
"node_modules/punycode": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
"integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
"engines": {
"node": ">=6"
}
},
"node_modules/qs": {
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
"integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==",
"engines": {
"node": ">=0.6"
}
},
"node_modules/request": {
"version": "2.88.2",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
"integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
"deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142",
"dependencies": {
"aws-sign2": "~0.7.0",
"aws4": "^1.8.0",
"caseless": "~0.12.0",
"combined-stream": "~1.0.6",
"extend": "~3.0.2",
"forever-agent": "~0.6.1",
"form-data": "~2.3.2",
"har-validator": "~5.1.3",
"http-signature": "~1.2.0",
"is-typedarray": "~1.0.0",
"isstream": "~0.1.2",
"json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.19",
"oauth-sign": "~0.9.0",
"performance-now": "^2.1.0",
"qs": "~6.5.2",
"safe-buffer": "^5.1.2",
"tough-cookie": "~2.5.0",
"tunnel-agent": "^0.6.0",
"uuid": "^3.3.2"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"node_modules/sshpk": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz",
"integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==",
"dependencies": {
"asn1": "~0.2.3",
"assert-plus": "^1.0.0",
"bcrypt-pbkdf": "^1.0.0",
"dashdash": "^1.12.0",
"ecc-jsbn": "~0.1.1",
"getpass": "^0.1.1",
"jsbn": "~0.1.0",
"safer-buffer": "^2.0.2",
"tweetnacl": "~0.14.0"
},
"bin": {
"sshpk-conv": "bin/sshpk-conv",
"sshpk-sign": "bin/sshpk-sign",
"sshpk-verify": "bin/sshpk-verify"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/tough-cookie": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
"dependencies": {
"psl": "^1.1.28",
"punycode": "^2.1.1"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
"dependencies": {
"safe-buffer": "^5.0.1"
},
"engines": {
"node": "*"
}
},
"node_modules/tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="
},
"node_modules/uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"dependencies": {
"punycode": "^2.1.0"
}
},
"node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
"bin": {
"uuid": "bin/uuid"
}
},
"node_modules/verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==",
"engines": [
"node >=0.6.0"
],
"dependencies": {
"assert-plus": "^1.0.0",
"core-util-is": "1.0.2",
"extsprintf": "^1.2.0"
}
}
},
"dependencies": {
"ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"asn1": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
"integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
"requires": {
"safer-buffer": "~2.1.0"
}
},
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw=="
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
"integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA=="
},
"aws4": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz",
"integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg=="
},
"bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
"requires": {
"tweetnacl": "^0.14.3"
}
},
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="
},
"dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==",
"requires": {
"assert-plus": "^1.0.0"
}
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
},
"ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
"integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==",
"requires": {
"jsbn": "~0.1.0",
"safer-buffer": "^2.1.0"
}
},
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g=="
},
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw=="
},
"form-data": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
}
},
"getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==",
"requires": {
"assert-plus": "^1.0.0"
}
},
"har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
"integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q=="
},
"har-validator": {
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
"integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
"requires": {
"ajv": "^6.12.3",
"har-schema": "^2.0.0"
}
},
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
"integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==",
"requires": {
"assert-plus": "^1.0.0",
"jsprim": "^1.2.2",
"sshpk": "^1.7.0"
}
},
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
},
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g=="
},
"jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg=="
},
"json-schema": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
"integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
},
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
},
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="
},
"jsprim": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
"integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
"requires": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
"json-schema": "0.4.0",
"verror": "1.10.0"
}
},
"mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
},
"mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"requires": {
"mime-db": "1.52.0"
}
},
"oauth-sign": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
},
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
},
"psl": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
"integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag=="
},
"punycode": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
"integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA=="
},
"qs": {
"version": "6.5.3",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
"integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA=="
},
"request": {
"version": "2.88.2",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
"integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
"requires": {
"aws-sign2": "~0.7.0",
"aws4": "^1.8.0",
"caseless": "~0.12.0",
"combined-stream": "~1.0.6",
"extend": "~3.0.2",
"forever-agent": "~0.6.1",
"form-data": "~2.3.2",
"har-validator": "~5.1.3",
"http-signature": "~1.2.0",
"is-typedarray": "~1.0.0",
"isstream": "~0.1.2",
"json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.19",
"oauth-sign": "~0.9.0",
"performance-now": "^2.1.0",
"qs": "~6.5.2",
"safe-buffer": "^5.1.2",
"tough-cookie": "~2.5.0",
"tunnel-agent": "^0.6.0",
"uuid": "^3.3.2"
}
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"sshpk": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz",
"integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==",
"requires": {
"asn1": "~0.2.3",
"assert-plus": "^1.0.0",
"bcrypt-pbkdf": "^1.0.0",
"dashdash": "^1.12.0",
"ecc-jsbn": "~0.1.1",
"getpass": "^0.1.1",
"jsbn": "~0.1.0",
"safer-buffer": "^2.0.2",
"tweetnacl": "~0.14.0"
}
},
"tough-cookie": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
"requires": {
"psl": "^1.1.28",
"punycode": "^2.1.1"
}
},
"tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
"requires": {
"safe-buffer": "^5.0.1"
}
},
"tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="
},
"uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"requires": {
"punycode": "^2.1.0"
}
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
},
"verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==",
"requires": {
"assert-plus": "^1.0.0",
"core-util-is": "1.0.2",
"extsprintf": "^1.2.0"
}
}
}
}
+5
View File
@@ -0,0 +1,5 @@
{
"dependencies": {
"request": "^2.88.2"
}
}