ec53c3d98fee67373dd1c9df110a5a7617d1a985
[henge/kiak.git] / host-test.js
1 document.title = "Strapp.io Host"
2
3
4 const conf = {"iceServers": [{ "urls": "stun:stun.1.google.com:19302" }] }
5 const clients = new Map([])
6 const iceCandidates = []
7 let dataChannel
8 let screenStream /* TODO: Remove if can access localStreams */
9 let tracks = []
10 let hpk
11
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
19 local storage */
20 crypto.subtle.generateKey(
21 { name:'RSA-OAEP',
22 modulusLength: 2048,
23 publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
24 hash: {name: "SHA-256"}
25 },
26 true,
27 ['encrypt', 'decrypt']
28 ).then((keyPair) => {
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'))
34 resolve(exportedKey)
35 })
36
37 })
38 }
39 else {
40 resolve(window.localStorage.getItem('publicKey'))
41 }
42 })
43 }
44
45 function sendClientICE(clientPubKey, hostPubKey, iceCandidate) {
46 console.log('Host: Allocating ice candidate for client')
47 console.log(iceCandidate)
48 iceCandidates.push(JSON.stringify({
49 cmd: "< ice pubKey",
50 ice: iceCandidate,
51 hostPubKey: hostPubKey, /* TODO: do we need to send this? */
52 clientPubKey: clientPubKey,
53 iceState: "a"
54 }))
55 }
56
57 function handleNewClientConnection(pubKey, sdpOffer) {
58 /* New Client Connection*/
59 hpc = new RTCPeerConnection(conf)
60 console.log('handleNewClientConnections()')
61 console.log(sdpOffer)
62 clients.set(pubKey, hpc)
63 console.log(pubKey)
64 hpc.setRemoteDescription(sdpOffer)
65 .then(() => {
66 hpc.createAnswer().then((answer) => {
67 return hpc.setLocalDescription(answer)
68 })
69 .then(() => {
70
71 hpc.onicecandidate = (event) => {
72 if (event.candidate) {
73 sendClientICE(pubKey, hpk.n, event.candidate)
74 }
75 else {
76 console.log('Host: Finished allocating ICE candidates')
77 }
78 }
79 console.log('Host: Sending answer to Client ')
80 wsock.send(JSON.stringify({
81 cmd: '< sdp pubKey',
82 sdp: hpc.localDescription,
83 hostPubKey: hpk.n,
84 clientPubKey: pubKey
85 }))
86
87 }).catch((err) => {
88 console.log(`error in host answer ${err}`)
89 })
90 }).catch((error) => {
91 console.log(`error in setRemoteDescription ${error}`)
92 })
93 hpc.oniceconnectionstatechange = () => {
94 console.log('iceConnectionState = ' + hpc.iceConnectionState)
95 }
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')
103 })
104 }
105 dataChannel.onopen = () => {
106 /* If !screenStream, gUM */
107 screenStream.getTracks().forEach( (track) => {
108 hpc.addTrack(track, screenStream)
109 })
110 console.log(hpc.getSenders())
111 /* Create offer */
112 hpc.createOffer().then((offer) => {
113 return hpc.setLocalDescription(offer)
114 }).then( () => {
115 dataChannel.send(JSON.stringify({
116 "cmd": "< screen dataChannel",
117 "sdp": hpc.localDescription,
118 "pubKey": hpc['hpk'].n
119 }))
120 })
121 }
122 }
123 hpc.onnegotiationneeded = () => {
124 console.log('negotiation needed')
125 }
126
127 }
128
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)
134 }
135
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)
143 } else {
144 if (hpc.iceGatheringState.localeCompare('gathering') === 0) {
145 wsock.send(`{"cmd" : "< ice pubKey", "clientPubKey":"${msg.pubKey}", "iceState": "g"}`)
146 }
147 else if (hpc.iceGatheringState.localeCompare('complete') === 0) {
148 wsock.send(`{"cmd" : "< ice pubKey", "clientPubKey":"${msg.pubKey}", "iceState": "c"}`)
149 }
150
151 }
152
153 }
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) {
169 console.log(e)
170 video.play()
171 }
172 })
173 .catch(function(err) {
174 document.body.innerHTML = 'Help me help you. Reload the page and allow screen sharing!'
175 console.log(err);
176 }); // always check for errors at the end.
177
178 getPublicKey()
179 .then((hpkVal) => {
180 hpk = hpkVal
181 })
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}`)
185 }
186
187 wsock.onmessage = (serverMsg) => {
188 /* msg is either offer or ice candidate or ice candidate request*/
189
190 /* What if data null? */
191 console.log(`serverMsg = ${serverMsg.data}`)
192
193 let msg = serverMsg.data.split(' ')
194 let clientID = msg[0]
195 let type = msg[1]
196 let data = JSON.parse(msg.slice(2).join(' '))
197
198 if (clients.has(clientID)) {
199 switch (type) {
200 case 'ice-candidate-submission':
201 handleNewIceCandidate(msg)
202 break
203 case 'ice-candidate-request':
204 handleIceRequest(msg)
205 break
206 case 'client-sdp-offer':
207 //repeatedoffer shouldnt happen here
208 }
209 }
210 else {
211 switch (type) {
212 case 'client-sdp-offer':
213 handleNewClientConnection(clientID, data)
214 break
215 case 'ice-candidate-request':
216 handleIceRequest()
217 break
218 case 'ice-candidate-submission':
219 handleNewIceCandidate
220 break
221 }
222 }
223 }
224
225
226
227 })
228 }
229 else {
230 document.addEventListener('DOMContentLoaded', () => {
231 document.body.innerHTML = 'Websockets not supported in your browser'
232 })
233 }