blob: 3ba76c965ae08ecf10eca298b61bd8a63bf66c69 [file] [log] [blame]
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart.io;
abstract class _IOResourceInfo {
final String type;
final int id;
String get name;
static int _count = 0;
static final Stopwatch _sw = Stopwatch()..start();
static final _startTime = DateTime.now().millisecondsSinceEpoch;
static int get timestamp => _startTime + _sw.elapsedMicroseconds ~/ 1000;
_IOResourceInfo(this.type) : id = _IOResourceInfo.getNextID();
/// Get the full set of values for a specific implementation. This is normally
/// looked up based on an id from a referenceValueMap.
Map<String, dynamic> get fullValueMap;
/// The reference map, used to return a list of values, e.g., getting
/// all open sockets. The structure of this is shared among all subclasses.
Map<String, dynamic> get referenceValueMap => {
// The type for a reference object is prefixed with @ in observatory.
'type': '@$type',
'id': id,
'name': name,
};
static int getNextID() => _count++;
}
abstract class _ReadWriteResourceInfo extends _IOResourceInfo {
int readBytes;
int writeBytes;
int readCount;
int writeCount;
int lastReadTime;
int lastWriteTime;
// Not all call sites use this. In some cases, e.g., a socket, a read does
// not always mean that we actually read some bytes (we may do a read to see
// if there are some bytes available).
void addRead(int bytes) {
readBytes += bytes;
readCount++;
lastReadTime = _IOResourceInfo.timestamp;
}
// In cases where we read but did not necessarily get any bytes, use this to
// update the readCount and timestamp. Manually update totalRead if any bytes
// where actually read.
void didRead() {
addRead(0);
}
void addWrite(int bytes) {
writeBytes += bytes;
writeCount++;
lastWriteTime = _IOResourceInfo.timestamp;
}
_ReadWriteResourceInfo(String type)
: readBytes = 0,
writeBytes = 0,
readCount = 0,
writeCount = 0,
lastReadTime = 0,
lastWriteTime = 0,
super(type);
Map<String, dynamic> get fullValueMap => {
'type': type,
'id': id,
'name': name,
'readBytes': readBytes,
'writeBytes': writeBytes,
'readCount': readCount,
'writeCount': writeCount,
'lastReadTime': lastReadTime,
'lastWriteTime': lastWriteTime
};
}
class _FileResourceInfo extends _ReadWriteResourceInfo {
static const String _type = 'OpenFile';
final file;
static Map<int, _FileResourceInfo> openFiles = {};
_FileResourceInfo(this.file) : super(_type) {
fileOpened(this);
}
static fileOpened(_FileResourceInfo info) {
assert(!openFiles.containsKey(info.id));
openFiles[info.id] = info;
}
static fileClosed(_FileResourceInfo info) {
assert(openFiles.containsKey(info.id));
openFiles.remove(info.id);
}
static Iterable<Map<String, dynamic>> getOpenFilesList() {
return List.from(openFiles.values.map(
(e) => e.referenceValueMap,
));
}
static Future<ServiceExtensionResponse> getOpenFiles(function, params) {
assert(function == 'ext.dart.io.getOpenFiles');
final data = {
'type': 'OpenFileList',
'files': getOpenFilesList(),
};
final jsonValue = json.encode(data);
return Future.value(ServiceExtensionResponse.result(jsonValue));
}
Map<String, dynamic> get fileInfoMap => fullValueMap;
static Future<ServiceExtensionResponse> getOpenFileInfoMapByID(
function, params) {
final id = int.parse(params['id']!);
final result = openFiles.containsKey(id) ? openFiles[id]!.fileInfoMap : {};
final jsonValue = json.encode(result);
return Future.value(ServiceExtensionResponse.result(jsonValue));
}
String get name => file.path;
}
class _SpawnedProcessResourceInfo extends _IOResourceInfo {
static const String _type = 'SpawnedProcess';
final process;
final int startedAt;
static Map<int, _SpawnedProcessResourceInfo> startedProcesses =
Map<int, _SpawnedProcessResourceInfo>();
_SpawnedProcessResourceInfo(this.process)
: startedAt = _IOResourceInfo.timestamp,
super(_type) {
processStarted(this);
}
String get name => process._path;
void stopped() => processStopped(this);
Map<String, dynamic> get fullValueMap => {
'type': type,
'id': id,
'name': name,
'pid': process.pid,
'startedAt': startedAt,
'arguments': process._arguments,
'workingDirectory':
process._workingDirectory == null ? '.' : process._workingDirectory,
};
static processStarted(_SpawnedProcessResourceInfo info) {
assert(!startedProcesses.containsKey(info.id));
startedProcesses[info.id] = info;
}
static processStopped(_SpawnedProcessResourceInfo info) {
assert(startedProcesses.containsKey(info.id));
startedProcesses.remove(info.id);
}
static Iterable<Map<String, dynamic>> getStartedProcessesList() =>
List.from(startedProcesses.values.map(
(e) => e.referenceValueMap,
));
static Future<ServiceExtensionResponse> getStartedProcesses(
String function, Map<String, String> params) {
assert(function == 'ext.dart.io.getSpawnedProcesses');
final data = {
'type': 'SpawnedProcessList',
'processes': getStartedProcessesList(),
};
final jsonValue = json.encode(data);
return Future.value(ServiceExtensionResponse.result(jsonValue));
}
static Future<ServiceExtensionResponse> getProcessInfoMapById(
String function, Map<String, String> params) {
final id = int.parse(params['id']!);
final result = startedProcesses.containsKey(id)
? startedProcesses[id]!.fullValueMap
: {};
final jsonValue = json.encode(result);
return Future.value(ServiceExtensionResponse.result(jsonValue));
}
}