OLD | NEW |
| (Empty) |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 part of dart.io; | |
6 | |
7 abstract class _IOResourceInfo { | |
8 final String type; | |
9 final int id; | |
10 String get name; | |
11 static int _count = 0; | |
12 | |
13 static final Stopwatch _sw = new Stopwatch()..start(); | |
14 static final _startTime = new DateTime.now().millisecondsSinceEpoch; | |
15 | |
16 static double get timestamp => _startTime + _sw.elapsedMicroseconds/1000; | |
17 | |
18 _IOResourceInfo(this.type) : id = _IOResourceInfo.getNextID(); | |
19 | |
20 /// Get the full set of values for a specific implementation. This is normally | |
21 /// looked up based on an id from a referenceValueMap. | |
22 Map<String, String> get fullValueMap; | |
23 | |
24 /// The reference map, used to return a list of values, e.g., getting | |
25 /// all open sockets. The structure of this is shared among all subclasses. | |
26 Map<String, String> get referenceValueMap => | |
27 { | |
28 // The type for a reference object is prefixed with @ in observatory. | |
29 'type': '@$type', | |
30 'id': id, | |
31 'name': name, | |
32 }; | |
33 | |
34 static int getNextID() => _count++; | |
35 } | |
36 | |
37 abstract class _ReadWriteResourceInfo extends _IOResourceInfo { | |
38 int totalRead; | |
39 int totalWritten; | |
40 int readCount; | |
41 int writeCount; | |
42 double lastRead; | |
43 double lastWrite; | |
44 | |
45 // Not all call sites use this. In some cases, e.g., a socket, a read does | |
46 // not always mean that we actually read some bytes (we may do a read to see | |
47 // if there are some bytes available). | |
48 void addRead(int bytes) { | |
49 totalRead += bytes; | |
50 readCount++; | |
51 lastRead = _IOResourceInfo.timestamp; | |
52 } | |
53 | |
54 // In cases where we read but did not neccesarily get any bytes, use this to | |
55 // update the readCount and timestamp. Manually update totalRead if any bytes | |
56 // where acutally read. | |
57 void didRead() { addRead(0); } | |
58 | |
59 void addWrite(int bytes) { | |
60 totalWritten += bytes; | |
61 writeCount++; | |
62 lastWrite = _IOResourceInfo.timestamp; | |
63 } | |
64 | |
65 _ReadWriteResourceInfo(String type) : | |
66 totalRead = 0, | |
67 totalWritten = 0, | |
68 readCount = 0, | |
69 writeCount = 0, | |
70 lastRead = 0.0, | |
71 lastWrite = 0.0, | |
72 super(type); | |
73 | |
74 Map<String, String> get fullValueMap => | |
75 { | |
76 'type': type, | |
77 'id': id, | |
78 'name': name, | |
79 'totalRead': totalRead, | |
80 'totalWritten': totalWritten, | |
81 'readCount': readCount, | |
82 'writeCount': writeCount, | |
83 'lastRead': lastRead, | |
84 'lastWrite': lastWrite | |
85 }; | |
86 } | |
87 | |
88 class _FileResourceInfo extends _ReadWriteResourceInfo { | |
89 static const String TYPE = '_file'; | |
90 | |
91 final file; | |
92 | |
93 static Map<int, _FileResourceInfo> openFiles = | |
94 new Map<int, _FileResourceInfo>(); | |
95 | |
96 _FileResourceInfo(this.file) : super(TYPE) { | |
97 FileOpened(this); | |
98 } | |
99 | |
100 static FileOpened(_FileResourceInfo info) { | |
101 assert(!openFiles.containsKey(info.id)); | |
102 openFiles[info.id] = info; | |
103 } | |
104 | |
105 static FileClosed(_FileResourceInfo info) { | |
106 assert(openFiles.containsKey(info.id)); | |
107 openFiles.remove(info.id); | |
108 } | |
109 | |
110 static Iterable<Map<String, String>> getOpenFilesList() { | |
111 return new List.from(openFiles.values.map((e) => e.referenceValueMap)); | |
112 } | |
113 | |
114 static Future<ServiceExtensionResponse> getOpenFiles(function, params) { | |
115 assert(function == 'ext.dart.io.getOpenFiles'); | |
116 var data = {'type': '_openfiles', 'data': getOpenFilesList()}; | |
117 var json = JSON.encode(data); | |
118 return new Future.value(new ServiceExtensionResponse.result(json)); | |
119 } | |
120 | |
121 Map<String, String> getFileInfoMap() { | |
122 var result = fullValueMap; | |
123 return result; | |
124 } | |
125 | |
126 static Future<ServiceExtensionResponse> getFileInfoMapByID(function, params) { | |
127 assert(params.containsKey('id')); | |
128 var id = int.parse(params['id']); | |
129 var result = | |
130 openFiles.containsKey(id) ? openFiles[id].getFileInfoMap() : {}; | |
131 var json = JSON.encode(result); | |
132 return new Future.value(new ServiceExtensionResponse.result(json)); | |
133 } | |
134 | |
135 String get name { | |
136 return '${file.path}'; | |
137 } | |
138 } | |
139 | |
140 class _ProcessResourceInfo extends _IOResourceInfo{ | |
141 static const String TYPE = '_process'; | |
142 final process; | |
143 final double startedAt; | |
144 | |
145 static Map<int, _ProcessResourceInfo> startedProcesses = | |
146 new Map<int, _ProcessResourceInfo>(); | |
147 | |
148 _ProcessResourceInfo(this.process) : | |
149 startedAt = _IOResourceInfo.timestamp, | |
150 super(TYPE) { | |
151 ProcessStarted(this); | |
152 } | |
153 | |
154 String get name => process._path; | |
155 | |
156 void stopped() { ProcessStopped(this); } | |
157 | |
158 Map<String, String> get fullValueMap => | |
159 { | |
160 'type': type, | |
161 'id': id, | |
162 'name': name, | |
163 'pid': process.pid, | |
164 'startedAt': startedAt, | |
165 'arguments': process._arguments, | |
166 'workingDirectory': | |
167 process._workingDirectory == null ? '.' : process._workingDirectory, | |
168 }; | |
169 | |
170 static ProcessStarted(_ProcessResourceInfo info) { | |
171 assert(!startedProcesses.containsKey(info.id)); | |
172 startedProcesses[info.id] = info; | |
173 } | |
174 | |
175 static ProcessStopped(_ProcessResourceInfo info) { | |
176 assert(startedProcesses.containsKey(info.id)); | |
177 startedProcesses.remove(info.id); | |
178 } | |
179 | |
180 static Iterable<Map<String, String>> getStartedProcessesList() => | |
181 new List.from(startedProcesses.values.map((e) => e.referenceValueMap)); | |
182 | |
183 static Future<ServiceExtensionResponse> getStartedProcesses( | |
184 String function, Map<String, String> params) { | |
185 assert(function == 'ext.dart.io.getProcesses'); | |
186 var data = {'type': '_startedprocesses', 'data': getStartedProcessesList()}; | |
187 var json = JSON.encode(data); | |
188 return new Future.value(new ServiceExtensionResponse.result(json)); | |
189 } | |
190 | |
191 static Future<ServiceExtensionResponse> getProcessInfoMapById( | |
192 String function, Map<String, String> params) { | |
193 var id = int.parse(params['id']); | |
194 var result = startedProcesses.containsKey(id) | |
195 ? startedProcesses[id].fullValueMap | |
196 : {}; | |
197 var json = JSON.encode(result); | |
198 return new Future.value(new ServiceExtensionResponse.result(json)); | |
199 } | |
200 } | |
201 | |
202 class _SocketResourceInfo extends _ReadWriteResourceInfo { | |
203 static const String TCP_STRING = 'TCP'; | |
204 static const String UDP_STRING = 'UDP'; | |
205 static const String TYPE = '_socket'; | |
206 | |
207 final socket; | |
208 | |
209 static Map<int, _SocketResourceInfo> openSockets = | |
210 new Map<int, _SocketResourceInfo>(); | |
211 | |
212 _SocketResourceInfo(this.socket) : super(TYPE) { | |
213 SocketOpened(this); | |
214 } | |
215 | |
216 String get name { | |
217 if (socket.isListening) { | |
218 return 'listening:${socket.address.host}:${socket.port}'; | |
219 } | |
220 var remote = ''; | |
221 try { | |
222 var remoteHost = socket.remoteAddress.host; | |
223 var remotePort = socket.remotePort; | |
224 remote = ' -> $remoteHost:$remotePort'; | |
225 } catch (e) { } // ignored if we can't get the information | |
226 return '${socket.address.host}:${socket.port}$remote'; | |
227 } | |
228 | |
229 static Iterable<Map<String, String>> getOpenSocketsList() { | |
230 return new List.from(openSockets.values.map((e) => e.referenceValueMap)); | |
231 } | |
232 | |
233 Map<String, String> getSocketInfoMap() { | |
234 var result = fullValueMap; | |
235 result['socketType'] = socket.isTcp ? TCP_STRING : UDP_STRING; | |
236 result['listening'] = socket.isListening; | |
237 result['host'] = socket.address.host; | |
238 result['port'] = socket.port; | |
239 if (!socket.isListening) { | |
240 try { | |
241 result['remoteHost'] = socket.remoteAddress.host; | |
242 result['remotePort'] = socket.remotePort; | |
243 } catch (e) { | |
244 // UDP. | |
245 result['remotePort'] = 'NA'; | |
246 result['remoteHost'] = 'NA'; | |
247 } | |
248 } else { | |
249 result['remotePort'] = 'NA'; | |
250 result['remoteHost'] = 'NA'; | |
251 } | |
252 result['addressType'] = socket.address.type.name; | |
253 return result; | |
254 } | |
255 | |
256 static Future<ServiceExtensionResponse> getSocketInfoMapByID( | |
257 String function, Map<String, String> params) { | |
258 assert(params.containsKey('id')); | |
259 var id = int.parse(params['id']); | |
260 var result = | |
261 openSockets.containsKey(id) ? openSockets[id].getSocketInfoMap() : {}; | |
262 var json = JSON.encode(result); | |
263 return new Future.value(new ServiceExtensionResponse.result(json)); | |
264 } | |
265 | |
266 static Future<ServiceExtensionResponse> getOpenSockets(function, params) { | |
267 assert(function == 'ext.dart.io.getOpenSockets'); | |
268 var data = {'type': '_opensockets', 'data': getOpenSocketsList()}; | |
269 var json = JSON.encode(data); | |
270 return new Future.value(new ServiceExtensionResponse.result(json)); | |
271 } | |
272 | |
273 static SocketOpened(_SocketResourceInfo info) { | |
274 assert(!openSockets.containsKey(info.id)); | |
275 openSockets[info.id] = info; | |
276 } | |
277 | |
278 static SocketClosed(_SocketResourceInfo info) { | |
279 assert(openSockets.containsKey(info.id)); | |
280 openSockets.remove(info.id); | |
281 } | |
282 | |
283 } | |
OLD | NEW |