1 document
.title
= "Strapp.io Host"
4 const conf
= {"iceServers": [{ "urls": "stun:stun.1.google.com:19302" }] }
5 const clients
= new Map([])
6 const iceCandidates
= []
8 let screenStream
/* TODO: Remove if can access localStreams */
12 /* TODO: duplicate in both client.js and host.jhs */
13 function getPublicKey() {
14 return new Promise( (resolve
, reject
) => {
15 /* Check local storage for public key */
16 if (!window
.localStorage
.getItem('public-key')) {
17 console
.log('public key is undefined')
18 /* If doesn't exist, generate public and private key pair, store in
20 crypto
.subtle
.generateKey(
23 publicExponent
: new Uint8Array([0x01, 0x00, 0x01]),
24 hash
: {name
: "SHA-256"}
27 ['encrypt', 'decrypt']
29 /* TODO: Do we need to store the private key as well? */
30 crypto
.subtle
.exportKey('jwk', keyPair
.publicKey
)
31 .then((exportedKey
) => {
32 window
.localStorage
.setItem('publicKey', exportedKey
)
33 console
.log('public key is' + window
.localStorage
.getItem('publicKey'))
40 resolve(window
.localStorage
.getItem('publicKey'))
45 function sendClientICE(clientPubKey
, hostPubKey
, iceCandidate
) {
46 console
.log('Host: Allocating ice candidate for client')
47 console
.log(iceCandidate
)
48 iceCandidates
.push(JSON
.stringify({
51 hostPubKey
: hostPubKey
, /* TODO: do we need to send this? */
52 clientPubKey
: clientPubKey
,
57 function handleNewClientConnection(pubKey
, sdpOffer
) {
58 /* New Client Connection*/
59 hpc
= new RTCPeerConnection(conf
)
60 console
.log('handleNewClientConnections()')
62 clients
.set(pubKey
, hpc
)
64 hpc
.setRemoteDescription(sdpOffer
)
66 hpc
.createAnswer().then((answer
) => {
67 return hpc
.setLocalDescription(answer
)
71 hpc
.onicecandidate
= (event
) => {
72 if (event
.candidate
) {
73 sendClientICE(pubKey
, hpk
.n
, event
.candidate
)
76 console
.log('Host: Finished allocating ICE candidates')
79 console
.log('Host: Sending answer to Client ')
80 wsock
.send(JSON
.stringify({
82 sdp
: hpc
.localDescription
,
88 console
.log(`error in host answer ${err}`)
91 console
.log(`error in setRemoteDescription ${error}`)
93 hpc
.oniceconnectionstatechange
= () => {
94 console
.log('iceConnectionState = ' + hpc
.iceConnectionState
)
96 hpc
.ondatachannel
= (evt
) => {
97 dataChannel
= evt
.channel
98 dataChannel
.onmessage
= (msg
) => {
99 let clientMessage
= JSON
.parse(msg
.data
)
100 console
.log(`client message is ${clientMessage}`)
101 hpc
.setRemoteDescription(clientMessage
.sdp
).then(() => {
102 console
.log('should be streaming now')
105 dataChannel
.onopen
= () => {
106 /* If !screenStream, gUM */
107 screenStream
.getTracks().forEach( (track
) => {
108 hpc
.addTrack(track
, screenStream
)
110 console
.log(hpc
.getSenders())
112 hpc
.createOffer().then((offer
) => {
113 return hpc
.setLocalDescription(offer
)
115 dataChannel
.send(JSON
.stringify({
116 "cmd": "< screen dataChannel",
117 "sdp": hpc
.localDescription
,
118 "pubKey": hpc
['hpk'].n
123 hpc
.onnegotiationneeded
= () => {
124 console
.log('negotiation needed')
129 function handleNewIceCandidate(msg
) {
130 console
.log('Host: Adding new ice candidate')
131 const hpc
= clients
.get(msg
.pubKey
)
132 let candidate
= new RTCIceCandidate(msg
.ice
)
133 hpc
.addIceCandidate(candidate
)
136 function handleIceRequest(msg
) {
137 console
.log('Host: Handling ice candidate request')
138 console
.log(iceCandidates
)
139 const hpc
= clients
.get(msg
.pubKey
)
140 const iceCandidate
= iceCandidates
.pop()
141 if (iceCandidate
!== undefined) {
142 wsock
.send(iceCandidate
)
144 if (hpc
.iceGatheringState
.localeCompare('gathering') === 0) {
145 wsock
.send(`{"cmd" : "< ice pubKey", "clientPubKey":"${msg.pubKey}", "iceState": "g"}`)
147 else if (hpc
.iceGatheringState
.localeCompare('complete') === 0) {
148 wsock
.send(`{"cmd" : "< ice pubKey", "clientPubKey":"${msg.pubKey}", "iceState": "c"}`)
154 if ("WebSocket" in window
) {
155 document
.addEventListener('DOMContentLoaded', (event
) => {
156 document
.body
.innerHTML
= '<div>Choose options for client</div> <video autoplay></video>'
157 navigator
.mediaDevices
.getUserMedia({
158 video
: { mediaSource
: "screen",
159 width
: {max
: '1920'},
160 height
: {max
: '1080'},
161 frameRate
: {max
: '10'}} })
162 .then(function(mediaStream
) {
163 let video
= document
.querySelector('video')
164 screenStream
= mediaStream
165 console
.log(mediaStream
)
166 video
.srcObject
= mediaStream
167 console
.log('Grabbed media')
168 video
.onloadedmetadata = function(e
) {
173 .catch(function(err
) {
174 document
.body
.innerHTML
= 'Help me help you. Reload the page and allow screen sharing!'
176 }); // always check for errors at the end.
182 wsock
= new WebSocket(`${_strapp_protocol}://${window.location.hostname}:${_strapp_port}`)
183 wsock
.onopen
= () => {
184 console
.log(`Strapped to ${_strapp_protocol}://${window.location.hostname}:${_strapp_port}`)
187 wsock
.onmessage
= (serverMsg
) => {
188 /* msg is either offer or ice candidate or ice candidate request*/
190 /* What if data null? */
191 console
.log(`serverMsg = ${serverMsg.data}`)
193 let msg
= serverMsg
.data
.split(' ')
194 let clientID
= msg
[0]
196 let data
= JSON
.parse(msg
.slice(2).join(' '))
198 if (clients
.has(clientID
)) {
200 case 'ice-candidate-submission':
201 handleNewIceCandidate(msg
)
203 case 'ice-candidate-request':
204 handleIceRequest(msg
)
206 case 'client-sdp-offer':
207 //repeatedoffer shouldnt happen here
212 case 'client-sdp-offer':
213 handleNewClientConnection(clientID
, data
)
215 case 'ice-candidate-request':
218 case 'ice-candidate-submission':
219 handleNewIceCandidate
230 document
.addEventListener('DOMContentLoaded', () => {
231 document
.body
.innerHTML
= 'Websockets not supported in your browser'