thali
Version:
460 lines (418 loc) • 23.8 kB
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Source: NextGeneration/thaliMobileNativeWrapper.js</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Source: NextGeneration/thaliMobileNativeWrapper.js</h1>
<section>
<article>
<pre class="prettyprint source linenums"><code>'use strict';
var Promise = require('lie');
var EventEmitter = require('events');
/** @module thaliMobileNativeWrapper */
/**
* @file
*
* This is the primary interface for those wishing to talk directly to the
* native layer. All the methods defined in this file are asynchronous. However,
* with the exception of {@link module:thaliMobileNativeWrapper.emitter} and
* {@link module:thaliMobileNativeWrapper.connect}, any time a method is called
* the invocation will immediately return but the request will actually be put
* on a queue and all incoming requests will be run out of that queue. This
* means that if one calls two start methods on say advertising or discovery
* then the first start method will execute, call back its promise and only then
* will the second start method start running. This restriction is in place to
* simplify the state model and reduce testing.
*
* ## Why not just call {@link module:thaliMobileNative} directly?
*
* Our contract in {@link module:thaliMobileNative} stipulates some behaviors
* that have to be enforced at the node.js layer. For example, we can only issue
* a single outstanding non-connect Mobile().callNative command at a time. We
* also want to change the callbacks from callbacks to promises as well as
* change registerToNative calls into Node.js events. All of that is handled
* here. So as a general rule nobody but this module should ever call {@link
* module:thaliMobileNative}. Anyone who wants to use the {@link
* module:thaliMobileNative} functionality should be calling this module.
*/
/*
METHODS
*/
/**
* This method MUST be called before any other method here other than
* registering for events on the emitter. This method will cause us to:
* - create a TCP server on a random port and host the router on that server.
* - create a {@link module:TCPServersManager}.
* - listen for the {@link module:TCPServersManager~failedConnection} event and
* then repeat it.
* - listen for the {@link module:TCPServersManager~routerPortConnectionFailed}
* event which we will then cause us to fire a {@link
* event:incomingConnectionToPortNumberFailed}.
* - call start on the {@link module:TCPServersManager} object and record the
* returned port.
*
* We MUST register for the native layer handlers exactly once.
*
* If the start fails then the object is not in start state and vice versa.
*
* This method is not idempotent. If called two times in a row without an
* intervening stop a "Call Stop!" Error MUST be returned.
*
* This method can be called after stop since this is a singleton object.
*
* @public
* @param {Object} router This is an Express Router object (for example,
* express-pouchdb is a router object) that the caller wants the non-TCP
* connections to be terminated with. This code will put that router at '/' so
* make sure your paths are set up appropriately.
* @returns {Promise<?Error>}
*/
module.exports.start = function (router) {
return new Promise();
};
/**
* This method will call all the stop methods, call stop on the {@link
* module:TCPServersManager} object and close the TCP server hosting the router.
*
* Once called the object is in stop state.
*
* This method is idempotent and so MUST be able to be called multiple times in
* a row without changing state.
*
* @returns {Promise<?Error>}
*/
module.exports.stop = function () {
return new Promise();
};
/**
* This method instructs the native layer to discover what other devices are
* within range using the platform's non-TCP P2P capabilities. When a device is
* discovered its information will be published via {@link
* event:nonTCPPeerAvailabilityChangedEvent}.
*
* This method is idempotent so multiple consecutive calls without an
* intervening call to stop will not cause a state change.
*
* This method MUST NOT be called if the object is not in start state or a "Call
* Start!" error MUST be returned.
*
* | Error String | Description |
* |--------------|-------------|
* | No Native Non-TCP Support | There are no non-TCP radios on this platform. |
* | Radio Turned Off | The radio(s) needed for this method are not turned on. |
* | Unspecified Error with Radio infrastructure | Something went wrong with the radios. Check the logs. |
* | Call Start! | The object is not in start state. |
*
* @public
* @returns {Promise<?Error>}
* @throws {Error}
*/
module.exports.startListeningForAdvertisements = function () {
return new Promise();
};
/**
* This method instructs the native layer to stop listening for discovery
* advertisements. Note that so long as discovery isn't occurring (because, for
* example, the radio needed isn't on) this method will return success.
*
* This method is idempotent and MAY be called even if
* startListeningForAdvertisements has not been called.
*
* This method MUST NOT terminate any existing connections created locally using
* {@link module:thaliMobileNativeWrapper.connect}.
*
* | Error String | Description |
* |--------------|-------------|
* | Failed | Somehow the stop method couldn't do its job. Check the logs. |
*
* @public
* @returns {Promise<?Error>}
*/
module.exports.stopListeningForAdvertisements = function () {
return new Promise();
};
/**
* This method has two separate but related functions. It's first function is to
* begin advertising the Thali peer's presence to other peers. The second
* purpose is to accept incoming non-TCP/IP connections (that will then be
* bridged to TCP/IP) from other peers.
*
* In Android these functions can be separated but with iOS the multi-peer
* connectivity framework is designed such that it is only possible for remote
* peers to connect to the current peer if and only if the current peer is
* advertising its presence. So we therefore have put the two functions together
* into a single method.
*
* This method MUST NOT be called unless in the start state otherwise a "Call
* Start!" error MUST be returned.
*
* ## Discovery
*
* Thali currently handles discovery by announcing over the discovery channel
* that the Thali peer has had a state change without providing any additional
* information, such as who the peer is or who the state changes are relevant
* to. The remote peers, when they get the state change notification, will have
* to connect to this peer in order to retrieve information about the state
* change.
*
* Therefore the purpose of this method is just to raise the "state changed"
* flag. Each time it is called a new event will be generated that will tell
* listeners that the system has changed state since the last call. Therefore
* this method is not idempotent since each call causes a state change.
*
* Once an advertisement is sent out as a result of calling this method
* typically any new peers who come in range will be able to retrieve the
* existing advertisement. So this is not a one time event but rather more of a
* case of publishing an ongoing advertisement regarding the peer's state.
*
* ## Incoming Connections
*
* By default all incoming TCP connections generated by {@link
* external:"Mobile('startUpdateAdvertisingAndListening')".ca
* llNative} MUST be passed through a multiplex layer. The details of how this
* layer works are given in {@link module:TCPServersManager}. This method will
* pass the port from {@link module:TCPServersManager.start} output to {@link
* external:"Mobile('startUpdateAdvertisingAndListening')".ca
* llNative}.
*
* ## Repeated calls
*
* By design this method is intended to be called multiple times without calling
* stop as each call causes the currently notification flag to change.
*
* | Error String | Description |
* |--------------|-------------|
* | No Native Non-TCP Support | There are no non-TCP radios on this platform. |
* | Radio Turned Off | The radio(s) needed for this method are not turned on. |
* | Unspecified Error with Radio infrastructure | Something went wrong with the radios. Check the logs. |
* | Call Start! | The object is not in start state. |
*
* @public
* @returns {Promise<?Error>}
*/
module.exports.startUpdateAdvertisingAndListening =
function () {
return new Promise();
};
/**
* This method tells the native layer to stop advertising the presence of the
* peer, stop accepting incoming connections over the non-TCP/IP transport and
* to disconnect all existing non-TCP/IP transport incoming connections.
*
* Note that so long as advertising has stopped and there are no incoming
* connections or the ability to accept them then this method will return
* success. So, for example, if advertising was never started then this method
* will return success.
*
* | Error String | Description |
* |--------------|-------------|
* | Failed | Somehow the stop method couldn't do its job. Check the logs. |
*
* @public
* @returns {Promise<?Error>}
*/
module.exports.stopAdvertisingAndListening = function () {
return new Promise();
};
/**
* This method returns the last value sent by the
* {@link module:thaliMobileNativeWrapper.event:networkChangedNonTCP}
* event.
*
* The reason we use a promise is that there is a race condition where
* someone could call this before we have gotten the first network
* status event. Rather than force everyone to play the game
* where they have to subscribe to the event and call this method
* just to figure out the status for things like UX that says
* "Hey you don't have the right radio!" we just use a promise that
* won't return until we have a value.
*
* @public
* @returns {Promise<module:thaliMobileNative~networkChanged>}
*/
module.exports.getNonTCPNetworkStatus = function() {
return new Promise();
}
/**
* # WARNING: This method is intended for internal Thali testing only. DO NOT
* USE!
*
* This method is only intended for iOS. It's job is to terminate all incoming
* and outgoing multipeer connectivity framework browser, advertiser, MCSession
* and stream connections immediately without using the normal stop and start
* interfaces or TCP/IP level connections. The goal is to simulate what would
* happen if we switched the phone to something like airplane mode. This
* simulates what would happen if peers went out of range.
*
* This method MUST return "Not Supported" if called on Android. On Android we
* can get this functionality by using JXCore's ability to disable the local
* radios.
*
* | Error String | Description |
* |--------------|-------------|
* | Failed | Somehow the stop method couldn't do its job. Check the logs. |
* | Not Supported | This method is not support on this platform. |
*
* @private
* @returns {Promise<?Error>}
*/
module.exports.killConnections = function () {
return new Promise();
};
/*
EVENTS
*/
/**
* When a {@link module:thaliMobileNative~peerAvailabilityChangedCallback}
* occurs each peer MUST be placed into a queue. Each peer in the queue MUST be
* processed as given below and only once all processing related to that peer
* has completed MAY the next peer be taken from the queue.
*
* If a peer's peerAvailable is set to false then we MUST use platform specific
* heuristics to decide how to process this. For example, on Android it is
* possible for a peer to go into the background at which point their BLE radio
* will go to low power even though their Bluetooth radio may still be
* reachable. So the system might decide to wait for a bit before issuing a
* peerAvailable = false for that peer. But when the system decides to issue a
* peer not available event it MUST issue a {@link
* event:nonTCPPeerAvailabilityChangedEvent} with peerIdentifier set to the
* value in the peer object, portNumber set to null and suggestedTCPTimeout not
* set.
*
* If a peer's peerAvailable is set to true then we MUST call {@link
* module:TCPServersManager.createPeerListener}. If an error is returned then
* the error MUST be logged and we MUST treat this as if we received the value
* with peerAvailable equal to false. If the call is a success then we MUST
* issue a {@link event:nonTCPPeerAvailabilityChangedEvent} with peerIdentifier
* set to the value in the peer object, portNumber set to the returned value and
* suggestedTCPTimeout set based on the behavior we have seen on the platform.
* That is, some non-TCP technologies can take longer to set up a connection
* than others so we need to warn those upstream of that.
*
* @public
* @typedef {Object} nonTCPPeerAvailabilityChanged
* @property {string} peerIdentifier See {@link module:thaliMobileNative~peer.peerIdentifier}.
* @property {number|null} portNumber If this value is null then the system is advertising that it no longer believes
* this peer is available. If this value is non-null then it is a port on 127.0.0.1 at which the local peer can
* connect in order to establish a TCP/IP connection to the remote peer.
* @property {number} [suggestedTCPTimeout] Based on the characteristics of the underlying non-TCP transport how long
* the system suggests that the caller be prepared to wait before the TCP/IP connection to the remote peer can be
* set up. This is measured in milliseconds.
*/
/**
* This event MAY start firing as soon as either of the start methods is called.
* Start listening for advertisements obviously looks for new peers but in some
* cases so does start advertising. This is because in some cases it's possible
* for peer A to discover peer B but not vice versa. This can result in peer A
* connecting to peer B who previously didn't know peer A exists. When that
* happens we will fire a discovery event.
*
* This event MUST stop firing when both stop methods have been called.
*
* The native layer does not guarantee that it will filter out duplicate
* peerAvailabilityChanged callbacks. This means it is possible to receive
* multiple announcements about the same peer in the same state.
*
* While the native layer can return multiple peers in a single callback the
* wrapper breaks them into individual events. See {@link
* module:thaliMobileNativeWrapper~nonTCPPeerAvailabilityChanged} for details on
* how to process each peer.
*
* If we receive a {@link module:TCPServersManager~failedConnection} then we
* MUST treat that as the equivalent of having received a peer for
* nonTCPPeerAvailabilityChanged with peerAvailable set to false.
*
* @public
* @event nonTCPPeerAvailabilityChangedEvent
* @type {Object}
* @property {module:thaliMobileNativeWrapper~nonTCPPeerAvailabilityChanged} peer
*/
/**
* This is used whenever discovery or advertising starts or stops. Since it's
* possible for these to be stopped (in particular) due to events outside of
* node.js's control (for example, someone turned off a radio) we provide a
* callback to track these changes. Note that there is no guarantee that the
* same callback value couldn't be sent multiple times in a row.
*
* But the general rule we will only fire this event in response to receiving
* the event from the native layer. That is, we won't fire it ourselves when
* someone calls start or stop advertising/incoming on the wrapper.
*
* @public
* @event discoveryAdvertisingStateUpdateNonTCPEvent
* @type {Object}
* @property {module:thaliMobileNative~discoveryAdvertisingStateUpdate} discoveryAdvertisingStateUpdateValue
*/
/**
* Provides a notification when the network's state changes as well as when our
* use of the network changes, specifically when discovery or
* advertising/listening starts and stops. This event can start firing as soon
* as the system starts.
*
* @public
* @event networkChangedNonTCP
* @type {Object}
* @property {module:thaliMobileNative~networkChanged} networkChangedValue
*/
/**
* This event specifies that our internal TCP servers are no longer accepting
* connections so we are in serious trouble. Stopping and restarting is almost
* certainly necessary at this point. We can discover this either because of an
* error in {@link module:TCPServersManager} or because of {@link
* external:"Mobile('incomingConnectionToPortNumberFailed')".registerToNative}.
*
* @public
* @event incomingConnectionToPortNumberFailed
* @property {number} portNumber the 127.0.0.1 port that the TCP/IP bridge tried
* to connect to.
*/
/**
* Use this emitter to subscribe to events.
*
* @public
* @fires event:nonTCPPeerAvailabilityChangedEvent
* @fires event:networkChangedNonTCP
* @fires event:incomingConnectionToPortNumberFailed
* @fires event:discoveryAdvertisingStateUpdateNonTCPEvent
* @fires module:TCPServersManager~failedConnection We repeat these events
*/
module.exports.emitter = new EventEmitter();
Mobile('PeerAvailabilityChange').registerToNative(function (peers) {
// do stuff!
});
Mobile('discoveryAdvertisingStateUpdateNonTCP').registerToNative(
function (discoveryAdvertisingStateUpdateValue) {
// do stuff!
});
Mobile('networkChanged').registerToNative(function (networkChanged) {
// do stuff!
});
Mobile('incomingConnectionToPortNumberFailed').registerToNative(
function (portNumber) {
// do stuff!
});
</code></pre>
</article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Modules</h3><ul><li><a href="module-TCPServersManager.html">TCPServersManager</a></li><li><a href="module-thaliMobile.html">thaliMobile</a></li><li><a href="module-thaliMobileNative.html">thaliMobileNative</a></li><li><a href="module-thaliMobileNativeWrapper.html">thaliMobileNativeWrapper</a></li><li><a href="module-thaliNotificationAction.html">thaliNotificationAction</a></li><li><a href="module-thaliNotificationBeacons.html">thaliNotificationBeacons</a></li><li><a href="module-thaliNotificationClient.html">thaliNotificationClient</a></li><li><a href="module-thaliNotificationServer.html">thaliNotificationServer</a></li><li><a href="module-thaliPeerAction.html">thaliPeerAction</a></li><li><a href="module-thaliPeerDictionary.html">thaliPeerDictionary</a></li><li><a href="module-thaliPeerPoolInterface.html">thaliPeerPoolInterface</a></li><li><a href="module-ThaliWifiInfrastructure.html">ThaliWifiInfrastructure</a></li><li><a href="module-WifiBasedNativeMock.html">WifiBasedNativeMock</a></li></ul><h3>Externals</h3><ul><li><a href="external-_Mobile(_connect_)_.html">Mobile('connect')</a></li><li><a href="external-_Mobile(_discoveryAdvertisingStateUpdateNonTCP_)_.html">Mobile('discoveryAdvertisingStateUpdateNonTCP')</a></li><li><a href="external-_Mobile(_incomingConnectionToPortNumberFailed_)_.html">Mobile('incomingConnectionToPortNumberFailed')</a></li><li><a href="external-_Mobile(_killConnections_)_.html">Mobile('killConnections')</a></li><li><a href="external-_Mobile(_networkChanged_)_.html">Mobile('networkChanged')</a></li><li><a href="external-_Mobile(_peerAvailabilityChanged_)_.html">Mobile('peerAvailabilityChanged')</a></li><li><a href="external-_Mobile(_startListeningForAdvertisements_)_.html">Mobile('startListeningForAdvertisements')</a></li><li><a href="external-_Mobile(_startUpdateAdvertisingAndListening_)_.html">Mobile('startUpdateAdvertisingAndListening')</a></li><li><a href="external-_Mobile(_stopAdvertisingAndListening_)_.html">Mobile('stopAdvertisingAndListening')</a></li><li><a href="external-_Mobile(_stopListeningForAdvertisements_)_.html">Mobile('stopListeningForAdvertisements')</a></li></ul><h3>Classes</h3><ul><li><a href="ConnectionTable.html">ConnectionTable</a></li><li><a href="module-TCPServersManager-TCPServersManager.html">TCPServersManager</a></li><li><a href="module-thaliNotificationAction-NotificationAction.html">NotificationAction</a></li><li><a href="module-thaliNotificationBeacons-ParseBeaconsResponse.html">ParseBeaconsResponse</a></li><li><a href="module-thaliNotificationClient-ThaliNotificationClient.html">ThaliNotificationClient</a></li><li><a href="module-thaliNotificationServer-ThaliNotificationServer.html">ThaliNotificationServer</a></li><li><a href="module-thaliPeerAction-PeerAction.html">PeerAction</a></li><li><a href="module-thaliPeerDictionary-NotificationPeerDictionaryEntry.html">NotificationPeerDictionaryEntry</a></li><li><a href="module-thaliPeerDictionary-PeerConnectionInformation.html">PeerConnectionInformation</a></li><li><a href="module-thaliPeerDictionary-PeerDictionary.html">PeerDictionary</a></li><li><a href="module-thaliPeerPoolInterface-ThaliPeerPoolInterface.html">ThaliPeerPoolInterface</a></li><li><a href="module-ThaliWifiInfrastructure-ThaliWifiInfrastructure.html">ThaliWifiInfrastructure</a></li><li><a href="module-WifiBasedNativeMock-MobileCallInstance.html">MobileCallInstance</a></li><li><a href="module-WifiBasedNativeMock-WifiBasedNativeMock.html">WifiBasedNativeMock</a></li></ul><h3>Events</h3><ul><li><a href="module-thaliMobileNativeWrapper.html#~event:discoveryAdvertisingStateUpdateNonTCPEvent">discoveryAdvertisingStateUpdateNonTCPEvent</a></li><li><a href="module-ThaliWifiInfrastructure.html#~event:discoveryAdvertisingStateUpdateWifiEvent">discoveryAdvertisingStateUpdateWifiEvent</a></li><li><a href="module-TCPServersManager.html#~event:failedConnection">failedConnection</a></li><li><a href="module-thaliMobileNativeWrapper.html#~event:incomingConnectionToPortNumberFailed">incomingConnectionToPortNumberFailed</a></li><li><a href="module-thaliMobileNativeWrapper.html#~event:networkChangedNonTCP">networkChangedNonTCP</a></li><li><a href="module-ThaliWifiInfrastructure.html#~event:networkChangedWifi">networkChangedWifi</a></li><li><a href="module-thaliMobileNativeWrapper.html#~event:nonTCPPeerAvailabilityChangedEvent">nonTCPPeerAvailabilityChangedEvent</a></li><li><a href="module-TCPServersManager.html#~event:routerPortConnectionFailed">routerPortConnectionFailed</a></li><li><a href="module-ThaliWifiInfrastructure.html#~event:wifiPeerAvailabilityChanged">wifiPeerAvailabilityChanged</a></li><li><a href="module-thaliMobile.html#.event:event:discoveryAdvertisingStateUpdate">discoveryAdvertisingStateUpdate</a></li><li><a href="module-thaliMobile.html#.event:event:networkChanged">networkChanged</a></li><li><a href="module-thaliMobile.html#.event:event:peerAvailabilityChanged">peerAvailabilityChanged</a></li><li><a href="module-thaliNotificationAction-NotificationAction.html#.event:event:Resolved">Resolved</a></li><li><a href="module-thaliNotificationClient.html#.event:event:peerAdvertisesDataForUs">peerAdvertisesDataForUs</a></li></ul><h3>Global</h3><ul><li><a href="global.html#getPKCS12Content">getPKCS12Content</a></li><li><a href="global.html#getPublicKeyHash">getPublicKeyHash</a></li><li><a href="global.html#stopThaliReplicationManager">stopThaliReplicationManager</a></li><li><a href="global.html#ThaliEmitter">ThaliEmitter</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.4.0</a> on Mon Jan 18 2016 11:19:31 GMT+0200 (EET)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>