1
- import { DeviceLiveSyncServiceBase } from "./device-livesync-service-base" ;
2
1
import * as helpers from "../../common/helpers" ;
3
2
import * as net from "net" ;
4
3
5
4
let currentPageReloadId = 0 ;
6
5
7
- class IOSLiveSyncService extends DeviceLiveSyncServiceBase < Mobile . IiOSDevice > implements IDeviceLiveSyncService {
6
+ class IOSLiveSyncService implements IDeviceLiveSyncService {
8
7
private static BACKEND_PORT = 18181 ;
9
8
private socket : net . Socket ;
9
+ private device : Mobile . IiOSDevice ;
10
10
11
11
constructor ( _device : Mobile . IDevice ,
12
12
private $iOSSocketRequestExecutor : IiOSSocketRequestExecutor ,
@@ -17,8 +17,9 @@ class IOSLiveSyncService extends DeviceLiveSyncServiceBase<Mobile.IiOSDevice> im
17
17
private $options : IOptions ,
18
18
private $iOSDebugService : IDebugService ,
19
19
private $childProcess : IChildProcess ,
20
- $liveSyncProvider : ILiveSyncProvider ) {
21
- super ( _device , $liveSyncProvider ) ;
20
+ private $fs : IFileSystem ,
21
+ private $liveSyncProvider : ILiveSyncProvider ) {
22
+ this . device = < Mobile . IiOSDevice > ( _device ) ;
22
23
}
23
24
24
25
public get debugService ( ) : IDebugService {
@@ -31,78 +32,135 @@ class IOSLiveSyncService extends DeviceLiveSyncServiceBase<Mobile.IiOSDevice> im
31
32
} ) . future < boolean > ( ) ( ) ;
32
33
}
33
34
35
+ private setupSocketIfNeeded ( ) : IFuture < boolean > {
36
+ return ( ( ) => {
37
+ if ( this . socket ) {
38
+ return true ;
39
+ }
40
+
41
+ let enableDebuggerMessage = `{ "method":"Debugger.enable","id":${ ++ currentPageReloadId } }` ;
42
+ if ( this . device . isEmulator ) {
43
+ this . $iOSEmulatorServices . postDarwinNotification ( this . $iOSNotification . attachRequest ) . wait ( ) ;
44
+ try {
45
+ this . socket = helpers . connectEventuallyUntilTimeout ( ( ) => net . connect ( IOSLiveSyncService . BACKEND_PORT ) , 5000 ) . wait ( ) ;
46
+ } catch ( e ) {
47
+ this . $logger . warn ( e ) ;
48
+
49
+ return false ;
50
+ }
51
+ } else {
52
+ let timeout = 9000 ;
53
+ this . $iOSSocketRequestExecutor . executeAttachRequest ( this . device , timeout ) . wait ( ) ;
54
+ this . socket = this . device . connectToPort ( IOSLiveSyncService . BACKEND_PORT ) ;
55
+ }
56
+
57
+ this . attachEventHandlers ( ) ;
58
+ this . sendMessage ( enableDebuggerMessage ) ;
59
+
60
+ return true ;
61
+ } ) . future < boolean > ( ) ( ) ;
62
+ }
63
+
34
64
public removeFiles ( appIdentifier : string , localToDevicePaths : Mobile . ILocalToDevicePathData [ ] ) : IFuture < void > {
35
65
return ( ( ) => {
36
66
_ . each ( localToDevicePaths , localToDevicePathData => this . device . fileSystem . deleteFile ( localToDevicePathData . getDevicePath ( ) , appIdentifier ) ) ;
37
67
} ) . future < void > ( ) ( ) ;
38
68
}
39
69
40
- protected restartApplication ( deviceAppData : Mobile . IDeviceAppData ) : IFuture < void > {
70
+ public refreshApplication ( deviceAppData : Mobile . IDeviceAppData , localToDevicePaths : Mobile . ILocalToDevicePathData [ ] , forceExecuteFullSync : boolean ) : IFuture < void > {
71
+ return ( ( ) => {
72
+ if ( forceExecuteFullSync ) {
73
+ this . restartApplication ( deviceAppData ) . wait ( ) ;
74
+ return ;
75
+ }
76
+ let scriptFiles = _ . filter ( localToDevicePaths , localToDevicePath => _ . endsWith ( localToDevicePath . getDevicePath ( ) , ".js" ) ) ;
77
+ let otherFiles = _ . difference ( localToDevicePaths , scriptFiles ) ;
78
+ let shouldRestart = _ . some ( otherFiles , ( localToDevicePath : Mobile . ILocalToDevicePathData ) => ! this . $liveSyncProvider . canExecuteFastSync ( localToDevicePath . getLocalPath ( ) , deviceAppData . platform ) ) ;
79
+
80
+ if ( shouldRestart ) {
81
+ this . restartApplication ( deviceAppData ) . wait ( ) ;
82
+
83
+ return ;
84
+ }
85
+
86
+ if ( ! this . $options . liveEdit && scriptFiles . length ) {
87
+ this . restartApplication ( deviceAppData ) . wait ( ) ;
88
+
89
+ return ;
90
+ }
91
+
92
+ if ( this . setupSocketIfNeeded ( ) . wait ( ) ) {
93
+ this . liveEdit ( scriptFiles ) ;
94
+ this . reloadPage ( deviceAppData , otherFiles ) . wait ( ) ;
95
+ }
96
+ } ) . future < void > ( ) ( ) ;
97
+ }
98
+
99
+ private restartApplication ( deviceAppData : Mobile . IDeviceAppData ) : IFuture < void > {
41
100
let projectData : IProjectData = this . $injector . resolve ( "projectData" ) ;
42
101
return this . device . applicationManager . restartApplication ( deviceAppData . appIdentifier , projectData . projectName ) ;
43
102
}
44
103
45
- protected reloadPage ( deviceAppData : Mobile . IDeviceAppData ) : IFuture < void > {
104
+ private reloadPage ( deviceAppData : Mobile . IDeviceAppData , localToDevicePaths : Mobile . ILocalToDevicePathData [ ] ) : IFuture < void > {
46
105
return ( ( ) => {
47
- let timeout = 9000 ;
48
- if ( this . device . isEmulator ) {
49
- if ( ! this . socket ) {
50
- helpers . connectEventually ( ( ) => net . connect ( IOSLiveSyncService . BACKEND_PORT ) , ( socket : net . Socket ) => {
51
- this . socket = socket ;
52
- this . attachEventHandlersIfNecessary ( ) ;
53
- this . sendPageReloadMessage ( ) ;
54
- } ) ;
55
- } else {
56
- this . sendPageReloadMessage ( ) ;
57
- }
58
- this . $iOSEmulatorServices . postDarwinNotification ( this . $iOSNotification . attachRequest ) . wait ( ) ;
59
- } else {
60
- if ( ! this . socket ) {
61
- this . $iOSSocketRequestExecutor . executeAttachRequest ( this . device , timeout ) . wait ( ) ;
62
- this . socket = this . device . connectToPort ( IOSLiveSyncService . BACKEND_PORT ) ;
63
- this . attachEventHandlersIfNecessary ( ) ;
64
- }
65
- this . sendPageReloadMessage ( ) ;
106
+ if ( localToDevicePaths . length ) {
107
+ let reloadMessage = `{ "method":"Page.reload","params":{"ignoreCache":false},"id":${ ++ currentPageReloadId } }` ;
108
+ this . sendMessage ( reloadMessage ) ;
66
109
}
67
110
} ) . future < void > ( ) ( ) ;
68
111
}
69
112
70
- private attachEventHandlersIfNecessary ( ) : void {
71
- if ( this . $options . watch ) {
72
- this . attachProcessExitHandlers ( ) ;
73
- this . attachSocketCloseEvent ( ) ;
74
- }
113
+ private liveEdit ( localToDevicePaths : Mobile . ILocalToDevicePathData [ ] ) {
114
+ return ( ( ) => {
115
+ _ . each ( localToDevicePaths , localToDevicePath => {
116
+ let content = this . $fs . readFile ( localToDevicePath . getLocalPath ( ) ) . wait ( ) . toString ( ) ;
117
+
118
+ content = helpers . stringReplaceAll ( content , "\n" , "\\n" ) ;
119
+ content = helpers . stringReplaceAll ( content , / \\ ' / g, "\\'" ) ;
120
+ content = helpers . stringReplaceAll ( content , "\"" , '\\"' ) ;
121
+ content = helpers . stringReplaceAll ( content , / \\ & / g, "\\&" ) ;
122
+ content = helpers . stringReplaceAll ( content , / \\ r / g, "\\r" ) ;
123
+ content = helpers . stringReplaceAll ( content , / \\ t / g, "\\t" ) ;
124
+ content = helpers . stringReplaceAll ( content , / \\ b / g, "\\b" ) ;
125
+ content = helpers . stringReplaceAll ( content , / \\ f / g, "\\f" ) ;
126
+
127
+ let message = `{ "method":"Debugger.setScriptSource","params":{"scriptUrl":"${ localToDevicePath . getDevicePath ( ) } ", "scriptSource": "${ content } "},"id":${ ++ currentPageReloadId } }` ;
128
+ this . sendMessage ( message ) ;
129
+ } ) ;
130
+ } ) . future < void > ( ) ( ) ;
75
131
}
76
132
77
- private attachSocketCloseEvent ( ) : void {
133
+ private attachEventHandlers ( ) : void {
134
+ this . attachProcessExitHandlers ( ) ;
135
+
78
136
this . socket . on ( "close" , ( hadError : boolean ) => {
79
137
this . $logger . trace ( `Socket closed, hadError is ${ hadError } .` ) ;
80
138
this . socket = null ;
81
139
} ) ;
140
+
141
+ this . socket . on ( "error" , ( error : any ) => {
142
+ this . $logger . trace ( `Socket error received: ${ error } ` ) ;
143
+ } ) ;
144
+
145
+ this . socket . on ( "data" , ( data : NodeBuffer | string ) => {
146
+ this . $logger . trace ( `Socket sent data: ${ data . toString ( ) } ` ) ;
147
+ } ) ;
82
148
}
83
149
84
- private sendPageReloadMessage ( ) : void {
150
+ private sendMessage ( message : string ) : void {
85
151
try {
86
- this . sendPageReloadMessageCore ( ) ;
87
- this . socket . on ( "data" , ( data : NodeBuffer | string ) => {
88
- this . $logger . trace ( `Socket sent data: ${ data . toString ( ) } ` ) ;
89
- this . destroySocketIfNecessary ( ) ;
90
- } ) ;
152
+ let length = Buffer . byteLength ( message , "utf16le" ) ;
153
+ let payload = new Buffer ( length + 4 ) ;
154
+ payload . writeInt32BE ( length , 0 ) ;
155
+ payload . write ( message , 4 , length , "utf16le" ) ;
156
+
157
+ this . socket . write ( payload ) ;
91
158
} catch ( err ) {
92
159
this . $logger . trace ( "Error while sending page reload:" , err ) ;
93
- this . destroySocketIfNecessary ( ) ;
160
+ this . destroySocket ( ) ;
94
161
}
95
162
}
96
163
97
- private sendPageReloadMessageCore ( ) : void {
98
- let message = `{ "method":"Page.reload","params":{"ignoreCache":false},"id":${ ++ currentPageReloadId } }` ;
99
- let length = Buffer . byteLength ( message , "utf16le" ) ;
100
- let payload = new Buffer ( length + 4 ) ;
101
- payload . writeInt32BE ( length , 0 ) ;
102
- payload . write ( message , 4 , length , "utf16le" ) ;
103
- this . socket . write ( payload ) ;
104
- }
105
-
106
164
private attachProcessExitHandlers ( ) : void {
107
165
process . on ( "exit" , ( exitCode : number ) => {
108
166
this . destroySocket ( ) ;
@@ -118,12 +176,6 @@ class IOSLiveSyncService extends DeviceLiveSyncServiceBase<Mobile.IiOSDevice> im
118
176
} ) ;
119
177
}
120
178
121
- private destroySocketIfNecessary ( ) : void {
122
- if ( ! this . $options . watch ) {
123
- this . destroySocket ( ) ;
124
- }
125
- }
126
-
127
179
private destroySocket ( ) : void {
128
180
if ( this . socket ) {
129
181
this . socket . destroy ( ) ;
0 commit comments