document.title = "Strapp.io Client"
body.appendChild(root)
document.body = body
-
+const conf = {"iceServers": [{ "url": "stun:stun.1.google.com:19302" }] }
/* Poll the server. Send get request, wait for timeout, send another request.
Do this until...? Can be used for either reconnecting or waiting for answer*/
function pollServerTimeout(url, data, resolve, reject) {
- console.log(`Polling server ${url} with`)
- console.log(data)
+ console.log(`Polling server ${url} with ${data}`)
const request = new XMLHttpRequest()
request.open('GET', url, true)
request.setRequestHeader('Content-Type', 'application/json' )
request.setRequestHeader('X-Strapp-Type', JSON.stringify(data))
request.onreadystatechange = () => {
if (request.status === 200) {
- console.log(request.response)
- resolve(request.response)
+ if(request.readyState === 4) {
+ console.log('Client: Recieved answer from Host')
+ console.log(request)
+ resolve(request.response)
+ }
}
else if (request.status === 504) {
console.log('timed out, resending')
reject('server unhandled response of status ' + request.status)
}
}
- console.log(data)
request.send()
}
/* Create, set, and get client Offer. Poll server for host answer.
Set host answer as client remoteDescription */
-const cpc = new RTCPeerConnection()
-console.log('creating offer')
+const cpc = new RTCPeerConnection(conf)
+cpc.oniceconnectionstatechange = () => {
+ console.log('iceConnectionState = ' + cpc.iceConnectionState)
+}
cpc.createOffer().then((offer) => {
return cpc.setLocalDescription(offer)
})
sdp: cpc.localDescription,
pubKey: cpk
}
+ cpc.onicecandidate = (event) => {
+ if (event.candidate) {
+ console.log('Client: Sending ice candidate to host')
+ pollServer(window.location, wsock.send(JSON.stringify({
+ cmd: '> ice pubkey',
+ ice: event.candidate,
+ pubKey: cpk /* TODO: do we need to send this? */
+ })), pollServerTimeout)
+ }
+ else {
+ /* Set up data channel here */
+ console.log('Client: Finished setting up ICE candidates')
+ }
+ }
+ /* TODO: start polling for ice candidates, and then addIceCandidate() to cpc */
+ //pollServer(window.location, {ice}, pollServerTimeout)
+
+
/* Poll for answer */
return pollServer(window.location, offer, pollServerTimeout)
- }).then((answer) => {
- //console.log(answer)
+ }).then((serverResponse) => {
+ const answer = JSON.parse(serverResponse)
+ console.log(answer)
/* TODO: State machine to parse answer */
+ console.log('Setting Remote Description')
cpc.setRemoteDescription(answer.sdp)
}).catch( (err) => {
console.log('error in sdp handshake: ' + err)
})
-})
- .catch((err) => {
+}).catch((err) => {
console.log(err)
- })
+})
document.title = "Strapp.io Host"
-const clients = [] //TODO: Change to Map
-if ("WebSocket" in window) {
- document.addEventListener('DOMContentLoaded', (event) => {
- const wsock = new WebSocket(`${_strapp_protocol}://${window.location.hostname}:${_strapp_port}`)
- wsock.onopen = () => {
- console.log(`Strapped to ${_strapp_protocol}://${window.location.hostname}:${_strapp_port}`)
+const conf = {"iceServers": [{ "url": "stun:stun.1.google.com:19302" }] }
+const clients = new Map([])
+const hpk = getPublicKey()
+
+/* TODO: duplicate in both client.js and host.jhs */
+function getPublicKey() {
+ return new Promise( (resolve, reject) => {
+ /* Check local storage for public key */
+ if (!window.localStorage.getItem('public-key')) {
+ console.log('public key is undefined')
+ /* If doesn't exist, generate public and private key pair, store in
+ local storage */
+ crypto.subtle.generateKey(
+ { name:'RSA-OAEP',
+ modulusLength: 2048,
+ publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
+ hash: {name: "SHA-256"}
+ },
+ true,
+ ['encrypt', 'decrypt']
+ ).then((keyPair) => {
+ /* TODO: Do we need to store the private key as well? */
+ crypto.subtle.exportKey('jwk', keyPair.publicKey)
+ .then((exportedKey) => {
+ window.localStorage.setItem('publicKey', exportedKey)
+ console.log('public key is' + window.localStorage.getItem('publicKey'))
+ resolve(exportedKey)
+ })
+ })
+ }
+ else {
+ resolve(window.localStorage.getItem('publicKey'))
}
- wsock.onmessage = (msg) => {
- /* Message is offer from client */
- /* TODO: Determine which client ?? */
- console.log("Incoming connection " + msg)
-
- /* TODO: State machine to parse offer */
-
- /* New Client Connection*/
- hpc = new RTCPeerConnection()
-
- hpc.createAnswer().then((offer) => {
- return hpc.setLocalDescription(offer)
- }).then(() => {
- return hpc.setRemoteDescription(msg.sdp)
- }).then(() => {
- const hpk = getPublicKey()
- wsock.send({
+ })
+}
+
+
+function handleNewClientConnection(offer) {
+ /* New Client Connection*/
+ hpc = new RTCPeerConnection(conf)
+ hpc.setRemoteDescription(offer.sdp)
+ .then(() => {
+ hpc.createAnswer().then((answer) => {
+ return hpc.setLocalDescription(answer)
+ })
+ .then(() => {
+ hpk.then(() => {
+ hpc.onicecandidate = (event) => {
+ if (event.candidate) {
+ console.log('Host: Sending ice candidate to client')
+ wsock.send(JSON.stringify({
+ cmd: '< ice pubKey',
+ ice: event.candidate,
+ pubKey: hpk /* TODO: do we need to send this? */
+ }))
+ }
+ else {
+ console.log('Host: Finished setting up ICE candidates')
+ }
+ }
+ console.log('Host: Sending answer to Host')
+ wsock.send(JSON.stringify({
cmd: '< sdp pubKey',
sdp: hpc.localDescription,
pubKey: hpk
- })
- clients.push({
+ }))
+ clients.set(offer.pubKey, {
hostsdp: hpc.localDescription,
- clientsdp: hpc.remoteDescription,
- clientPubKey: msg.pubKey
+ clientsdp: hpc.remoteDescription
})
})
+ }).catch((err) => {
+ console.log(`error in host answer ${err}`)
+ })
+ })
+}
+
+function handleNewIceCandidate(msg) {
+ const hpc = clients.get(msg.pubKey)
+ let candidate = new RTCIceCandidate(msg.ice)
+ hpc.addIceCandidate(candidate)
+}
+
+if ("WebSocket" in window) {
+ document.addEventListener('DOMContentLoaded', (event) => {
+ wsock = new WebSocket(`${_strapp_protocol}://${window.location.hostname}:${_strapp_port}`)
+ wsock.onopen = () => {
+ console.log(`Strapped to ${_strapp_protocol}://${window.location.hostname}:${_strapp_port}`)
+ }
+
+ wsock.onmessage = (serverMsg) => {
+ /* msg is either offer or ice candidate */
+ console.log(serverMsg.data)
+ let msg = JSON.parse(serverMsg.data)
+
+ const clientID = msg.pubKey
+ const msgType = msg.hasOwnProperty('sdp') ? 'o' : 'i'
+ if (clients.has(clientID)) {
+ switch(msgType) {
+ case 'o':
+ console.log('client exist && sending an offer == error')
+ break
+ case 'i':
+ handleNewIceCandidate(msg)
+ break
+ }
+ }
+ else {
+ switch(msgType) {
+ case 'o':
+ handleNewClientConnection(msg)
+ break
+ case 'i':
+ console.log('client !exist && ice candidate === error')
+ break
+ }
+ }
}
})
}
document.body.innerHTML = 'Websockets not supported in your browser'
})
}
-/* TODO: duplicate in both client.js and host.jhs */
-function getPublicKey() {
- /* Check local storage for public key */
- if (window.localStorage.getItem('public-key') === undefined) {
- /* If doesn't exist, generate public and private key pair, store in
- local storage */
- crypto.subtle.generateKey({name:'RSA-OAEP', length: 192}, true, ['encrypt', 'decrypt'])
- .then((keyPair) => {
- /* TODO: Do we need to store the private key as well? */
- window.localStorage.setItem('public-key', keyPair.type.public.toString())
- })
- }
- console.log(window.localStorage.getItem('public-key'))
- return window.localStorage.getItem('public-key')
-}
httpd: undefined,
wsProtocol: opts['no-tls'] ? 'ws' : 'wss',
respond: (request,response) => {
- let body = []
- request.on('error', function(err) {
- console.error(`error is ${err}`);
- }).on('data', function(chunk) {
- console.log(`chunk is ${chunk}`)
- body.push(chunk);
- }).on('end', function() {
- console.log(`body is ${body}`)
- })
console.log('server handling request')
const serveFile = (fPath) => {
fs.readFile(fPath, { encoding: 'utf8' }, (err, data) => {
// (this happens when a client connects to an active route with no currently-online host)
}
else { /* Client sent offer, waiting for answer */
- console.log(JSON.parse(request.headers['x-strapp-type']))
+ console.log('Server: Sending client offer to host')
+ route.socket.send(request.headers['x-strapp-type'])
route.socket.on('message', (hostResponse) => {
+ console.log('Server: Sending host answer to client')
console.log(hostResponse)
+ response.writeHead(200, { 'Content-Type': 'application/json' })
+ response.write(hostResponse)
+ response.end()
+
})
}