11import { AddPlatformService } from "../services/platform/add-platform-service" ;
22import { BuildPlatformService } from "../services/platform/build-platform-service" ;
33import { DeviceInstallAppService } from "../services/device/device-install-app-service" ;
4- import { DeviceRefreshAppService } from "../services/device/device-refresh-app-service" ;
54import { EventEmitter } from "events" ;
6- import { FILES_CHANGE_EVENT_NAME , INITIAL_SYNC_EVENT_NAME , LiveSyncEvents } from "../constants" ;
5+ import { FILES_CHANGE_EVENT_NAME , INITIAL_SYNC_EVENT_NAME , RunOnDeviceEvents } from "../constants" ;
76import { PreparePlatformService } from "../services/platform/prepare-platform-service" ;
87import { WorkflowDataService } from "../services/workflow/workflow-data-service" ;
9-
10- const deviceDescriptorPrimaryKey = "identifier" ;
8+ import { RunOnDevicesController } from "./run-on-devices-controller" ;
9+ import { RunOnDevicesDataService } from "../services/run-on-devices-data-service" ;
10+ import { cache } from "../common/decorators" ;
11+ import { DeviceDiscoveryEventNames } from "../common/constants" ;
1112
1213export class MainController extends EventEmitter {
13- private liveSyncProcessesInfo : IDictionary < ILiveSyncProcessInfo > = { } ;
14-
1514 constructor (
1615 private $addPlatformService : AddPlatformService ,
1716 private $buildPlatformService : BuildPlatformService ,
1817 private $deviceInstallAppService : DeviceInstallAppService ,
19- private $deviceRefreshAppService : DeviceRefreshAppService ,
2018 private $devicesService : Mobile . IDevicesService ,
2119 private $errors : IErrors ,
2220 private $hooksService : IHooksService ,
23- private $injector : IInjector ,
2421 private $logger : ILogger ,
25- private $mobileHelper : Mobile . IMobileHelper ,
2622 private $platformWatcherService : IPlatformWatcherService ,
2723 private $pluginsService : IPluginsService ,
2824 private $preparePlatformService : PreparePlatformService ,
2925 private $projectDataService : IProjectDataService ,
26+ private $runOnDevicesController : RunOnDevicesController ,
27+ private $runOnDevicesDataService : RunOnDevicesDataService ,
3028 private $workflowDataService : WorkflowDataService
3129 ) { super ( ) ; }
3230
@@ -46,7 +44,7 @@ export class MainController extends EventEmitter {
4644 return result ;
4745 }
4846
49- public async deployPlatform ( projectDir : string , deviceDescriptors : ILiveSyncDeviceInfo [ ] , liveSyncInfo : ILiveSyncInfo ) : Promise < void > {
47+ public async deployOnDevices ( projectDir : string , deviceDescriptors : ILiveSyncDeviceInfo [ ] , liveSyncInfo : ILiveSyncInfo ) : Promise < void > {
5048 const platforms = this . $devicesService . getPlatformsFromDeviceDescriptors ( deviceDescriptors ) ;
5149
5250 for ( const platform of platforms ) {
@@ -62,7 +60,7 @@ export class MainController extends EventEmitter {
6260 await this . $devicesService . execute ( executeAction , ( device : Mobile . IDevice ) => true ) ;
6361 }
6462
65- public async runPlatform ( projectDir : string , deviceDescriptors : ILiveSyncDeviceInfo [ ] , liveSyncInfo : ILiveSyncInfo ) : Promise < void > {
63+ public async runOnDevices ( projectDir : string , deviceDescriptors : ILiveSyncDeviceInfo [ ] , liveSyncInfo : ILiveSyncInfo ) : Promise < void > {
6664 const projectData = this . $projectDataService . getProjectData ( projectDir ) ;
6765 await this . initializeSetup ( projectData ) ;
6866
@@ -73,68 +71,34 @@ export class MainController extends EventEmitter {
7371 await this . $addPlatformService . addPlatformIfNeeded ( nativePlatformData , projectData , addPlatformData ) ;
7472 }
7573
76- this . setLiveSyncProcessInfo ( projectDir , liveSyncInfo , deviceDescriptors ) ;
74+ // TODO: Consider to handle correctly the descriptors when livesync is executed for second time for the same projectDir
7775
78- const shouldStartWatcher = ! liveSyncInfo . skipWatcher && ( liveSyncInfo . syncToPreviewApp || this . liveSyncProcessesInfo [ projectData . projectDir ] . deviceDescriptors . length ) ;
76+ this . $runOnDevicesDataService . persistData ( projectDir , liveSyncInfo , deviceDescriptors ) ;
77+
78+ const shouldStartWatcher = ! liveSyncInfo . skipWatcher && ( liveSyncInfo . syncToPreviewApp || this . $runOnDevicesDataService . hasDeviceDescriptors ( projectDir ) ) ;
7979 if ( shouldStartWatcher ) {
80+ this . handleRunOnDeviceEvents ( projectDir ) ;
81+
8082 this . $platformWatcherService . on ( INITIAL_SYNC_EVENT_NAME , async ( data : IInitialSyncEventData ) => {
81- const executeAction = async ( device : Mobile . IDevice ) => {
82- const deviceDescriptor = _ . find ( deviceDescriptors , dd => dd . identifier === device . deviceInfo . identifier ) ;
83- await this . syncInitialDataOnDevice ( device , deviceDescriptor , projectData , liveSyncInfo ) ;
84- } ;
85- const canExecuteAction = ( device : Mobile . IDevice ) => device . deviceInfo . platform . toLowerCase ( ) === data . platform . toLowerCase ( ) && _ . some ( deviceDescriptors , deviceDescriptor => deviceDescriptor . identifier === device . deviceInfo . identifier ) ;
86- await this . addActionToChain ( projectData . projectDir , ( ) => this . $devicesService . execute ( executeAction , canExecuteAction ) ) ;
83+ await this . $runOnDevicesController . syncInitialDataOnDevice ( data , projectData , liveSyncInfo , deviceDescriptors ) ;
8784 } ) ;
8885 this . $platformWatcherService . on ( FILES_CHANGE_EVENT_NAME , async ( data : IFilesChangeEventData ) => {
89- const executeAction = async ( device : Mobile . IDevice ) => {
90- const deviceDescriptor = _ . find ( deviceDescriptors , dd => dd . identifier === device . deviceInfo . identifier ) ;
91- await this . syncChangedDataOnDevice ( device , deviceDescriptor , data , projectData , liveSyncInfo ) ;
92- } ;
93- const canExecuteAction = ( device : Mobile . IDevice ) => {
94- const liveSyncProcessInfo = this . liveSyncProcessesInfo [ projectData . projectDir ] ;
95- return ( data . platform . toLowerCase ( ) === device . deviceInfo . platform . toLowerCase ( ) ) && liveSyncProcessInfo && _ . some ( liveSyncProcessInfo . deviceDescriptors , deviceDescriptor => deviceDescriptor . identifier === device . deviceInfo . identifier ) ;
96- } ;
97- await this . addActionToChain ( projectData . projectDir , ( ) => this . $devicesService . execute ( executeAction , canExecuteAction ) ) ;
86+ await this . $runOnDevicesController . syncChangedDataOnDevice ( data , projectData , liveSyncInfo , deviceDescriptors ) ;
9887 } ) ;
9988
10089 for ( const platform of platforms ) {
10190 const { nativePlatformData, preparePlatformData } = this . $workflowDataService . createWorkflowData ( platform , projectDir , liveSyncInfo ) ;
10291 await this . $platformWatcherService . startWatcher ( nativePlatformData , projectData , preparePlatformData ) ;
10392 }
10493 }
105- }
106-
107- private async syncInitialDataOnDevice ( device : Mobile . IDevice , deviceDescriptor : ILiveSyncDeviceInfo , projectData : IProjectData , liveSyncInfo : ILiveSyncInfo ) : Promise < void > {
108- const { nativePlatformData : platformData , buildPlatformData } = this . $workflowDataService . createWorkflowData ( device . deviceInfo . platform , projectData . projectDir , liveSyncInfo ) ;
109-
110- try {
111- const outputPath = deviceDescriptor . outputPath || platformData . getBuildOutputPath ( buildPlatformData ) ;
112- const packageFilePath = await this . $buildPlatformService . buildPlatformIfNeeded ( platformData , projectData , buildPlatformData , outputPath ) ;
11394
114- await this . $deviceInstallAppService . installOnDeviceIfNeeded ( device , platformData , projectData , buildPlatformData , packageFilePath , outputPath ) ;
95+ // TODO: Consider how to handle --justlaunch
11596
116- // TODO: Consider to improve this
117- const platformLiveSyncService = this . getLiveSyncService ( platformData . platformNameLowerCase ) ;
118- const { force, useHotModuleReload, skipWatcher } = liveSyncInfo ;
119- const liveSyncResultInfo = await platformLiveSyncService . fullSync ( { force, useHotModuleReload, projectData, device, watch : ! skipWatcher , liveSyncDeviceInfo : deviceDescriptor } ) ;
120-
121- await this . $deviceRefreshAppService . refreshApplication ( deviceDescriptor , projectData , liveSyncResultInfo , platformLiveSyncService , this ) ;
122- } catch ( err ) {
123- this . $logger . warn ( `Unable to apply changes on device: ${ device . deviceInfo . identifier } . Error is: ${ err . message } .` ) ;
124-
125- this . emitLivesyncEvent ( LiveSyncEvents . liveSyncError , {
126- error : err ,
127- deviceIdentifier : device . deviceInfo . identifier ,
128- projectDir : projectData . projectDir ,
129- applicationIdentifier : projectData . projectIdentifiers [ platformData . platformNameLowerCase ]
130- } ) ;
131-
132- await this . stopLiveSync ( projectData . projectDir , [ device . deviceInfo . identifier ] , { shouldAwaitAllActions : false } ) ;
133- }
97+ this . attachDeviceLostHandler ( ) ;
13498 }
13599
136- public async stopLiveSync ( projectDir : string , deviceIdentifiers ?: string [ ] , stopOptions ?: { shouldAwaitAllActions : boolean } ) : Promise < void > {
137- const liveSyncProcessInfo = this . liveSyncProcessesInfo [ projectDir ] ;
100+ public async stopRunOnDevices ( projectDir : string , deviceIdentifiers ?: string [ ] , stopOptions ?: { shouldAwaitAllActions : boolean } ) : Promise < void > {
101+ const liveSyncProcessInfo = this . $runOnDevicesDataService . getData ( projectDir ) ;
138102 if ( liveSyncProcessInfo && ! liveSyncProcessInfo . isStopped ) {
139103 // In case we are coming from error during livesync, the current action is the one that erred (but we are still executing it),
140104 // so we cannot await it as this will cause infinite loop.
@@ -180,59 +144,37 @@ export class MainController extends EventEmitter {
180144 await liveSyncProcessInfo . currentSyncAction ;
181145 }
182146
183- // Emit LiveSync stopped when we've really stopped.
147+ // Emit RunOnDevice stopped when we've really stopped.
184148 _ . each ( removedDeviceIdentifiers , deviceIdentifier => {
185- this . emitLivesyncEvent ( LiveSyncEvents . liveSyncStopped , { projectDir, deviceIdentifier } ) ;
149+ this . emit ( RunOnDeviceEvents . runOnDeviceStopped , { projectDir, deviceIdentifier } ) ;
186150 } ) ;
187151 }
188152 }
189153
190- public emitLivesyncEvent ( event : string , livesyncData : ILiveSyncEventData ) : boolean {
191- this . $logger . trace ( `Will emit event ${ event } with data` , livesyncData ) ;
192- return this . emit ( event , livesyncData ) ;
154+ public getRunOnDeviceDescriptors ( projectDir : string ) : ILiveSyncDeviceInfo [ ] {
155+ return this . $runOnDevicesDataService . getDeviceDescriptors ( projectDir ) ;
193156 }
194157
195- private async syncChangedDataOnDevice ( device : Mobile . IDevice , deviceDescriptor : ILiveSyncDeviceInfo , data : IFilesChangeEventData , projectData : IProjectData , liveSyncInfo : ILiveSyncInfo ) : Promise < void > {
196- console . log ( "syncChangedDataOnDevice================ " , data ) ;
197- const { nativePlatformData, buildPlatformData } = this . $workflowDataService . createWorkflowData ( device . deviceInfo . platform , projectData . projectDir , liveSyncInfo ) ;
198-
199- if ( data . hasNativeChanges ) {
200- // TODO: Consider to handle nativePluginsChange here (aar rebuilt)
201- await this . $buildPlatformService . buildPlatform ( nativePlatformData , projectData , buildPlatformData ) ;
202- }
203-
204- const platformLiveSyncService = this . getLiveSyncService ( device . deviceInfo . platform ) ;
205- const liveSyncResultInfo = await platformLiveSyncService . liveSyncWatchAction ( device , {
206- liveSyncDeviceInfo : deviceDescriptor ,
207- projectData,
208- filesToRemove : [ ] ,
209- filesToSync : data . files ,
210- isReinstalled : false ,
211- hmrData : null , // platformHmrData,
212- useHotModuleReload : liveSyncInfo . useHotModuleReload ,
213- force : liveSyncInfo . force ,
214- connectTimeout : 1000
158+ private handleRunOnDeviceEvents ( projectDir : string ) : void {
159+ this . $runOnDevicesController . on ( RunOnDeviceEvents . runOnDeviceError , async data => {
160+ this . emit ( RunOnDeviceEvents . runOnDeviceError , data ) ;
161+ await this . stopRunOnDevices ( projectDir , [ data . deviceIdentifier ] , { shouldAwaitAllActions : false } ) ;
215162 } ) ;
216163
217- await this . $deviceRefreshAppService . refreshApplication ( deviceDescriptor , projectData , liveSyncResultInfo , platformLiveSyncService , this ) ;
218- }
219-
220- public getLiveSyncDeviceDescriptors ( projectDir : string ) : ILiveSyncDeviceInfo [ ] {
221- const liveSyncProcessesInfo = this . liveSyncProcessesInfo [ projectDir ] || < ILiveSyncProcessInfo > { } ;
222- const currentDescriptors = liveSyncProcessesInfo . deviceDescriptors ;
223- return currentDescriptors || [ ] ;
164+ this . $runOnDevicesController . on ( RunOnDeviceEvents . runOnDeviceStarted , data => {
165+ this . emit ( RunOnDeviceEvents . runOnDeviceStarted , data ) ;
166+ } ) ;
224167 }
225168
226- private setLiveSyncProcessInfo ( projectDir : string , liveSyncInfo : ILiveSyncInfo , deviceDescriptors : ILiveSyncDeviceInfo [ ] ) : void {
227- this . liveSyncProcessesInfo [ projectDir ] = this . liveSyncProcessesInfo [ projectDir ] || Object . create ( null ) ;
228- this . liveSyncProcessesInfo [ projectDir ] . actionsChain = this . liveSyncProcessesInfo [ projectDir ] . actionsChain || Promise . resolve ( ) ;
229- this . liveSyncProcessesInfo [ projectDir ] . currentSyncAction = this . liveSyncProcessesInfo [ projectDir ] . actionsChain ;
230- this . liveSyncProcessesInfo [ projectDir ] . isStopped = false ;
231- this . liveSyncProcessesInfo [ projectDir ] . syncToPreviewApp = liveSyncInfo . syncToPreviewApp ;
169+ // TODO: expose previewOnDevice() method { }
170+ // TODO: enableDebugging -> mainController
171+ // TODO: disableDebugging -> mainController
172+ // TODO: attachDebugger -> mainController
173+ // mainController.runOnDevices(), runOnDevicesController.on("event", () => {})
232174
233- const currentDeviceDescriptors = this . getLiveSyncDeviceDescriptors ( projectDir ) ;
234- this . liveSyncProcessesInfo [ projectDir ] . deviceDescriptors = _ . uniqBy ( currentDeviceDescriptors . concat ( deviceDescriptors ) , deviceDescriptorPrimaryKey ) ;
235- }
175+ // debugOnDevicesController.enableDebugging()
176+ // debugOnDevicesController.disableDebugging()
177+ // debugOnDevicesController.attachDebugger
236178
237179 private async initializeSetup ( projectData : IProjectData ) : Promise < void > {
238180 try {
@@ -243,30 +185,21 @@ export class MainController extends EventEmitter {
243185 }
244186 }
245187
246- private async addActionToChain < T > ( projectDir : string , action : ( ) => Promise < T > ) : Promise < T > {
247- const liveSyncInfo = this . liveSyncProcessesInfo [ projectDir ] ;
248- if ( liveSyncInfo ) {
249- liveSyncInfo . actionsChain = liveSyncInfo . actionsChain . then ( async ( ) => {
250- if ( ! liveSyncInfo . isStopped ) {
251- liveSyncInfo . currentSyncAction = action ( ) ;
252- const res = await liveSyncInfo . currentSyncAction ;
253- return res ;
254- }
255- } ) ;
256-
257- const result = await liveSyncInfo . actionsChain ;
258- return result ;
259- }
260- }
261-
262- private getLiveSyncService ( platform : string ) : IPlatformLiveSyncService {
263- if ( this . $mobileHelper . isiOSPlatform ( platform ) ) {
264- return this . $injector . resolve ( "iOSLiveSyncService" ) ;
265- } else if ( this . $mobileHelper . isAndroidPlatform ( platform ) ) {
266- return this . $injector . resolve ( "androidLiveSyncService" ) ;
267- }
268-
269- this . $errors . failWithoutHelp ( `Invalid platform ${ platform } . Supported platforms are: ${ this . $mobileHelper . platformNames . join ( ", " ) } ` ) ;
188+ @cache ( )
189+ private attachDeviceLostHandler ( ) : void {
190+ this . $devicesService . on ( DeviceDiscoveryEventNames . DEVICE_LOST , async ( device : Mobile . IDevice ) => {
191+ this . $logger . trace ( `Received ${ DeviceDiscoveryEventNames . DEVICE_LOST } event in LiveSync service for ${ device . deviceInfo . identifier } . Will stop LiveSync operation for this device.` ) ;
192+
193+ // for (const projectDir in this.liveSyncProcessesInfo) {
194+ // try {
195+ // if (_.find(this.liveSyncProcessesInfo[projectDir].deviceDescriptors, d => d.identifier === device.deviceInfo.identifier)) {
196+ // await this.stopLiveSync(projectDir, [device.deviceInfo.identifier]);
197+ // }
198+ // } catch (err) {
199+ // this.$logger.warn(`Unable to stop LiveSync operation for ${device.deviceInfo.identifier}.`, err);
200+ // }
201+ // }
202+ } ) ;
270203 }
271204}
272205$injector . register ( "mainController" , MainController ) ;
0 commit comments