1e473809d61f4b8a6521f50d8d13286d936b7db5
[henge/kiak.git] / host.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(offer) {
58 /* New Client Connection*/
59 hpc = new RTCPeerConnection(conf)
60 //console.log(offer)
61 clients.set(offer.pubKey, hpc)
62 console.log(offer.sdp)
63 hpc.setRemoteDescription(offer.sdp)
64 .then(() => {
65 hpc.createAnswer().then((answer) => {
66 return hpc.setLocalDescription(answer)
67 })
68 .then(() => {
69
70 hpc.onicecandidate = (event) => {
71 if (event.candidate) {
72 sendClientICE(offer.pubKey, hpk.n, event.candidate)
73 }
74 else {
75 console.log('Host: Finished allocating ICE candidates')
76 }
77 }
78 console.log('Host: Sending answer to Client ')
79 wsock.send(JSON.stringify({
80 cmd: '< sdp pubKey',
81 sdp: hpc.localDescription,
82 hostPubKey: hpk.n,
83 clientPubKey: offer.pubKey
84 }))
85
86 }).catch((err) => {
87 console.log(`error in host answer ${err}`)
88 })
89 })
90 hpc.oniceconnectionstatechange = () => {
91 console.log('iceConnectionState = ' + hpc.iceConnectionState)
92 }
93 hpc.ondatachannel = (evt) => {
94 dataChannel = evt.channel
95 dataChannel.onmessage = (msg) => {
96 let clientMessage = JSON.parse(msg.data)
97 console.log(`client message is ${clientMessage}`)
98 hpc.setRemoteDescription(clientMessage.sdp).then(() => {
99 console.log('should be streaming now')
100 })
101 }
102 dataChannel.onopen = () => {
103 /* If !screenStream, gUM */
104 screenStream.getTracks().forEach( (track) => {
105 hpc.addTrack(track, screenStream)
106 })
107 console.log(hpc.getSenders())
108 /* Create offer */
109 hpc.createOffer().then((offer) => {
110 return hpc.setLocalDescription(offer)
111 }).then( () => {
112 dataChannel.send(JSON.stringify({
113 "cmd": "< screen dataChannel",
114 "sdp": hpc.localDescription,
115 "pubKey": hpc['hpk'].n
116 }))
117 })
118 }
119 }
120 hpc.onnegotiationneeded = () => {
121 console.log('negotiation needed')
122 }
123
124 }
125
126 function handleNewIceSubmission(msg) {
127 console.log('Host: Adding new ice candidate')
128 const hpc = clients.get(msg.pubKey)
129 let candidate = new RTCIceCandidate(msg.ice)
130 hpc.addIceCandidate(candidate)
131 }
132
133 function handleIceRequest(msg) {
134 console.log('Host: Handling ice candidate request')
135 console.log(iceCandidates)
136 const hpc = clients.get(msg.pubKey)
137 const iceCandidate = iceCandidates.pop()
138 if (iceCandidate !== undefined) {
139 wsock.send(iceCandidate)
140 } else {
141 if (hpc.iceGatheringState.localeCompare('gathering') === 0) {
142 wsock.send(`{"cmd" : "< ice pubKey", "clientPubKey":"${msg.pubKey}", "iceState": "g"}`)
143 }
144 else if (hpc.iceGatheringState.localeCompare('complete') === 0) {
145 wsock.send(`{"cmd" : "< ice pubKey", "clientPubKey":"${msg.pubKey}", "iceState": "c"}`)
146 }
147
148 }
149
150 }
151 if ("WebSocket" in window) {
152 document.addEventListener('DOMContentLoaded', (event) => {
153 document.body.innerHTML = '<div>Choose options for client</div> <video autoplay></video>'
154 navigator.mediaDevices.getUserMedia({
155 video : { mediaSource: "screen",
156 width: {max: '1920'},
157 height: {max: '1080'},
158 frameRate: {max: '10'}} })
159 .then(function(mediaStream) {
160 let video = document.querySelector('video')
161 screenStream = mediaStream
162 console.log(mediaStream)
163 video.srcObject = mediaStream
164 console.log('Grabbed media')
165 video.onloadedmetadata = function(e) {
166 console.log(e)
167 video.play()
168 }
169 })
170 .catch(function(err) {
171 document.body.innerHTML = 'Help me help you. Reload the page and allow screen sharing!'
172 console.log(err);
173 }); // always check for errors at the end.
174
175 getPublicKey()
176 .then((hpkVal) => {
177 hpk = hpkVal
178 })
179 wsock = new WebSocket(`${_strapp_protocol}://${window.location.hostname}:${_strapp_port}`)
180 wsock.onopen = () => {
181 console.log(`Strapped to ${_strapp_protocol}://${window.location.hostname}:${_strapp_port}`)
182 }
183
184 wsock.onmessage = (serverMsg) => {
185 /* msg is either offer or ice candidate or ice candidate request*/
186
187 /* What if data null? */
188 console.log(`serverMsg = ${serverMsg.data}`)
189 let msg = JSON.parse(serverMsg.data)
190
191 const clientID = msg.pubKey
192
193 /* TODO: redo this trash */
194 if (clients.has(clientID)) {
195 if (msg.ice) {
196 handleNewIceSubmission(msg)
197 } else if (msg.sdp) {
198 //handleRepeatedOffer
199 } else {
200 handleIceRequest(msg)
201 }
202 }
203 else {
204 if (msg.ice) {
205 console.log('Host: Client that doesnt exist is sending ice submissions')
206 } else if (msg.sdp) {
207 handleNewClientConnection(msg)
208 } else {
209 console.log('Host: Client that doesnt exist is sending ice requests')
210 }
211 }
212 }
213
214
215
216 })
217 }
218 else {
219 document.addEventListener('DOMContentLoaded', () => {
220 document.body.innerHTML = 'Websockets not supported in your browser'
221 })
222 }