OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2016, 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._vmservice; | |
6 | |
7 String _encodeDevFSDisabledError(Message message) { | |
8 return encodeRpcError( | |
9 message, kFeatureDisabled, | |
10 details: "DevFS is not supported by this Dart implementation"); | |
11 } | |
12 | |
13 String _encodeFileSystemAlreadyExistsError(Message message, String fsName) { | |
14 return encodeRpcError( | |
15 message, kFileSystemAlreadyExists, | |
16 details: "${message.method}: file system '${fsName}' already exists"); | |
17 } | |
18 | |
19 String _encodeFileSystemDoesNotExistError(Message message, String fsName) { | |
20 return encodeRpcError( | |
21 message, kFileSystemDoesNotExist, | |
22 details: "${message.method}: file system '${fsName}' does not exist"); | |
23 } | |
24 | |
25 class _FileSystem { | |
26 _FileSystem(this.name, this.uri); | |
27 | |
28 final String name; | |
29 final Uri uri; | |
30 | |
31 Uri resolvePath(String path) { | |
32 if (path.startsWith('/')) { | |
33 path = path.substring(1); | |
34 } | |
35 if (path.isEmpty) { | |
36 return null; | |
37 } | |
38 Uri pathUri; | |
39 try { | |
40 pathUri = Uri.parse(path); | |
41 } on FormatException catch(e) { | |
42 return null; | |
43 } | |
44 Uri resolvedUri = uri.resolveUri(pathUri); | |
45 if (!resolvedUri.toString().startsWith(uri.toString())) { | |
46 // Resolved uri must be within the filesystem's base uri. | |
47 return null; | |
48 } | |
49 return resolvedUri; | |
50 } | |
51 | |
52 Map toMap() { | |
53 return { | |
54 'type': 'FileSystem', | |
55 'name': name, | |
56 'uri': uri.toString(), | |
57 }; | |
58 } | |
59 } | |
60 | |
61 class DevFS { | |
62 DevFS(); | |
63 | |
64 Map<String, _FileSystem> _fsMap = {}; | |
65 | |
66 final Set _rpcNames = new Set.from([ | |
67 '_listDevFS', | |
68 '_createDevFS', | |
69 '_deleteDevFS', | |
70 '_readDevFSFile', | |
71 '_writeDevFSFile', | |
72 '_writeDevFSFiles', | |
73 '_listDevFSFiles', | |
74 ]); | |
75 | |
76 void cleanup() { | |
77 var deleteDir = VMServiceEmbedderHooks.deleteDir; | |
78 if (deleteDir == null) { | |
79 return; | |
80 } | |
81 var deletions = []; | |
82 for (var fs in _fsMap.values) { | |
83 deletions.add(deleteDir(fs.uri)); | |
84 } | |
85 Future.wait(deletions); | |
86 _fsMap.clear(); | |
87 } | |
88 | |
89 bool shouldHandleMessage(Message message) { | |
90 return _rpcNames.contains(message.method); | |
91 } | |
92 | |
93 Future<String> handleMessage(Message message) async { | |
94 switch (message.method) { | |
95 case '_listDevFS': | |
96 return _listDevFS(message); | |
97 case '_createDevFS': | |
98 return _createDevFS(message); | |
99 case '_deleteDevFS': | |
100 return _deleteDevFS(message); | |
101 case '_readDevFSFile': | |
102 return _readDevFSFile(message); | |
103 case '_writeDevFSFile': | |
104 return _writeDevFSFile(message); | |
105 case '_writeDevFSFiles': | |
106 return _writeDevFSFiles(message); | |
107 case '_listDevFSFiles': | |
108 return _listDevFSFiles(message); | |
109 default: | |
110 return encodeRpcError( | |
111 message, kInternalError, | |
112 details: 'Unexpected rpc ${message.method}'); | |
113 } | |
114 } | |
115 | |
116 Future<String> _listDevFS(Message message) async { | |
117 var result = {}; | |
118 result['type'] = 'FileSystemList'; | |
119 result['fsNames'] = _fsMap.keys.toList(); | |
120 return encodeResult(message, result); | |
121 } | |
122 | |
123 Future<String> _createDevFS(Message message) async { | |
124 var createTempDir = VMServiceEmbedderHooks.createTempDir; | |
125 if (createTempDir == null) { | |
126 return _encodeDevFSDisabledError(message); | |
127 } | |
128 var fsName = message.params['fsName']; | |
129 if (fsName == null) { | |
130 return encodeMissingParamError(message, 'fsName'); | |
131 } | |
132 if (fsName is! String) { | |
133 return encodeInvalidParamError(message, 'fsName'); | |
134 } | |
135 var fs = _fsMap[fsName]; | |
136 if (fs != null) { | |
137 return _encodeFileSystemAlreadyExistsError(message, fsName); | |
138 } | |
139 var tempDir = await createTempDir(fsName); | |
140 fs = new _FileSystem(fsName, tempDir); | |
141 _fsMap[fsName] = fs; | |
142 return encodeResult(message, fs.toMap()); | |
143 } | |
144 | |
145 Future<String> _deleteDevFS(Message message) async { | |
146 var deleteDir = VMServiceEmbedderHooks.deleteDir; | |
147 if (deleteDir == null) { | |
148 return _encodeDevFSDisabledError(message); | |
149 } | |
150 var fsName = message.params['fsName']; | |
151 if (fsName == null) { | |
152 return encodeMissingParamError(message, 'fsName'); | |
153 } | |
154 if (fsName is! String) { | |
Cutch
2016/07/01 21:23:17
(here and elsewhere) the null check above is redun
| |
155 return encodeInvalidParamError(message, 'fsName'); | |
156 } | |
157 var fs = _fsMap.remove(fsName); | |
158 if (fs == null) { | |
159 return _encodeFileSystemDoesNotExistError(message, fsName); | |
160 } | |
161 await deleteDir(fs.uri); | |
162 return encodeSuccess(message); | |
163 } | |
164 | |
165 Future<String> _readDevFSFile(Message message) async { | |
166 var readFile = VMServiceEmbedderHooks.readFile; | |
167 if (readFile == null) { | |
168 return _encodeDevFSDisabledError(message); | |
169 } | |
170 var fsName = message.params['fsName']; | |
171 if (fsName == null) { | |
172 return encodeMissingParamError(message, 'fsName'); | |
173 } | |
174 if (fsName is! String) { | |
175 return encodeInvalidParamError(message, 'fsName'); | |
176 } | |
177 var fs = _fsMap[fsName]; | |
178 if (fs == null) { | |
179 return _encodeFileSystemDoesNotExistError(message, fsName); | |
180 } | |
181 var path = message.params['path']; | |
182 if (path == null) { | |
183 return encodeMissingParamError(message, 'path'); | |
184 } | |
185 if (path is! String) { | |
186 return encodeInvalidParamError(message, 'path'); | |
187 } | |
188 Uri uri = fs.resolvePath(path); | |
189 if (uri == null) { | |
190 return encodeInvalidParamError(message, 'path'); | |
191 } | |
192 | |
193 try { | |
194 List<int> bytes = await readFile(uri); | |
195 var result = { | |
196 'type': 'FSFile', | |
197 'fileContents': BASE64.encode(bytes) | |
198 }; | |
199 return encodeResult(message, result); | |
200 } catch (e) { | |
201 return encodeRpcError( | |
202 message, kFileDoesNotExist, | |
203 details: "_readDevFSFile: $e"); | |
204 } | |
205 } | |
206 | |
207 Future<String> _writeDevFSFile(Message message) async { | |
208 var writeFile = VMServiceEmbedderHooks.writeFile; | |
209 if (writeFile == null) { | |
210 return _encodeDevFSDisabledError(message); | |
211 } | |
212 var fsName = message.params['fsName']; | |
213 if (fsName == null) { | |
214 return encodeMissingParamError(message, 'fsName'); | |
215 } | |
216 if (fsName is! String) { | |
217 return encodeInvalidParamError(message, 'fsName'); | |
218 } | |
219 var fs = _fsMap[fsName]; | |
220 if (fs == null) { | |
221 return _encodeFileSystemDoesNotExistError(message, fsName); | |
222 } | |
223 var path = message.params['path']; | |
224 if (path == null) { | |
225 return encodeMissingParamError(message, 'path'); | |
226 } | |
227 if (path is! String) { | |
228 return encodeInvalidParamError(message, 'path'); | |
229 } | |
230 Uri uri = fs.resolvePath(path); | |
231 if (uri == null) { | |
232 return encodeInvalidParamError(message, 'path'); | |
233 } | |
234 var fileContents = message.params['fileContents']; | |
235 if (fileContents == null) { | |
236 return encodeMissingParamError(message, 'fileContents'); | |
237 } | |
238 if (fileContents is! String) { | |
239 return encodeInvalidParamError(message, 'fileContents'); | |
240 } | |
241 List<int> decodedFileContents = BASE64.decode(fileContents); | |
242 | |
243 await writeFile(uri, decodedFileContents); | |
244 return encodeSuccess(message); | |
245 } | |
246 | |
247 Future<String> _writeDevFSFiles(Message message) async { | |
248 var writeFile = VMServiceEmbedderHooks.writeFile; | |
249 if (writeFile == null) { | |
250 return _encodeDevFSDisabledError(message); | |
251 } | |
252 var fsName = message.params['fsName']; | |
253 if (fsName == null) { | |
254 return encodeMissingParamError(message, 'fsName'); | |
255 } | |
256 if (fsName is! String) { | |
257 return encodeInvalidParamError(message, 'fsName'); | |
258 } | |
259 var fs = _fsMap[fsName]; | |
260 if (fs == null) { | |
261 return _encodeFileSystemDoesNotExistError(message, fsName); | |
262 } | |
263 var files = message.params['files']; | |
264 if (files == null) { | |
265 return encodeMissingParamError(message, 'files'); | |
266 } | |
267 if (files is! List) { | |
268 return encodeInvalidParamError(message, 'files'); | |
269 } | |
270 var uris = []; | |
271 for (int i = 0; i < files.length; i++) { | |
272 var fileInfo = files[i]; | |
273 if (fileInfo is! List || | |
274 fileInfo.length != 2 || | |
275 fileInfo[0] is! String || fileInfo[1] is! String) { | |
276 return encodeRpcError( | |
277 message, kInvalidParams, | |
278 details: "${message.method}: invalid 'files' parameter " | |
279 "at index ${i}: ${fileInfo}"); | |
280 } | |
281 var uri = fs.resolvePath(fileInfo[0]); | |
282 if (uri == null) { | |
283 return encodeRpcError( | |
284 message, kInvalidParams, | |
285 details: "${message.method}: invalid 'files' parameter " | |
286 "at index ${i}: ${fileInfo}"); | |
287 } | |
288 uris.add(uri); | |
289 } | |
290 var pendingWrites = []; | |
291 for (int i = 0; i < uris.length; i++) { | |
292 List<int> decodedFileContents = BASE64.decode(files[i][1]); | |
293 pendingWrites.add(writeFile(uris[i], decodedFileContents)); | |
294 } | |
295 await Future.wait(pendingWrites); | |
296 return encodeSuccess(message); | |
297 } | |
298 | |
299 Future<String> _listDevFSFiles(Message message) async { | |
300 var listFiles = VMServiceEmbedderHooks.listFiles; | |
301 if (listFiles == null) { | |
302 return _encodeDevFSDisabledError(message); | |
303 } | |
304 var fsName = message.params['fsName']; | |
305 if (fsName == null) { | |
306 return encodeMissingParamError(message, 'fsName'); | |
307 } | |
308 if (fsName is! String) { | |
309 return encodeInvalidParamError(message, 'fsName'); | |
310 } | |
311 var fs = _fsMap[fsName]; | |
312 if (fs == null) { | |
313 return _encodeFileSystemDoesNotExistError(message, fsName); | |
314 } | |
315 var fileList = await listFiles(fs.uri); | |
316 var result = { 'type': 'FSFileList', 'files': fileList }; | |
317 return encodeResult(message, result); | |
318 } | |
319 } | |
OLD | NEW |