data channel between host + client, sending/receiving ice candidates when needed...
[henge/kiak.git] / host.js
diff --git a/host.js b/host.js
index 95d3cc6..3af3426 100644 (file)
--- a/host.js
+++ b/host.js
 document.title = "Strapp.io Host"
-const clients = []
+const conf = {"iceServers": [{ "urls": "stun:stun.1.google.com:19302" }] }
+const clients = new Map([])
+const iceCandidates = []
+let dataChannel
+
+
+/* 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'))
+    }
+  })
+}
+
+function handleNewClientConnection(offer) {
+  /* New Client Connection*/
+  hpc = new RTCPeerConnection(conf)
+  //console.log(offer)
+  clients.set(offer.pubKey, hpc)
+  hpc.setRemoteDescription(offer.sdp)
+  .then(() => {
+    hpc.createAnswer().then((answer) => {
+      return hpc.setLocalDescription(answer)
+    })
+    .then(() => {
+      getPublicKey().then((hpk) => {
+        hpc.onicecandidate = (event) => {
+          if (event.candidate) {
+            console.log('Host: Allocating ice candidate for client')
+            iceCandidates.push(JSON.stringify({
+              cmd: "< ice pubKey",
+              ice: event.candidate,
+              hostPubKey: hpk.n, /* TODO: do we need to send this? */
+              clientPubKey: offer.pubKey,
+              iceCandidateAvailable: true
+            }))
+          }
+          else {
+            console.log('Host: Finished sending ICE candidates')
+          }
+        }
+        console.log('Host: Sending answer to Client')
+        wsock.send(JSON.stringify({
+          cmd: '< sdp pubKey',
+          sdp: hpc.localDescription,
+          hostPubKey: hpk.n,
+          clientPubKey: offer.pubKey
+        }))
+        hpc.ondatachannel = (evt) => {
+          dataChannel = evt.channel
+          console.log(evt)
+          dataChannel.onmessage = (msg) => {
+            console.log(msg.data)
+          }
+          dataChannel.onopen = () => {
+            dataChannel.send(`Hi ${offer.pubKey} -host`)
+          }
+        }
+        hpc.oniceconnectionstatechange = () => {
+          console.log('iceConnectionState = ' + hpc.iceConnectionState)
+        }
+      })
+    }).catch((err) => {
+      console.log(`error in host answer ${err}`)
+    })
+  })
+
+
+
+}
+
+function handleNewIceSubmission(msg) {
+  console.log('Host: Adding new ice candidate')
+  const hpc = clients.get(msg.pubKey)
+  let candidate = new RTCIceCandidate(msg.ice)
+  hpc.addIceCandidate(candidate)
+}
+
+function handleIceRequest(msg) {
+  console.log('Host: Handling ice candidate request')
+  console.log(iceCandidates)
+  const hpc = clients.get(msg)
+  const iceCandidate = iceCandidates.pop()
+  if (iceCandidate !== undefined) {
+    wsock.send(iceCandidate)
+  } else {
+    wsock.send(`{"cmd" : "< ice pubKey", "clientPubKey":"${msg.pubKey}", "iceCandidateAvailable": false}`)
+  }
+
+}
 if ("WebSocket" in window) {
   document.addEventListener('DOMContentLoaded', (event) => {
-    const wsock = new WebSocket(`${_strapp_protocol}://${window.location.hostname}:${_strapp_port}`)
+    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 = (evt) => {
-      console.log("Incoming connection from " + evt.data)
-      console.log("TODO: Open a socket to this client")
-      wsock.send("Got " + evt.data)
-      clients.push({
-       ip: evt.data,
-       dataChannel: undefined
-      })
+
+    wsock.onmessage = (serverMsg) => {
+      /* msg is either offer or ice candidate or ice candidate request*/
+
+      /* What if data null? */
+      let msg = JSON.parse(serverMsg.data)
+
+      const clientID = msg.pubKey
+
+      /* TODO: redo this trash */
+      if (clients.has(clientID)) {
+        if (msg.ice) {
+          handleNewIceSubmission(msg)
+        } else if (msg.sdp) {
+          //handleRepeatedOffer
+        } else {
+          handleIceRequest(msg)
+        }
+      }
+      else {
+        if (msg.ice) {
+          console.log('Host: Client that doesnt exist is sending ice submissions')
+        } else if (msg.sdp) {
+          handleNewClientConnection(msg)
+        } else {
+          console.log('Host: Client that doesnt exist is sending ice requests')
+        }
+      }
     }
   })
 }