init commit
This commit is contained in:
5
webapp/data/changelog/content.json
Normal file
5
webapp/data/changelog/content.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"ver": 8,
|
||||
"blurb": "- Client no longer disconnects when copying large amounts of text.\n- A new prompt to say Arcade goes away April 15, 2023.\n- [Windows] Windows 7 is now fully unsupported.\n- [Windows] Switch the WebSocket system to WinHTTP.\n- [Windows Paid] Virtual Tablets now works with up to 3 Screens.\n- [MacOS] Prompt to download the Apple Silicon build of Parsec.\n- [Ubuntu] We no longer block non text clipboard for other apps.",
|
||||
"date": "150-87b"
|
||||
}
|
445
webapp/data/errors/codes.json
Normal file
445
webapp/data/errors/codes.json
Normal file
@ -0,0 +1,445 @@
|
||||
{
|
||||
"3": {
|
||||
"url": "",
|
||||
"type": "warning",
|
||||
"title": "",
|
||||
"desc": "The host OS closed the Parsec application due to a login/logout event, please reconnect."
|
||||
},
|
||||
"4": {
|
||||
"url": "",
|
||||
"type": "warning",
|
||||
"title": "",
|
||||
"desc": "The host shut down."
|
||||
},
|
||||
"5": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/115002625091",
|
||||
"type": "warning",
|
||||
"title": "",
|
||||
"desc": "You have been kicked by the host."
|
||||
},
|
||||
"6": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/115002624531",
|
||||
"type": "warning",
|
||||
"title": "Your connection attempt wasn't approved in time",
|
||||
"desc": "The host needs to approve your connection for you to join."
|
||||
},
|
||||
"8": {
|
||||
"url": "",
|
||||
"type": "warning",
|
||||
"title": "Your connection attempt was rejected",
|
||||
"desc": "The host declined your request or blocked you."
|
||||
},
|
||||
"9": {
|
||||
"url": "",
|
||||
"type": "warning",
|
||||
"title": "",
|
||||
"desc": "You canceled the connection attempt."
|
||||
},
|
||||
"11": {
|
||||
"url": "",
|
||||
"type": "warning",
|
||||
"title": "The game or computer you tried to join is full",
|
||||
"desc": "Wait for a free slot or ask the host to increase the number of players."
|
||||
},
|
||||
"12": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/6371362020365",
|
||||
"type": "warning",
|
||||
"title": "",
|
||||
"desc": "You were disconnected from the host due to inactivity."
|
||||
},
|
||||
"30": {
|
||||
"url": "https://parsec.app/downloads",
|
||||
"label": "Download",
|
||||
"type": "warning",
|
||||
"title": "Your browser can not make connections in the web app",
|
||||
"desc": "The Parsec web app only works in recent versions of Chrome and Edge, please use one of these browsers or install the Parsec app on your client to continue."
|
||||
},
|
||||
"99": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/115002601752",
|
||||
"type": "warning",
|
||||
"title": "The computer you're connecting to is no longer available",
|
||||
"desc": "Check if the machine is online, get a new link if applicable, or try to restart Parsec on both ends."
|
||||
},
|
||||
"101": {
|
||||
"url": "",
|
||||
"type": "warning",
|
||||
"title": "Multi-factor authentication is required",
|
||||
"desc": "Your team requires that you enable multi-factor authentication before making connections."
|
||||
},
|
||||
"112": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360049831391",
|
||||
"type": "warning",
|
||||
"title": "You don't have the permission to connect to this computer",
|
||||
"desc": "You're not in the same Parsec Teams group as the computer you're attempting to connect to."
|
||||
},
|
||||
"-14": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/115002625712",
|
||||
"type": "error",
|
||||
"title": "Your device failed to decode the video stream",
|
||||
"desc": "Lower the host computer's resolution or check our article for more information."
|
||||
},
|
||||
"-18": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360001690972",
|
||||
"type": "error",
|
||||
"title": "Your device had issues decoding the video stream",
|
||||
"desc": "This device may be incompatible with Parsec, please check our article for more information."
|
||||
},
|
||||
"-19": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360002529252",
|
||||
"type": "error",
|
||||
"title": "Your device isn't supported by Parsec",
|
||||
"desc": "This Android device does not work with Parsec currently."
|
||||
},
|
||||
"-1002": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/115002626391",
|
||||
"type": "error",
|
||||
"title": "You don't have access to a host computer",
|
||||
"desc": "Running Parsec in CLI mode requires that you enable hosting on a Windows machine."
|
||||
},
|
||||
"-1003": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/115002626611",
|
||||
"type": "error",
|
||||
"title": "Parsec does not have sufficient permissions on this device",
|
||||
"desc": "Parsec was unable to write required data to your device."
|
||||
},
|
||||
"-1400": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1401": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1402": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1403": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1404": {
|
||||
"url": "",
|
||||
"type": "error",
|
||||
"title": "This game cannot be captured because it is running as administrator",
|
||||
"desc": "Ensure your game and game store isn't running as administrator before trying to host."
|
||||
},
|
||||
"-1405": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1406": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/6367984442765",
|
||||
"type": "error",
|
||||
"title": "Arcade's attempt to capture the game timed out",
|
||||
"desc": "Ensure the game is the active window, or check our article for more information."
|
||||
},
|
||||
"-1407": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360059600491",
|
||||
"type": "error",
|
||||
"title": "Arcade is missing some important files to capture this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1408": {
|
||||
"url": "",
|
||||
"type": "error",
|
||||
"title": "Arcade already interacted with this game previously",
|
||||
"desc": "Restart your game before trying to host it again."
|
||||
},
|
||||
"-1409": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1410": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1500": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1501": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1502": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1503": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1504": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1505": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1506": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1507": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1508": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1509": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1510": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1511": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1512": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1513": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1514": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-1515": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360037758052",
|
||||
"type": "error",
|
||||
"title": "Arcade had trouble capturing this game",
|
||||
"desc": "Please check our article for more information."
|
||||
},
|
||||
"-2001": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/115002626051",
|
||||
"type": "error",
|
||||
"title": "You do not have permission to make this connection",
|
||||
"desc": "You can't connect with this peer_id."
|
||||
},
|
||||
"-6023": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/115002601011",
|
||||
"type": "error",
|
||||
"title": "The peer-to-peer network connection between you and the other computer failed",
|
||||
"desc": "Something is preventing Parsec from making the connection, check our article for more information."
|
||||
},
|
||||
"-6024": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/115002601011",
|
||||
"type": "error",
|
||||
"title": "Failed to connect to Parsec STUN servers",
|
||||
"desc": "Something may be blocking your connection to the Parsec STUN server, check our article for more information."
|
||||
},
|
||||
"-6101": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360000059931",
|
||||
"type": "error",
|
||||
"title": "Parsec couldn't communicate with its servers",
|
||||
"desc": "Something is preventing Parsec from making a websocket connection to its backend."
|
||||
},
|
||||
"-6112": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360023178732",
|
||||
"type": "error",
|
||||
"title": "IPv6 is disabled or not supported",
|
||||
"desc": "Your device must support IPv6 even if you're using IPv4."
|
||||
},
|
||||
"-6200": {
|
||||
"url": "https://parsec.app/downloads",
|
||||
"label": "Download",
|
||||
"type": "error",
|
||||
"title": "The network connection between you and the other computer failed with webRTC",
|
||||
"desc": "Please install Parsec on your client which is more likely to work."
|
||||
},
|
||||
"-7000": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/115002626232",
|
||||
"type": "error",
|
||||
"title": "OpenGL was unable to be launched",
|
||||
"desc": "Make sure your device meets our minimum requirements and is setup correctly."
|
||||
},
|
||||
"-7007": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/115002626272",
|
||||
"type": "error",
|
||||
"title": "This device has an incompatible version of OpenGL",
|
||||
"desc": "Make sure your device meets our minimum requirements and is setup correctly."
|
||||
},
|
||||
"-6107": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/4410906958861",
|
||||
"type": "error",
|
||||
"title": "",
|
||||
"desc": "You must re-authenticate."
|
||||
},
|
||||
"-12007": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/115003074512",
|
||||
"type": "error",
|
||||
"title": "The network connection was lost",
|
||||
"desc": "The connection is unreliable, or the other computer has crashed."
|
||||
},
|
||||
"-12010": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/115003074532",
|
||||
"type": "error",
|
||||
"title": "The computer you were connected to disappeared",
|
||||
"desc": "The computer may have crashed or lost the internet connection."
|
||||
},
|
||||
"-13000": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/115002623532",
|
||||
"type": "error",
|
||||
"title": "The computer you're joining is trying to use an unsupported resolution",
|
||||
"desc": "Change the resolution to something else on the host computer's Parsec settings."
|
||||
},
|
||||
"-13008": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/115002623751",
|
||||
"type": "error",
|
||||
"title": "The computer you're joining is trying to use an unsupported resolution",
|
||||
"desc": "Change the resolution to something else on the host computer's Parsec settings."
|
||||
},
|
||||
"-13009": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360000159992",
|
||||
"type": "error",
|
||||
"title": "The host resolution is above our maximum supported resolution of 3840x2160",
|
||||
"desc": "Try to lower the resolution of the display on the host computer."
|
||||
},
|
||||
"-13012": {
|
||||
"url": "",
|
||||
"type": "warning",
|
||||
"title": "",
|
||||
"desc": "The host is not allowing any more guests."
|
||||
},
|
||||
"-13015": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360047224232",
|
||||
"type": "error",
|
||||
"title": "Something went wrong with the client device while initializing the stream",
|
||||
"desc": "Your government or ISP may be blocking Parsec's encryption, you can try to use our web app or a VPN to get around this."
|
||||
},
|
||||
"-14003": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360002165172",
|
||||
"type": "error",
|
||||
"title": "We were unable to capture the screen of the computer you were attempting to connect to",
|
||||
"desc": "Check our article for more information."
|
||||
},
|
||||
"-15000": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/115002624051",
|
||||
"type": "error",
|
||||
"title": "The computer you are attempting connect to does not support hardware video encoding",
|
||||
"desc": "The host computer may have unsupported hardware or its drivers need an update, check our article for more information."
|
||||
},
|
||||
"-15002": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360000513331",
|
||||
"type": "error",
|
||||
"title": "The host encoder failed",
|
||||
"desc": "This could be because on the host either HDR is active, the display resolution is too high, or the graphics driver needs an update."
|
||||
},
|
||||
"-15106": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360033132792",
|
||||
"type": "error",
|
||||
"title": "The host encoder failed",
|
||||
"desc": "This could be because on the host either HDR is active, or the display resolution is too high."
|
||||
},
|
||||
"-15107": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360001383432",
|
||||
"type": "error",
|
||||
"title": "The resolution is too high on the host",
|
||||
"desc": "Reduce the resolution on the host computer to connect."
|
||||
},
|
||||
"-17001": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/115002626412",
|
||||
"type": "error",
|
||||
"title": "Your Raspberry Pi is configured incorrectly",
|
||||
"desc": "Disable the experimental OpenGL driver or check our article for more information about how to set up Raspberry Pi correctly."
|
||||
},
|
||||
"-18000": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/115002626352",
|
||||
"type": "error",
|
||||
"title": "Parsec couldn't communicate with its servers",
|
||||
"desc": "Check if your internet is working, and if it is, check our article for more information."
|
||||
},
|
||||
"-22008": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360002165172",
|
||||
"type": "error",
|
||||
"title": "",
|
||||
"desc": "The host could not capture the screen."
|
||||
},
|
||||
"-32001": {
|
||||
"url": "https://parsec.app/downloads",
|
||||
"label": "Download",
|
||||
"type": "error",
|
||||
"title": "The web app failed to connect to your host",
|
||||
"desc": "Please install the Parsec app on your client and retry the connection."
|
||||
},
|
||||
"-32002": {
|
||||
"url": "https://parsec.app/downloads",
|
||||
"label": "Download",
|
||||
"type": "error",
|
||||
"title": "The web app failed to connect to your host",
|
||||
"desc": "Please install the Parsec app on your client and retry the connection."
|
||||
},
|
||||
"-32003": {
|
||||
"url": "https://parsec.app/downloads",
|
||||
"label": "Download",
|
||||
"type": "error",
|
||||
"title": "The web app failed to connect to your host",
|
||||
"desc": "Please install the Parsec app on your client and retry the connection."
|
||||
},
|
||||
"-800097": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360004310251",
|
||||
"type": "error",
|
||||
"title": "IPv6 is disabled",
|
||||
"desc": "Your device must have IPv6 enabled even if you're using IPv4."
|
||||
},
|
||||
"-800098": {
|
||||
"url": "https://support.parsec.app/hc/en-us/articles/360004310251",
|
||||
"type": "error",
|
||||
"title": "IPv6 is disabled",
|
||||
"desc": "Your device must have IPv6 enabled even if you're using IPv4."
|
||||
}
|
||||
}
|
1
webapp/data/notifications/downtime.json
Normal file
1
webapp/data/notifications/downtime.json
Normal file
@ -0,0 +1 @@
|
||||
{"display":false,"title":"","message":"","type":"","link_title":"","link_url":""}
|
BIN
webapp/favicon.ico
Normal file
BIN
webapp/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 108 KiB |
47
webapp/index.html
Normal file
47
webapp/index.html
Normal file
@ -0,0 +1,47 @@
|
||||
<!doctype html>
|
||||
<html lang='en-us'>
|
||||
|
||||
<head>
|
||||
<meta charset='utf-8'/>
|
||||
<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
|
||||
|
||||
<script src='static/lib/matoya.js'></script>
|
||||
<script src='static/lib/weblib.js'></script>
|
||||
<script src='static/lib/parsec.js'></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
function endFunc() {
|
||||
const sp = new URLSearchParams(window.location.search);
|
||||
|
||||
if (sp.get('session_id')) {
|
||||
window.location = 'https://parsec.app/signup';
|
||||
|
||||
} else {
|
||||
window.close();
|
||||
}
|
||||
}
|
||||
|
||||
(async function () {
|
||||
if (!await MTY_Start('parsecd', PARSEC_ENV, endFunc)) {
|
||||
document.body.style.fontFamily = 'sans-serif';
|
||||
document.body.style.fontSize = '30px';
|
||||
document.body.style.background = 'black';
|
||||
document.body.style.color = 'white';
|
||||
document.body.style.textAlign = 'center';
|
||||
document.body.style.padding = '10% 30px 0 30px';
|
||||
|
||||
document.body.innerHTML =
|
||||
'<div>Your browser does not support the Parsec web app. The web app requires WebGL and WebAssembly 64-bit support.</div>' +
|
||||
'<div style="margin-top:30px">Check the <a href="https://parsec.app/downloads">Downloads</a> page for our native app.</div>';
|
||||
}
|
||||
|
||||
window.history.replaceState(null, document.title, '/');
|
||||
document.querySelector("body > textarea").remove();
|
||||
})();
|
||||
|
||||
console.log('%cSTOP! ✋ This area is intended for developers. Pasting something here could give strangers access to your Parsec account.', 'font-size: 18px; font-weight: 700;');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
46
webapp/index.html.bak
Normal file
46
webapp/index.html.bak
Normal file
@ -0,0 +1,46 @@
|
||||
<!doctype html>
|
||||
<html lang='en-us'>
|
||||
|
||||
<head>
|
||||
<meta charset='utf-8'/>
|
||||
<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
|
||||
|
||||
<script src='static/lib/matoya.js'></script>
|
||||
<script src='static/lib/weblib.js'></script>
|
||||
<script src='static/lib/parsec.js'></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>
|
||||
function endFunc() {
|
||||
const sp = new URLSearchParams(window.location.search);
|
||||
|
||||
if (sp.get('session_id')) {
|
||||
window.location = 'https://parsec.app/signup';
|
||||
|
||||
} else {
|
||||
window.close();
|
||||
}
|
||||
}
|
||||
|
||||
(async function () {
|
||||
if (!await MTY_Start('parsecd', PARSEC_ENV, endFunc)) {
|
||||
document.body.style.fontFamily = 'sans-serif';
|
||||
document.body.style.fontSize = '30px';
|
||||
document.body.style.background = 'black';
|
||||
document.body.style.color = 'white';
|
||||
document.body.style.textAlign = 'center';
|
||||
document.body.style.padding = '10% 30px 0 30px';
|
||||
|
||||
document.body.innerHTML =
|
||||
'<div>Your browser does not support the Parsec web app. The web app requires WebGL and WebAssembly 64-bit support.</div>' +
|
||||
'<div style="margin-top:30px">Check the <a href="https://parsec.app/downloads">Downloads</a> page for our native app.</div>';
|
||||
}
|
||||
|
||||
window.history.replaceState(null, document.title, '/');
|
||||
})();
|
||||
|
||||
console.log('%cSTOP! ✋ This area is intended for developers. Pasting something here could give strangers access to your Parsec account.', 'font-size: 18px; font-weight: 700;');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
BIN
webapp/parsecd
Normal file
BIN
webapp/parsecd
Normal file
Binary file not shown.
1512
webapp/static/lib/matoya.js
Normal file
1512
webapp/static/lib/matoya.js
Normal file
File diff suppressed because it is too large
Load Diff
46
webapp/static/lib/parsec.js
Normal file
46
webapp/static/lib/parsec.js
Normal file
@ -0,0 +1,46 @@
|
||||
'use strict';var h;function q(a){var b=0;return function(){return b<a.length?{done:!1,value:a[b++]}:{done:!0}}}function r(a){var b="undefined"!=typeof Symbol&&Symbol.iterator&&a[Symbol.iterator];return b?b.call(a):{next:q(a)}}var w="undefined"!=typeof window&&window===this?this:"undefined"!=typeof global&&null!=global?global:this,x="function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,d){a!=Array.prototype&&a!=Object.prototype&&(a[b]=d.value)};
|
||||
function y(a,b){if(b){var d=w;a=a.split(".");for(var c=0;c<a.length-1;c++){var g=a[c];g in d||(d[g]={});d=d[g]}a=a[a.length-1];c=d[a];b=b(c);b!=c&&null!=b&&x(d,a,{configurable:!0,writable:!0,value:b})}}
|
||||
y("Promise",function(a){function b(e){this.c=0;this.h=void 0;this.b=[];var f=this.f();try{e(f.resolve,f.reject)}catch(m){f.reject(m)}}function d(){this.b=null}function c(e){return e instanceof b?e:new b(function(f){f(e)})}if(a)return a;d.prototype.c=function(e){if(null==this.b){this.b=[];var f=this;this.f(function(){f.h()})}this.b.push(e)};var g=w.setTimeout;d.prototype.f=function(e){g(e,0)};d.prototype.h=function(){for(;this.b&&this.b.length;){var e=this.b;this.b=[];for(var f=0;f<e.length;++f){var m=
|
||||
e[f];e[f]=null;try{m()}catch(p){this.g(p)}}}this.b=null};d.prototype.g=function(e){this.f(function(){throw e;})};b.prototype.f=function(){function e(p){return function(t){m||(m=!0,p.call(f,t))}}var f=this,m=!1;return{resolve:e(this.o),reject:e(this.g)}};b.prototype.o=function(e){if(e===this)this.g(new TypeError("A Promise cannot resolve to itself"));else if(e instanceof b)this.s(e);else{a:switch(typeof e){case "object":var f=null!=e;break a;case "function":f=!0;break a;default:f=!1}f?this.m(e):this.i(e)}};
|
||||
b.prototype.m=function(e){var f=void 0;try{f=e.then}catch(m){this.g(m);return}"function"==typeof f?this.B(f,e):this.i(e)};b.prototype.g=function(e){this.j(2,e)};b.prototype.i=function(e){this.j(1,e)};b.prototype.j=function(e,f){if(0!=this.c)throw Error("Cannot settle("+e+", "+f+"): Promise already settled in state"+this.c);this.c=e;this.h=f;this.l()};b.prototype.l=function(){if(null!=this.b){for(var e=0;e<this.b.length;++e)k.c(this.b[e]);this.b=null}};var k=new d;b.prototype.s=function(e){var f=this.f();
|
||||
e.v(f.resolve,f.reject)};b.prototype.B=function(e,f){var m=this.f();try{e.call(f,m.resolve,m.reject)}catch(p){m.reject(p)}};b.prototype.then=function(e,f){function m(n,u){return"function"==typeof n?function(v){try{p(n(v))}catch(A){t(A)}}:u}var p,t,l=new b(function(n,u){p=n;t=u});this.v(m(e,p),m(f,t));return l};b.prototype.catch=function(e){return this.then(void 0,e)};b.prototype.v=function(e,f){function m(){switch(p.c){case 1:e(p.h);break;case 2:f(p.h);break;default:throw Error("Unexpected state: "+
|
||||
p.c);}}var p=this;null==this.b?k.c(m):this.b.push(m)};b.resolve=c;b.reject=function(e){return new b(function(f,m){m(e)})};b.race=function(e){return new b(function(f,m){for(var p=r(e),t=p.next();!t.done;t=p.next())c(t.value).v(f,m)})};b.all=function(e){var f=r(e),m=f.next();return m.done?c([]):new b(function(p,t){function l(v){return function(A){n[v]=A;u--;0==u&&p(n)}}var n=[],u=0;do n.push(void 0),u++,c(m.value).v(l(n.length-1),t),m=f.next();while(!m.done)})};return b});
|
||||
function z(){z=function(){};w.Symbol||(w.Symbol=aa)}function B(a,b){this.b=a;x(this,"description",{configurable:!0,writable:!0,value:b})}B.prototype.toString=function(){return this.b};var aa=function(){function a(d){if(this instanceof a)throw new TypeError("Symbol is not a constructor");return new B("jscomp_symbol_"+(d||"")+"_"+b++,d)}var b=0;return a}();
|
||||
function C(){z();var a=w.Symbol.iterator;a||(a=w.Symbol.iterator=w.Symbol("Symbol.iterator"));"function"!=typeof Array.prototype[a]&&x(Array.prototype,a,{configurable:!0,writable:!0,value:function(){return ba(q(this))}});C=function(){}}function ba(a){C();a={next:a};a[w.Symbol.iterator]=function(){return this};return a}function D(){this.g=!1;this.c=null;this.i=void 0;this.b=1;this.l=this.h=0;this.f=null}function E(a){if(a.g)throw new TypeError("Generator is already running");a.g=!0}
|
||||
D.prototype.j=function(a){this.i=a};function F(a,b){a.f={F:b,U:!0};a.b=a.h||a.l}D.prototype.return=function(a){this.f={return:a};this.b=this.l};function G(a,b,d){a.b=d;return{value:b}}function ca(a){this.b=new D;this.c=a}function da(a,b){E(a.b);var d=a.b.c;if(d)return H(a,"return"in d?d["return"]:function(c){return{value:c,done:!0}},b,a.b.return);a.b.return(b);return I(a)}
|
||||
function H(a,b,d,c){try{var g=b.call(a.b.c,d);if(!(g instanceof Object))throw new TypeError("Iterator result "+g+" is not an object");if(!g.done)return a.b.g=!1,g;var k=g.value}catch(e){return a.b.c=null,F(a.b,e),I(a)}a.b.c=null;c.call(a.b,k);return I(a)}function I(a){for(;a.b.b;)try{var b=a.c(a.b);if(b)return a.b.g=!1,{value:b.value,done:!1}}catch(d){a.b.i=void 0,F(a.b,d)}a.b.g=!1;if(a.b.f){b=a.b.f;a.b.f=null;if(b.U)throw b.F;return{value:b.return,done:!0}}return{value:void 0,done:!0}}
|
||||
function ea(a){this.next=function(b){E(a.b);a.b.c?b=H(a,a.b.c.next,b,a.b.j):(a.b.j(b),b=I(a));return b};this.throw=function(b){E(a.b);a.b.c?b=H(a,a.b.c["throw"],b,a.b.j):(F(a.b,b),b=I(a));return b};this.return=function(b){return da(a,b)};C();this[Symbol.iterator]=function(){return this}}function fa(a){function b(c){return a.next(c)}function d(c){return a.throw(c)}return new Promise(function(c,g){function k(e){e.done?c(e.value):Promise.resolve(e.value).then(b,d).then(k,g)}k(a.next())})}
|
||||
function J(a){return fa(new ea(new ca(a)))}y("Object.entries",function(a){return a?a:function(b){var d=[],c;for(c in b)Object.prototype.hasOwnProperty.call(b,c)&&d.push([c,b[c]]);return d}});
|
||||
y("Array.from",function(a){return a?a:function(b,d,c){d=null!=d?d:function(f){return f};var g=[],k="undefined"!=typeof Symbol&&Symbol.iterator&&b[Symbol.iterator];if("function"==typeof k){b=k.call(b);for(var e=0;!(k=b.next()).done;)g.push(d.call(c,k.value,e++))}else for(k=b.length,e=0;e<k;e++)g.push(d.call(c,b[e],e));return g}});function K(a,b){if(null==a)throw new TypeError("The 'this' value for String.prototype."+b+" must not be null or undefined");return a+""}
|
||||
y("String.prototype.repeat",function(a){return a?a:function(b){var d=K(this,"repeat");if(0>b||1342177279<b)throw new RangeError("Invalid count value");b|=0;for(var c="";b;)if(b&1&&(c+=d),b>>>=1)d+=d;return c}});y("String.prototype.padStart",function(a){return a?a:function(b,d){var c=K(this,"padStart");b-=c.length;d=void 0!==d?String(d):" ";return(0<b&&d?d.repeat(Math.ceil(b/d.length)).substring(0,b):"")+c}});
|
||||
var L={PARSEC_OK:0,PARSEC_CONNECTING:20,PARSEC_WRN_BROWSER:30,CONNECT_WRN_APPROVAL:6,CONNECT_WRN_DECLINED:8,CONNECT_WRN_PEER_GONE:99,CONNECT_WRN_UNCONFIRMED:100,PARSEC_NOT_RUNNING:-3,WS_ERR_CONNECT:-6101,WS_ERR_CLOSE:-6105,NAT_ERR_WEBRTC:-6200};function M(a,b,d,c){d=c?d.bind(c):d;a.addEventListener(b,d);return[a,b,d]}function ha(a){a=r(a);for(var b=a.next();!b.done;b=a.next())b=b.value,b[0].removeEventListener(b[1],b[2])}
|
||||
function N(a,b,d,c,g){a=new DataView(a);a.setInt32(0,d);a.setInt32(4,c);a.setInt32(8,g);a.setInt8(12,b)}function O(a,b,d,c){var g=new ArrayBuffer(13);N(g,a,b,d,c);return g}function ia(a,b,d){var c=new ArrayBuffer(13+d.length+1);N(c,a,d.length+1,b,0);a=(new TextEncoder).encode(d);b=new Int8Array(c,13);for(var g=0;g<d.length;g++)b[g]=a[g];return c}
|
||||
function ja(a,b){a=JSON.stringify({_version:1,_max_w:6E4,_max_h:6E4,_flags:0,resolutionX:a,resolutionY:b,refreshRate:60,mediaContainer:2});return ia(11,0,a)}
|
||||
function ka(a,b){switch(a.type){case 4:if(!a.relative){var d=b.videoWidth,c=b.videoHeight,g=Math.round(b.offsetWidth*window.devicePixelRatio),k=Math.round(b.offsetHeight*window.devicePixelRatio),e=Math.min(g/d,k/c);b=d*e;e*=c;k=Math.max((k-e)/2,0);g=Math.round(d/b*(a.x-Math.max((g-b)/2,0)));g===d-1&&(g=d);g>d&&(g=d);0>g&&(g=0);a.x=g;d=Math.round(c/e*(a.y-k));d===c-1&&(d=c);d>c&&(d=c);0>d&&(d=0);a.y=d}return O(3,a.relative?1:0,a.x,a.y);case 8:return c=new ArrayBuffer(28),N(c,23,a.id,0,0),d=new DataView(c),
|
||||
d.setUint16(16,a.buttons),d.setInt16(18,a.thumbLX),d.setInt16(20,a.thumbLY),d.setInt16(22,a.thumbRX),d.setInt16(24,a.thumbRY),d.setUint8(26,a.leftTrigger),d.setUint8(27,a.rightTrigger),c;case 2:return O(1,a.button,a.pressed?1:0,0);case 1:return O(0,a.code,a.mod,a.pressed?1:0);case 3:return O(2,a.x,a.y,0);case 5:return O(4,a.button,a.pressed?1:0,a.id);case 6:return O(5,a.axis,a.value,a.id);case 7:return O(6,0,0,a.id);case 9:return O(24,0,0,0)}}var P={},la=1;
|
||||
function ma(a){var b=la++;P[b]=a;return b}function na(a){var b=a.getInt16(32),d=a.getInt32(16),c=0<d?new Uint8Array(a.buffer,34,d):null;c=c?ma(c):0;return{type:1,cursor:{size:d,positionX:a.getInt16(24),positionY:a.getInt16(26),width:a.getInt16(20),height:a.getInt16(22),hotX:a.getInt16(28),hotY:a.getInt16(30),imageUpdate:0<c,relative:!!(b&256),hidden:!!(b&512),stream:0},key:c}}function oa(a,b){b=ma(new Uint8Array(b.buffer,13,a.u));return{type:3,id:a.w,key:b}}
|
||||
function pa(){var a=new Uint8Array(16);crypto.getRandomValues(a);return a.map(function(b){return b%10}).join("")}
|
||||
function Q(a){var b=this;this.l=a;this.i=!1;this.j="";this.h=!1;this.b=this.sdp=null;this.c={};this.g=[];this.f=null;this.b=new RTCPeerConnection({iceServers:[{urls:"stun:stun.parsec.gg:3478"}]});this.b.onicecandidate=function(d){d.candidate&&(d=d.candidate.candidate.replace("candidate:","").split(" "),8<=d.length&&"udp"===d[2].toLowerCase()&&b.l(d[4],parseInt(d[5],10),!1,"srflx"===d[7],"host"===d[7]))}}
|
||||
Q.prototype.close=function(){for(var a=r(Object.entries(this.c)),b=a.next();!b.done;b=a.next())b.value[1].close();this.b.close()};function R(a,b,d,c,g){a.c[d]=a.b.createDataChannel(b,{negotiated:!0,id:d});a.c[d].binaryType="arraybuffer";a.c[d].onopen=c;a.c[d].onmessage=g}
|
||||
function qa(a){var b;return J(function(d){if(1==d.b)return b=a,G(d,a.b.createOffer(),2);b.f=d.i;for(var c=a.f.sdp.split("\n"),g={},k=0;k<c.length;k++){var e=c[k].split("="),f=e[0];e=e[1];f&&("a"===f?(g.a||(g.a={}),f=e.split(/:(.+)/),g.a[f[0]]=f[1]):g[f]=e)}a.sdp=g;return d.return({ice_ufrag:a.sdp.a["ice-ufrag"],ice_pwd:a.sdp.a["ice-pwd"],fingerprint:a.sdp.a.fingerprint})})}Q.prototype.send=function(a,b){"open"==this.c[b].readyState&&this.c[b].send(a)};
|
||||
function ra(a){for(;0<a.g.length;){var b=a.g.shift();a.b.addIceCandidate(new RTCIceCandidate({candidate:"candidate:2395300328 1 udp 2113937151 "+b.ip+" "+(b.port+" typ "+(b.from_stun?"srflx":"host")+" generation 0 ufrag "+a.j+" network-cost 50"),sdpMid:a.sdp.a.mid,sdpMLineIndex:0}))}}
|
||||
function sa(a,b,d,c){var g,k;J(function(e){switch(e.b){case 1:if(!a.f)throw"Offer is not set";if(a.h){e.b=0;break}a.j=b;return G(e,a.b.setLocalDescription(a.f),3);case 3:e.h=4;var f=a.sdp.a.mid;g="v=0\r\no=- "+(pa()+" 2 IN IP4 127.0.0.1\r\ns=-\r\nt=0 0\r\na=group:BUNDLE ")+(f+"\r\na=msid-semantic: WMS *\r\nm=application 9 DTLS/SCTP 5000\r\nc=IN IP4 0.0.0.0\r\nb=AS:30\r\na=ice-ufrag:")+(b+"\r\na=ice-pwd:")+(d+"\r\na=ice-options:trickle\r\na=fingerprint:")+(c+"\r\na=setup:active\r\na=mid:")+(f+"\r\na=sendrecv\r\na=sctpmap:5000 webrtc-datachannel 256\r\na=max-message-size:1073741823\r\n");
|
||||
return G(e,a.b.setRemoteDescription(new RTCSessionDescription({type:"answer",sdp:g})),6);case 6:e.b=5;e.h=0;break;case 4:e.h=0,f=e.f.F,e.f=null,k=f,console.log(k);case 5:a.i&&ra(a),a.h=!0,e.b=0}})}function ta(a,b,d,c,g){c?(a.i=!0,setTimeout(function(){a.l("1.2.3.4",1234,!0,!1,!1)},500)):a.g.push({ip:b.replace("::ffff:",""),port:d,from_stun:g});a.h&&a.i&&ra(a)}function S(a,b){this.h={};this.c=b;this.j=a;this.i="";this.b=null;this.f=[];this.g=this.l=!1;this.timeout=null}
|
||||
function ua(a,b,d,c,g,k,e){a.b=new WebSocket("wss://kessel-ws.evan.run:443/?session_id=_&role=client&version=1&sdk_version=0",b);a.i=d;a.b.onclose=function(){a.g||a.c(L.WS_ERR_CLOSE)};a.b.onerror=function(){a.c(L.WS_ERR_CONNECT)};a.b.onopen=function(){for(;0<a.f.length;)a.b.send(a.f.shift());a.send({action:"offer",version:1,payload:{to:a.i,attempt_id:a.j,secret:c?c:"",data:{ver_data:1,creds:g,mode:2,versions:{p2p:1,bud:1,init:1,video:1,audio:1,control:1}}}});a.timeout=setTimeout(function(){a.c(L.CONNECT_WRN_APPROVAL)},
|
||||
3E4)};a.b.onmessage=function(f){f=JSON.parse(f.data);switch(f.action){case "answer_relay":a.l=!0;if(!f.payload.approved){a.c(L.CONNECT_WRN_DECLINED);break}a.timeout&&clearTimeout(a.timeout);a.timeout=setTimeout(function(){a.c(L.NAT_ERR_WEBRTC)},1E4);f=f.payload.data.creds;k(f.ice_ufrag,f.ice_pwd,f.fingerprint);break;case "candex_relay":f=f.payload.data;e(f.ip,f.port,f.sync,f.from_stun);break;case "close":var m=L.WS_ERR_CLOSE;switch(f.payload.reason){case "HOST_NOT_FOUND":m=L.CONNECT_WRN_PEER_GONE;
|
||||
break;case "USER_UNCONFIRMED":m=L.CONNECT_WRN_UNCONFIRMED}a.c(m)}}}S.prototype.send=function(a){this.b&&(a=JSON.stringify(a),this.b.readyState==WebSocket.OPEN?this.b.send(a):this.f.push(a))};S.prototype.close=function(a){this.g=!0;this.b&&(this.b.close(a),this.b=null);this.timeout&&(clearTimeout(this.timeout),this.timeout=null)};var T=1E3/60/1E3,U=(/(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)?200:100)/1E3;function V(a,b){a.playbackRate=b;a.play().catch(function(){})}
|
||||
function W(a,b,d){var c=this;this.b=a;this.l=!0;this.type=b;this.o=d;this.f=this.c=null;this.m='video/mp4; codecs="avc1.64001e"'===this.type;this.g=[];this.j=[];this.h=null;this.i=0;this.B=function(){var g=c.b.seekable;if(g&&0<g.length){g=g.end(0);var k=g-c.b.currentTime;'video/mp4; codecs="avc1.64001e"'===c.type?(c.i=k>1.5*T?c.i+1:0,60<c.i&&1==c.b.playbackRate?V(c.b,k>3*T?10:1.25):k<T&&1!=c.b.playbackRate&&V(c.b,1)):k>3*U?c.b.currentTime=g+1E3:k>1.5*U&&1==c.b.playbackRate?V(c.b,10):k<U&&10==c.b.playbackRate&&
|
||||
V(c.b,1)}}}W.prototype.s=function(){if(0<this.j.length&&this.c&&!this.c.updating)try{var a=this.j.shift();this.c.appendBuffer(a)}catch(b){console.warn(b),X(this),this.o&&this.o()}};
|
||||
function va(a){a.f=new MediaSource;a.b.src=URL.createObjectURL(a.f);a.b.load();a.g.push(M(a.b,"error",function(){console.error(a.b.error.message)},null));a.g.push(M(a.f,"sourceopen",function(){a.c=a.f.addSourceBuffer(a.type);a.c.mode="sequence";a.g.push(M(a.c,"update",a.s,a));a.b.play().catch(function(){});a.h=setInterval(a.B,1)},null))}
|
||||
function X(a){a.h&&clearInterval(a.h);a.b.pause();ha(a.g);a.f&&(a.c&&(a.f.removeSourceBuffer(a.c),a.c=null),a.f.endOfStream(),URL.revokeObjectURL(a.b.src),a.f=null);a.b.src="";'video/mp4; codecs="avc1.64001e"'===a.type&&a.b.load();a.l=!0;a.m='video/mp4; codecs="avc1.64001e"'===a.type;a.g=[];a.j=[];a.h=null;a.i=0}
|
||||
function wa(a,b){b=new Uint8Array(b);'audio/mp4; codecs="opus"'===a.type&&a.l&&(a.l=!1,va(a));'video/mp4; codecs="avc1.64001e"'===a.type&&102===b[4]&&(X(a),va(a),a.m=!1);a.m||(a.j.push(b),a.s())}function xa(){for(var a=[],b=new Uint8Array(4),d=0;6>d;d++)crypto.getRandomValues(b),a.push(Array.from(b).map(function(c){return c.toString(16).padStart(2,"0")}).join(""));return a.join("-")}
|
||||
function Y(a,b){var d=this;this.status=L.PARSEC_NOT_RUNNING;this.o=performance.now();this.s={encodeLatency:0,decodeLatency:0,networkLatency:0};this.c=[];this.signal=this.b=null;this.h=[];this.f="";this.video=a;this.l=[];this.j={};this.m=0;this.i=new W(b,'audio/mp4; codecs="opus"',null);this.g=new W(a,'video/mp4; codecs="avc1.64001e"',function(){console.warn("Attempting to recover stream...");d.b&&d.b.send(O(13,0,0,1),0)});this.h.push(M(window,"beforeunload",function(){d.C();return null},null))}
|
||||
function Z(a,b){a.signal&&(a.signal.close(1E3),a.signal=null);b!=L.PARSEC_OK&&(a.b&&a.status==L.PARSEC_OK&&a.b.send(O(10,0,0,0),0),a.b&&(a.b.close(),a.b=null),X(a.g),X(a.i));a.status=b;a.l=[];a.j={};a.m=0}h=Y.prototype;h.C=function(){ha(this.h);this.D()};h.X=function(){};h.S=function(){return this.f};h.T=function(a){var b=P[a];void 0!=b&&delete P[a];return void 0==b?null:b};
|
||||
h.G=function(a,b,d){var c=this,g,k,e,f,m,p;return J(function(t){if(1==t.b){g=/Chrome/.test(navigator.userAgent)&&/Google Inc/.test(navigator.vendor);if(!g)return c.status=L.PARSEC_WRN_BROWSER,t.return();if(c.status!=L.PARSEC_NOT_RUNNING)return t.return();c.status=L.PARSEC_CONNECTING;P={};la=1;X(c.i);X(c.g);c.c=[];c.f=xa();c.signal=new S(c.f,function(l){Z(c,l)});k=function(l,n,u,v,A){c.c.push({type:8,attemptID:c.f,ip:l,port:n,lan:A,fromStun:v,sync:u})};e=function(){c.h.push(M(document,"visibilitychange",
|
||||
function(){document.hidden?(X(c.g),c.b&&c.b.send(O(19,0,0,0),0)):c.b&&c.b.send(O(13,0,0,0),0)},null));var l=window.screen.width,n=window.screen.height;if(800>l||600>n||1920<l||1080<n)l=1920,n=1080;c.b&&c.b.send(ja(l,n),0);Z(c,L.PARSEC_OK)};c.b=new Q(k);R(c.b,"control",0,e,function(l){c.o=performance.now();var n=new DataView(l.data);l={u:n.getInt32(0),w:n.getInt32(4),R:n.getInt32(8),type:n.getInt8(12)};switch(l.type){case 10:c.status=l.u;break;case 21:c.s={encodeLatency:parseFloat(l.w)/1E3,decodeLatency:0,
|
||||
networkLatency:0,packetsSent:0,fastRTs:0,slowRTs:0,bitrate:0};break;case 20:c.c.push({type:2,gamepadID:l.u,motorBig:l.w,motorSmall:l.R});break;case 16:c.c.push({type:l.u?4:5});break;case 28:c.m=l.u;break;case 17:c.c.push(oa(l,n));break;case 9:c.c.push(na(n));break;case 25:n=JSON.parse((new TextDecoder("utf-8")).decode(new Uint8Array(n.buffer,13,l.u-1)));for(var u={},v=0;v<n.length;v++)n[v].id==l.w&&(u=n[v]);l={list:n,me:u};c.l=l.list;c.j=l.me}});R(c.b,"video",1,null,function(l){wa(c.g,l.data)});R(c.b,
|
||||
"audio",2,null,function(l){wa(c.i,l.data)});return G(t,qa(c.b),2)}f=t.i;m=function(l,n,u){c.b&&sa(c.b,l,n,u)};p=function(l,n,u,v){c.b&&ta(c.b,l,n,u,v)};c.signal&&ua(c.signal,a,b,d,f,m,p);t.b=0})};h.L=function(){return this.status};h.K=function(){return this.j};h.I=function(){return this.m};h.H=function(){return this.l};h.D=function(){Z(this,L.PARSEC_NOT_RUNNING)};h.P=function(a,b){this.b&&this.status==L.PARSEC_OK&&this.b.send(ia(17,a,b),0)};
|
||||
h.O=function(a){this.b&&this.status==L.PARSEC_OK&&this.b.send(ka(a,this.video),0)};h.N=function(){return this.c.shift()};h.J=function(){return this.s};h.M=function(){return this.status==L.PARSEC_OK&&5E3<performance.now()-this.o};h.W=function(a,b,d,c,g,k){if(this.signal){var e=this.A(a);e&&this.signal.send({action:"candex",version:1,payload:{to:e,attempt_id:a,data:{ver_data:1,ip:b,port:d,lan:k?!0:!1,from_stun:g?!0:!1,sync:c?!0:!1}}})}};
|
||||
h.V=function(a){if(this.signal){var b=this.A(a);b&&this.signal.send({action:"offer_cancel",version:1,payload:{to:b,attempt_id:a}})}};h.Y=function(a,b){this.signal&&(this.signal.h[a]=b)};h.A=function(a){if(this.signal)return(a=this.signal.h[a])?a:""};Y.prototype.destroy=Y.prototype.C;Y.prototype.setLogCallback=Y.prototype.X;Y.prototype.getAttemptID=Y.prototype.S;Y.prototype.getBuffer=Y.prototype.T;Y.prototype.clientConnect=Y.prototype.G;Y.prototype.clientGetStatus=Y.prototype.L;
|
||||
Y.prototype.clientGetSelf=Y.prototype.K;Y.prototype.clientGetHostMode=Y.prototype.I;Y.prototype.clientGetGuests=Y.prototype.H;Y.prototype.clientDisconnect=Y.prototype.D;Y.prototype.clientSendUserData=Y.prototype.P;Y.prototype.clientSendMessage=Y.prototype.O;Y.prototype.clientPollEvents=Y.prototype.N;Y.prototype.clientGetMetrics=Y.prototype.J;Y.prototype.clientNetworkFailure=Y.prototype.M;Y.prototype.sendCandidate=Y.prototype.W;Y.prototype.setPeerID=Y.prototype.Y;Y.prototype.getPeerID=Y.prototype.A;
|
||||
Y.prototype.sendCancel=Y.prototype.V;Y.prototype.Status=L;window.Parsec=Y;
|
252
webapp/static/lib/weblib.js
Normal file
252
webapp/static/lib/weblib.js
Normal file
@ -0,0 +1,252 @@
|
||||
let PARSEC;
|
||||
let AUDIO;
|
||||
let DAEMON_WAITING = false;
|
||||
let PEER_ID_C;
|
||||
|
||||
const PARSEC_ENV = {
|
||||
// user.bin
|
||||
bin_user_bin_get: function (asset_dir_c, session_id_c, size) {
|
||||
try {
|
||||
const cookies = document.cookie.split(';');
|
||||
|
||||
for (let x = 0; x < cookies.length; x++) {
|
||||
const cookie = cookies[x].trim();
|
||||
const name = 'parsec_login=';
|
||||
|
||||
if (cookie.indexOf(name) == 0) {
|
||||
const auth = JSON.parse(cookie.substring(name.length, cookie.length));
|
||||
MTY_StrToC(auth['token'], session_id_c, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
return -1;
|
||||
},
|
||||
bin_user_bin_set: function (asset_dir_c, session_id_c) {
|
||||
const session_id = MTY_StrToJS(session_id_c);
|
||||
|
||||
const value = JSON.stringify({
|
||||
'token': session_id,
|
||||
'userId': 0,
|
||||
});
|
||||
|
||||
const hostname = window.location.hostname.replace(/.*?\./, '');
|
||||
const secure = window.location.protocol == 'https:';
|
||||
document.cookie = 'parsec_login=' + value + ';domain=' + hostname + ';path=/;' +
|
||||
(secure ? 'secure' : '') + ';max-age=31536000;samesite=strict;';
|
||||
},
|
||||
bin_user_bin_delete: function (asset_dir_c) {
|
||||
const hostname = window.location.hostname.replace(/.*?\./, '');
|
||||
document.cookie = 'parsec_login=;domain=' + hostname + ';path=/;expires=Thu, 01 Jan 1970 00:00:00 GMT;';
|
||||
},
|
||||
|
||||
|
||||
// Audio control
|
||||
web_mute: function (muted) {
|
||||
AUDIO.muted = muted;
|
||||
},
|
||||
|
||||
|
||||
// ws-api
|
||||
signal_set_peer_id: function (s, attempt_id, peer_id) {
|
||||
if (!PARSEC)
|
||||
return;
|
||||
|
||||
PARSEC.setPeerID(MTY_StrToJS(attempt_id), MTY_StrToJS(peer_id));
|
||||
},
|
||||
signal_get_peer_id: function (s, attempt_id) {
|
||||
if (!PARSEC)
|
||||
return;
|
||||
|
||||
const peer_id = PARSEC.getPeerID(MTY_StrToJS(attempt_id));
|
||||
|
||||
if (!PEER_ID_C)
|
||||
PEER_ID_C = MTY_Alloc(128);
|
||||
|
||||
MTY_StrToC(peer_id, PEER_ID_C, 128);
|
||||
|
||||
return PEER_ID_C;
|
||||
},
|
||||
signal_client_cancel: function (s, ps) {
|
||||
if (!PARSEC)
|
||||
return;
|
||||
|
||||
PARSEC.sendCancel(PARSEC.getAttemptID());
|
||||
PARSEC_ENV.parsec_web_disconnect();
|
||||
},
|
||||
web_send_candex: function (attempt_id, ip, port, sync, fromStun, lan) {
|
||||
if (!PARSEC)
|
||||
return;
|
||||
|
||||
PARSEC.sendCandidate(MTY_StrToJS(attempt_id),
|
||||
MTY_StrToJS(ip), port, sync, fromStun, lan);
|
||||
},
|
||||
signal_host_allow_guest: function (s, ps, attempt_id, allow) {
|
||||
},
|
||||
signal_host_stop: function (s, ps) {
|
||||
},
|
||||
signal_send_conn_update: function (s, ps) {
|
||||
},
|
||||
signal_host_set_permissions: function (s, ps, guest_id, perms) {
|
||||
},
|
||||
signal_host_start: function (s, ps, mode, cfg, priv, session_id) {
|
||||
return -1;
|
||||
},
|
||||
signal_host_set_config: function (s, ps, cfg, priv) {
|
||||
},
|
||||
signal_client_connect: function (s, ps, cfg, peer_id_c, session_id_c, secret_c) {
|
||||
//XXX TODO this should create a new attempt and send the offer
|
||||
|
||||
const session_id = MTY_StrToJS(session_id_c);
|
||||
const peer_id = MTY_StrToJS(peer_id_c);
|
||||
const secret = MTY_StrToJS(secret_c);
|
||||
|
||||
if (ps) {
|
||||
const connect = () => {
|
||||
if (!PARSEC) {
|
||||
setTimeout(connect, 100);
|
||||
|
||||
} else {
|
||||
PARSEC.clientConnect(session_id, peer_id, secret);
|
||||
PARSEC.setPeerID(PARSEC.getAttemptID(), peer_id);
|
||||
}
|
||||
};
|
||||
|
||||
connect();
|
||||
|
||||
} else {
|
||||
window.location.assign('parsec://peer_id=' + peer_id + '&host_secret=' + secret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
},
|
||||
signal_init: function (s_out, role, host, port, loader_v, service_v, device_id, cbs, opaque) {
|
||||
const role_js = MTY_StrToJS(role);
|
||||
const host_js = MTY_StrToJS(host);
|
||||
|
||||
// XXX TODO create context, but don't yet connect to websocket
|
||||
},
|
||||
signal_destroy: function (s_out) {
|
||||
// XXX TODO full clean up and null out context
|
||||
},
|
||||
signal_update: function (s, host, session_id) {
|
||||
const host_js = MTY_StrToJS(host);
|
||||
const session_id_js = MTY_StrToJS(session_id);
|
||||
|
||||
// XXX TODO reconnect websocket with new session_id and websocket host
|
||||
|
||||
return false;
|
||||
},
|
||||
signal_stop: function (s) {
|
||||
// XXX TODO Disconnect from websocket, clear message queue
|
||||
},
|
||||
|
||||
|
||||
// parsec SDK
|
||||
parsec_web_init: function () {
|
||||
if (PARSEC)
|
||||
return;
|
||||
|
||||
AUDIO = document.createElement('audio');
|
||||
document.body.appendChild(AUDIO);
|
||||
|
||||
const container = document.createElement('div');
|
||||
container.style.zIndex = -1;
|
||||
container.style.background = 'black';
|
||||
container.style.position = 'fixed';
|
||||
container.style.top = 0;
|
||||
container.style.right = 0;
|
||||
container.style.bottom = 0;
|
||||
container.style.left = 0;
|
||||
document.body.appendChild(container);
|
||||
|
||||
const video = document.createElement('video');
|
||||
video.muted = true;
|
||||
video.style.width = '100%';
|
||||
video.style.height = '100%';
|
||||
container.appendChild(video);
|
||||
|
||||
PARSEC = new Parsec(video, AUDIO);
|
||||
},
|
||||
parsec_web_destroy: function () {
|
||||
if (!PARSEC)
|
||||
return;
|
||||
|
||||
PARSEC.destroy();
|
||||
PARSEC = undefined;
|
||||
},
|
||||
parsec_web_disconnect: function () {
|
||||
PARSEC.clientDisconnect();
|
||||
},
|
||||
parsec_web_get_status: function () {
|
||||
return DAEMON_WAITING ? PARSEC.Status.PARSEC_CONNECTING : PARSEC.clientGetStatus();
|
||||
},
|
||||
parsec_web_send_user_data: function (id, msg_c) {
|
||||
PARSEC.clientSendUserData(id, MTY_StrToJS(msg_c));
|
||||
},
|
||||
parsec_web_get_guests: function (jstr_c, len) {
|
||||
MTY_StrToC(JSON.stringify(PARSEC.clientGetGuests()), jstr_c, len);
|
||||
},
|
||||
parsec_web_get_attempt_id: function (attempt_id_c, len) {
|
||||
MTY_StrToC(PARSEC.getAttemptID(), attempt_id_c, len);
|
||||
},
|
||||
parsec_web_poll_events: function (event_str_c, len) {
|
||||
const event = PARSEC.clientPollEvents();
|
||||
|
||||
if (event) {
|
||||
MTY_StrToC(JSON.stringify(event), event_str_c, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
parsec_web_get_buffer: function (key) {
|
||||
const buffer = PARSEC.getBuffer(key);
|
||||
|
||||
if (buffer) {
|
||||
const ptr = MTY_Alloc(buffer.length);
|
||||
MTY_Memcpy(ptr, buffer);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
},
|
||||
parsec_web_set_log_callback: function (callback_c, opaque) {
|
||||
PARSEC.setLogCallback((level, msg) => {
|
||||
const msg_c = MTY_Alloc(1024);
|
||||
MTY_StrToC(msg, msg_c, 1024);
|
||||
|
||||
MTY_CFunc(callback_c)(level, msg_c, opaque);
|
||||
MTY_Free(msg_c);
|
||||
});
|
||||
},
|
||||
parsec_web_send_message: function (msg_c) {
|
||||
const msg = JSON.parse(MTY_StrToJS(msg_c));
|
||||
|
||||
PARSEC.clientSendMessage(msg);
|
||||
},
|
||||
parsec_web_get_metrics: function (decode_ptr, encode_ptr, network_ptr) {
|
||||
const metrics = PARSEC.clientGetMetrics();
|
||||
|
||||
MTY_SetFloat(decode_ptr, metrics['decodeLatency']);
|
||||
MTY_SetFloat(encode_ptr, metrics['encodeLatency']);
|
||||
MTY_SetFloat(network_ptr, metrics['networkLatency']);
|
||||
},
|
||||
parsec_web_get_network_failure: function () {
|
||||
return PARSEC.clientNetworkFailure();
|
||||
},
|
||||
parsec_web_get_self: function (owner_ptr, id_ptr) {
|
||||
const me = PARSEC.clientGetSelf();
|
||||
|
||||
MTY_SetInt8(owner_ptr, me['owner']);
|
||||
MTY_SetInt32(id_ptr, me['id']);
|
||||
},
|
||||
parsec_web_get_host_mode: function () {
|
||||
return PARSEC.clientGetHostMode();
|
||||
},
|
||||
};
|
Reference in New Issue
Block a user