UNPKG

tahi

Version:

A shared peer-to-peer state for multiple users connected by WebRTC.

2 lines (1 loc) 6.75 kB
"use strict";function _defineProperty(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function _objectSpread(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{},r=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(r=r.concat(Object.getOwnPropertySymbols(n).filter(function(e){return Object.getOwnPropertyDescriptor(n,e).enumerable}))),r.forEach(function(t){_defineProperty(e,t,n[t])})}return e}function _objectWithoutPropertiesLoose(e,t){if(null==e)return{};var n,r,i={},o=Object.keys(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||(i[n]=e[n]);return i}function _objectWithoutProperties(e,t){if(null==e)return{};var n,r,i=_objectWithoutPropertiesLoose(e,t);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);for(r=0;r<o.length;r++)n=o[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(i[n]=e[n])}return i}function _slicedToArray(e,t){return _arrayWithHoles(e)||_iterableToArrayLimit(e,t)||_nonIterableRest()}function _arrayWithHoles(e){if(Array.isArray(e))return e}function _iterableToArrayLimit(e,t){var n=[],r=!0,i=!1,o=void 0;try{for(var a,s=e[Symbol.iterator]();!(r=(a=s.next()).done)&&(n.push(a.value),!t||n.length!==t);r=!0);}catch(e){i=!0,o=e}finally{try{r||null==s.return||s.return()}finally{if(i)throw o}}return n}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance")}Object.defineProperty(exports,"__esModule",{value:!0});var Peer=require("simple-peer"),cuid=require("cuid"),log=function(){if("development"===process.env.NODE_ENV){for(var e,t=arguments.length,n=new Array(t),r=0;r<t;r++)n[r]=arguments[r];(e=console).log.apply(e,["tahi:"].concat(n))}},autoMesh={invitesRequested:new Set,invitesAwaitingAnswer:{},answersRequested:new Set};function createStore(e,t,n){if("function"==typeof t&&"function"==typeof n||"function"==typeof n&&"function"==typeof arguments[3])throw new Error("It looks like you are passing several store enhancers to createStore(). This is not supported. Instead, compose them together to a single function");if("function"==typeof t&&void 0===n&&(n=t,t=void 0),void 0!==n){if("function"!=typeof n)throw new Error("Expected the enhancer to be a function.");return n(createStore)(e,t)}if("function"!=typeof e)throw new Error("Expected the reducer to be a function.");var r=cuid(),i=e(t,{type:"@@INIT"}),o=i,a=[],s=a,c=!1,u=[],l=-1,f={};function d(){s===a&&(s=a.slice())}function p(t){var n=t.timestamp,r=t.id,f=t.action;try{c=!0;var d=(u[l]||{}).timestamp;if(n>(void 0===d?0:d))u.push(t),o=e(Object.assign({},o),f);else{var p=!1,g=u.findIndex(function(e){var t=e.timestamp,i=e.id;if(n<t)return!0;if(n===t){if(r===i)return p=!0,!0;if(r<i)return!0}return!1});p||(u.splice(g,0,t),o=u.reduce(function(t,n){var r=n.action;return e(t,r)},i))}}finally{c=!1,l++}(a=s).forEach(function(e){e()})}function g(e,t,n,i){log("Awaiting peer connect..."),e.on("error",function(e){log("TODO: handle error:",e),/Ice connection failed/.test(e)&&(delete f[t],n(t,e),log("Ice connection failed",e))}),e.on("connect",function(){log("Peer connected"),i();var o=function(t){log("Sending message to peer:",t),e.send(JSON.stringify(t))};e.on("data",function(e){var t=new TextDecoder("utf-8").decode(e),n=JSON.parse(t);switch(log("Peer message:",n),n.type){case"AUTO_MESH_REQUEST_INVITE":null==f[n.peerInviting]&&null==autoMesh.invitesAwaitingAnswer[n.peerInviting]&&v().then(function(e){var t=e.inviteCode,i=e.completeInvitation;autoMesh.invitesAwaitingAnswer[n.peerInviting]=i,f[n.bridgePeer].send({type:"AUTO_MESH_RESPOND_INVITE",inviteCode:t,respondPeer:r,peerInviting:n.peerInviting})}).catch(function(e){console.log("tahi:","Auto-mesh invite error:",e)});break;case"AUTO_MESH_RESPOND_INVITE":autoMesh.invitesRequested.has("".concat(n.respondPeer,"-").concat(n.peerInviting))&&(autoMesh.invitesRequested.delete("".concat(n.respondPeer,"-").concat(n.peerInviting)),autoMesh.answersRequested.add(n.peerInviting),f[n.peerInviting].send({type:"AUTO_MESH_REQUEST_ANSWER",invitingPeer:n.respondPeer,inviteCode:n.inviteCode,bridgePeer:r}));break;case"AUTO_MESH_REQUEST_ANSWER":null==f[n.invitingPeer]&&(autoMesh.answersRequested.add(n.peerInviting),h(n.inviteCode).then(function(e){f[n.bridgePeer].send({type:"AUTO_MESH_RESPOND_ANSWER",answer:e,invitingPeer:n.invitingPeer,answeringPeer:r})}).catch(function(e){console.log("tahi:","Auto-mesh join error:",e)}));break;case"AUTO_MESH_RESPOND_ANSWER":autoMesh.answersRequested.has(n.answeringPeer)&&(autoMesh.answersRequested.delete(n.answeringPeer),f[n.invitingPeer].send({type:"AUTO_MESH_COMPLETE_INVITE",answeringPeer:n.answeringPeer,answer:n.answer}));break;case"AUTO_MESH_COMPLETE_INVITE":autoMesh.invitesAwaitingAnswer[n.answeringPeer]&&(autoMesh.invitesAwaitingAnswer[n.answeringPeer](n.answer,function(){}),delete autoMesh.invitesAwaitingAnswer[n.answeringPeer]);break;default:p(n)}}),e.on("close",function(){log("Peer connection closed. PeerId:",t),delete f[t],n(t),e.destroy()}),Object.entries(f).forEach(function(e){var n=_slicedToArray(e,2),i=n[0],o=n[1].send;autoMesh.invitesRequested.add("".concat(i,"-").concat(t)),o({type:"AUTO_MESH_REQUEST_INVITE",bridgePeer:r,peerInviting:t})}),f[t]={send:o},log("Update new peer with my state"),u.forEach(o)})}function v(e){log("Inviting...");var t=new Peer({initiator:!0});log("Invite peer"),t.on("signal",function(n){log("Host peer signal:",n),log("Resolving, invite code:",btoa(JSON.stringify(_objectSpread({},n,{peerId:r})))),e(null,{inviteCode:btoa(JSON.stringify(_objectSpread({},n,{peerId:r}))),completeInvitation:function(e,n,r){try{var i=JSON.parse(atob(e)),o=i.peerId,a=_objectWithoutProperties(i,["peerId"]);g(t,o,n,function(){r(null)}),t.signal(a)}catch(e){r(e)}}})})}function h(e,t,n){var i=new Peer;i.on("signal",function(e){log("Guest peer signal:",e),n(null,btoa(JSON.stringify(_objectSpread({},e,{peerId:r}))))});try{var o=JSON.parse(atob(e)),a=o.peerId,s=_objectWithoutProperties(o,["peerId"]);g(i,a,t,function(){n(null,null,!0)}),i.signal(s)}catch(e){n(e)}}return{getState:function(){return Object.assign({},o)},subscribe:function(e){if("function"!=typeof e)throw new Error("Expected the listener to be a function.");if(c)throw new Error("You may not call store.subscribe() while the reducer is executing.");var t=!0;return d(),s.push(e),function(){if(t){if(c)throw new Error("You may not unsubscribe while the reducer is executing.");t=!1,d();var n=s.indexOf(e);s.splice(n,1)}}},dispatch:function(e){var t={timestamp:Date.now(),id:r,action:e};return p(t),Object.values(f).forEach(function(e){(0,e.send)(t)}),e},removePeer:function(e){delete f[e]},getId:function(){return r},invitePeer:v,joinPeer:h}}exports.createStore=createStore;