| 
									
										
										
										
											2017-02-18 06:02:33 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							|  |  |  | * Setup a node.js child_process communications channel and listen and  | 
					
						
							|  |  |  | * exec commands... | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | **********************************************************************/ | 
					
						
							|  |  |  | ((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define) | 
					
						
							|  |  |  | (function(require){ var module={} // make module AMD/node compatible...
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-01 00:44:02 +03:00
										 |  |  | if(typeof(process) != 'undefined'){ | 
					
						
							|  |  |  | 	var child_process = requirejs('child_process') | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-18 06:02:33 +03:00
										 |  |  | var actions = require('lib/actions') | 
					
						
							|  |  |  | var features = require('lib/features') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var core = require('features/core') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-24 23:15:03 +03:00
										 |  |  | var object = require('lib/object') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-18 06:02:33 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-24 19:47:04 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | // helpers...
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-25 01:23:07 +03:00
										 |  |  | // Cooperative promise object...
 | 
					
						
							|  |  |  | // 
 | 
					
						
							|  |  |  | // This is like a promise but is not resolved internally, rather this 
 | 
					
						
							|  |  |  | // resolves (is set) via a different promise of value passed to it via 
 | 
					
						
							|  |  |  | // the .set(..) method...
 | 
					
						
							|  |  |  | // 
 | 
					
						
							|  |  |  | // Example:
 | 
					
						
							|  |  |  | // 	// create a promise...
 | 
					
						
							|  |  |  | // 	var p = (new CooperativePromise())
 | 
					
						
							|  |  |  | // 		// bind normally...
 | 
					
						
							|  |  |  | // 		.then(function(){ .. })
 | 
					
						
							|  |  |  | // 		
 | 
					
						
							|  |  |  | // 	// this will resolve p and trigger all the .then(..) callbacks...
 | 
					
						
							|  |  |  | // 	p.set(new Promise(function(resolve, reject){ resolve() }))
 | 
					
						
							|  |  |  | // 	
 | 
					
						
							|  |  |  | // Note that .set(..) can be passed any value, passing a non-promise has
 | 
					
						
							|  |  |  | // the same effect as passing the same value to resolve(..) of a Promise
 | 
					
						
							|  |  |  | // object...
 | 
					
						
							|  |  |  | // 
 | 
					
						
							| 
									
										
										
										
											2017-02-26 01:33:14 +03:00
										 |  |  | // XXX should this be a separate package???
 | 
					
						
							| 
									
										
										
										
											2017-02-24 23:15:03 +03:00
										 |  |  | // XXX can we make this an instance of Promise for passing the
 | 
					
						
							|  |  |  | // 		x instanceof Promise test???
 | 
					
						
							|  |  |  | var CooperativePromisePrototype = { | 
					
						
							|  |  |  | 	__base: null, | 
					
						
							|  |  |  | 	__promise: null, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// XXX error if already set...
 | 
					
						
							|  |  |  | 	set: function(promise){ | 
					
						
							|  |  |  | 		if(this.__promise == null){ | 
					
						
							|  |  |  | 			// setting a non-promise...
 | 
					
						
							|  |  |  | 			if(promise.catch == null && promise.then == null){ | 
					
						
							|  |  |  | 				Object.defineProperty(this, '__promise', { | 
					
						
							|  |  |  | 					value: false, | 
					
						
							|  |  |  | 					enumerable: false, | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 				this.__resolve(promise) | 
					
						
							|  |  |  | 				 | 
					
						
							|  |  |  | 			// setting a promise...
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				Object.defineProperty(this, '__promise', { | 
					
						
							|  |  |  | 					value: promise, | 
					
						
							|  |  |  | 					enumerable: false, | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// connect the base and the set promises...
 | 
					
						
							|  |  |  | 				promise.catch(this.__reject.bind(this)) | 
					
						
							|  |  |  | 				promise.then(this.__resolve.bind(this)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// cleanup...
 | 
					
						
							|  |  |  | 				delete this.__base | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// cleanup...
 | 
					
						
							|  |  |  | 			delete this.__resolve | 
					
						
							|  |  |  | 			delete this.__reject | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			// XXX throw err???
 | 
					
						
							|  |  |  | 			console.error('Setting a cooperative promise twice', this) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Promise API...
 | 
					
						
							|  |  |  | 	catch: function(func){ | 
					
						
							|  |  |  | 		return (this.__promise || this.__base).catch(func) }, | 
					
						
							|  |  |  | 	then: function(func){ | 
					
						
							|  |  |  | 		return (this.__promise || this.__base).then(func) }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	__init__: function(){ | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		var base = new Promise(function(resolve, reject){ | 
					
						
							|  |  |  | 			Object.defineProperties(that, { | 
					
						
							|  |  |  | 				__resolve: { | 
					
						
							|  |  |  | 					value: resolve, | 
					
						
							|  |  |  | 					enumerable: false, | 
					
						
							|  |  |  | 					configurable: true, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				__reject: { | 
					
						
							|  |  |  | 					value: reject, | 
					
						
							|  |  |  | 					enumerable: false, | 
					
						
							|  |  |  | 					configurable: true, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		Object.defineProperty(this, '__base', { | 
					
						
							|  |  |  | 			value: base, | 
					
						
							|  |  |  | 			enumerable: false, | 
					
						
							|  |  |  | 			configurable: true, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var CooperativePromise = | 
					
						
							| 
									
										
										
										
											2017-02-26 01:33:14 +03:00
										 |  |  | module.CooperativePromise = | 
					
						
							| 
									
										
										
										
											2017-02-24 23:15:03 +03:00
										 |  |  | object.makeConstructor('CooperativePromise',  | 
					
						
							|  |  |  | 	Promise, | 
					
						
							|  |  |  | 	CooperativePromisePrototype) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | 	 | 
					
						
							| 
									
										
										
										
											2017-02-26 01:33:14 +03:00
										 |  |  | // XXX would be nice to list the protocols supported by the action in 
 | 
					
						
							|  |  |  | // 		an action attr...
 | 
					
						
							|  |  |  | var makeProtocolHandler = | 
					
						
							|  |  |  | module.makeProtocolHandler = | 
					
						
							|  |  |  | function(protocol, func){ | 
					
						
							| 
									
										
										
										
											2017-02-24 23:15:03 +03:00
										 |  |  | 	return function(id){ | 
					
						
							|  |  |  | 		return id.startsWith(protocol + ':') | 
					
						
							| 
									
										
										
										
											2017-02-26 01:33:14 +03:00
										 |  |  | 			&& function(res){  | 
					
						
							|  |  |  | 				res.set(func.apply(this, [].slice.call(arguments, 1))) }}}  | 
					
						
							| 
									
										
										
										
											2017-02-24 19:47:04 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-18 06:02:33 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // XXX this is a generic API, add ability to define protocols...
 | 
					
						
							|  |  |  | // 		Protocols:
 | 
					
						
							|  |  |  | // 			- child_process
 | 
					
						
							| 
									
										
										
										
											2017-02-22 17:49:31 +03:00
										 |  |  | // 			- PeerJS
 | 
					
						
							|  |  |  | // 			- https
 | 
					
						
							| 
									
										
										
										
											2017-02-22 17:46:40 +03:00
										 |  |  | // 			- rpc (???)
 | 
					
						
							|  |  |  | // 			- mq (???)
 | 
					
						
							| 
									
										
										
										
											2017-02-19 05:55:53 +03:00
										 |  |  | // 			- ...
 | 
					
						
							| 
									
										
										
										
											2017-03-05 06:31:20 +03:00
										 |  |  | // XXX there seem to be two ways to go with peers:
 | 
					
						
							|  |  |  | //		- proxy a set of actions...
 | 
					
						
							|  |  |  | //			+ simple
 | 
					
						
							|  |  |  | //			- non-transparent in most cases...
 | 
					
						
							|  |  |  | //				...considering that all peer calls are async, making this
 | 
					
						
							|  |  |  | //				transparent for actions that do not return a promise
 | 
					
						
							|  |  |  | //				will be problematic...
 | 
					
						
							|  |  |  | //		- custom actions that communicate with a peer...
 | 
					
						
							|  |  |  | //			+ no need to be compatible with existing actions
 | 
					
						
							|  |  |  | //			- manual...
 | 
					
						
							|  |  |  | //		Need to play around with use-cases and see what fits best...
 | 
					
						
							| 
									
										
										
										
											2017-03-06 16:22:50 +03:00
										 |  |  | // XXX should/can this do "sync"???
 | 
					
						
							| 
									
										
										
										
											2017-02-22 17:47:49 +03:00
										 |  |  | // XXX should the couch api be implemented over this of independently???
 | 
					
						
							| 
									
										
										
										
											2017-02-18 06:02:33 +03:00
										 |  |  | var PeerActions = actions.Actions({ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-20 04:27:09 +03:00
										 |  |  | 	// Format:
 | 
					
						
							|  |  |  | 	// 	{
 | 
					
						
							|  |  |  | 	// 		<id>: <spec>,
 | 
					
						
							|  |  |  | 	// 	}
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX <spec> format???
 | 
					
						
							| 
									
										
										
										
											2017-03-07 06:06:47 +03:00
										 |  |  | 	// XXX id/url aliases...
 | 
					
						
							| 
									
										
										
										
											2017-02-21 06:56:05 +03:00
										 |  |  | 	// XXX Q: should peer adapter be a feature that defines/extnds a set 
 | 
					
						
							|  |  |  | 	// 		of actions???
 | 
					
						
							|  |  |  | 	// 		...e.g. base peerCreate(..) defines the protocol but does 
 | 
					
						
							|  |  |  | 	// 		nothing, while each implementation checks if the url is 
 | 
					
						
							|  |  |  | 	// 		compatible and handles it accordingly...
 | 
					
						
							| 
									
										
										
										
											2017-02-20 04:27:09 +03:00
										 |  |  | 	__peers: null, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-18 06:02:33 +03:00
										 |  |  | 	// XXX need more control...
 | 
					
						
							|  |  |  | 	// 		- get proxies to specific peer...
 | 
					
						
							|  |  |  | 	get peeractions(){ | 
					
						
							| 
									
										
										
										
											2018-01-20 01:14:59 +03:00
										 |  |  | 		this.cache('peeractions', function(d){ | 
					
						
							| 
									
										
										
										
											2018-01-21 06:07:29 +03:00
										 |  |  | 			return d instanceof Array ? d.slice() : this.getPeerActions() }) }, | 
					
						
							| 
									
										
										
										
											2017-02-18 06:02:33 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 06:30:17 +03:00
										 |  |  | 	getPeerActions: ['- System/Peer/', | 
					
						
							| 
									
										
										
										
											2017-02-18 06:02:33 +03:00
										 |  |  | 		function(id){ | 
					
						
							| 
									
										
										
										
											2017-02-19 05:55:53 +03:00
										 |  |  | 			var that = this | 
					
						
							|  |  |  | 			return this.actions.filter(id ?  | 
					
						
							|  |  |  | 				function(action){ | 
					
						
							|  |  |  | 					return that.getActionAttr(action, '__peer__') == id } | 
					
						
							|  |  |  | 				// get all peer actions...
 | 
					
						
							|  |  |  | 				: function(action){ | 
					
						
							|  |  |  | 					return that.getActionAttr(action, '__peer__') }) | 
					
						
							| 
									
										
										
										
											2017-02-18 06:02:33 +03:00
										 |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2017-02-19 05:55:53 +03:00
										 |  |  | 	// XXX should this also check props???
 | 
					
						
							| 
									
										
										
										
											2017-03-05 06:30:17 +03:00
										 |  |  | 	isPeerAction: ['- System/Peer/', | 
					
						
							| 
									
										
										
										
											2017-02-19 05:55:53 +03:00
										 |  |  | 		function(name){ | 
					
						
							|  |  |  | 			return !!this.getActionAttr(name, '__peer__') }], | 
					
						
							| 
									
										
										
										
											2017-02-18 06:02:33 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-22 04:59:47 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-02-22 05:07:07 +03:00
										 |  |  | 	// NOTE: it is the responsibility of the overloading action to trigger
 | 
					
						
							|  |  |  | 	// 		the appropriate events...
 | 
					
						
							| 
									
										
										
										
											2017-02-22 04:59:47 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX should this be sync or async???
 | 
					
						
							| 
									
										
										
										
											2017-02-22 04:54:31 +03:00
										 |  |  | 	// XXX this should create or connect to a peer depending on protocol...
 | 
					
						
							| 
									
										
										
										
											2017-02-22 04:59:47 +03:00
										 |  |  | 	// XXX the events should get called on the peer too -- who is 
 | 
					
						
							|  |  |  | 	// 		responsible for this???
 | 
					
						
							| 
									
										
										
										
											2017-03-05 06:30:17 +03:00
										 |  |  | 	peerConnect: ['- System/Peer/', | 
					
						
							| 
									
										
										
										
											2017-02-24 23:15:03 +03:00
										 |  |  | 		function(id, options){ return new CooperativePromise() }], | 
					
						
							| 
									
										
										
										
											2017-03-05 06:30:17 +03:00
										 |  |  | 	peerDisconnect: ['- System/Peer/', | 
					
						
							| 
									
										
										
										
											2017-02-24 23:15:03 +03:00
										 |  |  | 		function(id){ return new CooperativePromise() }], | 
					
						
							| 
									
										
										
										
											2017-02-18 06:02:33 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-01 04:35:01 +03:00
										 |  |  | 	// events...
 | 
					
						
							|  |  |  | 	// XXX do proper docs...
 | 
					
						
							|  |  |  | 	// XXX do we need these???
 | 
					
						
							| 
									
										
										
										
											2017-03-05 06:30:17 +03:00
										 |  |  | 	peerConnected: ['- System/Peer/', | 
					
						
							| 
									
										
										
										
											2018-02-13 01:14:35 +03:00
										 |  |  | 		core.Event(function(id){ | 
					
						
							| 
									
										
										
										
											2017-02-18 06:02:33 +03:00
										 |  |  | 			// XXX
 | 
					
						
							| 
									
										
										
										
											2017-02-19 05:55:53 +03:00
										 |  |  | 		})], | 
					
						
							| 
									
										
										
										
											2017-03-05 06:30:17 +03:00
										 |  |  | 	peerDisconnected: ['- System/Peer/', | 
					
						
							| 
									
										
										
										
											2018-02-13 01:14:35 +03:00
										 |  |  | 		core.Event(function(id){ | 
					
						
							| 
									
										
										
										
											2017-02-18 06:02:33 +03:00
										 |  |  | 			// XXX
 | 
					
						
							| 
									
										
										
										
											2017-02-19 05:55:53 +03:00
										 |  |  | 		})], | 
					
						
							| 
									
										
										
										
											2017-02-18 06:02:33 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 06:30:17 +03:00
										 |  |  | 	// NOTE: .peerCall(..) is just a front-end to .peerApply(..) so there
 | 
					
						
							|  |  |  | 	// 		is no need to reload it...
 | 
					
						
							|  |  |  | 	peerCall: ['- System/Peer/', | 
					
						
							| 
									
										
										
										
											2017-03-04 05:34:53 +03:00
										 |  |  | 		function(id, action){ | 
					
						
							|  |  |  | 			var args = [].slice.call(arguments, 2) | 
					
						
							|  |  |  | 			return this.peerApply(id, action, args) | 
					
						
							|  |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2017-03-05 06:30:17 +03:00
										 |  |  | 	peerApply: ['- System/Peer/', | 
					
						
							| 
									
										
										
										
											2017-02-26 01:33:14 +03:00
										 |  |  | 		function(id, action, args){ return new CooperativePromise() }], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 06:30:17 +03:00
										 |  |  | 	peerList: ['- System/Peer/', | 
					
						
							| 
									
										
										
										
											2017-02-21 06:56:05 +03:00
										 |  |  | 		function(){ return Object.keys(this.__peers || {}) }], | 
					
						
							| 
									
										
										
										
											2017-03-05 06:30:17 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-01 04:35:01 +03:00
										 |  |  | 	// XXX do we need these???
 | 
					
						
							| 
									
										
										
										
											2017-02-22 04:54:31 +03:00
										 |  |  | 	// XXX format spec!!!
 | 
					
						
							| 
									
										
										
										
											2017-03-05 06:30:17 +03:00
										 |  |  | 	peerSpec: ['- System/Peer/', | 
					
						
							| 
									
										
										
										
											2017-02-19 06:22:32 +03:00
										 |  |  | 		function(id){ | 
					
						
							| 
									
										
										
										
											2017-02-18 06:02:33 +03:00
										 |  |  | 			// XXX
 | 
					
						
							|  |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2017-03-05 06:30:17 +03:00
										 |  |  | 	peerProxy: ['- System/Peer/', | 
					
						
							|  |  |  | 		function(id, action, target){ | 
					
						
							|  |  |  | 			target = target || action | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this[action] = actions.Action.apply(actions.Action, [ | 
					
						
							|  |  |  | 				action, | 
					
						
							|  |  |  | 				`- System/Peer/Proxy to action ${target} of peer "${id}"`, | 
					
						
							|  |  |  | 				{ __peer__: true }, | 
					
						
							|  |  |  | 				function(){  | 
					
						
							|  |  |  | 					return this.peerApply(id, target, arguments) }, | 
					
						
							|  |  |  | 			])  | 
					
						
							| 
									
										
										
										
											2017-02-18 06:02:33 +03:00
										 |  |  | 		}], | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var Peer =  | 
					
						
							|  |  |  | module.Peer = core.ImageGridFeatures.Feature({ | 
					
						
							|  |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-22 05:02:13 +03:00
										 |  |  | 	tag: 'peer', | 
					
						
							| 
									
										
										
										
											2017-03-01 00:44:02 +03:00
										 |  |  | 	suggested: [ | 
					
						
							|  |  |  | 		'child-process-peer', | 
					
						
							|  |  |  | 	], | 
					
						
							| 
									
										
										
										
											2017-02-18 06:02:33 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	actions: PeerActions,  | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-22 05:02:13 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-24 19:47:04 +03:00
										 |  |  | // XXX all the return values here will be ignored -- need a way to figure
 | 
					
						
							|  |  |  | // 		out a cooperative mechanic to return promises...
 | 
					
						
							| 
									
										
										
										
											2017-02-22 05:02:13 +03:00
										 |  |  | var ChildProcessPeerActions = actions.Actions({ | 
					
						
							| 
									
										
										
										
											2017-03-01 00:44:02 +03:00
										 |  |  | 	// XXX do better message handling...
 | 
					
						
							| 
									
										
										
										
											2017-03-05 06:30:17 +03:00
										 |  |  | 	peerConnect: ['- System/Peer/', | 
					
						
							| 
									
										
										
										
											2017-02-26 01:33:14 +03:00
										 |  |  | 		makeProtocolHandler('child', function(id, options){ | 
					
						
							| 
									
										
										
										
											2017-02-24 19:47:04 +03:00
										 |  |  | 			return new Promise((function(resolve, reject){ | 
					
						
							|  |  |  | 				// already connected...
 | 
					
						
							| 
									
										
										
										
											2017-02-24 23:15:03 +03:00
										 |  |  | 				// XXX check if child is alive...
 | 
					
						
							| 
									
										
										
										
											2017-03-01 00:44:02 +03:00
										 |  |  | 				if(this.__peers  | 
					
						
							|  |  |  | 						&& id in this.__peers  | 
					
						
							|  |  |  | 						&& this.__peers[id].peer.connected){ | 
					
						
							| 
									
										
										
										
											2017-02-24 19:47:04 +03:00
										 |  |  | 					return resolve(id)  | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-01 00:44:02 +03:00
										 |  |  | 				this.__peers = this.__peers || {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var p = this.__peers[id] = { | 
					
						
							|  |  |  | 					id: id, | 
					
						
							|  |  |  | 					peer: child_process.fork('ig.js'), | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				var peer = p.peer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// XXX setup message handlers...
 | 
					
						
							|  |  |  | 				// 		...should be about the same as in setup below...
 | 
					
						
							|  |  |  | 				// XXX use a standard handler....
 | 
					
						
							|  |  |  | 				peer.on('message', (function(msg){ | 
					
						
							|  |  |  | 					if(msg.type == 'action-call-result'){ | 
					
						
							|  |  |  | 						var callback = (this.__peer_result_callbacks || {})[msg.id] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						callback  | 
					
						
							|  |  |  | 							&& (delete this.__peer_result_callbacks[msg.id]) | 
					
						
							|  |  |  | 							&& callback(msg.value, msg.error) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}).bind(this)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				resolve(id) | 
					
						
							| 
									
										
										
										
											2017-02-24 19:47:04 +03:00
										 |  |  | 			}).bind(this)) | 
					
						
							|  |  |  | 		})], | 
					
						
							| 
									
										
										
										
											2017-03-01 04:31:09 +03:00
										 |  |  | 	// XXX should this call .stop() on the child???
 | 
					
						
							|  |  |  | 	// 		...does the child handle kill gracefully???
 | 
					
						
							| 
									
										
										
										
											2017-03-05 06:30:17 +03:00
										 |  |  | 	peerDisconnect: ['- System/Peer/', | 
					
						
							| 
									
										
										
										
											2017-02-26 01:33:14 +03:00
										 |  |  | 		makeProtocolHandler('child', function(id){ | 
					
						
							| 
									
										
										
										
											2017-02-24 19:47:04 +03:00
										 |  |  | 			return new Promise((function(resolve, reject){ | 
					
						
							| 
									
										
										
										
											2017-02-24 23:15:03 +03:00
										 |  |  | 				var that = this | 
					
						
							| 
									
										
										
										
											2017-02-24 19:47:04 +03:00
										 |  |  | 				// already disconnected...
 | 
					
						
							| 
									
										
										
										
											2017-03-05 06:30:17 +03:00
										 |  |  | 				if(this.__peers == null || this.__peers[id] == null){ | 
					
						
							| 
									
										
										
										
											2017-02-24 19:47:04 +03:00
										 |  |  | 					return resolve(id)  | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-01 00:44:02 +03:00
										 |  |  | 				// terminate child...
 | 
					
						
							|  |  |  | 				that.__peers[id].peer.kill() | 
					
						
							|  |  |  | 				delete that.__peers[id] | 
					
						
							| 
									
										
										
										
											2017-02-24 23:15:03 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-24 19:47:04 +03:00
										 |  |  | 			}).bind(this)) | 
					
						
							|  |  |  | 		})], | 
					
						
							| 
									
										
										
										
											2017-02-22 05:07:07 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-01 04:31:09 +03:00
										 |  |  | 	// XXX can we do sync???
 | 
					
						
							|  |  |  | 	// 		...this would be useful to 100% match the action api and 
 | 
					
						
							|  |  |  | 	// 		make the thing transparent...
 | 
					
						
							| 
									
										
										
										
											2017-03-02 06:10:10 +03:00
										 |  |  | 	// XXX prop access???
 | 
					
						
							| 
									
										
										
										
											2017-03-05 06:30:17 +03:00
										 |  |  | 	peerApply: ['- System/Peer/', | 
					
						
							| 
									
										
										
										
											2017-02-26 01:33:14 +03:00
										 |  |  | 		makeProtocolHandler('child', function(id, action, args){ | 
					
						
							| 
									
										
										
										
											2017-02-24 19:47:04 +03:00
										 |  |  | 			return new Promise((function(resolve, reject){ | 
					
						
							| 
									
										
										
										
											2017-03-01 00:44:02 +03:00
										 |  |  | 				// XXX is this the right way to go???
 | 
					
						
							|  |  |  | 				var call_id = id +'-'+ Date.now() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 06:30:17 +03:00
										 |  |  | 				if(this.__peers == null || this.__peers[id] == null){ | 
					
						
							|  |  |  | 					return reject(`Peer "${id}" is not connected.`) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-01 00:44:02 +03:00
										 |  |  | 				// do the call...
 | 
					
						
							|  |  |  | 				this.__peers[id].peer.send({ | 
					
						
							|  |  |  | 					id: call_id,  | 
					
						
							|  |  |  | 					type: 'action-call', | 
					
						
							|  |  |  | 					action: action, | 
					
						
							|  |  |  | 					args: args, | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// handle return value...
 | 
					
						
							|  |  |  | 				var handlers = this.__peer_result_callbacks = this.__peer_result_callbacks || {} | 
					
						
							|  |  |  | 				handlers[call_id] = function(res, err){ err ? reject(err) : resolve(res) } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-24 19:47:04 +03:00
										 |  |  | 			}).bind(this)) | 
					
						
							|  |  |  | 		})], | 
					
						
							| 
									
										
										
										
											2017-02-22 05:02:13 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ChildProcessPeer =  | 
					
						
							|  |  |  | module.ChildProcessPeer = core.ImageGridFeatures.Feature({ | 
					
						
							|  |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tag: 'child-process-peer', | 
					
						
							| 
									
										
										
										
											2017-02-22 05:10:50 +03:00
										 |  |  | 	depends: [ | 
					
						
							|  |  |  | 		'peer', | 
					
						
							|  |  |  | 	], | 
					
						
							| 
									
										
										
										
											2017-02-22 05:02:13 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-04 08:08:40 +03:00
										 |  |  | 	isApplicable: function(){ return this.runtime.node }, | 
					
						
							| 
									
										
										
										
											2017-02-24 19:47:04 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-22 05:02:13 +03:00
										 |  |  | 	actions: ChildProcessPeerActions,  | 
					
						
							| 
									
										
										
										
											2017-02-27 03:20:51 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	handlers: [ | 
					
						
							|  |  |  | 		// XXX check if we are a child and setup communications with the
 | 
					
						
							|  |  |  | 		// 		parent...
 | 
					
						
							| 
									
										
										
										
											2017-03-01 04:28:37 +03:00
										 |  |  | 		// 		...checking if child is simple:
 | 
					
						
							| 
									
										
										
										
											2017-03-01 04:35:01 +03:00
										 |  |  | 		// 			process.send != null // -> child
 | 
					
						
							| 
									
										
										
										
											2017-02-27 03:20:51 +03:00
										 |  |  | 		['start',  | 
					
						
							|  |  |  | 			function(){ | 
					
						
							| 
									
										
										
										
											2017-02-28 05:36:02 +03:00
										 |  |  | 				var that = this | 
					
						
							| 
									
										
										
										
											2017-03-01 00:44:02 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// XXX do we need to handle stdout/stderr here???
 | 
					
						
							|  |  |  | 				// XXX need to handle both the child and parent processes...
 | 
					
						
							| 
									
										
										
										
											2017-03-01 04:28:37 +03:00
										 |  |  | 				// 		...make this reusable...
 | 
					
						
							|  |  |  | 			 | 
					
						
							| 
									
										
										
										
											2017-02-28 05:36:02 +03:00
										 |  |  | 				process.on('message', function(msg){ | 
					
						
							|  |  |  | 					// Handle action call...
 | 
					
						
							|  |  |  | 					//
 | 
					
						
							|  |  |  | 					// Format:
 | 
					
						
							|  |  |  | 					// 	{
 | 
					
						
							|  |  |  | 					// 		type: 'action-call',
 | 
					
						
							|  |  |  | 					//
 | 
					
						
							|  |  |  | 					// 		id: <id>,
 | 
					
						
							|  |  |  | 					//
 | 
					
						
							|  |  |  | 					// 		action: <action-name>,
 | 
					
						
							|  |  |  | 					//
 | 
					
						
							|  |  |  | 					// 		args: [<arg>, .. ] | null,
 | 
					
						
							|  |  |  | 					//
 | 
					
						
							|  |  |  | 					// 		ignore_return: <bool>,
 | 
					
						
							|  |  |  | 					// 	}
 | 
					
						
							|  |  |  | 					if(msg.type == 'action-call' && msg.action in that){ | 
					
						
							| 
									
										
										
										
											2017-03-01 00:44:02 +03:00
										 |  |  | 						if(msg.action in that){ | 
					
						
							|  |  |  | 							try{ | 
					
						
							| 
									
										
										
										
											2017-03-05 06:30:17 +03:00
										 |  |  | 								var cur = that | 
					
						
							|  |  |  | 								var prev = that | 
					
						
							|  |  |  | 								msg.action | 
					
						
							|  |  |  | 									.split(/\./g) | 
					
						
							|  |  |  | 									.forEach(function(a){  | 
					
						
							|  |  |  | 										prev = cur | 
					
						
							|  |  |  | 										cur = cur[a]  | 
					
						
							|  |  |  | 									}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-01 00:44:02 +03:00
										 |  |  | 								// do the call...
 | 
					
						
							| 
									
										
										
										
											2017-03-05 06:30:17 +03:00
										 |  |  | 								//var res = that[msg.action].apply(that, msg.args || [])
 | 
					
						
							|  |  |  | 								var res = cur.apply(prev, msg.args || []) | 
					
						
							| 
									
										
										
										
											2017-03-01 00:44:02 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 								// return the value...
 | 
					
						
							|  |  |  | 								if(!msg.ignore_return){ | 
					
						
							| 
									
										
										
										
											2017-03-01 04:26:10 +03:00
										 |  |  | 									res.then ? | 
					
						
							|  |  |  | 										// promise result...
 | 
					
						
							|  |  |  | 										res | 
					
						
							|  |  |  | 											.then(function(res){ | 
					
						
							|  |  |  | 												process.send({ | 
					
						
							|  |  |  | 													type: 'action-call-result', | 
					
						
							|  |  |  | 													id: msg.id, | 
					
						
							|  |  |  | 													value: res, | 
					
						
							|  |  |  | 												}) | 
					
						
							|  |  |  | 											}) | 
					
						
							|  |  |  | 											.catch(function(err){ | 
					
						
							|  |  |  | 												process.send({ | 
					
						
							|  |  |  | 													type: 'action-call-result', | 
					
						
							|  |  |  | 													id: msg.id, | 
					
						
							|  |  |  | 													error: err, | 
					
						
							|  |  |  | 												}) | 
					
						
							|  |  |  | 											}) | 
					
						
							|  |  |  | 										// normal result...
 | 
					
						
							|  |  |  | 										: process | 
					
						
							|  |  |  | 											.send({ | 
					
						
							|  |  |  | 												type: 'action-call-result', | 
					
						
							|  |  |  | 												id: msg.id, | 
					
						
							|  |  |  | 												value: res === that ? null : res, | 
					
						
							|  |  |  | 											}) | 
					
						
							| 
									
										
										
										
											2017-03-05 06:30:17 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 								// notify parent that we are done...
 | 
					
						
							|  |  |  | 								// XXX do we actually need this???
 | 
					
						
							|  |  |  | 								} else { | 
					
						
							|  |  |  | 									process | 
					
						
							|  |  |  | 										.send({ | 
					
						
							|  |  |  | 											type: 'action-call-result', | 
					
						
							|  |  |  | 											id: msg.id, | 
					
						
							|  |  |  | 										}) | 
					
						
							| 
									
										
										
										
											2017-03-01 00:44:02 +03:00
										 |  |  | 								} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							// error...
 | 
					
						
							|  |  |  | 							} catch(err){ | 
					
						
							|  |  |  | 								process.send({ | 
					
						
							|  |  |  | 									type: 'action-call-result', | 
					
						
							|  |  |  | 									id: msg.id, | 
					
						
							|  |  |  | 									// XXX is this serializable???
 | 
					
						
							|  |  |  | 									error: err, | 
					
						
							|  |  |  | 								}) | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						// error: action does not exist...
 | 
					
						
							|  |  |  | 						} else { | 
					
						
							| 
									
										
										
										
											2017-02-28 05:36:02 +03:00
										 |  |  | 							process.send({ | 
					
						
							|  |  |  | 								type: 'action-call-result', | 
					
						
							|  |  |  | 								id: msg.id, | 
					
						
							| 
									
										
										
										
											2017-03-01 00:44:02 +03:00
										 |  |  | 								error: `Action "${msg.action}" does not exist.`, | 
					
						
							| 
									
										
										
										
											2017-02-28 05:36:02 +03:00
										 |  |  | 							}) | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 						 | 
					
						
							|  |  |  | 					// Handle action call result...
 | 
					
						
							|  |  |  | 					// 
 | 
					
						
							|  |  |  | 					// Format:
 | 
					
						
							|  |  |  | 					// {
 | 
					
						
							|  |  |  | 					// 		type: 'action-call-result',
 | 
					
						
							|  |  |  | 					// 		id: <id>,
 | 
					
						
							|  |  |  | 					// 		value: <object> | null,
 | 
					
						
							|  |  |  | 					// }
 | 
					
						
							|  |  |  | 					} else if(msg.type == 'action-call-result'){ | 
					
						
							|  |  |  | 						var callback = (this.__peer_result_callbacks || {})[msg.id] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						callback  | 
					
						
							|  |  |  | 							&& (delete this.__peer_result_callbacks[msg.id]) | 
					
						
							| 
									
										
										
										
											2017-03-01 00:44:02 +03:00
										 |  |  | 							&& callback(msg.value, msg.error) | 
					
						
							| 
									
										
										
										
											2017-02-28 05:36:02 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					// Handle logger calls...
 | 
					
						
							|  |  |  | 					// 
 | 
					
						
							|  |  |  | 					// Format:
 | 
					
						
							|  |  |  | 					// 	{
 | 
					
						
							|  |  |  | 					// 		type: 'logger-emit',
 | 
					
						
							|  |  |  | 					// 		value: [ .. ],
 | 
					
						
							|  |  |  | 					// 	}
 | 
					
						
							|  |  |  | 					} else if(msg.type == 'logger-emit' && this.logger){ | 
					
						
							|  |  |  | 						this.logger.emit.apply(this.logger, msg.value) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2017-02-27 03:20:51 +03:00
										 |  |  | 			}], | 
					
						
							|  |  |  | 	], | 
					
						
							| 
									
										
										
										
											2017-02-22 05:02:13 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-18 06:02:33 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | * vim:set ts=4 sw=4 :                               */ return module }) |