From: jordan lavatai Date: Sat, 1 Jul 2017 06:54:54 +0000 (-0700) Subject: need to do ICE step X-Git-Url: https://git.kengrimes.com/?p=henge%2Fkiak.git;a=commitdiff_plain;h=b5c8f98ab42b8e7128441e4a456dfd4fc02f0e86 need to do ICE step --- diff --git a/client.js b/client.js index 8813f55..d389945 100644 --- a/client.js +++ b/client.js @@ -3,20 +3,22 @@ const root = document.createElement('div') 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') @@ -26,7 +28,6 @@ function pollServerTimeout(url, data, resolve, reject) { reject('server unhandled response of status ' + request.status) } } - console.log(data) request.send() } @@ -73,8 +74,10 @@ function getPublicKey() { /* 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) }) @@ -87,16 +90,35 @@ cpc.createOffer().then((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) - }) +}) diff --git a/host.js b/host.js index dd48d10..34d7c9d 100644 --- a/host.js +++ b/host.js @@ -1,40 +1,123 @@ 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 + } + } } }) } @@ -43,18 +126,3 @@ else { 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') -} diff --git a/main.js b/main.js index f123a41..35cffef 100644 --- a/main.js +++ b/main.js @@ -25,15 +25,6 @@ const router = { 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) => { @@ -82,9 +73,15 @@ const router = { // (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() + }) }