Merge pull request #14 from DrMarcII/refactor
Refactor event handling/transforming for domains.
diff --git a/lib/src/console.dart b/lib/src/console.dart
index cd528f6..1b2e256 100644
--- a/lib/src/console.dart
+++ b/lib/src/console.dart
@@ -4,49 +4,18 @@
part of wip;
class WipConsole extends WipDomain {
- final _messageController =
- new StreamController<ConsoleMessageEvent>.broadcast();
- final _clearedController = new StreamController.broadcast();
-
- ConsoleMessageEvent _lastMessage;
-
- WipConsole(WipConnection connection) : super(connection) {
- connection._registerDomain('Console', this);
-
- _register('Console.messageAdded', _messageAdded);
- _register('Console.messageRepeatCountUpdated', _messageRepeatCountUpdated);
- _register('Console.messagesCleared', _messagesCleared);
- }
+ WipConsole(WipConnection connection) : super(connection);
Future enable() => _sendCommand('Console.enable');
Future disable() => _sendCommand('Console.disable');
Future clearMessages() => _sendCommand('Console.clearMessages');
- Stream<ConsoleMessageEvent> get onMessage => _messageController.stream;
- Stream get onCleared => _clearedController.stream;
-
- void _messageAdded(WipEvent event) {
- _lastMessage = new ConsoleMessageEvent(event);
- _messageController.add(_lastMessage);
- }
-
- void _messageRepeatCountUpdated(WipEvent event) {
- if (_lastMessage != null) {
- _lastMessage.params['repeatCount'] = event.params['count'];
- _messageController.add(_lastMessage);
- }
- }
-
- void _messagesCleared(WipEvent event) {
- _lastMessage = null;
- _clearedController.add(null);
- }
-
- @override
- void close() {
- _messageController.close();
- _clearedController.close();
- }
+ Stream<ConsoleMessageEvent> get onMessage => _eventStream(
+ 'Console.messageAdded',
+ (WipEvent event) => new ConsoleMessageEvent(event));
+ Stream<ConsoleClearedEvent> get onCleared => _eventStream(
+ 'Console.messagesCleared',
+ (WipEvent event) => new ConsoleClearedEvent(event));
}
/**
@@ -74,6 +43,10 @@
String toString() => text;
}
+class ConsoleClearedEvent extends _WrappedWipEvent {
+ ConsoleClearedEvent(WipEvent event) : super(event);
+}
+
class WipConsoleCallFrame {
final Map<String, dynamic> _map;
diff --git a/lib/src/debugger.dart b/lib/src/debugger.dart
index bc92596..7c70557 100644
--- a/lib/src/debugger.dart
+++ b/lib/src/debugger.dart
@@ -4,32 +4,23 @@
part of wip;
class WipDebugger extends WipDomain {
- final _pausedController =
- new StreamController<DebuggerPausedEvent>.broadcast();
- final _resumedController = new StreamController.broadcast();
-
- Map<String, WipScript> _scripts = {};
+ final _scripts = <String, WipScript>{};
WipDebugger(WipConnection connection) : super(connection) {
- connection._registerDomain('Debugger', this);
-
- // TODO:
- //_register('Debugger.breakpointResolved', _breakpointResolved);
- _register('Debugger.globalObjectCleared', _globalObjectCleared);
- _register('Debugger.paused', _paused);
- _register('Debugger.resumed', _resumed);
- //_register('Debugger.scriptFailedToParse', _scriptFailedToParse);
- _register('Debugger.scriptParsed', _scriptParsed);
+ onScriptParsed.listen((event) {
+ _scripts[event.script.scriptId] = event.script;
+ });
+ onGlobalObjectCleared.listen((_) {
+ _scripts.clear();
+ });
}
Future enable() => _sendCommand('Debugger.enable');
Future disable() => _sendCommand('Debugger.disable');
- Future<String> getScriptSource(String scriptId) async {
- var resp =
- await _sendCommand('Debugger.getScriptSource', {'scriptId': scriptId});
- return resp.result['scriptSource'];
- }
+ Future<String> getScriptSource(String scriptId) async => (await _sendCommand(
+ 'Debugger.getScriptSource', {'scriptId': scriptId})).result[
+ 'scriptSource'];
Future pause() => _sendCommand('Debugger.pause');
Future resume() => _sendCommand('Debugger.resume');
@@ -38,39 +29,52 @@
Future stepOut() => _sendCommand('Debugger.stepOut');
Future stepOver() => _sendCommand('Debugger.stepOver');
- /**
- * State should be one of "all", "none", or "uncaught".
- */
- Future setPauseOnExceptions(String state) =>
- _sendCommand('Debugger.setPauseOnExceptions', {'state': state});
+ Future setPauseOnExceptions(PauseState state) => _sendCommand(
+ 'Debugger.setPauseOnExceptions', {'state': _pauseStateToString(state)});
- Stream get onPaused => _pausedController.stream;
- Stream get onResumed => _resumedController.stream;
+ Stream<DebuggerPausedEvent> get onPaused => _eventStream(
+ 'Debugger.paused', (WipEvent event) => new DebuggerPausedEvent(event));
+ Stream<GlobalObjectClearedEvent> get onGlobalObjectCleared => _eventStream(
+ 'Debugger.globalObjectCleared',
+ (WipEvent event) => new GlobalObjectClearedEvent(event));
+ Stream<DebuggerResumedEvent> get onResumed => _eventStream(
+ 'Debugger.resumed', (WipEvent event) => new DebuggerResumedEvent(event));
+ Stream<ScriptParsedEvent> get onScriptParsed => _eventStream(
+ 'Debugger.scriptParsed',
+ (WipEvent event) => new ScriptParsedEvent(event));
- WipScript getScript(String scriptId) => _scripts[scriptId];
+ Map<String, WipScript> get scripts => new UnmodifiableMapView(_scripts);
+}
- void _globalObjectCleared(WipEvent event) {
- _scripts.clear();
+String _pauseStateToString(PauseState state) {
+ switch (state) {
+ case PauseState.all:
+ return 'all';
+ case PauseState.none:
+ return 'none';
+ case PauseState.uncaught:
+ return 'uncaught';
+ default:
+ throw new ArgumentError('unknown state: $state');
}
+}
- void _paused(WipEvent event) {
- _pausedController.add(new DebuggerPausedEvent(event));
- }
+enum PauseState { all, none, uncaught }
- void _resumed(WipEvent event) {
- _resumedController.add(null);
- }
+class ScriptParsedEvent extends _WrappedWipEvent {
+ final WipScript script;
- void _scriptParsed(WipEvent event) {
- var script = new WipScript(event.params);
- _scripts[script.scriptId] = script;
- }
+ ScriptParsedEvent(WipEvent event)
+ : this.script = new WipScript(event.params),
+ super(event);
+}
- @override
- void close() {
- _pausedController.close();
- _resumedController.close();
- }
+class GlobalObjectClearedEvent extends _WrappedWipEvent {
+ GlobalObjectClearedEvent(WipEvent event) : super(event);
+}
+
+class DebuggerResumedEvent extends _WrappedWipEvent {
+ DebuggerResumedEvent(WipEvent event) : super(event);
}
class DebuggerPausedEvent extends _WrappedWipEvent {
diff --git a/lib/src/dom.dart b/lib/src/dom.dart
index b3d0c62..db0bf05 100644
--- a/lib/src/dom.dart
+++ b/lib/src/dom.dart
@@ -6,18 +6,7 @@
/// Implementation of the
/// https://developer.chrome.com/devtools/docs/protocol/1.1/dom
class WipDom extends WipDomain {
- WipDom(WipConnection connection) : super(connection) {
- connection._registerDomain('DOM', this);
-
- _register('DOM.attributeModified', _attributeModified);
- _register('DOM.attributeRemoved', _attributeRemoved);
- _register('DOM.characterDataModified', _characterDataModified);
- _register('DOM.childNodeCountUpdated', _childNodeCountUpdated);
- _register('DOM.childNodeInserted', _childNodeInserted);
- _register('DOM.childNodeRemoved', _childNodeRemoved);
- _register('DOM.documentUpdated', _documentUpdated);
- _register('DOM.setChildNodes', _setChildNodes);
- }
+ WipDom(WipConnection connection) : super(connection);
Future<Map<String, String>> getAttributes(int nodeId) async {
WipResponse resp =
@@ -106,10 +95,13 @@
Future removeAttribute(int nodeId, String name) =>
_sendCommand('DOM.removeAttribute', {'nodeId': nodeId, 'name': name});
+
Future removeNode(int nodeId) =>
_sendCommand('DOM.removeNode', {'nodeId': nodeId});
+
Future requestChildNodes(int nodeId) =>
_sendCommand('DOM.requestChildNodes', {'nodeId': nodeId});
+
Future<int> requestNode(String objectId) async {
var resp = await _sendCommand('DOM.requestNode', {'objectId': objectId});
return resp.result['nodeId'];
@@ -131,6 +123,7 @@
'name': name,
'value': value
});
+
Future setAttributesAsText(int nodeId, String text, {String name}) {
var params = {'nodeId': nodeId, 'text': text};
if (name != null) {
@@ -151,75 +144,29 @@
Future setOuterHtml(int nodeId, String outerHtml) => _sendCommand(
'DOM.setOuterHTML', {'nodeId': nodeId, 'outerHtml': outerHtml});
- final _attributeModifiedController =
- new StreamController<AttributeModifiedEvent>.broadcast();
- Stream<AttributeModifiedEvent> get onAttributeModified =>
- _attributeModifiedController.stream;
- void _attributeModified(WipEvent event) =>
- _attributeModifiedController.add(new AttributeModifiedEvent(event));
-
- final _attributeRemovedController =
- new StreamController<AttributeRemovedEvent>.broadcast();
- Stream<AttributeRemovedEvent> get onAttributeRemoved =>
- _attributeRemovedController.stream;
- void _attributeRemoved(WipEvent event) =>
- _attributeRemovedController.add(new AttributeRemovedEvent(event));
-
- final _characterDataModifiedController =
- new StreamController<CharacterDataModifiedEvent>.broadcast();
+ Stream<AttributeModifiedEvent> get onAttributeModified => _eventStream(
+ 'DOM.attributeModified',
+ (WipEvent event) => new AttributeModifiedEvent(event));
+ Stream<AttributeRemovedEvent> get onAttributeRemoved => _eventStream(
+ 'DOM.attributeRemoved',
+ (WipEvent event) => new AttributeRemovedEvent(event));
Stream<CharacterDataModifiedEvent> get onCharacterDataModified =>
- _characterDataModifiedController.stream;
- void _characterDataModified(WipEvent event) =>
- _characterDataModifiedController
- .add(new CharacterDataModifiedEvent(event));
-
- final _childNodeCountUpdatedController =
- new StreamController<ChildNodeCountUpdatedEvent>.broadcast();
+ _eventStream('DOM.characterDataModified',
+ (WipEvent event) => new CharacterDataModifiedEvent(event));
Stream<ChildNodeCountUpdatedEvent> get onChildNodeCountUpdated =>
- _childNodeCountUpdatedController.stream;
- void _childNodeCountUpdated(WipEvent event) =>
- _childNodeCountUpdatedController
- .add(new ChildNodeCountUpdatedEvent(event));
-
- final _childNodeInsertedController =
- new StreamController<ChildNodeInsertedEvent>.broadcast();
- Stream<ChildNodeInsertedEvent> get onChildNodeInserted =>
- _childNodeInsertedController.stream;
- void _childNodeInserted(WipEvent event) =>
- _childNodeInsertedController.add(new ChildNodeInsertedEvent(event));
-
- final _childNodeRemovedController =
- new StreamController<ChildNodeRemovedEvent>.broadcast();
- Stream<ChildNodeRemovedEvent> get onChildNodeRemoved =>
- _childNodeRemovedController.stream;
- void _childNodeRemoved(WipEvent event) =>
- _childNodeRemovedController.add(new ChildNodeRemovedEvent(event));
-
- final _documentUpdatedController =
- new StreamController<DocumentUpdatedEvent>.broadcast();
- Stream<DocumentUpdatedEvent> get onDocumentUpdated =>
- _documentUpdatedController.stream;
- void _documentUpdated(WipEvent event) =>
- _documentUpdatedController.add(new DocumentUpdatedEvent(event));
-
- final _setChildNodesController =
- new StreamController<SetChildNodesEvent>.broadcast();
- Stream<SetChildNodesEvent> get onSetChildNodes =>
- _setChildNodesController.stream;
- void _setChildNodes(WipEvent event) =>
- _setChildNodesController.add(new SetChildNodesEvent(event));
-
- @override
- void close() {
- _attributeModifiedController.close();
- _attributeRemovedController.close();
- _characterDataModifiedController.close();
- _childNodeCountUpdatedController.close();
- _childNodeInsertedController.close();
- _childNodeRemovedController.close();
- _documentUpdatedController.close();
- _setChildNodesController.close();
- }
+ _eventStream('DOM.childNodeCountUpdated',
+ (WipEvent event) => new ChildNodeCountUpdatedEvent(event));
+ Stream<ChildNodeInsertedEvent> get onChildNodeInserted => _eventStream(
+ 'DOM.childNodeInserted',
+ (WipEvent event) => new ChildNodeInsertedEvent(event));
+ Stream<ChildNodeRemovedEvent> get onChildNodeRemoved => _eventStream(
+ 'DOM.childNodeRemoved',
+ (WipEvent event) => new ChildNodeRemovedEvent(event));
+ Stream<DocumentUpdatedEvent> get onDocumentUpdated => _eventStream(
+ 'DOM.documentUpdated',
+ (WipEvent event) => new DocumentUpdatedEvent(event));
+ Stream<SetChildNodesEvent> get onSetChildNodes => _eventStream(
+ 'DOM.setChildNodes', (WipEvent event) => new SetChildNodesEvent(event));
}
class AttributeModifiedEvent extends _WrappedWipEvent {
diff --git a/lib/src/page.dart b/lib/src/page.dart
index 5305c80..7bb20a1 100644
--- a/lib/src/page.dart
+++ b/lib/src/page.dart
@@ -4,13 +4,7 @@
part of wip;
class WipPage extends WipDomain {
- WipPage(WipConnection connection) : super(connection) {
- connection._registerDomain('Page', this);
-
- // TODO:
- // Page.loadEventFired
- // Page.domContentEventFired
- }
+ WipPage(WipConnection connection) : super(connection);
Future enable() => _sendCommand('Page.enable');
Future disable() => _sendCommand('Page.disable');
@@ -30,7 +24,4 @@
return _sendCommand('Page.navigate', params);
}
-
- @override
- void close() {}
}
diff --git a/lib/webkit_inspection_protocol.dart b/lib/webkit_inspection_protocol.dart
index b9f3ab1..4966fae 100644
--- a/lib/webkit_inspection_protocol.dart
+++ b/lib/webkit_inspection_protocol.dart
@@ -6,7 +6,14 @@
*/
library wip;
-import 'dart:async' show Completer, Future, Stream, StreamController;
+import 'dart:async'
+ show
+ Completer,
+ EventSink,
+ Future,
+ Stream,
+ StreamController,
+ StreamTransformer;
import 'dart:collection' show UnmodifiableMapView;
import 'dart:convert' show JSON, UTF8;
import 'dart:io' show HttpClient, HttpClientResponse, WebSocket;
@@ -131,8 +138,6 @@
var _page;
WipPage get page => _page;
- final _domains = <String, WipDomain>{};
-
final _completers = <int, Completer<WipResponse>>{};
final _closeController = new StreamController<WipConnection>.broadcast();
@@ -168,12 +173,9 @@
String toString() => url;
- void _registerDomain(String domainId, WipDomain domain) {
- _domains[domainId] = domain;
- }
-
Future<WipResponse> sendCommand(String method,
[Map<String, dynamic> params]) {
+ _log.finest('Sending command: $method($params)');
var completer = new Completer<WipResponse>();
var json = {'id': _nextId++, 'method': method};
if (params != null) {
@@ -185,26 +187,18 @@
}
void _handleNotification(Map<String, dynamic> json) {
- var event = new WipEvent(json);
- var domainId = event.method;
- var index = domainId.indexOf('.');
- if (index != -1) {
- domainId = domainId.substring(0, index);
- }
- if (_domains.containsKey(domainId)) {
- _domains[domainId]._handleNotification(event);
- } else {
- _log.warning('unhandled event notification: ${event.method}');
- }
- _notificationController.add(event);
+ _log.finest('Received notification: $json');
+ _notificationController.add(new WipEvent(json));
}
void _handleResponse(Map<String, dynamic> event) {
var completer = _completers.remove(event['id']);
if (event.containsKey('error')) {
+ _log.info('Received error: $event');
completer.completeError(new WipError(event));
} else {
+ _log.finest('Received response: $event');
completer.complete(new WipResponse(event));
}
}
@@ -213,7 +207,6 @@
_closeController.add(this);
_closeController.close();
_notificationController.close();
- _domains.values.forEach((d) => d.close());
}
}
@@ -250,28 +243,36 @@
String toString() => 'WipResponse $id: $result';
}
-typedef WipEventCallback(WipEvent event);
+typedef WipEvent WipEventTransformer(WipEvent event);
abstract class WipDomain {
- Map<String, WipEventCallback> _callbacks = {};
+ static final _log = new Logger('WipDomain');
+
+ Map<String, Stream> _eventStreams = {};
final WipConnection connection;
+ var _onClosed;
+ Stream<WipDomain> get onClosed => _onClosed;
- WipDomain(this.connection);
-
- void _register(String method, WipEventCallback callback) {
- _callbacks[method] = callback;
+ WipDomain(WipConnection connection) : this.connection = connection {
+ this._onClosed = new StreamTransformer.fromHandlers(
+ handleData: (event, EventSink sink) {
+ sink.add(this);
+ }).bind(connection.onClose);
}
- void _handleNotification(WipEvent event) {
- var f = _callbacks[event.method];
- if (f != null) f(event);
- }
+ Stream<WipEvent> _eventStream(
+ String method, WipEventTransformer transformer) => _eventStreams
+ .putIfAbsent(method, () => new StreamTransformer.fromHandlers(
+ handleData: (WipEvent event, EventSink<WipEvent> sink) {
+ if (event.method == method) {
+ _log.finest('Transforming $event to $method');
+ sink.add(transformer(event));
+ }
+ }).bind(connection.onNotification));
Future<WipResponse> _sendCommand(String method,
[Map<String, dynamic> params]) => connection.sendCommand(method, params);
-
- void close();
}
class _WrappedWipEvent implements WipEvent {