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) { |
| 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 |