11import { Node } from '@stencila/schema'
22import { JSONSchema7Definition } from 'json-schema'
33import Ajv from 'ajv'
4- import Client from './Client'
4+ import Client , { ClientType } from './Client'
55import Server from './Server'
66import { Address , Transport } from './Transports'
77import { getLogger } from '@stencila/logga'
@@ -132,13 +132,22 @@ const ajv = new Ajv()
132132 * a `WebSocketClient` to an executor running on
133133 * a remote machine.
134134 */
135- class Peer {
135+ export class Peer {
136136 /**
137137 * The manifest of the peer executor.
138138 */
139139 private manifest : Manifest
140140
141- // private Clients: new ()
141+ /**
142+ * A list of classes, that extend `Client`, and are available
143+ * to connect to peer executors.
144+ *
145+ * This property is used for dependency injection, rather than importing
146+ * clients for all transports into this module when they may
147+ * not be used (e.g. `StdioClient` in a browser hosted `Executor`).
148+ * The order of this list, defines the preference for the transport.
149+ */
150+ private readonly clientTypes : ClientType [ ]
142151
143152 /**
144153 * The client for the peer executor.
@@ -156,8 +165,9 @@ class Peer {
156165 */
157166 private validators : { [ key : string ] : Ajv . ValidateFunction } = { }
158167
159- public constructor ( manifest : Manifest ) {
168+ public constructor ( manifest : Manifest , clientTypes : ClientType [ ] ) {
160169 this . manifest = manifest
170+ this . clientTypes = clientTypes
161171 }
162172
163173 /**
@@ -186,25 +196,56 @@ class Peer {
186196 return validator ( params ) as boolean
187197 }
188198
189- public connect ( ) : Client {
190- let client : Client
191- // @ts -ignore
192- return client
199+ /**
200+ * Connect to the remote `Executor`.
201+ *
202+ * Finds the first client type that the peer
203+ * executor supports.
204+ *
205+ * @returns A client instance or `undefined` if not able to connect
206+ */
207+ public connect ( ) : boolean {
208+ for ( const ClientType of this . clientTypes ) {
209+ // Get the transport for the client type
210+ // There should be a better way to do this
211+ const transportMap : { [ key : string ] : Transport } = {
212+ DirectClient : Transport . direct ,
213+ StdioClient : Transport . stdio ,
214+ VsockClient : Transport . vsock ,
215+ TcpClient : Transport . tcp ,
216+ HttpClient : Transport . http ,
217+ WebsocketClient : Transport . ws
218+ }
219+ const transport = transportMap [ ClientType . name ]
220+ if ( transport === undefined )
221+ throw new Error ( 'Wooah! This should not happen!' )
222+
223+ // See if the peer has an address the transport
224+ const address = this . manifest . addresses [ transport ]
225+ if ( address !== undefined ) {
226+ this . client = new ClientType ( address )
227+ return true
228+ }
229+ }
230+ // Unable to connect to the peer
231+ return false
193232 }
194233
195234 /**
196235 * Call a method of a remote `Executor`.
197236 *
237+ * Ensures that there is a connection to the
238+ * executor and then passes the request to it.
239+ *
198240 * @param method The name of the method
199241 * @param params Values of parameters (i.e. arguments)
200242 */
201243 public async call < Type > (
202244 method : Method ,
203245 params : { [ key : string ] : any } = { }
204246 ) : Promise < Type > {
205- if ( this . client === undefined ) {
206- this . client = this . connect ( )
207- }
247+ if ( this . client === undefined )
248+ throw new Error ( "WTF, no client! You shouldn't be calling this!" )
208249 return this . client . call < Type > ( method , params )
209250 }
210251}
@@ -230,9 +271,11 @@ export default class Executor implements Interface {
230271 */
231272 private servers : Server [ ] = [ ]
232273
233- public constructor ( peers : Manifest [ ] = [ ] ) {
234- // Create peers using the manifests provided
235- this . peers = peers . map ( peer => new Peer ( peer ) )
274+ public constructor (
275+ manifests : Manifest [ ] = [ ] ,
276+ clientTypes : ClientType [ ] = [ ]
277+ ) {
278+ this . peers = manifests . map ( manifest => new Peer ( manifest , clientTypes ) )
236279 }
237280
238281 /**
@@ -355,7 +398,9 @@ export default class Executor implements Interface {
355398 // Attempt to delegate to a peer
356399 for ( const peer of this . peers ) {
357400 if ( peer . capable ( method , params ) ) {
358- return peer . call < Type > ( method , params )
401+ if ( peer . connect ( ) ) {
402+ return peer . call < Type > ( method , params )
403+ }
359404 }
360405 }
361406 // No peer has necessary capability so resort to fallback
0 commit comments