1- import { INITIAL_SYNC_EVENT_NAME , FILES_CHANGE_EVENT_NAME } from "../constants" ;
1+ import { INITIAL_SYNC_EVENT_NAME , FILES_CHANGE_EVENT_NAME , LiveSyncEvents } from "../constants" ;
22import { WorkflowDataService } from "./workflow/workflow-data-service" ;
33import { AddPlatformService } from "./platform/add-platform-service" ;
44import { BuildPlatformService } from "./platform/build-platform-service" ;
55import { PreparePlatformService } from "./platform/prepare-platform-service" ;
6+ import { EventEmitter } from "events" ;
7+ import { DeviceRefreshApplicationService } from "./device/device-refresh-application-service" ;
68
79const deviceDescriptorPrimaryKey = "identifier" ;
810
9- export class BundleWorkflowService implements IBundleWorkflowService {
10- private liveSyncProcessesInfo : IDictionary < any > = { } ;
11+ export class BundleWorkflowService extends EventEmitter implements IBundleWorkflowService {
12+ private liveSyncProcessesInfo : IDictionary < ILiveSyncProcessInfo > = { } ;
1113
1214 constructor (
15+ private $addPlatformService : AddPlatformService ,
16+ private $buildPlatformService : BuildPlatformService ,
1317 private $deviceInstallationService : IDeviceInstallationService ,
14- private $deviceRestartApplicationService : IDeviceRestartApplicationService ,
18+ private $deviceRefreshApplicationService : DeviceRefreshApplicationService ,
1519 private $devicesService : Mobile . IDevicesService ,
1620 private $errors : IErrors ,
21+ private $hooksService : IHooksService ,
1722 private $injector : IInjector ,
18- private $mobileHelper : Mobile . IMobileHelper ,
1923 private $logger : ILogger ,
20- private $preparePlatformService : PreparePlatformService ,
21- private $addPlatformService : AddPlatformService ,
22- private $buildPlatformService : BuildPlatformService ,
24+ private $mobileHelper : Mobile . IMobileHelper ,
2325 private $platformWatcherService : IPlatformWatcherService ,
2426 private $pluginsService : IPluginsService ,
27+ private $preparePlatformService : PreparePlatformService ,
2528 private $projectDataService : IProjectDataService ,
2629 private $workflowDataService : WorkflowDataService
27- ) { }
30+ ) { super ( ) ; }
2831
2932 public async preparePlatform ( platform : string , projectDir : string , options : IOptions ) : Promise < void > {
3033 const { nativePlatformData, projectData, addPlatformData, preparePlatformData } = this . $workflowDataService . createWorkflowData ( platform , projectDir , options ) ;
@@ -53,11 +56,6 @@ export class BundleWorkflowService implements IBundleWorkflowService {
5356 const { nativePlatformData, projectData, buildPlatformData } = this . $workflowDataService . createWorkflowData ( device . deviceInfo . platform , projectDir , liveSyncInfo ) ;
5457 await this . $buildPlatformService . buildPlatformIfNeeded ( nativePlatformData , projectData , buildPlatformData ) ;
5558 await this . $deviceInstallationService . installOnDeviceIfNeeded ( device , nativePlatformData , projectData , buildPlatformData ) ;
56- await device . applicationManager . startApplication ( {
57- appId : projectData . projectIdentifiers [ device . deviceInfo . platform . toLowerCase ( ) ] ,
58- projectName : projectData . projectName
59- } ) ;
60- this . $logger . out ( `Successfully started on device with identifier '${ device . deviceInfo . identifier } '.` ) ;
6159 } ;
6260
6361 await this . $devicesService . execute ( executeAction , ( device : Mobile . IDevice ) => true ) ;
@@ -108,17 +106,89 @@ export class BundleWorkflowService implements IBundleWorkflowService {
108106 private async syncInitialDataOnDevice ( device : Mobile . IDevice , deviceDescriptor : ILiveSyncDeviceInfo , projectData : IProjectData , liveSyncInfo : ILiveSyncInfo ) : Promise < void > {
109107 const { nativePlatformData : platformData , buildPlatformData } = this . $workflowDataService . createWorkflowData ( device . deviceInfo . platform , projectData . projectDir , liveSyncInfo ) ;
110108
111- const outputPath = deviceDescriptor . outputPath || platformData . getBuildOutputPath ( buildPlatformData ) ;
112- const packageFilePath = await this . $buildPlatformService . buildPlatformIfNeeded ( platformData , projectData , buildPlatformData , outputPath ) ;
109+ try {
110+ const outputPath = deviceDescriptor . outputPath || platformData . getBuildOutputPath ( buildPlatformData ) ;
111+ const packageFilePath = await this . $buildPlatformService . buildPlatformIfNeeded ( platformData , projectData , buildPlatformData , outputPath ) ;
113112
114- await this . $deviceInstallationService . installOnDeviceIfNeeded ( device , platformData , projectData , buildPlatformData , packageFilePath , outputPath ) ;
113+ await this . $deviceInstallationService . installOnDeviceIfNeeded ( device , platformData , projectData , buildPlatformData , packageFilePath , outputPath ) ;
115114
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 } ) ;
115+ // TODO: Consider to improve this
116+ const platformLiveSyncService = this . getLiveSyncService ( platformData . platformNameLowerCase ) ;
117+ const { force, useHotModuleReload, skipWatcher } = liveSyncInfo ;
118+ const liveSyncResultInfo = await platformLiveSyncService . fullSync ( { force, useHotModuleReload, projectData, device, watch : ! skipWatcher , liveSyncDeviceInfo : deviceDescriptor } ) ;
120119
121- await this . $deviceRestartApplicationService . restartOnDevice ( deviceDescriptor , projectData , liveSyncResultInfo , platformLiveSyncService ) ;
120+ await this . $deviceRefreshApplicationService . refreshApplication ( deviceDescriptor , projectData , liveSyncResultInfo , platformLiveSyncService , this ) ;
121+ } catch ( err ) {
122+ this . $logger . warn ( `Unable to apply changes on device: ${ device . deviceInfo . identifier } . Error is: ${ err . message } .` ) ;
123+
124+ this . emitLivesyncEvent ( LiveSyncEvents . liveSyncError , {
125+ error : err ,
126+ deviceIdentifier : device . deviceInfo . identifier ,
127+ projectDir : projectData . projectDir ,
128+ applicationIdentifier : projectData . projectIdentifiers [ platformData . platformNameLowerCase ]
129+ } ) ;
130+
131+ await this . stopLiveSync ( projectData . projectDir , [ device . deviceInfo . identifier ] , { shouldAwaitAllActions : false } ) ;
132+ }
133+ }
134+
135+ public async stopLiveSync ( projectDir : string , deviceIdentifiers ?: string [ ] , stopOptions ?: { shouldAwaitAllActions : boolean } ) : Promise < void > {
136+ const liveSyncProcessInfo = this . liveSyncProcessesInfo [ projectDir ] ;
137+ if ( liveSyncProcessInfo && ! liveSyncProcessInfo . isStopped ) {
138+ // In case we are coming from error during livesync, the current action is the one that erred (but we are still executing it),
139+ // so we cannot await it as this will cause infinite loop.
140+ const shouldAwaitPendingOperation = ! stopOptions || stopOptions . shouldAwaitAllActions ;
141+
142+ const deviceIdentifiersToRemove = deviceIdentifiers || _ . map ( liveSyncProcessInfo . deviceDescriptors , d => d . identifier ) ;
143+
144+ const removedDeviceIdentifiers = _ . remove ( liveSyncProcessInfo . deviceDescriptors , descriptor => _ . includes ( deviceIdentifiersToRemove , descriptor . identifier ) )
145+ . map ( descriptor => descriptor . identifier ) ;
146+
147+ // In case deviceIdentifiers are not passed, we should stop the whole LiveSync.
148+ if ( ! deviceIdentifiers || ! deviceIdentifiers . length || ! liveSyncProcessInfo . deviceDescriptors || ! liveSyncProcessInfo . deviceDescriptors . length ) {
149+ if ( liveSyncProcessInfo . timer ) {
150+ clearTimeout ( liveSyncProcessInfo . timer ) ;
151+ }
152+
153+ if ( liveSyncProcessInfo . watcherInfo && liveSyncProcessInfo . watcherInfo . watcher ) {
154+ liveSyncProcessInfo . watcherInfo . watcher . close ( ) ;
155+ }
156+
157+ liveSyncProcessInfo . watcherInfo = null ;
158+ liveSyncProcessInfo . isStopped = true ;
159+
160+ if ( liveSyncProcessInfo . actionsChain && shouldAwaitPendingOperation ) {
161+ await liveSyncProcessInfo . actionsChain ;
162+ }
163+
164+ liveSyncProcessInfo . deviceDescriptors = [ ] ;
165+
166+ if ( liveSyncProcessInfo . syncToPreviewApp ) {
167+ // await this.$previewAppLiveSyncService.stopLiveSync();
168+ // this.$previewAppLiveSyncService.removeAllListeners();
169+ }
170+
171+ // Kill typescript watcher
172+ const projectData = this . $projectDataService . getProjectData ( projectDir ) ;
173+ await this . $hooksService . executeAfterHooks ( 'watch' , {
174+ hookArgs : {
175+ projectData
176+ }
177+ } ) ;
178+ } else if ( liveSyncProcessInfo . currentSyncAction && shouldAwaitPendingOperation ) {
179+ await liveSyncProcessInfo . currentSyncAction ;
180+ }
181+
182+ // Emit LiveSync stopped when we've really stopped.
183+ _ . each ( removedDeviceIdentifiers , deviceIdentifier => {
184+ this . emitLivesyncEvent ( LiveSyncEvents . liveSyncStopped , { projectDir, deviceIdentifier } ) ;
185+ } ) ;
186+ }
187+ }
188+
189+ public emitLivesyncEvent ( event : string , livesyncData : ILiveSyncEventData ) : boolean {
190+ this . $logger . trace ( `Will emit event ${ event } with data` , livesyncData ) ;
191+ return this . emit ( event , livesyncData ) ;
122192 }
123193
124194 private async syncChangedDataOnDevice ( device : Mobile . IDevice , deviceDescriptor : ILiveSyncDeviceInfo , data : IFilesChangeEventData , projectData : IProjectData , liveSyncInfo : ILiveSyncInfo ) : Promise < void > {
@@ -142,7 +212,8 @@ export class BundleWorkflowService implements IBundleWorkflowService {
142212 force : liveSyncInfo . force ,
143213 connectTimeout : 1000
144214 } ) ;
145- await this . $deviceRestartApplicationService . restartOnDevice ( deviceDescriptor , projectData , liveSyncResultInfo , platformLiveSyncService ) ;
215+
216+ await this . $deviceRefreshApplicationService . refreshApplication ( deviceDescriptor , projectData , liveSyncResultInfo , platformLiveSyncService , this ) ;
146217 }
147218
148219 public getLiveSyncDeviceDescriptors ( projectDir : string ) : ILiveSyncDeviceInfo [ ] {
0 commit comments