feat(WebWorker) Add channel support to MessageBus
closes #3661 and #3686
This commit is contained in:
parent
104302a958
commit
0b59e664ec
@ -81,13 +81,13 @@ class ObservableWrapper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class EventEmitter extends Stream {
|
class EventEmitter extends Stream {
|
||||||
StreamController<String> _controller;
|
StreamController<dynamic> _controller;
|
||||||
|
|
||||||
EventEmitter() {
|
EventEmitter() {
|
||||||
_controller = new StreamController.broadcast();
|
_controller = new StreamController.broadcast();
|
||||||
}
|
}
|
||||||
|
|
||||||
StreamSubscription listen(void onData(String line),
|
StreamSubscription listen(void onData(dynamic line),
|
||||||
{void onError(Error error), void onDone(), bool cancelOnError}) {
|
{void onError(Error error), void onDone(), bool cancelOnError}) {
|
||||||
return _controller.stream.listen(onData,
|
return _controller.stream.listen(onData,
|
||||||
onError: onError, onDone: onDone, cancelOnError: cancelOnError);
|
onError: onError, onDone: onDone, cancelOnError: cancelOnError);
|
||||||
|
@ -0,0 +1,76 @@
|
|||||||
|
library angular2.src.web_workers.shared.isolate_message_bus;
|
||||||
|
|
||||||
|
import 'dart:isolate';
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:core';
|
||||||
|
import 'package:angular2/src/web-workers/shared/message_bus.dart'
|
||||||
|
show MessageBus, MessageBusSink, MessageBusSource;
|
||||||
|
import 'package:angular2/src/facade/async.dart';
|
||||||
|
|
||||||
|
class IsolateMessageBus implements MessageBus {
|
||||||
|
final IsolateMessageBusSink sink;
|
||||||
|
final IsolateMessageBusSource source;
|
||||||
|
|
||||||
|
IsolateMessageBus(IsolateMessageBusSink sink, IsolateMessageBusSource source)
|
||||||
|
: sink = sink,
|
||||||
|
source = source;
|
||||||
|
|
||||||
|
EventEmitter from(String channel) {
|
||||||
|
return source.from(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
EventEmitter to(String channel) {
|
||||||
|
return sink.to(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class IsolateMessageBusSink implements MessageBusSink {
|
||||||
|
final SendPort _port;
|
||||||
|
final Map<String, EventEmitter> _channels = new Map<String, EventEmitter>();
|
||||||
|
|
||||||
|
IsolateMessageBusSink(SendPort port) : _port = port;
|
||||||
|
|
||||||
|
EventEmitter to(String channel) {
|
||||||
|
if (_channels.containsKey(channel)) {
|
||||||
|
return _channels[channel];
|
||||||
|
} else {
|
||||||
|
var emitter = new EventEmitter();
|
||||||
|
emitter.listen((message) {
|
||||||
|
_port.send({'channel': channel, 'message': message});
|
||||||
|
});
|
||||||
|
_channels[channel] = emitter;
|
||||||
|
return emitter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class IsolateMessageBusSource extends MessageBusSource {
|
||||||
|
final Stream rawDataStream;
|
||||||
|
final Map<String, EventEmitter> _channels = new Map<String, EventEmitter>();
|
||||||
|
|
||||||
|
IsolateMessageBusSource(ReceivePort port)
|
||||||
|
: rawDataStream = port.asBroadcastStream() {
|
||||||
|
rawDataStream.listen((message) {
|
||||||
|
if (message is SendPort){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message.containsKey("channel")) {
|
||||||
|
var channel = message['channel'];
|
||||||
|
if (_channels.containsKey(channel)) {
|
||||||
|
_channels[channel].add(message['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
EventEmitter from(String channel) {
|
||||||
|
if (_channels.containsKey(channel)) {
|
||||||
|
return _channels[channel];
|
||||||
|
} else {
|
||||||
|
var emitter = new EventEmitter();
|
||||||
|
_channels[channel] = emitter;
|
||||||
|
return emitter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,26 +1,52 @@
|
|||||||
// TODO(jteplitz602) to be idiomatic these should be releated to Observable's or Streams
|
import {EventEmitter} from 'angular2/src/facade/async';
|
||||||
/**
|
import {BaseException} from 'angular2/src/facade/lang';
|
||||||
* Message Bus is a low level API used to communicate between the UI and the worker.
|
// TODO(jteplitz602): Replace both the interface and the exported class with an abstract class #3683
|
||||||
* It smooths out the differences between Javascript's postMessage and Dart's Isolate
|
|
||||||
* allowing you to work with one consistent API.
|
function _abstract() {
|
||||||
*/
|
throw new BaseException("This method is abstract");
|
||||||
export interface MessageBus {
|
|
||||||
sink: MessageBusSink;
|
|
||||||
source: MessageBusSource;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SourceListener {
|
/**
|
||||||
(data: any): void; // TODO: Replace this any type with the type of a real messaging protocol
|
* Message Bus is a low level API used to communicate between the UI and the background.
|
||||||
|
* Communication is based on a channel abstraction. Messages published in a
|
||||||
|
* given channel to one MessageBusSink are received on the same channel
|
||||||
|
* by the corresponding MessageBusSource.
|
||||||
|
* TODO(jteplitz602): This should just extend both the source and the sink once
|
||||||
|
* https://github.com/angular/ts2dart/issues/263 is closed.
|
||||||
|
*/
|
||||||
|
export interface MessageBusInterface {
|
||||||
|
/**
|
||||||
|
* Returns an {@link EventEmitter} that emits every time a messsage
|
||||||
|
* is received on the given channel.
|
||||||
|
*/
|
||||||
|
from(channel: string): EventEmitter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an {@link EventEmitter} for the given channel
|
||||||
|
* To publish methods to that channel just call next (or add in dart) on the returned emitter
|
||||||
|
*/
|
||||||
|
to(channel: string): EventEmitter;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MessageBusSource {
|
export interface MessageBusSource {
|
||||||
/**
|
/**
|
||||||
* Attaches the SourceListener to this source.
|
* Returns an {@link EventEmitter} that emits every time a messsage
|
||||||
* The SourceListener will get called whenever the bus receives a message
|
* is received on the given channel.
|
||||||
* Returns a listener id that can be passed to {removeListener}
|
|
||||||
*/
|
*/
|
||||||
addListener(fn: SourceListener): number;
|
from(channel: string): EventEmitter;
|
||||||
removeListener(index: number);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MessageBusSink { send(message: Object): void; }
|
export interface MessageBusSink {
|
||||||
|
/**
|
||||||
|
* Returns an {@link EventEmitter} for the given channel
|
||||||
|
* To publish methods to that channel just call next (or add in dart) on the returned emitter
|
||||||
|
*/
|
||||||
|
to(channel: string): EventEmitter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(jteplitz602): Remove this class once we have abstract classes #3683
|
||||||
|
export class MessageBus implements MessageBusInterface {
|
||||||
|
from(channel: string): EventEmitter { throw _abstract(); }
|
||||||
|
|
||||||
|
to(channel: string): EventEmitter { throw _abstract(); }
|
||||||
|
}
|
||||||
|
9
modules/angular2/src/web-workers/shared/messaging_api.ts
Normal file
9
modules/angular2/src/web-workers/shared/messaging_api.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* All channels used by angular's WebWorker components are listed here.
|
||||||
|
* You should not use these channels in your application code.
|
||||||
|
*/
|
||||||
|
export const SETUP_CHANNEL = "ng-WebWorkerSetup";
|
||||||
|
export const RENDER_COMPILER_CHANNEL = "ng-RenderCompiler";
|
||||||
|
export const RENDERER_CHANNEL = "ng-Renderer";
|
||||||
|
export const XHR_CHANNEL = "ng-XHR";
|
||||||
|
export const EVENT_CHANNEL = "ng-events";
|
@ -0,0 +1,3 @@
|
|||||||
|
// PostMessageBus can't be implemented in dart since dart doesn't use postMessage
|
||||||
|
// This file is only here to prevent ts2dart from trying to transpile the PostMessageBus
|
||||||
|
library angular2.src.web_workers.shared.post_message_bus;
|
75
modules/angular2/src/web-workers/shared/post_message_bus.ts
Normal file
75
modules/angular2/src/web-workers/shared/post_message_bus.ts
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import {
|
||||||
|
MessageBusInterface,
|
||||||
|
MessageBusSource,
|
||||||
|
MessageBusSink
|
||||||
|
} from "angular2/src/web-workers/shared/message_bus";
|
||||||
|
import {EventEmitter} from 'angular2/src/facade/async';
|
||||||
|
import {StringMap, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||||
|
import {Injectable} from "angular2/di";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A TypeScript implementation of {@link MessageBus} for communicating via JavaScript's
|
||||||
|
* postMessage API.
|
||||||
|
*/
|
||||||
|
@Injectable()
|
||||||
|
export class PostMessageBus implements MessageBusInterface {
|
||||||
|
constructor(private _sink: PostMessageBusSink, private _source: PostMessageBusSource) {}
|
||||||
|
|
||||||
|
from(channel: string): EventEmitter { return this._source.from(channel); }
|
||||||
|
|
||||||
|
to(channel: string): EventEmitter { return this._sink.to(channel); }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PostMessageBusSink implements MessageBusSink {
|
||||||
|
private _channels: StringMap<string, EventEmitter> = StringMapWrapper.create();
|
||||||
|
|
||||||
|
constructor(private _postMessageTarget: PostMessageTarget) {}
|
||||||
|
|
||||||
|
public to(channel: string): EventEmitter {
|
||||||
|
if (StringMapWrapper.contains(this._channels, channel)) {
|
||||||
|
return this._channels[channel];
|
||||||
|
} else {
|
||||||
|
var emitter = new EventEmitter();
|
||||||
|
emitter.observer({
|
||||||
|
next: (message: Object) => {
|
||||||
|
this._postMessageTarget.postMessage({channel: channel, message: message});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return emitter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PostMessageBusSource implements MessageBusSource {
|
||||||
|
private _channels: StringMap<string, EventEmitter> = StringMapWrapper.create();
|
||||||
|
|
||||||
|
constructor(eventTarget?: EventTarget) {
|
||||||
|
if (eventTarget) {
|
||||||
|
eventTarget.addEventListener("message", (ev: MessageEvent) => this._handleMessage(ev));
|
||||||
|
} else {
|
||||||
|
// if no eventTarget is given we assume we're in a WebWorker and listen on the global scope
|
||||||
|
addEventListener("message", (ev: MessageEvent) => this._handleMessage(ev));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleMessage(ev: MessageEvent) {
|
||||||
|
var data = ev.data;
|
||||||
|
var channel = data.channel;
|
||||||
|
if (StringMapWrapper.contains(this._channels, channel)) {
|
||||||
|
this._channels[channel].next(data.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public from(channel: string): EventEmitter {
|
||||||
|
if (StringMapWrapper.contains(this._channels, channel)) {
|
||||||
|
return this._channels[channel];
|
||||||
|
} else {
|
||||||
|
var emitter = new EventEmitter();
|
||||||
|
this._channels[channel] = emitter;
|
||||||
|
return emitter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(jteplitz602) Replace this with the definition in lib.webworker.d.ts(#3492)
|
||||||
|
export interface PostMessageTarget { postMessage: (message: any, transfer?:[ArrayBuffer]) => void; }
|
@ -4,8 +4,9 @@ import 'dart:isolate';
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:core';
|
import 'dart:core';
|
||||||
import 'package:angular2/src/web-workers/shared/message_bus.dart'
|
import 'package:angular2/src/web-workers/shared/message_bus.dart'
|
||||||
show MessageBus, MessageBusSink, MessageBusSource;
|
show MessageBus;
|
||||||
import 'package:angular2/src/web-workers/ui/impl.dart' show bootstrapUICommon;
|
import 'package:angular2/src/web-workers/ui/impl.dart' show bootstrapUICommon;
|
||||||
|
import 'package:angular2/src/web-workers/shared/isolate_message_bus.dart';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bootstrapping a WebWorker
|
* Bootstrapping a WebWorker
|
||||||
@ -23,63 +24,22 @@ Future<MessageBus> bootstrap(String uri) {
|
|||||||
/**
|
/**
|
||||||
* To be called from the main thread to spawn and communicate with the worker thread
|
* To be called from the main thread to spawn and communicate with the worker thread
|
||||||
*/
|
*/
|
||||||
Future<UIMessageBus> spawnWebWorker(Uri uri) {
|
Future<MessageBus> spawnWebWorker(Uri uri) {
|
||||||
var receivePort = new ReceivePort();
|
var receivePort = new ReceivePort();
|
||||||
var isolateEndSendPort = receivePort.sendPort;
|
var isolateEndSendPort = receivePort.sendPort;
|
||||||
return Isolate.spawnUri(uri, const [], isolateEndSendPort).then((_) {
|
return Isolate.spawnUri(uri, const [], isolateEndSendPort).then((_) {
|
||||||
var source = new UIMessageBusSource(receivePort);
|
var source = new UIMessageBusSource(receivePort);
|
||||||
return source.sink.then((sendPort) {
|
return source.sink.then((sendPort) {
|
||||||
var sink = new UIMessageBusSink(sendPort);
|
var sink = new IsolateMessageBusSink(sendPort);
|
||||||
return new UIMessageBus(sink, source);
|
return new IsolateMessageBus(sink, source);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class UIMessageBus extends MessageBus {
|
class UIMessageBusSource extends IsolateMessageBusSource {
|
||||||
final UIMessageBusSink sink;
|
UIMessageBusSource(ReceivePort port) : super(port);
|
||||||
final UIMessageBusSource source;
|
|
||||||
|
|
||||||
UIMessageBus(UIMessageBusSink sink, UIMessageBusSource source)
|
|
||||||
: sink = sink,
|
|
||||||
source = source;
|
|
||||||
}
|
|
||||||
|
|
||||||
class UIMessageBusSink extends MessageBusSink {
|
|
||||||
final SendPort _port;
|
|
||||||
|
|
||||||
UIMessageBusSink(SendPort port) : _port = port;
|
|
||||||
|
|
||||||
void send(message) {
|
|
||||||
_port.send(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class UIMessageBusSource extends MessageBusSource {
|
|
||||||
final ReceivePort _port;
|
|
||||||
final Stream rawDataStream;
|
|
||||||
Map<int, StreamSubscription> _listenerStore =
|
|
||||||
new Map<int, StreamSubscription>();
|
|
||||||
int _numListeners = 0;
|
|
||||||
|
|
||||||
UIMessageBusSource(ReceivePort port)
|
|
||||||
: _port = port,
|
|
||||||
rawDataStream = port.asBroadcastStream();
|
|
||||||
|
|
||||||
Future<SendPort> get sink => rawDataStream.firstWhere((message) {
|
Future<SendPort> get sink => rawDataStream.firstWhere((message) {
|
||||||
return message is SendPort;
|
return message is SendPort;
|
||||||
});
|
});
|
||||||
|
|
||||||
int addListener(Function fn) {
|
|
||||||
var subscription = rawDataStream.listen((message) {
|
|
||||||
fn({"data": message});
|
|
||||||
});
|
|
||||||
|
|
||||||
_listenerStore[++_numListeners] = subscription;
|
|
||||||
return _numListeners;
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeListener(int index) {
|
|
||||||
_listenerStore[index].cancel();
|
|
||||||
_listenerStore.remove(index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import {
|
import {
|
||||||
MessageBus,
|
PostMessageBus,
|
||||||
MessageBusSource,
|
PostMessageBusSink,
|
||||||
MessageBusSink,
|
PostMessageBusSource
|
||||||
SourceListener
|
} from 'angular2/src/web-workers/shared/post_message_bus';
|
||||||
} from "angular2/src/web-workers/shared/message_bus";
|
import {MessageBus} from 'angular2/src/web-workers/shared/message_bus';
|
||||||
import {BaseException} from "angular2/src/facade/lang";
|
import {BaseException} from "angular2/src/facade/lang";
|
||||||
import {bootstrapUICommon} from "angular2/src/web-workers/ui/impl";
|
import {bootstrapUICommon} from "angular2/src/web-workers/ui/impl";
|
||||||
|
|
||||||
@ -23,33 +23,7 @@ export function bootstrap(uri: string): MessageBus {
|
|||||||
|
|
||||||
export function spawnWebWorker(uri: string): MessageBus {
|
export function spawnWebWorker(uri: string): MessageBus {
|
||||||
var webWorker: Worker = new Worker(uri);
|
var webWorker: Worker = new Worker(uri);
|
||||||
return new UIMessageBus(new UIMessageBusSink(webWorker), new UIMessageBusSource(webWorker));
|
var sink = new PostMessageBusSink(webWorker);
|
||||||
}
|
var source = new PostMessageBusSource(webWorker);
|
||||||
|
return new PostMessageBus(sink, source);
|
||||||
export class UIMessageBus implements MessageBus {
|
|
||||||
constructor(public sink: UIMessageBusSink, public source: UIMessageBusSource) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class UIMessageBusSink implements MessageBusSink {
|
|
||||||
constructor(private _webWorker: Worker) {}
|
|
||||||
|
|
||||||
send(message: Object): void { this._webWorker.postMessage(message); }
|
|
||||||
}
|
|
||||||
|
|
||||||
export class UIMessageBusSource implements MessageBusSource {
|
|
||||||
private _listenerStore: Map<int, SourceListener> = new Map<int, SourceListener>();
|
|
||||||
private _numListeners: int = 0;
|
|
||||||
|
|
||||||
constructor(private _webWorker: Worker) {}
|
|
||||||
|
|
||||||
public addListener(fn: SourceListener): int {
|
|
||||||
this._webWorker.addEventListener("message", fn);
|
|
||||||
this._listenerStore[++this._numListeners] = fn;
|
|
||||||
return this._numListeners;
|
|
||||||
}
|
|
||||||
|
|
||||||
public removeListener(index: int): void {
|
|
||||||
removeEventListener("message", this._listenerStore[index]);
|
|
||||||
this._listenerStore.delete(index);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,11 @@ import {
|
|||||||
} from 'angular2/src/web-workers/shared/render_view_with_fragments_store';
|
} from 'angular2/src/web-workers/shared/render_view_with_fragments_store';
|
||||||
import {AnchorBasedAppRootUrl} from 'angular2/src/services/anchor_based_app_root_url';
|
import {AnchorBasedAppRootUrl} from 'angular2/src/services/anchor_based_app_root_url';
|
||||||
import {WebWorkerMain} from 'angular2/src/web-workers/ui/impl';
|
import {WebWorkerMain} from 'angular2/src/web-workers/ui/impl';
|
||||||
|
import {MessageBus, MessageBusInterface} from 'angular2/src/web-workers/shared/message_bus';
|
||||||
|
import {MessageBasedRenderCompiler} from 'angular2/src/web-workers/ui/render_compiler';
|
||||||
|
import {MessageBasedRenderer} from 'angular2/src/web-workers/ui/renderer';
|
||||||
|
import {MessageBasedXHRImpl} from 'angular2/src/web-workers/ui/xhr_impl';
|
||||||
|
import {WebWorkerSetup} from 'angular2/src/web-workers/ui/setup';
|
||||||
|
|
||||||
var _rootInjector: Injector;
|
var _rootInjector: Injector;
|
||||||
|
|
||||||
@ -129,13 +134,18 @@ function _injectorBindings(): List<Type | Binding | List<any>> {
|
|||||||
Testability,
|
Testability,
|
||||||
AnchorBasedAppRootUrl,
|
AnchorBasedAppRootUrl,
|
||||||
bind(AppRootUrl).toAlias(AnchorBasedAppRootUrl),
|
bind(AppRootUrl).toAlias(AnchorBasedAppRootUrl),
|
||||||
WebWorkerMain
|
WebWorkerMain,
|
||||||
|
WebWorkerSetup,
|
||||||
|
MessageBasedRenderCompiler,
|
||||||
|
MessageBasedXHRImpl,
|
||||||
|
MessageBasedRenderer
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createInjector(zone: NgZone): Injector {
|
export function createInjector(zone: NgZone, bus: MessageBusInterface): Injector {
|
||||||
BrowserDomAdapter.makeCurrent();
|
BrowserDomAdapter.makeCurrent();
|
||||||
_rootBindings.push(bind(NgZone).toValue(zone));
|
_rootBindings.push(bind(NgZone).toValue(zone));
|
||||||
|
_rootBindings.push(bind(MessageBus).toValue(bus));
|
||||||
var injector: Injector = Injector.resolveAndCreate(_rootBindings);
|
var injector: Injector = Injector.resolveAndCreate(_rootBindings);
|
||||||
return injector.resolveAndCreateChild(_injectorBindings());
|
return injector.resolveAndCreateChild(_injectorBindings());
|
||||||
}
|
}
|
||||||
|
110
modules/angular2/src/web-workers/ui/event_dispatcher.ts
Normal file
110
modules/angular2/src/web-workers/ui/event_dispatcher.ts
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
import {
|
||||||
|
RenderViewRef,
|
||||||
|
RenderEventDispatcher,
|
||||||
|
} from 'angular2/src/render/api';
|
||||||
|
import {Serializer} from 'angular2/src/web-workers/shared/serializer';
|
||||||
|
import {
|
||||||
|
serializeMouseEvent,
|
||||||
|
serializeKeyboardEvent,
|
||||||
|
serializeGenericEvent,
|
||||||
|
serializeEventWithTarget
|
||||||
|
} from 'angular2/src/web-workers/ui/event_serializer';
|
||||||
|
import {BaseException} from "angular2/src/facade/lang";
|
||||||
|
import {StringMapWrapper} from 'angular2/src/facade/collection';
|
||||||
|
import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
|
||||||
|
|
||||||
|
export class EventDispatcher implements RenderEventDispatcher {
|
||||||
|
constructor(private _viewRef: RenderViewRef, private _sink: EventEmitter,
|
||||||
|
private _serializer: Serializer) {}
|
||||||
|
|
||||||
|
dispatchRenderEvent(elementIndex: number, eventName: string, locals: Map<string, any>) {
|
||||||
|
var e = locals.get('$event');
|
||||||
|
var serializedEvent;
|
||||||
|
// TODO (jteplitz602): support custom events #3350
|
||||||
|
switch (e.type) {
|
||||||
|
case "click":
|
||||||
|
case "mouseup":
|
||||||
|
case "mousedown":
|
||||||
|
case "dblclick":
|
||||||
|
case "contextmenu":
|
||||||
|
case "mouseenter":
|
||||||
|
case "mouseleave":
|
||||||
|
case "mousemove":
|
||||||
|
case "mouseout":
|
||||||
|
case "mouseover":
|
||||||
|
case "show":
|
||||||
|
serializedEvent = serializeMouseEvent(e);
|
||||||
|
break;
|
||||||
|
case "keydown":
|
||||||
|
case "keypress":
|
||||||
|
case "keyup":
|
||||||
|
serializedEvent = serializeKeyboardEvent(e);
|
||||||
|
break;
|
||||||
|
case "input":
|
||||||
|
case "change":
|
||||||
|
case "blur":
|
||||||
|
serializedEvent = serializeEventWithTarget(e);
|
||||||
|
break;
|
||||||
|
case "abort":
|
||||||
|
case "afterprint":
|
||||||
|
case "beforeprint":
|
||||||
|
case "cached":
|
||||||
|
case "canplay":
|
||||||
|
case "canplaythrough":
|
||||||
|
case "chargingchange":
|
||||||
|
case "chargingtimechange":
|
||||||
|
case "close":
|
||||||
|
case "dischargingtimechange":
|
||||||
|
case "DOMContentLoaded":
|
||||||
|
case "downloading":
|
||||||
|
case "durationchange":
|
||||||
|
case "emptied":
|
||||||
|
case "ended":
|
||||||
|
case "error":
|
||||||
|
case "fullscreenchange":
|
||||||
|
case "fullscreenerror":
|
||||||
|
case "invalid":
|
||||||
|
case "languagechange":
|
||||||
|
case "levelfchange":
|
||||||
|
case "loadeddata":
|
||||||
|
case "loadedmetadata":
|
||||||
|
case "obsolete":
|
||||||
|
case "offline":
|
||||||
|
case "online":
|
||||||
|
case "open":
|
||||||
|
case "orientatoinchange":
|
||||||
|
case "pause":
|
||||||
|
case "pointerlockchange":
|
||||||
|
case "pointerlockerror":
|
||||||
|
case "play":
|
||||||
|
case "playing":
|
||||||
|
case "ratechange":
|
||||||
|
case "readystatechange":
|
||||||
|
case "reset":
|
||||||
|
case "seeked":
|
||||||
|
case "seeking":
|
||||||
|
case "stalled":
|
||||||
|
case "submit":
|
||||||
|
case "success":
|
||||||
|
case "suspend":
|
||||||
|
case "timeupdate":
|
||||||
|
case "updateready":
|
||||||
|
case "visibilitychange":
|
||||||
|
case "volumechange":
|
||||||
|
case "waiting":
|
||||||
|
serializedEvent = serializeGenericEvent(e);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new BaseException(eventName + " not supported on WebWorkers");
|
||||||
|
}
|
||||||
|
var serializedLocals = StringMapWrapper.create();
|
||||||
|
StringMapWrapper.set(serializedLocals, '$event', serializedEvent);
|
||||||
|
|
||||||
|
ObservableWrapper.callNext(this._sink, {
|
||||||
|
"viewRef": this._serializer.serialize(this._viewRef, RenderViewRef),
|
||||||
|
"elementIndex": elementIndex,
|
||||||
|
"eventName": eventName,
|
||||||
|
"locals": serializedLocals
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -6,39 +6,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {createInjector} from "./di_bindings";
|
import {createInjector} from "./di_bindings";
|
||||||
import {
|
|
||||||
Renderer,
|
|
||||||
RenderCompiler,
|
|
||||||
RenderDirectiveMetadata,
|
|
||||||
ProtoViewDto,
|
|
||||||
ViewDefinition,
|
|
||||||
RenderProtoViewRef,
|
|
||||||
RenderProtoViewMergeMapping,
|
|
||||||
RenderViewRef,
|
|
||||||
RenderEventDispatcher,
|
|
||||||
RenderFragmentRef
|
|
||||||
} from "angular2/src/render/api";
|
|
||||||
import {Type, print, BaseException, isFunction} from "angular2/src/facade/lang";
|
|
||||||
import {Promise, PromiseWrapper} from "angular2/src/facade/async";
|
|
||||||
import {StringMapWrapper, SetWrapper} from 'angular2/src/facade/collection';
|
|
||||||
import {Serializer} from "angular2/src/web-workers/shared/serializer";
|
|
||||||
import {MessageBus, MessageBusSink} from "angular2/src/web-workers/shared/message_bus";
|
import {MessageBus, MessageBusSink} from "angular2/src/web-workers/shared/message_bus";
|
||||||
import {
|
|
||||||
RenderViewWithFragmentsStore
|
|
||||||
} from 'angular2/src/web-workers/shared/render_view_with_fragments_store';
|
|
||||||
import {createNgZone} from 'angular2/src/core/application_common';
|
import {createNgZone} from 'angular2/src/core/application_common';
|
||||||
import {WebWorkerElementRef} from 'angular2/src/web-workers/shared/api';
|
|
||||||
import {AnchorBasedAppRootUrl} from 'angular2/src/services/anchor_based_app_root_url';
|
|
||||||
import {Injectable} from 'angular2/di';
|
import {Injectable} from 'angular2/di';
|
||||||
import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter';
|
import {BrowserDomAdapter} from 'angular2/src/dom/browser_adapter';
|
||||||
import {XHR} from 'angular2/src/render/xhr';
|
|
||||||
import {
|
|
||||||
serializeMouseEvent,
|
|
||||||
serializeKeyboardEvent,
|
|
||||||
serializeGenericEvent,
|
|
||||||
serializeEventWithTarget
|
|
||||||
} from 'angular2/src/web-workers/ui/event_serializer';
|
|
||||||
import {wtfInit} from 'angular2/src/profile/wtf_init';
|
import {wtfInit} from 'angular2/src/profile/wtf_init';
|
||||||
|
import {WebWorkerSetup} from 'angular2/src/web-workers/ui/setup';
|
||||||
|
import {MessageBasedRenderCompiler} from 'angular2/src/web-workers/ui/render_compiler';
|
||||||
|
import {MessageBasedRenderer} from 'angular2/src/web-workers/ui/renderer';
|
||||||
|
import {MessageBasedXHRImpl} from 'angular2/src/web-workers/ui/xhr_impl';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a zone, sets up the DI bindings
|
* Creates a zone, sets up the DI bindings
|
||||||
@ -49,305 +25,20 @@ export function bootstrapUICommon(bus: MessageBus) {
|
|||||||
var zone = createNgZone();
|
var zone = createNgZone();
|
||||||
wtfInit();
|
wtfInit();
|
||||||
zone.run(() => {
|
zone.run(() => {
|
||||||
var injector = createInjector(zone);
|
var injector = createInjector(zone, bus);
|
||||||
var webWorkerMain = injector.get(WebWorkerMain);
|
// necessary to kick off all the message based components
|
||||||
webWorkerMain.attachToWebWorker(bus);
|
injector.get(WebWorkerMain);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WebWorkerMain {
|
export class WebWorkerMain {
|
||||||
private _rootUrl: string;
|
constructor(public renderCompiler: MessageBasedRenderCompiler,
|
||||||
private _bus: MessageBus;
|
public renderer: MessageBasedRenderer, public xhr: MessageBasedXHRImpl,
|
||||||
|
public setup: WebWorkerSetup) {}
|
||||||
constructor(private _renderCompiler: RenderCompiler, private _renderer: Renderer,
|
|
||||||
private _renderViewWithFragmentsStore: RenderViewWithFragmentsStore,
|
|
||||||
private _serializer: Serializer, rootUrl: AnchorBasedAppRootUrl, private _xhr: XHR) {
|
|
||||||
this._rootUrl = rootUrl.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Attach's this WebWorkerMain instance to the given MessageBus
|
|
||||||
* This instance will now listen for all messages from the worker and handle them appropriately
|
|
||||||
* Note: Don't attach more than one WebWorkerMain instance to the same MessageBus.
|
|
||||||
*/
|
|
||||||
attachToWebWorker(bus: MessageBus) {
|
|
||||||
this._bus = bus;
|
|
||||||
this._bus.source.addListener((message) => { this._handleWebWorkerMessage(message); });
|
|
||||||
}
|
|
||||||
|
|
||||||
private _sendInitMessage() { this._sendWebWorkerMessage("init", {"rootUrl": this._rootUrl}); }
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Sends an error back to the worker thread in response to an opeartion on the UI thread
|
|
||||||
*/
|
|
||||||
private _sendWebWorkerError(id: string, error: any) {
|
|
||||||
this._sendWebWorkerMessage("error", {"error": error}, id);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _sendWebWorkerMessage(type: string, value: StringMap<string, any>, id?: string) {
|
|
||||||
this._bus.sink.send({'type': type, 'id': id, 'value': value});
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Transfer the types with the serialized data so this can be automated?
|
|
||||||
private _handleCompilerMessage(data: ReceivedMessage) {
|
|
||||||
var promise: Promise<any>;
|
|
||||||
switch (data.method) {
|
|
||||||
case "compileHost":
|
|
||||||
var directiveMetadata = this._serializer.deserialize(data.args[0], RenderDirectiveMetadata);
|
|
||||||
promise = this._renderCompiler.compileHost(directiveMetadata);
|
|
||||||
this._wrapWebWorkerPromise(data.id, promise, ProtoViewDto);
|
|
||||||
break;
|
|
||||||
case "compile":
|
|
||||||
var view = this._serializer.deserialize(data.args[0], ViewDefinition);
|
|
||||||
promise = this._renderCompiler.compile(view);
|
|
||||||
this._wrapWebWorkerPromise(data.id, promise, ProtoViewDto);
|
|
||||||
break;
|
|
||||||
case "mergeProtoViewsRecursively":
|
|
||||||
var views = this._serializer.deserialize(data.args[0], RenderProtoViewRef);
|
|
||||||
promise = this._renderCompiler.mergeProtoViewsRecursively(views);
|
|
||||||
this._wrapWebWorkerPromise(data.id, promise, RenderProtoViewMergeMapping);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new BaseException("not implemented");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _createViewHelper(args: List<any>, method) {
|
|
||||||
var hostProtoView = this._serializer.deserialize(args[0], RenderProtoViewRef);
|
|
||||||
var fragmentCount = args[1];
|
|
||||||
var startIndex, renderViewWithFragments;
|
|
||||||
if (method == "createView") {
|
|
||||||
startIndex = args[2];
|
|
||||||
renderViewWithFragments = this._renderer.createView(hostProtoView, fragmentCount);
|
|
||||||
} else {
|
|
||||||
var selector = args[2];
|
|
||||||
startIndex = args[3];
|
|
||||||
renderViewWithFragments =
|
|
||||||
this._renderer.createRootHostView(hostProtoView, fragmentCount, selector);
|
|
||||||
}
|
|
||||||
this._renderViewWithFragmentsStore.store(renderViewWithFragments, startIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _handleRendererMessage(data: ReceivedMessage) {
|
|
||||||
var args = data.args;
|
|
||||||
switch (data.method) {
|
|
||||||
case "createRootHostView":
|
|
||||||
case "createView":
|
|
||||||
this._createViewHelper(args, data.method);
|
|
||||||
break;
|
|
||||||
case "destroyView":
|
|
||||||
var viewRef = this._serializer.deserialize(args[0], RenderViewRef);
|
|
||||||
this._renderer.destroyView(viewRef);
|
|
||||||
break;
|
|
||||||
case "attachFragmentAfterFragment":
|
|
||||||
var previousFragment = this._serializer.deserialize(args[0], RenderFragmentRef);
|
|
||||||
var fragment = this._serializer.deserialize(args[1], RenderFragmentRef);
|
|
||||||
this._renderer.attachFragmentAfterFragment(previousFragment, fragment);
|
|
||||||
break;
|
|
||||||
case "attachFragmentAfterElement":
|
|
||||||
var element = this._serializer.deserialize(args[0], WebWorkerElementRef);
|
|
||||||
var fragment = this._serializer.deserialize(args[1], RenderFragmentRef);
|
|
||||||
this._renderer.attachFragmentAfterElement(element, fragment);
|
|
||||||
break;
|
|
||||||
case "detachFragment":
|
|
||||||
var fragment = this._serializer.deserialize(args[0], RenderFragmentRef);
|
|
||||||
this._renderer.detachFragment(fragment);
|
|
||||||
break;
|
|
||||||
case "hydrateView":
|
|
||||||
var viewRef = this._serializer.deserialize(args[0], RenderViewRef);
|
|
||||||
this._renderer.hydrateView(viewRef);
|
|
||||||
break;
|
|
||||||
case "dehydrateView":
|
|
||||||
var viewRef = this._serializer.deserialize(args[0], RenderViewRef);
|
|
||||||
this._renderer.dehydrateView(viewRef);
|
|
||||||
break;
|
|
||||||
case "setText":
|
|
||||||
var viewRef = this._serializer.deserialize(args[0], RenderViewRef);
|
|
||||||
var textNodeIndex = args[1];
|
|
||||||
var text = args[2];
|
|
||||||
this._renderer.setText(viewRef, textNodeIndex, text);
|
|
||||||
break;
|
|
||||||
case "setElementProperty":
|
|
||||||
var elementRef = this._serializer.deserialize(args[0], WebWorkerElementRef);
|
|
||||||
var propName = args[1];
|
|
||||||
var propValue = args[2];
|
|
||||||
this._renderer.setElementProperty(elementRef, propName, propValue);
|
|
||||||
break;
|
|
||||||
case "setElementAttribute":
|
|
||||||
var elementRef = this._serializer.deserialize(args[0], WebWorkerElementRef);
|
|
||||||
var attributeName = args[1];
|
|
||||||
var attributeValue = args[2];
|
|
||||||
this._renderer.setElementAttribute(elementRef, attributeName, attributeValue);
|
|
||||||
break;
|
|
||||||
case "setElementClass":
|
|
||||||
var elementRef = this._serializer.deserialize(args[0], WebWorkerElementRef);
|
|
||||||
var className = args[1];
|
|
||||||
var isAdd = args[2];
|
|
||||||
this._renderer.setElementClass(elementRef, className, isAdd);
|
|
||||||
break;
|
|
||||||
case "setElementStyle":
|
|
||||||
var elementRef = this._serializer.deserialize(args[0], WebWorkerElementRef);
|
|
||||||
var styleName = args[1];
|
|
||||||
var styleValue = args[2];
|
|
||||||
this._renderer.setElementStyle(elementRef, styleName, styleValue);
|
|
||||||
break;
|
|
||||||
case "invokeElementMethod":
|
|
||||||
var elementRef = this._serializer.deserialize(args[0], WebWorkerElementRef);
|
|
||||||
var methodName = args[1];
|
|
||||||
var methodArgs = args[2];
|
|
||||||
this._renderer.invokeElementMethod(elementRef, methodName, methodArgs);
|
|
||||||
break;
|
|
||||||
case "setEventDispatcher":
|
|
||||||
var viewRef = this._serializer.deserialize(args[0], RenderViewRef);
|
|
||||||
var dispatcher = new EventDispatcher(viewRef, this._bus.sink, this._serializer);
|
|
||||||
this._renderer.setEventDispatcher(viewRef, dispatcher);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new BaseException("Not Implemented");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _handleXhrMessage(data: ReceivedMessage) {
|
|
||||||
var args = data.args;
|
|
||||||
switch (data.method) {
|
|
||||||
case "get":
|
|
||||||
var url = args[0];
|
|
||||||
var promise = this._xhr.get(url);
|
|
||||||
this._wrapWebWorkerPromise(data.id, promise, String);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new BaseException(data.method + " Not Implemented");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(jteplitz602): Create message type enum #3044
|
|
||||||
private _handleWebWorkerMessage(message: StringMap<string, any>) {
|
|
||||||
var data: ReceivedMessage = new ReceivedMessage(message['data']);
|
|
||||||
// TODO(jteplitz602): Replace these with MessageBUs channels #3661
|
|
||||||
switch (data.type) {
|
|
||||||
case "ready":
|
|
||||||
return this._sendInitMessage();
|
|
||||||
case "compiler":
|
|
||||||
return this._handleCompilerMessage(data);
|
|
||||||
case "renderer":
|
|
||||||
return this._handleRendererMessage(data);
|
|
||||||
case "xhr":
|
|
||||||
return this._handleXhrMessage(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private _wrapWebWorkerPromise(id: string, promise: Promise<any>, type: Type): void {
|
|
||||||
PromiseWrapper.then(promise, (result: any) => {
|
|
||||||
try {
|
|
||||||
this._sendWebWorkerMessage("result", this._serializer.serialize(result, type), id);
|
|
||||||
} catch (e) {
|
|
||||||
print(e);
|
|
||||||
}
|
|
||||||
}, (error: any) => { this._sendWebWorkerError(id, error); });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class EventDispatcher implements RenderEventDispatcher {
|
export class ReceivedMessage {
|
||||||
constructor(private _viewRef: RenderViewRef, private _sink: MessageBusSink,
|
|
||||||
private _serializer: Serializer) {}
|
|
||||||
|
|
||||||
dispatchRenderEvent(elementIndex: number, eventName: string, locals: Map<string, any>) {
|
|
||||||
var e = locals.get('$event');
|
|
||||||
var serializedEvent;
|
|
||||||
// TODO (jteplitz602): support custom events #3350
|
|
||||||
switch (e.type) {
|
|
||||||
case "click":
|
|
||||||
case "mouseup":
|
|
||||||
case "mousedown":
|
|
||||||
case "dblclick":
|
|
||||||
case "contextmenu":
|
|
||||||
case "mouseenter":
|
|
||||||
case "mouseleave":
|
|
||||||
case "mousemove":
|
|
||||||
case "mouseout":
|
|
||||||
case "mouseover":
|
|
||||||
case "show":
|
|
||||||
serializedEvent = serializeMouseEvent(e);
|
|
||||||
break;
|
|
||||||
case "keydown":
|
|
||||||
case "keypress":
|
|
||||||
case "keyup":
|
|
||||||
serializedEvent = serializeKeyboardEvent(e);
|
|
||||||
break;
|
|
||||||
case "input":
|
|
||||||
case "change":
|
|
||||||
case "blur":
|
|
||||||
serializedEvent = serializeEventWithTarget(e);
|
|
||||||
break;
|
|
||||||
case "abort":
|
|
||||||
case "afterprint":
|
|
||||||
case "beforeprint":
|
|
||||||
case "cached":
|
|
||||||
case "canplay":
|
|
||||||
case "canplaythrough":
|
|
||||||
case "chargingchange":
|
|
||||||
case "chargingtimechange":
|
|
||||||
case "close":
|
|
||||||
case "dischargingtimechange":
|
|
||||||
case "DOMContentLoaded":
|
|
||||||
case "downloading":
|
|
||||||
case "durationchange":
|
|
||||||
case "emptied":
|
|
||||||
case "ended":
|
|
||||||
case "error":
|
|
||||||
case "fullscreenchange":
|
|
||||||
case "fullscreenerror":
|
|
||||||
case "invalid":
|
|
||||||
case "languagechange":
|
|
||||||
case "levelfchange":
|
|
||||||
case "loadeddata":
|
|
||||||
case "loadedmetadata":
|
|
||||||
case "obsolete":
|
|
||||||
case "offline":
|
|
||||||
case "online":
|
|
||||||
case "open":
|
|
||||||
case "orientatoinchange":
|
|
||||||
case "pause":
|
|
||||||
case "pointerlockchange":
|
|
||||||
case "pointerlockerror":
|
|
||||||
case "play":
|
|
||||||
case "playing":
|
|
||||||
case "ratechange":
|
|
||||||
case "readystatechange":
|
|
||||||
case "reset":
|
|
||||||
case "seeked":
|
|
||||||
case "seeking":
|
|
||||||
case "stalled":
|
|
||||||
case "submit":
|
|
||||||
case "success":
|
|
||||||
case "suspend":
|
|
||||||
case "timeupdate":
|
|
||||||
case "updateready":
|
|
||||||
case "visibilitychange":
|
|
||||||
case "volumechange":
|
|
||||||
case "waiting":
|
|
||||||
serializedEvent = serializeGenericEvent(e);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new BaseException(eventName + " not supported on WebWorkers");
|
|
||||||
}
|
|
||||||
var serializedLocals = StringMapWrapper.create();
|
|
||||||
StringMapWrapper.set(serializedLocals, '$event', serializedEvent);
|
|
||||||
|
|
||||||
this._sink.send({
|
|
||||||
"type": "event",
|
|
||||||
"value": {
|
|
||||||
"viewRef": this._serializer.serialize(this._viewRef, RenderViewRef),
|
|
||||||
"elementIndex": elementIndex,
|
|
||||||
"eventName": eventName,
|
|
||||||
"locals": serializedLocals
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ReceivedMessage {
|
|
||||||
method: string;
|
method: string;
|
||||||
args: List<any>;
|
args: List<any>;
|
||||||
id: string;
|
id: string;
|
||||||
|
63
modules/angular2/src/web-workers/ui/render_compiler.ts
Normal file
63
modules/angular2/src/web-workers/ui/render_compiler.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import {Injectable} from 'angular2/di';
|
||||||
|
import {MessageBus} from 'angular2/src/web-workers/shared/message_bus';
|
||||||
|
import {Serializer} from 'angular2/src/web-workers/shared/serializer';
|
||||||
|
import {
|
||||||
|
RenderDirectiveMetadata,
|
||||||
|
ProtoViewDto,
|
||||||
|
ViewDefinition,
|
||||||
|
RenderProtoViewRef,
|
||||||
|
RenderProtoViewMergeMapping,
|
||||||
|
RenderCompiler
|
||||||
|
} from 'angular2/src/render/api';
|
||||||
|
import {EventEmitter, ObservableWrapper, PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||||
|
import {RENDER_COMPILER_CHANNEL} from 'angular2/src/web-workers/shared/messaging_api';
|
||||||
|
import {ReceivedMessage} from 'angular2/src/web-workers/ui/impl';
|
||||||
|
import {BaseException, Type} from 'angular2/src/facade/lang';
|
||||||
|
|
||||||
|
// TODO(jteplitz602): Create parent UIComponent class #3703
|
||||||
|
@Injectable()
|
||||||
|
export class MessageBasedRenderCompiler {
|
||||||
|
private _sink: EventEmitter;
|
||||||
|
private _source: EventEmitter;
|
||||||
|
|
||||||
|
constructor(bus: MessageBus, private _serializer: Serializer,
|
||||||
|
private _renderCompiler: RenderCompiler) {
|
||||||
|
this._sink = bus.to(RENDER_COMPILER_CHANNEL);
|
||||||
|
this._source = bus.from(RENDER_COMPILER_CHANNEL);
|
||||||
|
ObservableWrapper.subscribe(this._source,
|
||||||
|
(message: StringMap<string, any>) => this._handleMessage(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleMessage(map: StringMap<string, any>): void {
|
||||||
|
var message = new ReceivedMessage(map);
|
||||||
|
var args = message.args;
|
||||||
|
var promise: Promise<any>;
|
||||||
|
switch (message.method) {
|
||||||
|
case "compileHost":
|
||||||
|
var directiveMetadata = this._serializer.deserialize(args[0], RenderDirectiveMetadata);
|
||||||
|
promise = this._renderCompiler.compileHost(directiveMetadata);
|
||||||
|
this._wrapWebWorkerPromise(message.id, promise, ProtoViewDto);
|
||||||
|
break;
|
||||||
|
case "compile":
|
||||||
|
var view = this._serializer.deserialize(args[0], ViewDefinition);
|
||||||
|
promise = this._renderCompiler.compile(view);
|
||||||
|
this._wrapWebWorkerPromise(message.id, promise, ProtoViewDto);
|
||||||
|
break;
|
||||||
|
case "mergeProtoViewsRecursively":
|
||||||
|
var views = this._serializer.deserialize(args[0], RenderProtoViewRef);
|
||||||
|
promise = this._renderCompiler.mergeProtoViewsRecursively(views);
|
||||||
|
this._wrapWebWorkerPromise(message.id, promise, RenderProtoViewMergeMapping);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new BaseException("not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _wrapWebWorkerPromise(id: string, promise: Promise<any>, type: Type): void {
|
||||||
|
PromiseWrapper.then(promise, (result: any) => {
|
||||||
|
ObservableWrapper.callNext(
|
||||||
|
this._sink,
|
||||||
|
{'type': 'result', 'value': this._serializer.serialize(result, type), 'id': id});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
127
modules/angular2/src/web-workers/ui/renderer.ts
Normal file
127
modules/angular2/src/web-workers/ui/renderer.ts
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
import {Injectable} from 'angular2/di';
|
||||||
|
import {MessageBus} from 'angular2/src/web-workers/shared/message_bus';
|
||||||
|
import {Serializer} from 'angular2/src/web-workers/shared/serializer';
|
||||||
|
import {
|
||||||
|
RenderViewRef,
|
||||||
|
RenderFragmentRef,
|
||||||
|
RenderProtoViewRef,
|
||||||
|
Renderer
|
||||||
|
} from 'angular2/src/render/api';
|
||||||
|
import {WebWorkerElementRef} from 'angular2/src/web-workers/shared/api';
|
||||||
|
import {EventEmitter, ObservableWrapper, PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||||
|
import {EVENT_CHANNEL, RENDERER_CHANNEL} from 'angular2/src/web-workers/shared/messaging_api';
|
||||||
|
import {ReceivedMessage} from 'angular2/src/web-workers/ui/impl';
|
||||||
|
import {BaseException, Type} from 'angular2/src/facade/lang';
|
||||||
|
import {EventDispatcher} from 'angular2/src/web-workers/ui/event_dispatcher';
|
||||||
|
import {
|
||||||
|
RenderViewWithFragmentsStore
|
||||||
|
} from 'angular2/src/web-workers/shared/render_view_with_fragments_store';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class MessageBasedRenderer {
|
||||||
|
constructor(private _bus: MessageBus, private _serializer: Serializer,
|
||||||
|
private _renderViewWithFragmentsStore: RenderViewWithFragmentsStore,
|
||||||
|
private _renderer: Renderer) {
|
||||||
|
var source = _bus.from(RENDERER_CHANNEL);
|
||||||
|
ObservableWrapper.subscribe(source,
|
||||||
|
(message: StringMap<string, any>) => this._handleMessage(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
private _createViewHelper(args: List<any>, method) {
|
||||||
|
var hostProtoView = this._serializer.deserialize(args[0], RenderProtoViewRef);
|
||||||
|
var fragmentCount = args[1];
|
||||||
|
var startIndex, renderViewWithFragments;
|
||||||
|
if (method == "createView") {
|
||||||
|
startIndex = args[2];
|
||||||
|
renderViewWithFragments = this._renderer.createView(hostProtoView, fragmentCount);
|
||||||
|
} else {
|
||||||
|
var selector = args[2];
|
||||||
|
startIndex = args[3];
|
||||||
|
renderViewWithFragments =
|
||||||
|
this._renderer.createRootHostView(hostProtoView, fragmentCount, selector);
|
||||||
|
}
|
||||||
|
this._renderViewWithFragmentsStore.store(renderViewWithFragments, startIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private _handleMessage(map: StringMap<string, any>): void {
|
||||||
|
var data = new ReceivedMessage(map);
|
||||||
|
var args = data.args;
|
||||||
|
switch (data.method) {
|
||||||
|
case "createRootHostView":
|
||||||
|
case "createView":
|
||||||
|
this._createViewHelper(args, data.method);
|
||||||
|
break;
|
||||||
|
case "destroyView":
|
||||||
|
var viewRef = this._serializer.deserialize(args[0], RenderViewRef);
|
||||||
|
this._renderer.destroyView(viewRef);
|
||||||
|
break;
|
||||||
|
case "attachFragmentAfterFragment":
|
||||||
|
var previousFragment = this._serializer.deserialize(args[0], RenderFragmentRef);
|
||||||
|
var fragment = this._serializer.deserialize(args[1], RenderFragmentRef);
|
||||||
|
this._renderer.attachFragmentAfterFragment(previousFragment, fragment);
|
||||||
|
break;
|
||||||
|
case "attachFragmentAfterElement":
|
||||||
|
var element = this._serializer.deserialize(args[0], WebWorkerElementRef);
|
||||||
|
var fragment = this._serializer.deserialize(args[1], RenderFragmentRef);
|
||||||
|
this._renderer.attachFragmentAfterElement(element, fragment);
|
||||||
|
break;
|
||||||
|
case "detachFragment":
|
||||||
|
var fragment = this._serializer.deserialize(args[0], RenderFragmentRef);
|
||||||
|
this._renderer.detachFragment(fragment);
|
||||||
|
break;
|
||||||
|
case "hydrateView":
|
||||||
|
var viewRef = this._serializer.deserialize(args[0], RenderViewRef);
|
||||||
|
this._renderer.hydrateView(viewRef);
|
||||||
|
break;
|
||||||
|
case "dehydrateView":
|
||||||
|
var viewRef = this._serializer.deserialize(args[0], RenderViewRef);
|
||||||
|
this._renderer.dehydrateView(viewRef);
|
||||||
|
break;
|
||||||
|
case "setText":
|
||||||
|
var viewRef = this._serializer.deserialize(args[0], RenderViewRef);
|
||||||
|
var textNodeIndex = args[1];
|
||||||
|
var text = args[2];
|
||||||
|
this._renderer.setText(viewRef, textNodeIndex, text);
|
||||||
|
break;
|
||||||
|
case "setElementProperty":
|
||||||
|
var elementRef = this._serializer.deserialize(args[0], WebWorkerElementRef);
|
||||||
|
var propName = args[1];
|
||||||
|
var propValue = args[2];
|
||||||
|
this._renderer.setElementProperty(elementRef, propName, propValue);
|
||||||
|
break;
|
||||||
|
case "setElementAttribute":
|
||||||
|
var elementRef = this._serializer.deserialize(args[0], WebWorkerElementRef);
|
||||||
|
var attributeName = args[1];
|
||||||
|
var attributeValue = args[2];
|
||||||
|
this._renderer.setElementAttribute(elementRef, attributeName, attributeValue);
|
||||||
|
break;
|
||||||
|
case "setElementClass":
|
||||||
|
var elementRef = this._serializer.deserialize(args[0], WebWorkerElementRef);
|
||||||
|
var className = args[1];
|
||||||
|
var isAdd = args[2];
|
||||||
|
this._renderer.setElementClass(elementRef, className, isAdd);
|
||||||
|
break;
|
||||||
|
case "setElementStyle":
|
||||||
|
var elementRef = this._serializer.deserialize(args[0], WebWorkerElementRef);
|
||||||
|
var styleName = args[1];
|
||||||
|
var styleValue = args[2];
|
||||||
|
this._renderer.setElementStyle(elementRef, styleName, styleValue);
|
||||||
|
break;
|
||||||
|
case "invokeElementMethod":
|
||||||
|
var elementRef = this._serializer.deserialize(args[0], WebWorkerElementRef);
|
||||||
|
var methodName = args[1];
|
||||||
|
var methodArgs = args[2];
|
||||||
|
this._renderer.invokeElementMethod(elementRef, methodName, methodArgs);
|
||||||
|
break;
|
||||||
|
case "setEventDispatcher":
|
||||||
|
var viewRef = this._serializer.deserialize(args[0], RenderViewRef);
|
||||||
|
var dispatcher =
|
||||||
|
new EventDispatcher(viewRef, this._bus.to(EVENT_CHANNEL), this._serializer);
|
||||||
|
this._renderer.setEventDispatcher(viewRef, dispatcher);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new BaseException("Not Implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
modules/angular2/src/web-workers/ui/setup.ts
Normal file
20
modules/angular2/src/web-workers/ui/setup.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import {SETUP_CHANNEL} from 'angular2/src/web-workers/shared/messaging_api';
|
||||||
|
import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
|
||||||
|
import {MessageBus} from 'angular2/src/web-workers/shared/message_bus';
|
||||||
|
import {AnchorBasedAppRootUrl} from 'angular2/src/services/anchor_based_app_root_url';
|
||||||
|
import {Injectable} from 'angular2/di';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class WebWorkerSetup {
|
||||||
|
constructor(bus: MessageBus, anchorBasedAppRootUrl: AnchorBasedAppRootUrl) {
|
||||||
|
var rootUrl = anchorBasedAppRootUrl.value;
|
||||||
|
var sink = bus.to(SETUP_CHANNEL);
|
||||||
|
var source = bus.from(SETUP_CHANNEL);
|
||||||
|
|
||||||
|
ObservableWrapper.subscribe(source, (message: string) => {
|
||||||
|
if (message === "ready") {
|
||||||
|
ObservableWrapper.callNext(sink, {"rootUrl": rootUrl});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
44
modules/angular2/src/web-workers/ui/xhr_impl.ts
Normal file
44
modules/angular2/src/web-workers/ui/xhr_impl.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import {Injectable} from 'angular2/di';
|
||||||
|
import {MessageBus} from 'angular2/src/web-workers/shared/message_bus';
|
||||||
|
import {Serializer} from 'angular2/src/web-workers/shared/serializer';
|
||||||
|
import {EventEmitter, ObservableWrapper, PromiseWrapper, Promise} from 'angular2/src/facade/async';
|
||||||
|
import {XHR_CHANNEL} from 'angular2/src/web-workers/shared/messaging_api';
|
||||||
|
import {ReceivedMessage} from 'angular2/src/web-workers/ui/impl';
|
||||||
|
import {BaseException, Type} from 'angular2/src/facade/lang';
|
||||||
|
import {XHR} from 'angular2/src/render/xhr';
|
||||||
|
|
||||||
|
// TODO(jteplitz602): Create parent UIComponent class #3703
|
||||||
|
@Injectable()
|
||||||
|
export class MessageBasedXHRImpl {
|
||||||
|
private _sink: EventEmitter;
|
||||||
|
private _source: EventEmitter;
|
||||||
|
|
||||||
|
constructor(bus: MessageBus, private _serializer: Serializer, private _xhr: XHR) {
|
||||||
|
this._sink = bus.to(XHR_CHANNEL);
|
||||||
|
this._source = bus.from(XHR_CHANNEL);
|
||||||
|
ObservableWrapper.subscribe(this._source,
|
||||||
|
(message: StringMap<string, any>) => this._handleMessage(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleMessage(map: StringMap<string, any>) {
|
||||||
|
var message = new ReceivedMessage(map);
|
||||||
|
var args = message.args;
|
||||||
|
switch (message.method) {
|
||||||
|
case "get":
|
||||||
|
var url = args[0];
|
||||||
|
var promise = this._xhr.get(url);
|
||||||
|
this._wrapWebWorkerPromise(message.id, promise, String);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new BaseException(message.method + " Not Implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _wrapWebWorkerPromise(id: string, promise: Promise<any>, type: Type): void {
|
||||||
|
PromiseWrapper.then(promise, (result: any) => {
|
||||||
|
ObservableWrapper.callNext(
|
||||||
|
this._sink,
|
||||||
|
{'type': 'result', 'value': this._serializer.serialize(result, type), 'id': id});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,6 @@
|
|||||||
library angular2.src.web_workers.worker;
|
library angular2.src.web_workers.worker;
|
||||||
|
|
||||||
import "package:angular2/src/web-workers/shared/message_bus.dart"
|
import "package:angular2/src/web-workers/shared/isolate_message_bus.dart";
|
||||||
show MessageBus, MessageBusSource, MessageBusSink;
|
|
||||||
import "package:angular2/src/web-workers/worker/application_common.dart"
|
import "package:angular2/src/web-workers/worker/application_common.dart"
|
||||||
show bootstrapWebWorkerCommon;
|
show bootstrapWebWorkerCommon;
|
||||||
import "package:angular2/src/facade/async.dart" show Future;
|
import "package:angular2/src/facade/async.dart" show Future;
|
||||||
@ -26,56 +25,15 @@ Future<ApplicationRef> bootstrapWebWorker(
|
|||||||
SendPort replyTo, Type appComponentType,
|
SendPort replyTo, Type appComponentType,
|
||||||
[List<dynamic> componentInjectableBindings = null]) {
|
[List<dynamic> componentInjectableBindings = null]) {
|
||||||
ReceivePort rPort = new ReceivePort();
|
ReceivePort rPort = new ReceivePort();
|
||||||
WebWorkerMessageBus bus = new WebWorkerMessageBus.fromPorts(replyTo, rPort);
|
var sink = new WebWorkerMessageBusSink(replyTo, rPort);
|
||||||
|
var source = new IsolateMessageBusSource(rPort);
|
||||||
|
IsolateMessageBus bus = new IsolateMessageBus(sink, source);
|
||||||
return bootstrapWebWorkerCommon(
|
return bootstrapWebWorkerCommon(
|
||||||
appComponentType, bus, componentInjectableBindings);
|
appComponentType, bus, componentInjectableBindings);
|
||||||
}
|
}
|
||||||
|
|
||||||
class WebWorkerMessageBus extends MessageBus {
|
class WebWorkerMessageBusSink extends IsolateMessageBusSink {
|
||||||
final WebWorkerMessageBusSink sink;
|
WebWorkerMessageBusSink(SendPort sPort, ReceivePort rPort) : super(sPort) {
|
||||||
final WebWorkerMessageBusSource source;
|
sPort.send(rPort.sendPort);
|
||||||
|
|
||||||
WebWorkerMessageBus(this.sink, this.source);
|
|
||||||
|
|
||||||
WebWorkerMessageBus.fromPorts(SendPort sPort, ReceivePort rPort)
|
|
||||||
: sink = new WebWorkerMessageBusSink(sPort, rPort),
|
|
||||||
source = new WebWorkerMessageBusSource(rPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
class WebWorkerMessageBusSink extends MessageBusSink {
|
|
||||||
final SendPort _port;
|
|
||||||
|
|
||||||
WebWorkerMessageBusSink(SendPort sPort, ReceivePort rPort) : _port = sPort {
|
|
||||||
this.send(rPort.sendPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
void send(dynamic message) {
|
|
||||||
this._port.send(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class WebWorkerMessageBusSource extends MessageBusSource {
|
|
||||||
final ReceivePort _port;
|
|
||||||
final Stream rawDataStream;
|
|
||||||
Map<int, StreamSubscription> _listenerStore =
|
|
||||||
new Map<int, StreamSubscription>();
|
|
||||||
int _numListeners = 0;
|
|
||||||
|
|
||||||
WebWorkerMessageBusSource(ReceivePort rPort)
|
|
||||||
: _port = rPort,
|
|
||||||
rawDataStream = rPort.asBroadcastStream();
|
|
||||||
|
|
||||||
int addListener(Function fn) {
|
|
||||||
var subscription = rawDataStream.listen((message) {
|
|
||||||
fn({"data": message});
|
|
||||||
});
|
|
||||||
|
|
||||||
_listenerStore[++_numListeners] = subscription;
|
|
||||||
return _numListeners;
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeListener(int index) {
|
|
||||||
_listenerStore[index].cancel();
|
|
||||||
_listenerStore.remove(index);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,21 @@
|
|||||||
import {
|
import {
|
||||||
MessageBus,
|
PostMessageBus,
|
||||||
MessageBusSource,
|
PostMessageBusSink,
|
||||||
MessageBusSink,
|
PostMessageBusSource
|
||||||
SourceListener
|
} from 'angular2/src/web-workers/shared/post_message_bus';
|
||||||
} from "angular2/src/web-workers/shared/message_bus";
|
|
||||||
import {Type, BaseException} from "angular2/src/facade/lang";
|
import {Type, BaseException} from "angular2/src/facade/lang";
|
||||||
import {Binding} from "angular2/di";
|
import {Binding} from "angular2/di";
|
||||||
|
import {Map} from 'angular2/src/facade/collection';
|
||||||
|
import {Promise} from 'angular2/src/facade/async';
|
||||||
import {bootstrapWebWorkerCommon} from "angular2/src/web-workers/worker/application_common";
|
import {bootstrapWebWorkerCommon} from "angular2/src/web-workers/worker/application_common";
|
||||||
import {ApplicationRef} from "angular2/src/core/application";
|
import {ApplicationRef} from "angular2/src/core/application";
|
||||||
import {Injectable} from "angular2/di";
|
import {Injectable} from "angular2/di";
|
||||||
|
|
||||||
// TODO(jteplitz602) remove this and compile with lib.webworker.d.ts (#3492)
|
// TODO(jteplitz602) remove this and compile with lib.webworker.d.ts (#3492)
|
||||||
var _postMessage: (message: any, transferrables?:[ArrayBuffer]) => void = <any>postMessage;
|
interface PostMessageInterface {
|
||||||
|
(message: any, transferrables?:[ArrayBuffer]): void;
|
||||||
|
}
|
||||||
|
var _postMessage: PostMessageInterface = <any>postMessage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bootstrapping a Webworker Application
|
* Bootstrapping a Webworker Application
|
||||||
@ -26,44 +29,12 @@ var _postMessage: (message: any, transferrables?:[ArrayBuffer]) => void = <any>p
|
|||||||
export function bootstrapWebWorker(
|
export function bootstrapWebWorker(
|
||||||
appComponentType: Type, componentInjectableBindings: List<Type | Binding | List<any>> = null):
|
appComponentType: Type, componentInjectableBindings: List<Type | Binding | List<any>> = null):
|
||||||
Promise<ApplicationRef> {
|
Promise<ApplicationRef> {
|
||||||
var bus: WebWorkerMessageBus =
|
var sink = new PostMessageBusSink({
|
||||||
new WebWorkerMessageBus(new WebWorkerMessageBusSink(), new WebWorkerMessageBusSource());
|
postMessage:
|
||||||
|
(message: any, transferrables?:[ArrayBuffer]) => { _postMessage(message, transferrables); }
|
||||||
|
});
|
||||||
|
var source = new PostMessageBusSource();
|
||||||
|
var bus = new PostMessageBus(sink, source);
|
||||||
|
|
||||||
return bootstrapWebWorkerCommon(appComponentType, bus, componentInjectableBindings);
|
return bootstrapWebWorkerCommon(appComponentType, bus, componentInjectableBindings);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class WebWorkerMessageBus implements MessageBus {
|
|
||||||
sink: WebWorkerMessageBusSink;
|
|
||||||
source: WebWorkerMessageBusSource;
|
|
||||||
|
|
||||||
constructor(sink: WebWorkerMessageBusSink, source: WebWorkerMessageBusSource) {
|
|
||||||
this.sink = sink;
|
|
||||||
this.source = source;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class WebWorkerMessageBusSink implements MessageBusSink {
|
|
||||||
public send(message: Object) { _postMessage(message); }
|
|
||||||
}
|
|
||||||
|
|
||||||
export class WebWorkerMessageBusSource implements MessageBusSource {
|
|
||||||
private listenerStore: Map<int, SourceListener>;
|
|
||||||
private numListeners: int;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.numListeners = 0;
|
|
||||||
this.listenerStore = new Map<int, SourceListener>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public addListener(fn: SourceListener): int {
|
|
||||||
addEventListener("message", fn);
|
|
||||||
this.listenerStore[++this.numListeners] = fn;
|
|
||||||
return this.numListeners;
|
|
||||||
}
|
|
||||||
|
|
||||||
public removeListener(index: int): void {
|
|
||||||
removeEventListener("message", this.listenerStore[index]);
|
|
||||||
this.listenerStore.delete(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -52,8 +52,8 @@ import {WebWorkerRenderer, WebWorkerCompiler} from './renderer';
|
|||||||
import {Renderer, RenderCompiler} from 'angular2/src/render/api';
|
import {Renderer, RenderCompiler} from 'angular2/src/render/api';
|
||||||
import {internalView} from 'angular2/src/core/compiler/view_ref';
|
import {internalView} from 'angular2/src/core/compiler/view_ref';
|
||||||
|
|
||||||
import {MessageBroker} from 'angular2/src/web-workers/worker/broker';
|
import {MessageBrokerFactory} from 'angular2/src/web-workers/worker/broker';
|
||||||
import {WebWorkerMessageBus} from 'angular2/src/web-workers/worker/application';
|
import {MessageBus, MessageBusInterface} from 'angular2/src/web-workers/shared/message_bus';
|
||||||
import {APP_COMPONENT_REF_PROMISE, APP_COMPONENT} from 'angular2/src/core/application_tokens';
|
import {APP_COMPONENT_REF_PROMISE, APP_COMPONENT} from 'angular2/src/core/application_tokens';
|
||||||
import {ApplicationRef} from 'angular2/src/core/application';
|
import {ApplicationRef} from 'angular2/src/core/application';
|
||||||
import {createNgZone} from 'angular2/src/core/application_common';
|
import {createNgZone} from 'angular2/src/core/application_common';
|
||||||
@ -63,6 +63,9 @@ import {RenderProtoViewRefStore} from 'angular2/src/web-workers/shared/render_pr
|
|||||||
import {
|
import {
|
||||||
RenderViewWithFragmentsStore
|
RenderViewWithFragmentsStore
|
||||||
} from 'angular2/src/web-workers/shared/render_view_with_fragments_store';
|
} from 'angular2/src/web-workers/shared/render_view_with_fragments_store';
|
||||||
|
import {ObservableWrapper} from 'angular2/src/facade/async';
|
||||||
|
import {SETUP_CHANNEL} from 'angular2/src/web-workers/shared/messaging_api';
|
||||||
|
import {WebWorkerEventDispatcher} from 'angular2/src/web-workers/worker/event_dispatcher';
|
||||||
|
|
||||||
var _rootInjector: Injector;
|
var _rootInjector: Injector;
|
||||||
|
|
||||||
@ -75,7 +78,7 @@ class PrintLogger {
|
|||||||
logGroupEnd() {}
|
logGroupEnd() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _injectorBindings(appComponentType, bus: WebWorkerMessageBus,
|
function _injectorBindings(appComponentType, bus: MessageBusInterface,
|
||||||
initData: StringMap<string, any>): List<Type | Binding | List<any>> {
|
initData: StringMap<string, any>): List<Type | Binding | List<any>> {
|
||||||
var bestChangeDetection: Type = DynamicChangeDetection;
|
var bestChangeDetection: Type = DynamicChangeDetection;
|
||||||
if (PreGeneratedChangeDetection.isSupported()) {
|
if (PreGeneratedChangeDetection.isSupported()) {
|
||||||
@ -100,10 +103,8 @@ function _injectorBindings(appComponentType, bus: WebWorkerMessageBus,
|
|||||||
bind(LifeCycle).toFactory((exceptionHandler) => new LifeCycle(null, assertionsEnabled()),
|
bind(LifeCycle).toFactory((exceptionHandler) => new LifeCycle(null, assertionsEnabled()),
|
||||||
[ExceptionHandler]),
|
[ExceptionHandler]),
|
||||||
Serializer,
|
Serializer,
|
||||||
bind(WebWorkerMessageBus).toValue(bus),
|
bind(MessageBus).toValue(bus),
|
||||||
bind(MessageBroker)
|
MessageBrokerFactory,
|
||||||
.toFactory((a, b, c) => new MessageBroker(a, b, c),
|
|
||||||
[WebWorkerMessageBus, Serializer, NgZone]),
|
|
||||||
WebWorkerRenderer,
|
WebWorkerRenderer,
|
||||||
bind(Renderer).toAlias(WebWorkerRenderer),
|
bind(Renderer).toAlias(WebWorkerRenderer),
|
||||||
WebWorkerCompiler,
|
WebWorkerCompiler,
|
||||||
@ -136,12 +137,13 @@ function _injectorBindings(appComponentType, bus: WebWorkerMessageBus,
|
|||||||
StyleUrlResolver,
|
StyleUrlResolver,
|
||||||
DynamicComponentLoader,
|
DynamicComponentLoader,
|
||||||
Testability,
|
Testability,
|
||||||
bind(AppRootUrl).toValue(new AppRootUrl(initData['rootUrl']))
|
bind(AppRootUrl).toValue(new AppRootUrl(initData['rootUrl'])),
|
||||||
|
WebWorkerEventDispatcher
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function bootstrapWebWorkerCommon(
|
export function bootstrapWebWorkerCommon(
|
||||||
appComponentType: Type, bus: WebWorkerMessageBus,
|
appComponentType: Type, bus: MessageBusInterface,
|
||||||
componentInjectableBindings: List<Type | Binding | List<any>> = null): Promise<ApplicationRef> {
|
componentInjectableBindings: List<Type | Binding | List<any>> = null): Promise<ApplicationRef> {
|
||||||
var bootstrapProcess: PromiseCompleter<any> = PromiseWrapper.completer();
|
var bootstrapProcess: PromiseCompleter<any> = PromiseWrapper.completer();
|
||||||
|
|
||||||
@ -151,14 +153,12 @@ export function bootstrapWebWorkerCommon(
|
|||||||
// index.html and main.js are possible.
|
// index.html and main.js are possible.
|
||||||
//
|
//
|
||||||
|
|
||||||
var listenerId: int;
|
|
||||||
listenerId = bus.source.addListener((message: StringMap<string, any>) => {
|
|
||||||
if (message["data"]["type"] !== "init") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var appInjector = _createAppInjector(appComponentType, componentInjectableBindings, zone, bus,
|
var subscription: any;
|
||||||
message["data"]["value"]);
|
var emitter = bus.from(SETUP_CHANNEL);
|
||||||
|
subscription = ObservableWrapper.subscribe(emitter, (message: StringMap<string, any>) => {
|
||||||
|
var appInjector =
|
||||||
|
_createAppInjector(appComponentType, componentInjectableBindings, zone, bus, message);
|
||||||
var compRefToken = PromiseWrapper.wrap(() => {
|
var compRefToken = PromiseWrapper.wrap(() => {
|
||||||
try {
|
try {
|
||||||
return appInjector.get(APP_COMPONENT_REF_PROMISE);
|
return appInjector.get(APP_COMPONENT_REF_PROMISE);
|
||||||
@ -178,17 +178,17 @@ export function bootstrapWebWorkerCommon(
|
|||||||
PromiseWrapper.then(compRefToken, tick,
|
PromiseWrapper.then(compRefToken, tick,
|
||||||
(err, stackTrace) => { bootstrapProcess.reject(err, stackTrace); });
|
(err, stackTrace) => { bootstrapProcess.reject(err, stackTrace); });
|
||||||
|
|
||||||
bus.source.removeListener(listenerId);
|
ObservableWrapper.dispose(subscription);
|
||||||
});
|
});
|
||||||
|
|
||||||
bus.sink.send({'type': "ready"});
|
ObservableWrapper.callNext(bus.to(SETUP_CHANNEL), "ready");
|
||||||
});
|
});
|
||||||
|
|
||||||
return bootstrapProcess.promise;
|
return bootstrapProcess.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _createAppInjector(appComponentType: Type, bindings: List<Type | Binding | List<any>>,
|
function _createAppInjector(appComponentType: Type, bindings: List<Type | Binding | List<any>>,
|
||||||
zone: NgZone, bus: WebWorkerMessageBus,
|
zone: NgZone, bus: MessageBusInterface,
|
||||||
initData: StringMap<string, any>): Injector {
|
initData: StringMap<string, any>): Injector {
|
||||||
if (isBlank(_rootInjector)) _rootInjector = Injector.resolveAndCreate(_rootBindings);
|
if (isBlank(_rootInjector)) _rootInjector = Injector.resolveAndCreate(_rootBindings);
|
||||||
var mergedBindings: any[] =
|
var mergedBindings: any[] =
|
||||||
@ -197,4 +197,4 @@ function _createAppInjector(appComponentType: Type, bindings: List<Type | Bindin
|
|||||||
_injectorBindings(appComponentType, bus, initData);
|
_injectorBindings(appComponentType, bus, initData);
|
||||||
mergedBindings.push(bind(NgZone).toValue(zone));
|
mergedBindings.push(bind(NgZone).toValue(zone));
|
||||||
return _rootInjector.resolveAndCreateChild(mergedBindings);
|
return _rootInjector.resolveAndCreateChild(mergedBindings);
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,35 @@
|
|||||||
/// <reference path="../../../globals.d.ts" />
|
/// <reference path="../../../globals.d.ts" />
|
||||||
import {MessageBus} from "angular2/src/web-workers/shared/message_bus";
|
import {MessageBus} from "angular2/src/web-workers/shared/message_bus";
|
||||||
import {print, isPresent, DateWrapper, stringify} from "../../facade/lang";
|
import {print, isPresent, DateWrapper, stringify} from "../../facade/lang";
|
||||||
import {Promise, PromiseCompleter, PromiseWrapper} from "angular2/src/facade/async";
|
import {
|
||||||
|
Promise,
|
||||||
|
PromiseCompleter,
|
||||||
|
PromiseWrapper,
|
||||||
|
ObservableWrapper,
|
||||||
|
EventEmitter
|
||||||
|
} from "angular2/src/facade/async";
|
||||||
import {ListWrapper, StringMapWrapper, MapWrapper} from "../../facade/collection";
|
import {ListWrapper, StringMapWrapper, MapWrapper} from "../../facade/collection";
|
||||||
import {Serializer} from "angular2/src/web-workers/shared/serializer";
|
import {Serializer} from "angular2/src/web-workers/shared/serializer";
|
||||||
import {Injectable} from "angular2/di";
|
import {Injectable} from "angular2/di";
|
||||||
import {Type} from "angular2/src/facade/lang";
|
import {Type} from "angular2/src/facade/lang";
|
||||||
import {RenderViewRef, RenderEventDispatcher} from 'angular2/src/render/api';
|
|
||||||
import {NgZone} from 'angular2/src/core/zone/ng_zone';
|
|
||||||
import {deserializeGenericEvent} from './event_deserializer';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
|
export class MessageBrokerFactory {
|
||||||
|
constructor(private _messageBus: MessageBus, protected _serializer: Serializer) {}
|
||||||
|
|
||||||
|
createMessageBroker(channel: string): MessageBroker {
|
||||||
|
return new MessageBroker(this._messageBus, this._serializer, channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class MessageBroker {
|
export class MessageBroker {
|
||||||
private _pending: Map<string, PromiseCompleter<any>> = new Map<string, PromiseCompleter<any>>();
|
private _pending: Map<string, PromiseCompleter<any>> = new Map<string, PromiseCompleter<any>>();
|
||||||
private _eventDispatchRegistry: Map<RenderViewRef, RenderEventDispatcher> =
|
private _sink: EventEmitter;
|
||||||
new Map<RenderViewRef, RenderEventDispatcher>();
|
|
||||||
|
|
||||||
constructor(private _messageBus: MessageBus, protected _serializer: Serializer,
|
constructor(messageBus: MessageBus, protected _serializer: Serializer, public channel) {
|
||||||
private _zone: NgZone) {
|
this._sink = messageBus.to(channel);
|
||||||
this._messageBus.source.addListener((data) => this._handleMessage(data['data']));
|
var source = messageBus.from(channel);
|
||||||
|
ObservableWrapper.subscribe(source, (message) => this._handleMessage(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
private _generateMessageId(name: string): string {
|
private _generateMessageId(name: string): string {
|
||||||
@ -48,7 +59,7 @@ export class MessageBroker {
|
|||||||
var id: string = null;
|
var id: string = null;
|
||||||
if (returnType != null) {
|
if (returnType != null) {
|
||||||
var completer: PromiseCompleter<any> = PromiseWrapper.completer();
|
var completer: PromiseCompleter<any> = PromiseWrapper.completer();
|
||||||
id = this._generateMessageId(args.type + args.method);
|
id = this._generateMessageId(args.method);
|
||||||
this._pending.set(id, completer);
|
this._pending.set(id, completer);
|
||||||
PromiseWrapper.catchError(completer.promise, (err, stack?) => {
|
PromiseWrapper.catchError(completer.promise, (err, stack?) => {
|
||||||
print(err);
|
print(err);
|
||||||
@ -66,22 +77,20 @@ export class MessageBroker {
|
|||||||
promise = null;
|
promise = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(jteplitz602): Create a class for these messages so we don't keep using StringMap
|
// TODO(jteplitz602): Create a class for these messages so we don't keep using StringMap #3685
|
||||||
var message = {'type': args.type, 'method': args.method, 'args': fnArgs};
|
var message = {'method': args.method, 'args': fnArgs};
|
||||||
if (id != null) {
|
if (id != null) {
|
||||||
message['id'] = id;
|
message['id'] = id;
|
||||||
}
|
}
|
||||||
this._messageBus.sink.send(message);
|
ObservableWrapper.callNext(this._sink, message);
|
||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleMessage(message: StringMap<string, any>): void {
|
private _handleMessage(message: StringMap<string, any>): void {
|
||||||
var data = new MessageData(message);
|
var data = new MessageData(message);
|
||||||
// TODO(jteplitz602): replace these strings with messaging constants
|
// TODO(jteplitz602): replace these strings with messaging constants #3685
|
||||||
if (data.type === "event") {
|
if (data.type === "result" || data.type === "error") {
|
||||||
this._dispatchEvent(new RenderEventData(data.value, this._serializer));
|
|
||||||
} else if (data.type === "result" || data.type === "error") {
|
|
||||||
var id = data.id;
|
var id = data.id;
|
||||||
if (this._pending.has(id)) {
|
if (this._pending.has(id)) {
|
||||||
if (data.type === "result") {
|
if (data.type === "result") {
|
||||||
@ -93,32 +102,6 @@ export class MessageBroker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _dispatchEvent(eventData: RenderEventData): void {
|
|
||||||
var dispatcher = this._eventDispatchRegistry.get(eventData.viewRef);
|
|
||||||
this._zone.run(() => {
|
|
||||||
eventData.locals['$event'] = deserializeGenericEvent(eventData.locals['$event']);
|
|
||||||
dispatcher.dispatchRenderEvent(eventData.elementIndex, eventData.eventName, eventData.locals);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
registerEventDispatcher(viewRef: RenderViewRef, dispatcher: RenderEventDispatcher): void {
|
|
||||||
this._eventDispatchRegistry.set(viewRef, dispatcher);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RenderEventData {
|
|
||||||
viewRef: RenderViewRef;
|
|
||||||
elementIndex: number;
|
|
||||||
eventName: string;
|
|
||||||
locals: Map<string, any>;
|
|
||||||
|
|
||||||
constructor(message: StringMap<string, any>, serializer: Serializer) {
|
|
||||||
this.viewRef = serializer.deserialize(message['viewRef'], RenderViewRef);
|
|
||||||
this.elementIndex = message['elementIndex'];
|
|
||||||
this.eventName = message['eventName'];
|
|
||||||
this.locals = MapWrapper.createFromStringMap(message['locals']);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class MessageData {
|
class MessageData {
|
||||||
@ -149,5 +132,5 @@ export class FnArg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class UiArguments {
|
export class UiArguments {
|
||||||
constructor(public type: string, public method: string, public args?: List<FnArg>) {}
|
constructor(public method: string, public args?: List<FnArg>) {}
|
||||||
}
|
}
|
||||||
|
49
modules/angular2/src/web-workers/worker/event_dispatcher.ts
Normal file
49
modules/angular2/src/web-workers/worker/event_dispatcher.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import {Injectable} from 'angular2/di';
|
||||||
|
import {Map, MapWrapper} from 'angular2/src/facade/collection';
|
||||||
|
import {RenderViewRef, RenderEventDispatcher} from 'angular2/src/render/api';
|
||||||
|
import {Serializer} from 'angular2/src/web-workers/shared/serializer';
|
||||||
|
import {EVENT_CHANNEL} from 'angular2/src/web-workers/shared/messaging_api';
|
||||||
|
import {MessageBus} from 'angular2/src/web-workers/shared/message_bus';
|
||||||
|
import {EventEmitter, ObservableWrapper} from 'angular2/src/facade/async';
|
||||||
|
import {deserializeGenericEvent} from './event_deserializer';
|
||||||
|
import {NgZone} from 'angular2/src/core/zone/ng_zone';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class WebWorkerEventDispatcher {
|
||||||
|
private _eventDispatchRegistry: Map<RenderViewRef, RenderEventDispatcher> =
|
||||||
|
new Map<RenderViewRef, RenderEventDispatcher>();
|
||||||
|
|
||||||
|
constructor(bus: MessageBus, private _serializer: Serializer, private _zone: NgZone) {
|
||||||
|
var source = bus.from(EVENT_CHANNEL);
|
||||||
|
ObservableWrapper.subscribe(
|
||||||
|
source, (message) => this._dispatchEvent(new RenderEventData(message, _serializer)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private _dispatchEvent(eventData: RenderEventData): void {
|
||||||
|
var dispatcher = this._eventDispatchRegistry.get(eventData.viewRef);
|
||||||
|
this._zone.run(() => {
|
||||||
|
eventData.locals['$event'] = deserializeGenericEvent(eventData.locals['$event']);
|
||||||
|
dispatcher.dispatchRenderEvent(eventData.elementIndex, eventData.eventName, eventData.locals);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
registerEventDispatcher(viewRef: RenderViewRef, dispatcher: RenderEventDispatcher): void {
|
||||||
|
this._eventDispatchRegistry.set(viewRef, dispatcher);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class RenderEventData {
|
||||||
|
viewRef: RenderViewRef;
|
||||||
|
elementIndex: number;
|
||||||
|
eventName: string;
|
||||||
|
locals: Map<string, any>;
|
||||||
|
|
||||||
|
constructor(message: StringMap<string, any>, serializer: Serializer) {
|
||||||
|
this.viewRef = serializer.deserialize(message['viewRef'], RenderViewRef);
|
||||||
|
this.elementIndex = message['elementIndex'];
|
||||||
|
this.eventName = message['eventName'];
|
||||||
|
this.locals = MapWrapper.createFromStringMap(message['locals']);
|
||||||
|
}
|
||||||
|
}
|
@ -13,7 +13,12 @@ import {
|
|||||||
RenderFragmentRef
|
RenderFragmentRef
|
||||||
} from 'angular2/src/render/api';
|
} from 'angular2/src/render/api';
|
||||||
import {Promise, PromiseWrapper} from "angular2/src/facade/async";
|
import {Promise, PromiseWrapper} from "angular2/src/facade/async";
|
||||||
import {MessageBroker, FnArg, UiArguments} from "angular2/src/web-workers/worker/broker";
|
import {
|
||||||
|
MessageBroker,
|
||||||
|
MessageBrokerFactory,
|
||||||
|
FnArg,
|
||||||
|
UiArguments
|
||||||
|
} from "angular2/src/web-workers/worker/broker";
|
||||||
import {isPresent, print, BaseException} from "angular2/src/facade/lang";
|
import {isPresent, print, BaseException} from "angular2/src/facade/lang";
|
||||||
import {Injectable} from "angular2/di";
|
import {Injectable} from "angular2/di";
|
||||||
import {
|
import {
|
||||||
@ -21,16 +26,24 @@ import {
|
|||||||
WebWorkerRenderViewRef
|
WebWorkerRenderViewRef
|
||||||
} from 'angular2/src/web-workers/shared/render_view_with_fragments_store';
|
} from 'angular2/src/web-workers/shared/render_view_with_fragments_store';
|
||||||
import {WebWorkerElementRef} from 'angular2/src/web-workers/shared/api';
|
import {WebWorkerElementRef} from 'angular2/src/web-workers/shared/api';
|
||||||
|
import {
|
||||||
|
RENDER_COMPILER_CHANNEL,
|
||||||
|
RENDERER_CHANNEL
|
||||||
|
} from 'angular2/src/web-workers/shared/messaging_api';
|
||||||
|
import {WebWorkerEventDispatcher} from 'angular2/src/web-workers/worker/event_dispatcher';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WebWorkerCompiler implements RenderCompiler {
|
export class WebWorkerCompiler implements RenderCompiler {
|
||||||
constructor(private _messageBroker: MessageBroker) {}
|
private _messageBroker;
|
||||||
|
constructor(messageBrokerFactory: MessageBrokerFactory) {
|
||||||
|
this._messageBroker = messageBrokerFactory.createMessageBroker(RENDER_COMPILER_CHANNEL);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Creats a ProtoViewDto that contains a single nested component with the given componentId.
|
* Creats a ProtoViewDto that contains a single nested component with the given componentId.
|
||||||
*/
|
*/
|
||||||
compileHost(directiveMetadata: RenderDirectiveMetadata): Promise<ProtoViewDto> {
|
compileHost(directiveMetadata: RenderDirectiveMetadata): Promise<ProtoViewDto> {
|
||||||
var fnArgs: List<FnArg> = [new FnArg(directiveMetadata, RenderDirectiveMetadata)];
|
var fnArgs: List<FnArg> = [new FnArg(directiveMetadata, RenderDirectiveMetadata)];
|
||||||
var args: UiArguments = new UiArguments("compiler", "compileHost", fnArgs);
|
var args: UiArguments = new UiArguments("compileHost", fnArgs);
|
||||||
return this._messageBroker.runOnUiThread(args, ProtoViewDto);
|
return this._messageBroker.runOnUiThread(args, ProtoViewDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +54,7 @@ export class WebWorkerCompiler implements RenderCompiler {
|
|||||||
*/
|
*/
|
||||||
compile(view: ViewDefinition): Promise<ProtoViewDto> {
|
compile(view: ViewDefinition): Promise<ProtoViewDto> {
|
||||||
var fnArgs: List<FnArg> = [new FnArg(view, ViewDefinition)];
|
var fnArgs: List<FnArg> = [new FnArg(view, ViewDefinition)];
|
||||||
var args: UiArguments = new UiArguments("compiler", "compile", fnArgs);
|
var args: UiArguments = new UiArguments("compile", fnArgs);
|
||||||
return this._messageBroker.runOnUiThread(args, ProtoViewDto);
|
return this._messageBroker.runOnUiThread(args, ProtoViewDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +70,7 @@ export class WebWorkerCompiler implements RenderCompiler {
|
|||||||
mergeProtoViewsRecursively(
|
mergeProtoViewsRecursively(
|
||||||
protoViewRefs: List<RenderProtoViewRef | List<any>>): Promise<RenderProtoViewMergeMapping> {
|
protoViewRefs: List<RenderProtoViewRef | List<any>>): Promise<RenderProtoViewMergeMapping> {
|
||||||
var fnArgs: List<FnArg> = [new FnArg(protoViewRefs, RenderProtoViewRef)];
|
var fnArgs: List<FnArg> = [new FnArg(protoViewRefs, RenderProtoViewRef)];
|
||||||
var args: UiArguments = new UiArguments("compiler", "mergeProtoViewsRecursively", fnArgs);
|
var args: UiArguments = new UiArguments("mergeProtoViewsRecursively", fnArgs);
|
||||||
return this._messageBroker.runOnUiThread(args, RenderProtoViewMergeMapping);
|
return this._messageBroker.runOnUiThread(args, RenderProtoViewMergeMapping);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,8 +78,12 @@ export class WebWorkerCompiler implements RenderCompiler {
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WebWorkerRenderer implements Renderer {
|
export class WebWorkerRenderer implements Renderer {
|
||||||
constructor(private _messageBroker: MessageBroker,
|
private _messageBroker;
|
||||||
private _renderViewStore: RenderViewWithFragmentsStore) {}
|
constructor(messageBrokerFactory: MessageBrokerFactory,
|
||||||
|
private _renderViewStore: RenderViewWithFragmentsStore,
|
||||||
|
private _eventDispatcher: WebWorkerEventDispatcher) {
|
||||||
|
this._messageBroker = messageBrokerFactory.createMessageBroker(RENDERER_CHANNEL);
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Creates a root host view that includes the given element.
|
* Creates a root host view that includes the given element.
|
||||||
* Note that the fragmentCount needs to be passed in so that we can create a result
|
* Note that the fragmentCount needs to be passed in so that we can create a result
|
||||||
@ -108,7 +125,7 @@ export class WebWorkerRenderer implements Renderer {
|
|||||||
}
|
}
|
||||||
fnArgs.push(new FnArg(startIndex, null));
|
fnArgs.push(new FnArg(startIndex, null));
|
||||||
|
|
||||||
var args = new UiArguments("renderer", method, fnArgs);
|
var args = new UiArguments(method, fnArgs);
|
||||||
this._messageBroker.runOnUiThread(args, null);
|
this._messageBroker.runOnUiThread(args, null);
|
||||||
|
|
||||||
return renderViewWithFragments;
|
return renderViewWithFragments;
|
||||||
@ -119,7 +136,7 @@ export class WebWorkerRenderer implements Renderer {
|
|||||||
*/
|
*/
|
||||||
destroyView(viewRef: RenderViewRef) {
|
destroyView(viewRef: RenderViewRef) {
|
||||||
var fnArgs = [new FnArg(viewRef, RenderViewRef)];
|
var fnArgs = [new FnArg(viewRef, RenderViewRef)];
|
||||||
var args = new UiArguments("renderer", "destroyView", fnArgs);
|
var args = new UiArguments("destroyView", fnArgs);
|
||||||
this._messageBroker.runOnUiThread(args, null);
|
this._messageBroker.runOnUiThread(args, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,7 +149,7 @@ export class WebWorkerRenderer implements Renderer {
|
|||||||
new FnArg(previousFragmentRef, RenderFragmentRef),
|
new FnArg(previousFragmentRef, RenderFragmentRef),
|
||||||
new FnArg(fragmentRef, RenderFragmentRef)
|
new FnArg(fragmentRef, RenderFragmentRef)
|
||||||
];
|
];
|
||||||
var args = new UiArguments("renderer", "attachFragmentAfterFragment", fnArgs);
|
var args = new UiArguments("attachFragmentAfterFragment", fnArgs);
|
||||||
this._messageBroker.runOnUiThread(args, null);
|
this._messageBroker.runOnUiThread(args, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +159,7 @@ export class WebWorkerRenderer implements Renderer {
|
|||||||
attachFragmentAfterElement(elementRef: RenderElementRef, fragmentRef: RenderFragmentRef) {
|
attachFragmentAfterElement(elementRef: RenderElementRef, fragmentRef: RenderFragmentRef) {
|
||||||
var fnArgs =
|
var fnArgs =
|
||||||
[new FnArg(elementRef, WebWorkerElementRef), new FnArg(fragmentRef, RenderFragmentRef)];
|
[new FnArg(elementRef, WebWorkerElementRef), new FnArg(fragmentRef, RenderFragmentRef)];
|
||||||
var args = new UiArguments("renderer", "attachFragmentAfterElement", fnArgs);
|
var args = new UiArguments("attachFragmentAfterElement", fnArgs);
|
||||||
this._messageBroker.runOnUiThread(args, null);
|
this._messageBroker.runOnUiThread(args, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +168,7 @@ export class WebWorkerRenderer implements Renderer {
|
|||||||
*/
|
*/
|
||||||
detachFragment(fragmentRef: RenderFragmentRef) {
|
detachFragment(fragmentRef: RenderFragmentRef) {
|
||||||
var fnArgs = [new FnArg(fragmentRef, RenderFragmentRef)];
|
var fnArgs = [new FnArg(fragmentRef, RenderFragmentRef)];
|
||||||
var args = new UiArguments("renderer", "detachFragment", fnArgs);
|
var args = new UiArguments("detachFragment", fnArgs);
|
||||||
this._messageBroker.runOnUiThread(args, null);
|
this._messageBroker.runOnUiThread(args, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +178,7 @@ export class WebWorkerRenderer implements Renderer {
|
|||||||
*/
|
*/
|
||||||
hydrateView(viewRef: RenderViewRef) {
|
hydrateView(viewRef: RenderViewRef) {
|
||||||
var fnArgs = [new FnArg(viewRef, RenderViewRef)];
|
var fnArgs = [new FnArg(viewRef, RenderViewRef)];
|
||||||
var args = new UiArguments("renderer", "hydrateView", fnArgs);
|
var args = new UiArguments("hydrateView", fnArgs);
|
||||||
this._messageBroker.runOnUiThread(args, null);
|
this._messageBroker.runOnUiThread(args, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +188,7 @@ export class WebWorkerRenderer implements Renderer {
|
|||||||
*/
|
*/
|
||||||
dehydrateView(viewRef: RenderViewRef) {
|
dehydrateView(viewRef: RenderViewRef) {
|
||||||
var fnArgs = [new FnArg(viewRef, RenderViewRef)];
|
var fnArgs = [new FnArg(viewRef, RenderViewRef)];
|
||||||
var args = new UiArguments("renderer", "dehydrateView", fnArgs);
|
var args = new UiArguments("dehydrateView", fnArgs);
|
||||||
this._messageBroker.runOnUiThread(args, null);
|
this._messageBroker.runOnUiThread(args, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,7 +207,7 @@ export class WebWorkerRenderer implements Renderer {
|
|||||||
new FnArg(propertyName, null),
|
new FnArg(propertyName, null),
|
||||||
new FnArg(propertyValue, null)
|
new FnArg(propertyValue, null)
|
||||||
];
|
];
|
||||||
var args = new UiArguments("renderer", "setElementProperty", fnArgs);
|
var args = new UiArguments("setElementProperty", fnArgs);
|
||||||
this._messageBroker.runOnUiThread(args, null);
|
this._messageBroker.runOnUiThread(args, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,7 +220,7 @@ export class WebWorkerRenderer implements Renderer {
|
|||||||
new FnArg(attributeName, null),
|
new FnArg(attributeName, null),
|
||||||
new FnArg(attributeValue, null)
|
new FnArg(attributeValue, null)
|
||||||
];
|
];
|
||||||
var args = new UiArguments("renderer", "setElementAttribute", fnArgs);
|
var args = new UiArguments("setElementAttribute", fnArgs);
|
||||||
this._messageBroker.runOnUiThread(args, null);
|
this._messageBroker.runOnUiThread(args, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,7 +233,7 @@ export class WebWorkerRenderer implements Renderer {
|
|||||||
new FnArg(className, null),
|
new FnArg(className, null),
|
||||||
new FnArg(isAdd, null)
|
new FnArg(isAdd, null)
|
||||||
];
|
];
|
||||||
var args = new UiArguments("renderer", "setElementClass", fnArgs);
|
var args = new UiArguments("setElementClass", fnArgs);
|
||||||
this._messageBroker.runOnUiThread(args, null);
|
this._messageBroker.runOnUiThread(args, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +246,7 @@ export class WebWorkerRenderer implements Renderer {
|
|||||||
new FnArg(styleName, null),
|
new FnArg(styleName, null),
|
||||||
new FnArg(styleValue, null)
|
new FnArg(styleValue, null)
|
||||||
];
|
];
|
||||||
var args = new UiArguments("renderer", "setElementStyle", fnArgs);
|
var args = new UiArguments("setElementStyle", fnArgs);
|
||||||
this._messageBroker.runOnUiThread(args, null);
|
this._messageBroker.runOnUiThread(args, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,7 +260,7 @@ export class WebWorkerRenderer implements Renderer {
|
|||||||
new FnArg(methodName, null),
|
new FnArg(methodName, null),
|
||||||
new FnArg(args, null)
|
new FnArg(args, null)
|
||||||
];
|
];
|
||||||
var uiArgs = new UiArguments("renderer", "invokeElementMethod", fnArgs);
|
var uiArgs = new UiArguments("invokeElementMethod", fnArgs);
|
||||||
this._messageBroker.runOnUiThread(uiArgs, null);
|
this._messageBroker.runOnUiThread(uiArgs, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,7 +270,7 @@ export class WebWorkerRenderer implements Renderer {
|
|||||||
setText(viewRef: RenderViewRef, textNodeIndex: number, text: string) {
|
setText(viewRef: RenderViewRef, textNodeIndex: number, text: string) {
|
||||||
var fnArgs =
|
var fnArgs =
|
||||||
[new FnArg(viewRef, RenderViewRef), new FnArg(textNodeIndex, null), new FnArg(text, null)];
|
[new FnArg(viewRef, RenderViewRef), new FnArg(textNodeIndex, null), new FnArg(text, null)];
|
||||||
var args = new UiArguments("renderer", "setText", fnArgs);
|
var args = new UiArguments("setText", fnArgs);
|
||||||
this._messageBroker.runOnUiThread(args, null);
|
this._messageBroker.runOnUiThread(args, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,8 +279,8 @@ export class WebWorkerRenderer implements Renderer {
|
|||||||
*/
|
*/
|
||||||
setEventDispatcher(viewRef: RenderViewRef, dispatcher: RenderEventDispatcher) {
|
setEventDispatcher(viewRef: RenderViewRef, dispatcher: RenderEventDispatcher) {
|
||||||
var fnArgs = [new FnArg(viewRef, RenderViewRef)];
|
var fnArgs = [new FnArg(viewRef, RenderViewRef)];
|
||||||
var args = new UiArguments("renderer", "setEventDispatcher", fnArgs);
|
var args = new UiArguments("setEventDispatcher", fnArgs);
|
||||||
this._messageBroker.registerEventDispatcher(viewRef, dispatcher);
|
this._eventDispatcher.registerEventDispatcher(viewRef, dispatcher);
|
||||||
this._messageBroker.runOnUiThread(args, null);
|
this._messageBroker.runOnUiThread(args, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
import {Injectable} from 'angular2/di';
|
import {Injectable} from 'angular2/di';
|
||||||
import {Promise} from 'angular2/src/facade/async';
|
import {Promise} from 'angular2/src/facade/async';
|
||||||
import {XHR} from 'angular2/src/render/xhr';
|
import {XHR} from 'angular2/src/render/xhr';
|
||||||
import {FnArg, UiArguments, MessageBroker} from 'angular2/src/web-workers/worker/broker';
|
import {
|
||||||
|
FnArg,
|
||||||
|
UiArguments,
|
||||||
|
MessageBroker,
|
||||||
|
MessageBrokerFactory
|
||||||
|
} from 'angular2/src/web-workers/worker/broker';
|
||||||
|
import {XHR_CHANNEL} from 'angular2/src/web-workers/shared/messaging_api';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of render/xhr that relays XHR requests to the UI side where they are sent
|
* Implementation of render/xhr that relays XHR requests to the UI side where they are sent
|
||||||
@ -9,11 +15,16 @@ import {FnArg, UiArguments, MessageBroker} from 'angular2/src/web-workers/worker
|
|||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WebWorkerXHRImpl extends XHR {
|
export class WebWorkerXHRImpl extends XHR {
|
||||||
constructor(private _messageBroker: MessageBroker) { super(); }
|
private _messageBroker: MessageBroker;
|
||||||
|
|
||||||
|
constructor(messageBrokerFactory: MessageBrokerFactory) {
|
||||||
|
super();
|
||||||
|
this._messageBroker = messageBrokerFactory.createMessageBroker(XHR_CHANNEL);
|
||||||
|
}
|
||||||
|
|
||||||
get(url: string): Promise<string> {
|
get(url: string): Promise<string> {
|
||||||
var fnArgs: List<FnArg> = [new FnArg(url, null)];
|
var fnArgs: List<FnArg> = [new FnArg(url, null)];
|
||||||
var args: UiArguments = new UiArguments("xhr", "get", fnArgs);
|
var args: UiArguments = new UiArguments("get", fnArgs);
|
||||||
return this._messageBroker.runOnUiThread(args, String);
|
return this._messageBroker.runOnUiThread(args, String);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
94
modules/angular2/test/web-workers/shared/message_bus_spec.ts
Normal file
94
modules/angular2/test/web-workers/shared/message_bus_spec.ts
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
import {
|
||||||
|
AsyncTestCompleter,
|
||||||
|
inject,
|
||||||
|
describe,
|
||||||
|
it,
|
||||||
|
expect,
|
||||||
|
beforeEach,
|
||||||
|
createTestInjector,
|
||||||
|
beforeEachBindings,
|
||||||
|
SpyObject,
|
||||||
|
proxy
|
||||||
|
} from 'angular2/test_lib';
|
||||||
|
import {ObservableWrapper} from 'angular2/src/facade/async';
|
||||||
|
import {MessageBusInterface} from 'angular2/src/web-workers/shared/message_bus';
|
||||||
|
import {createConnectedMessageBus} from './message_bus_util';
|
||||||
|
|
||||||
|
export function main() {
|
||||||
|
/**
|
||||||
|
* Tests the PostMessageBus in TypeScript and the IsolateMessageBus in Dart
|
||||||
|
*/
|
||||||
|
describe("MessageBus", () => {
|
||||||
|
var bus: MessageBusInterface;
|
||||||
|
|
||||||
|
beforeEach(() => { bus = createConnectedMessageBus(); });
|
||||||
|
|
||||||
|
it("should pass messages in the same channel from sink to source",
|
||||||
|
inject([AsyncTestCompleter], (async) => {
|
||||||
|
const CHANNEL = "CHANNEL 1";
|
||||||
|
const MESSAGE = "Test message";
|
||||||
|
|
||||||
|
var fromEmitter = bus.from(CHANNEL);
|
||||||
|
ObservableWrapper.subscribe(fromEmitter, (message: any) => {
|
||||||
|
expect(message).toEqual(MESSAGE);
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
var toEmitter = bus.to(CHANNEL);
|
||||||
|
ObservableWrapper.callNext(toEmitter, MESSAGE);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("should broadcast", inject([AsyncTestCompleter], (async) => {
|
||||||
|
const CHANNEL = "CHANNEL 1";
|
||||||
|
const MESSAGE = "TESTING";
|
||||||
|
const NUM_LISTENERS = 2;
|
||||||
|
|
||||||
|
var callCount = 0;
|
||||||
|
var emitHandler = (message: any) => {
|
||||||
|
expect(message).toEqual(MESSAGE);
|
||||||
|
callCount++;
|
||||||
|
if (callCount == NUM_LISTENERS) {
|
||||||
|
async.done();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var i = 0; i < NUM_LISTENERS; i++) {
|
||||||
|
var emitter = bus.from(CHANNEL);
|
||||||
|
ObservableWrapper.subscribe(emitter, emitHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
var toEmitter = bus.to(CHANNEL);
|
||||||
|
ObservableWrapper.callNext(toEmitter, MESSAGE);
|
||||||
|
}));
|
||||||
|
|
||||||
|
it("should keep channels independent", inject([AsyncTestCompleter], (async) => {
|
||||||
|
const CHANNEL_ONE = "CHANNEL 1";
|
||||||
|
const CHANNEL_TWO = "CHANNEL 2";
|
||||||
|
const MESSAGE_ONE = "This is a message on CHANNEL 1";
|
||||||
|
const MESSAGE_TWO = "This is a message on CHANNEL 2";
|
||||||
|
var callCount = 0;
|
||||||
|
|
||||||
|
var firstFromEmitter = bus.from(CHANNEL_ONE);
|
||||||
|
ObservableWrapper.subscribe(firstFromEmitter, (message) => {
|
||||||
|
expect(message).toEqual(MESSAGE_ONE);
|
||||||
|
callCount++;
|
||||||
|
if (callCount == 2) {
|
||||||
|
async.done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var secondFromEmitter = bus.from(CHANNEL_TWO);
|
||||||
|
ObservableWrapper.subscribe(secondFromEmitter, (message) => {
|
||||||
|
expect(message).toEqual(MESSAGE_TWO);
|
||||||
|
callCount++;
|
||||||
|
if (callCount == 2) {
|
||||||
|
async.done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var firstToEmitter = bus.to(CHANNEL_ONE);
|
||||||
|
ObservableWrapper.callNext(firstToEmitter, MESSAGE_ONE);
|
||||||
|
|
||||||
|
var secondToEmitter = bus.to(CHANNEL_TWO);
|
||||||
|
ObservableWrapper.callNext(secondToEmitter, MESSAGE_TWO);
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
library angular2.test.web_workers.shared.message_bus_util;
|
||||||
|
|
||||||
|
import 'dart:isolate';
|
||||||
|
import 'package:angular2/src/web-workers/shared/message_bus.dart'
|
||||||
|
show MessageBusInterface;
|
||||||
|
import 'package:angular2/src/web-workers/shared/isolate_message_bus.dart';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns an IsolateMessageBus thats sink is connected to its own source.
|
||||||
|
* Useful for testing the sink and source.
|
||||||
|
*/
|
||||||
|
MessageBusInterface createConnectedMessageBus() {
|
||||||
|
var receivePort = new ReceivePort();
|
||||||
|
var sendPort = receivePort.sendPort;
|
||||||
|
|
||||||
|
var sink = new IsolateMessageBusSink(sendPort);
|
||||||
|
var source = new IsolateMessageBusSource(receivePort);
|
||||||
|
|
||||||
|
return new IsolateMessageBus(sink, source);
|
||||||
|
}
|
30
modules/angular2/test/web-workers/shared/message_bus_util.ts
Normal file
30
modules/angular2/test/web-workers/shared/message_bus_util.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import {
|
||||||
|
PostMessageBusSource,
|
||||||
|
PostMessageBusSink,
|
||||||
|
PostMessageBus
|
||||||
|
} from 'angular2/src/web-workers/shared/post_message_bus';
|
||||||
|
import {MessageBusInterface} from 'angular2/src/web-workers/shared/message_bus';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Returns a PostMessageBus thats sink is connected to its own source.
|
||||||
|
* Useful for testing the sink and source.
|
||||||
|
*/
|
||||||
|
export function createConnectedMessageBus(): MessageBusInterface {
|
||||||
|
var mockPostMessage = new MockPostMessage();
|
||||||
|
var source = new PostMessageBusSource(<any>mockPostMessage);
|
||||||
|
var sink = new PostMessageBusSink(mockPostMessage);
|
||||||
|
|
||||||
|
return new PostMessageBus(sink, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
class MockPostMessage {
|
||||||
|
private _listener: EventListener;
|
||||||
|
|
||||||
|
addEventListener(type: string, listener: EventListener, useCapture?: boolean): void {
|
||||||
|
if (type === "message") {
|
||||||
|
this._listener = listener;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
postMessage(data: any, transfer?:[ArrayBuffer]): void { this._listener(<any>{data: data}); }
|
||||||
|
}
|
@ -13,8 +13,6 @@ import {
|
|||||||
import {IMPLEMENTS} from 'angular2/src/facade/lang';
|
import {IMPLEMENTS} from 'angular2/src/facade/lang';
|
||||||
import {Serializer} from 'angular2/src/web-workers/shared/serializer';
|
import {Serializer} from 'angular2/src/web-workers/shared/serializer';
|
||||||
import {NgZone} from 'angular2/src/core/zone/ng_zone';
|
import {NgZone} from 'angular2/src/core/zone/ng_zone';
|
||||||
import {MessageBroker} from 'angular2/src/web-workers/worker/broker';
|
|
||||||
import {MockMessageBus, MockMessageBusSink, MockMessageBusSource} from './worker_test_util';
|
|
||||||
import {ON_WEB_WORKER} from 'angular2/src/web-workers/shared/api';
|
import {ON_WEB_WORKER} from 'angular2/src/web-workers/shared/api';
|
||||||
import {bind} from 'angular2/di';
|
import {bind} from 'angular2/di';
|
||||||
import {RenderProtoViewRefStore} from 'angular2/src/web-workers/shared/render_proto_view_ref_store';
|
import {RenderProtoViewRefStore} from 'angular2/src/web-workers/shared/render_proto_view_ref_store';
|
||||||
@ -23,9 +21,13 @@ import {
|
|||||||
WebWorkerRenderViewRef
|
WebWorkerRenderViewRef
|
||||||
} from 'angular2/src/web-workers/shared/render_view_with_fragments_store';
|
} from 'angular2/src/web-workers/shared/render_view_with_fragments_store';
|
||||||
import {RenderEventDispatcher, RenderViewRef} from 'angular2/src/render/api';
|
import {RenderEventDispatcher, RenderViewRef} from 'angular2/src/render/api';
|
||||||
|
import {createPairedMessageBuses} from './worker_test_util';
|
||||||
|
import {WebWorkerEventDispatcher} from 'angular2/src/web-workers/worker/event_dispatcher';
|
||||||
|
import {ObservableWrapper} from 'angular2/src/facade/async';
|
||||||
|
import {EVENT_CHANNEL} from 'angular2/src/web-workers/shared/messaging_api';
|
||||||
|
|
||||||
export function main() {
|
export function main() {
|
||||||
describe("MessageBroker", () => {
|
describe("EventDispatcher", () => {
|
||||||
beforeEachBindings(() => [
|
beforeEachBindings(() => [
|
||||||
bind(ON_WEB_WORKER)
|
bind(ON_WEB_WORKER)
|
||||||
.toValue(true),
|
.toValue(true),
|
||||||
@ -33,47 +35,41 @@ export function main() {
|
|||||||
RenderViewWithFragmentsStore
|
RenderViewWithFragmentsStore
|
||||||
]);
|
]);
|
||||||
|
|
||||||
it("should dispatch events", inject([Serializer, NgZone], (serializer, zone) => {
|
it("should dispatch events",
|
||||||
var bus = new MockMessageBus(new MockMessageBusSink(), new MockMessageBusSource());
|
inject([Serializer, NgZone, AsyncTestCompleter], (serializer, zone, async) => {
|
||||||
var broker = new MessageBroker(bus, serializer, zone);
|
var messageBuses = createPairedMessageBuses();
|
||||||
|
var webWorkerEventDispatcher =
|
||||||
var eventDispatcher = new SpyEventDispatcher();
|
new WebWorkerEventDispatcher(messageBuses.worker, serializer, zone);
|
||||||
var viewRef = new WebWorkerRenderViewRef(0);
|
|
||||||
serializer.allocateRenderViews(0); // serialize the ref so it's in the store
|
|
||||||
viewRef =
|
|
||||||
serializer.deserialize(serializer.serialize(viewRef, RenderViewRef), RenderViewRef);
|
|
||||||
broker.registerEventDispatcher(viewRef, eventDispatcher);
|
|
||||||
|
|
||||||
var elementIndex = 15;
|
var elementIndex = 15;
|
||||||
var eventName = 'click';
|
var eventName = 'click';
|
||||||
|
|
||||||
bus.source.receive({
|
var eventDispatcher = new SpyEventDispatcher((elementIndex, eventName, locals) => {
|
||||||
'data': {
|
expect(elementIndex).toEqual(elementIndex);
|
||||||
'type': 'event',
|
expect(eventName).toEqual(eventName);
|
||||||
'value': {
|
async.done();
|
||||||
'viewRef': viewRef.serialize(),
|
|
||||||
'elementIndex': elementIndex,
|
|
||||||
'eventName': eventName,
|
|
||||||
'locals': {'$event': {'target': {value: null}}}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(eventDispatcher.wasDispatched).toBeTruthy();
|
var viewRef = new WebWorkerRenderViewRef(0);
|
||||||
expect(eventDispatcher.elementIndex).toEqual(elementIndex);
|
serializer.allocateRenderViews(0); // serialize the ref so it's in the store
|
||||||
expect(eventDispatcher.eventName).toEqual(eventName);
|
viewRef =
|
||||||
|
serializer.deserialize(serializer.serialize(viewRef, RenderViewRef), RenderViewRef);
|
||||||
|
webWorkerEventDispatcher.registerEventDispatcher(viewRef, eventDispatcher);
|
||||||
|
|
||||||
|
ObservableWrapper.callNext(messageBuses.ui.to(EVENT_CHANNEL), {
|
||||||
|
'viewRef': viewRef.serialize(),
|
||||||
|
'elementIndex': elementIndex,
|
||||||
|
'eventName': eventName,
|
||||||
|
'locals': {'$event': {'target': {value: null}}}
|
||||||
|
});
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class SpyEventDispatcher implements RenderEventDispatcher {
|
class SpyEventDispatcher implements RenderEventDispatcher {
|
||||||
wasDispatched: boolean = false;
|
constructor(private _callback: Function) {}
|
||||||
elementIndex: number;
|
|
||||||
eventName: string;
|
|
||||||
|
|
||||||
dispatchRenderEvent(elementIndex: number, eventName: string, locals: Map<string, any>) {
|
dispatchRenderEvent(elementIndex: number, eventName: string, locals: Map<string, any>) {
|
||||||
this.wasDispatched = true;
|
this._callback(elementIndex, eventName, locals);
|
||||||
this.elementIndex = elementIndex;
|
|
||||||
this.eventName = eventName;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
library angular2.test.web_workers.worker.mock_event_emitter;
|
||||||
|
|
||||||
|
import 'dart:core';
|
||||||
|
import 'dart:async';
|
||||||
|
import "package:angular2/src/facade/async.dart";
|
||||||
|
|
||||||
|
class MockEventEmitter extends EventEmitter {
|
||||||
|
List<Function> _nextFns = new List();
|
||||||
|
|
||||||
|
@override
|
||||||
|
StreamSubscription listen(void onData(dynamic line),
|
||||||
|
{void onError(Error error), void onDone(), bool cancelOnError}) {
|
||||||
|
_nextFns.add(onData);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void add(value) {
|
||||||
|
_nextFns.forEach((fn) => fn(value));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
import {EventEmitter} from 'angular2/src/facade/async';
|
||||||
|
import * as Rx from 'rx';
|
||||||
|
import {ListWrapper} from 'angular2/src/facade/collection';
|
||||||
|
|
||||||
|
export class MockEventEmitter extends EventEmitter {
|
||||||
|
private _nextFns: List<Function> = [];
|
||||||
|
|
||||||
|
constructor() { super(); }
|
||||||
|
|
||||||
|
observer(generator: any): Rx.IDisposable {
|
||||||
|
this._nextFns.push(generator.next);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
next(value: any) {
|
||||||
|
ListWrapper.forEach(this._nextFns, (fn) => { fn(value); });
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,7 @@ import {DOM} from 'angular2/src/dom/dom_adapter';
|
|||||||
import {DomTestbed, TestRootView, elRef} from '../../render/dom/dom_testbed';
|
import {DomTestbed, TestRootView, elRef} from '../../render/dom/dom_testbed';
|
||||||
import {bind} from 'angular2/di';
|
import {bind} from 'angular2/di';
|
||||||
import {WebWorkerCompiler, WebWorkerRenderer} from "angular2/src/web-workers/worker/renderer";
|
import {WebWorkerCompiler, WebWorkerRenderer} from "angular2/src/web-workers/worker/renderer";
|
||||||
import {MessageBroker, UiArguments, FnArg} from "angular2/src/web-workers/worker/broker";
|
import {MessageBrokerFactory, UiArguments, FnArg} from "angular2/src/web-workers/worker/broker";
|
||||||
import {Serializer} from "angular2/src/web-workers/shared/serializer";
|
import {Serializer} from "angular2/src/web-workers/shared/serializer";
|
||||||
import {isPresent, isBlank, BaseException, Type} from "angular2/src/facade/lang";
|
import {isPresent, isBlank, BaseException, Type} from "angular2/src/facade/lang";
|
||||||
import {MapWrapper, ListWrapper} from "angular2/src/facade/collection";
|
import {MapWrapper, ListWrapper} from "angular2/src/facade/collection";
|
||||||
@ -37,42 +37,47 @@ import {
|
|||||||
import {resolveInternalDomProtoView, DomProtoView} from 'angular2/src/render/dom/view/proto_view';
|
import {resolveInternalDomProtoView, DomProtoView} from 'angular2/src/render/dom/view/proto_view';
|
||||||
import {someComponent} from '../../render/dom/dom_renderer_integration_spec';
|
import {someComponent} from '../../render/dom/dom_renderer_integration_spec';
|
||||||
import {WebWorkerMain} from 'angular2/src/web-workers/ui/impl';
|
import {WebWorkerMain} from 'angular2/src/web-workers/ui/impl';
|
||||||
import {AnchorBasedAppRootUrl} from 'angular2/src/services/anchor_based_app_root_url';
|
import {MessageBasedRenderCompiler} from 'angular2/src/web-workers/ui/render_compiler';
|
||||||
import {MockMessageBus, MockMessageBusSink, MockMessageBusSource} from './worker_test_util';
|
import {MessageBasedRenderer} from 'angular2/src/web-workers/ui/renderer';
|
||||||
|
import {
|
||||||
|
createPairedMessageBuses
|
||||||
|
} from './worker_test_util'
|
||||||
|
|
||||||
export function main() {
|
export function
|
||||||
function createBroker(workerSerializer: Serializer, uiSerializer: Serializer, tb: DomTestbed,
|
main() {
|
||||||
uiRenderViewStore: RenderViewWithFragmentsStore,
|
function createBrokerFactory(workerSerializer: Serializer, uiSerializer: Serializer,
|
||||||
workerRenderViewStore: RenderViewWithFragmentsStore): MessageBroker {
|
tb: DomTestbed, uiRenderViewStore: RenderViewWithFragmentsStore,
|
||||||
// set up the two message buses to pass messages to each other
|
workerRenderViewStore: RenderViewWithFragmentsStore):
|
||||||
var uiMessageBus = new MockMessageBus(new MockMessageBusSink(), new MockMessageBusSource());
|
MessageBrokerFactory {
|
||||||
var workerMessageBus = new MockMessageBus(new MockMessageBusSink(), new MockMessageBusSource());
|
var messageBuses = createPairedMessageBuses();
|
||||||
uiMessageBus.attachToBus(workerMessageBus);
|
var uiMessageBus = messageBuses.ui;
|
||||||
workerMessageBus.attachToBus(uiMessageBus);
|
var workerMessageBus = messageBuses.worker;
|
||||||
|
|
||||||
// set up the worker side
|
// set up the worker side
|
||||||
var broker = new MessageBroker(workerMessageBus, workerSerializer, null);
|
var brokerFactory = new MessageBrokerFactory(workerMessageBus, workerSerializer);
|
||||||
|
|
||||||
// set up the ui side
|
// set up the ui side
|
||||||
var webWorkerMain = new WebWorkerMain(tb.compiler, tb.renderer, uiRenderViewStore, uiSerializer,
|
var renderCompiler = new MessageBasedRenderCompiler(uiMessageBus, uiSerializer, tb.compiler);
|
||||||
new AnchorBasedAppRootUrl(), null);
|
var renderer =
|
||||||
webWorkerMain.attachToWebWorker(uiMessageBus);
|
new MessageBasedRenderer(uiMessageBus, uiSerializer, uiRenderViewStore, tb.renderer);
|
||||||
return broker;
|
new WebWorkerMain(renderCompiler, renderer, null, null);
|
||||||
|
|
||||||
|
return brokerFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createWorkerRenderer(workerSerializer: Serializer, uiSerializer: Serializer,
|
function createWorkerRenderer(workerSerializer: Serializer, uiSerializer: Serializer,
|
||||||
tb: DomTestbed, uiRenderViewStore: RenderViewWithFragmentsStore,
|
tb: DomTestbed, uiRenderViewStore: RenderViewWithFragmentsStore,
|
||||||
workerRenderViewStore: RenderViewWithFragmentsStore):
|
workerRenderViewStore: RenderViewWithFragmentsStore):
|
||||||
WebWorkerRenderer {
|
WebWorkerRenderer {
|
||||||
var broker =
|
var brokerFactory = createBrokerFactory(workerSerializer, uiSerializer, tb, uiRenderViewStore,
|
||||||
createBroker(workerSerializer, uiSerializer, tb, uiRenderViewStore, workerRenderViewStore);
|
workerRenderViewStore);
|
||||||
return new WebWorkerRenderer(broker, workerRenderViewStore);
|
return new WebWorkerRenderer(brokerFactory, workerRenderViewStore, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createWorkerCompiler(workerSerializer: Serializer, uiSerializer: Serializer,
|
function createWorkerCompiler(workerSerializer: Serializer, uiSerializer: Serializer,
|
||||||
tb: DomTestbed): WebWorkerCompiler {
|
tb: DomTestbed): WebWorkerCompiler {
|
||||||
var broker = createBroker(workerSerializer, uiSerializer, tb, null, null);
|
var brokerFactory = createBrokerFactory(workerSerializer, uiSerializer, tb, null, null);
|
||||||
return new WebWorkerCompiler(broker);
|
return new WebWorkerCompiler(brokerFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("Web Worker Compiler", function() {
|
describe("Web Worker Compiler", function() {
|
@ -1,36 +1,60 @@
|
|||||||
|
import {StringMap, StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
||||||
import {
|
import {
|
||||||
MessageBus,
|
MessageBusInterface,
|
||||||
MessageBusSource,
|
|
||||||
MessageBusSink,
|
MessageBusSink,
|
||||||
SourceListener
|
MessageBusSource,
|
||||||
} from "angular2/src/web-workers/shared/message_bus";
|
MessageBus
|
||||||
import {MapWrapper} from "angular2/src/facade/collection";
|
} from 'angular2/src/web-workers/shared/message_bus';
|
||||||
|
import {MockEventEmitter} from './mock_event_emitter';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns two MessageBus instances that are attached to each other.
|
||||||
|
* Such that whatever goes into one's sink comes out the others source.
|
||||||
|
*/
|
||||||
|
export function createPairedMessageBuses(): PairedMessageBuses {
|
||||||
|
var firstChannels: StringMap<string, MockEventEmitter> = {};
|
||||||
|
var workerMessageBusSink = new MockMessageBusSink(firstChannels);
|
||||||
|
var uiMessageBusSource = new MockMessageBusSource(firstChannels);
|
||||||
|
|
||||||
|
var secondChannels: StringMap<string, MockEventEmitter> = {};
|
||||||
|
var uiMessageBusSink = new MockMessageBusSink(secondChannels);
|
||||||
|
var workerMessageBusSource = new MockMessageBusSource(secondChannels);
|
||||||
|
|
||||||
|
return new PairedMessageBuses(new MockMessageBus(uiMessageBusSink, uiMessageBusSource),
|
||||||
|
new MockMessageBus(workerMessageBusSink, workerMessageBusSource));
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PairedMessageBuses {
|
||||||
|
constructor(public ui: MessageBusInterface, public worker: MessageBusInterface) {}
|
||||||
|
}
|
||||||
|
|
||||||
export class MockMessageBusSource implements MessageBusSource {
|
export class MockMessageBusSource implements MessageBusSource {
|
||||||
private _listenerStore: Map<int, SourceListener> = new Map<int, SourceListener>();
|
constructor(private _channels: StringMap<string, MockEventEmitter>) {}
|
||||||
private _numListeners: number = 0;
|
|
||||||
|
|
||||||
addListener(fn: SourceListener): int {
|
from(channel: string): MockEventEmitter {
|
||||||
this._listenerStore.set(++this._numListeners, fn);
|
if (!StringMapWrapper.contains(this._channels, channel)) {
|
||||||
return this._numListeners;
|
this._channels[channel] = new MockEventEmitter();
|
||||||
}
|
}
|
||||||
|
return this._channels[channel];
|
||||||
removeListener(index: int): void { MapWrapper.delete(this._listenerStore, index); }
|
|
||||||
|
|
||||||
receive(message: Object): void {
|
|
||||||
MapWrapper.forEach(this._listenerStore, (fn: SourceListener, key: int) => { fn(message); });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MockMessageBusSink implements MessageBusSink {
|
export class MockMessageBusSink implements MessageBusSink {
|
||||||
private _sendTo: MockMessageBusSource;
|
constructor(private _channels: StringMap<string, MockEventEmitter>) {}
|
||||||
|
|
||||||
send(message: Object): void { this._sendTo.receive({'data': message}); }
|
to(channel: string): MockEventEmitter {
|
||||||
|
if (!StringMapWrapper.contains(this._channels, channel)) {
|
||||||
attachToSource(source: MockMessageBusSource) { this._sendTo = source; }
|
this._channels[channel] = new MockEventEmitter();
|
||||||
|
}
|
||||||
|
return this._channels[channel];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class MockMessageBus implements MessageBus {
|
export class MockMessageBus extends MessageBus {
|
||||||
constructor(public sink: MockMessageBusSink, public source: MockMessageBusSource) {}
|
constructor(public sink: MockMessageBusSink, public source: MockMessageBusSource) { super(); }
|
||||||
attachToBus(bus: MockMessageBus) { this.sink.attachToSource(bus.source); }
|
|
||||||
|
|
||||||
|
to(channel: string): MockEventEmitter { return this.sink.to(channel); }
|
||||||
|
|
||||||
|
from(channel: string): MockEventEmitter { return this.source.from(channel); }
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,11 @@ import {
|
|||||||
proxy
|
proxy
|
||||||
} from 'angular2/test_lib';
|
} from 'angular2/test_lib';
|
||||||
import {IMPLEMENTS, Type} from 'angular2/src/facade/lang';
|
import {IMPLEMENTS, Type} from 'angular2/src/facade/lang';
|
||||||
import {MessageBroker, UiArguments} from 'angular2/src/web-workers/worker/broker';
|
import {
|
||||||
|
MessageBroker,
|
||||||
|
UiArguments,
|
||||||
|
MessageBrokerFactory
|
||||||
|
} from 'angular2/src/web-workers/worker/broker';
|
||||||
import {WebWorkerXHRImpl} from "angular2/src/web-workers/worker/xhr_impl";
|
import {WebWorkerXHRImpl} from "angular2/src/web-workers/worker/xhr_impl";
|
||||||
import {PromiseWrapper} from "angular2/src/facade/async";
|
import {PromiseWrapper} from "angular2/src/facade/async";
|
||||||
|
|
||||||
@ -25,14 +29,13 @@ export function main() {
|
|||||||
var messageBroker: any = new SpyMessageBroker();
|
var messageBroker: any = new SpyMessageBroker();
|
||||||
messageBroker.spy("runOnUiThread")
|
messageBroker.spy("runOnUiThread")
|
||||||
.andCallFake((args: UiArguments, returnType: Type) => {
|
.andCallFake((args: UiArguments, returnType: Type) => {
|
||||||
expect(args.type).toEqual("xhr");
|
|
||||||
expect(args.method).toEqual("get");
|
expect(args.method).toEqual("get");
|
||||||
expect(args.args.length).toEqual(1);
|
expect(args.args.length).toEqual(1);
|
||||||
expect(args.args[0].value).toEqual(URL);
|
expect(args.args[0].value).toEqual(URL);
|
||||||
return PromiseWrapper.wrap(() => { return RESPONSE; });
|
return PromiseWrapper.wrap(() => { return RESPONSE; });
|
||||||
});
|
});
|
||||||
|
|
||||||
var xhrImpl = new WebWorkerXHRImpl(messageBroker);
|
var xhrImpl = new WebWorkerXHRImpl(new MockMessageBrokerFactory(messageBroker));
|
||||||
xhrImpl.get(URL).then((response) => {
|
xhrImpl.get(URL).then((response) => {
|
||||||
expect(response).toEqual(RESPONSE);
|
expect(response).toEqual(RESPONSE);
|
||||||
async.done();
|
async.done();
|
||||||
@ -47,3 +50,8 @@ class SpyMessageBroker extends SpyObject {
|
|||||||
constructor() { super(MessageBroker); }
|
constructor() { super(MessageBroker); }
|
||||||
noSuchMethod(m) { return super.noSuchMethod(m); }
|
noSuchMethod(m) { return super.noSuchMethod(m); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MockMessageBrokerFactory extends MessageBrokerFactory {
|
||||||
|
constructor(private _messageBroker: MessageBroker) { super(null, null); }
|
||||||
|
createMessageBroker(channel: string) { return this._messageBroker; }
|
||||||
|
}
|
||||||
|
@ -1,28 +1,29 @@
|
|||||||
library angular2.examples.message_broker.background_index;
|
library angular2.examples.message_broker.background_index;
|
||||||
|
|
||||||
import "package:angular2/src/web-workers/worker/application.dart"
|
|
||||||
show WebWorkerMessageBus;
|
|
||||||
import "package:angular2/src/web-workers/worker/broker.dart"
|
import "package:angular2/src/web-workers/worker/broker.dart"
|
||||||
show MessageBroker, UiArguments;
|
show MessageBroker, UiArguments;
|
||||||
import "package:angular2/src/web-workers/shared/serializer.dart"
|
import "package:angular2/src/web-workers/shared/serializer.dart"
|
||||||
show Serializer;
|
show Serializer;
|
||||||
|
import "package:angular2/src/web-workers/shared/isolate_message_bus.dart";
|
||||||
|
import "package:angular2/src/web-workers/worker/application.dart"
|
||||||
|
show WebWorkerMessageBusSink;
|
||||||
|
import "package:angular2/src/facade/async.dart";
|
||||||
import "dart:isolate";
|
import "dart:isolate";
|
||||||
|
|
||||||
main(List<String> args, SendPort replyTo) {
|
main(List<String> args, SendPort replyTo) {
|
||||||
ReceivePort rPort = new ReceivePort();
|
ReceivePort rPort = new ReceivePort();
|
||||||
WebWorkerMessageBus bus = new WebWorkerMessageBus.fromPorts(replyTo, rPort);
|
var sink = new WebWorkerMessageBusSink(replyTo, rPort);
|
||||||
bus.source.addListener((message) {
|
var source = new IsolateMessageBusSource(rPort);
|
||||||
if (identical(message['data']['type'], "echo")) {
|
IsolateMessageBus bus = new IsolateMessageBus(sink, source);
|
||||||
bus.sink
|
|
||||||
.send({"type": "echo_response", "value": message['data']['value']});
|
ObservableWrapper.subscribe(bus.from("echo"), (value) {
|
||||||
}
|
ObservableWrapper.callNext(bus.to("echo"), value);
|
||||||
});
|
});
|
||||||
|
|
||||||
MessageBroker broker =
|
MessageBroker broker =
|
||||||
new MessageBroker(bus, new Serializer(null, null, null), null);
|
new MessageBroker(bus, new Serializer(null, null, null), "test");
|
||||||
var args = new UiArguments("test", "tester");
|
var args = new UiArguments("tester");
|
||||||
broker.runOnUiThread(args, String).then((data) {
|
broker.runOnUiThread(args, String).then((data) {
|
||||||
bus.sink.send({"type": "result", "value": data});
|
ObservableWrapper.callNext(bus.to("result"), data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,30 @@
|
|||||||
import {
|
import {
|
||||||
WebWorkerMessageBus,
|
PostMessageBus,
|
||||||
WebWorkerMessageBusSource,
|
PostMessageBusSink,
|
||||||
WebWorkerMessageBusSink
|
PostMessageBusSource
|
||||||
} from "angular2/src/web-workers/worker/application";
|
} from 'angular2/src/web-workers/shared/post_message_bus';
|
||||||
|
import {ObservableWrapper} from 'angular2/src/facade/async';
|
||||||
import {MessageBroker, UiArguments} from "angular2/src/web-workers/worker/broker";
|
import {MessageBroker, UiArguments} from "angular2/src/web-workers/worker/broker";
|
||||||
import {Serializer} from "angular2/src/web-workers/shared/serializer";
|
import {Serializer} from "angular2/src/web-workers/shared/serializer";
|
||||||
|
|
||||||
export function main() {
|
interface PostMessageInterface {
|
||||||
var bus = new WebWorkerMessageBus(new WebWorkerMessageBusSink(), new WebWorkerMessageBusSource());
|
(message: any, transferrables?:[ArrayBuffer]): void;
|
||||||
bus.source.addListener((message) => {
|
}
|
||||||
if (message.data.type === "echo") {
|
var _postMessage: PostMessageInterface = <any>postMessage;
|
||||||
bus.sink.send({type: "echo_response", 'value': message.data.value});
|
|
||||||
}
|
export function main() {
|
||||||
});
|
var sink = new PostMessageBusSink({
|
||||||
|
postMessage:
|
||||||
var broker = new MessageBroker(bus, new Serializer(null, null, null), null);
|
(message: any, transferrables?:[ArrayBuffer]) => { _postMessage(message, transferrables); }
|
||||||
var args = new UiArguments("test", "tester");
|
});
|
||||||
broker.runOnUiThread(args, String)
|
var source = new PostMessageBusSource();
|
||||||
.then((data: string) => { bus.sink.send({type: "result", value: data}); });
|
var bus = new PostMessageBus(sink, source);
|
||||||
|
|
||||||
|
ObservableWrapper.subscribe(bus.from("echo"),
|
||||||
|
(value) => { ObservableWrapper.callNext(bus.to("echo"), value); });
|
||||||
|
|
||||||
|
var broker = new MessageBroker(bus, new Serializer(null, null, null), "test");
|
||||||
|
var args = new UiArguments("tester");
|
||||||
|
broker.runOnUiThread(args, String)
|
||||||
|
.then((data: string) => { ObservableWrapper.callNext(bus.to("result"), data); });
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
library angular2.examples.message_broker.index;
|
library angular2.examples.message_broker.index;
|
||||||
|
|
||||||
import "package:angular2/src/web-workers/ui/application.dart"
|
import "package:angular2/src/web-workers/ui/application.dart"
|
||||||
show spawnWebWorker, UIMessageBus, UIMessageBusSink, UIMessageBusSource;
|
show spawnWebWorker;
|
||||||
|
import "package:angular2/src/facade/async.dart";
|
||||||
import "dart:html";
|
import "dart:html";
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
@ -10,21 +10,21 @@ main() {
|
|||||||
spawnWebWorker(Uri.parse("background_index.dart")).then((bus) {
|
spawnWebWorker(Uri.parse("background_index.dart")).then((bus) {
|
||||||
querySelector("#send_echo").addEventListener("click", (e) {
|
querySelector("#send_echo").addEventListener("click", (e) {
|
||||||
var val = (querySelector("#echo_input") as InputElement).value;
|
var val = (querySelector("#echo_input") as InputElement).value;
|
||||||
bus.sink.send({'type': 'echo', 'value': val});
|
ObservableWrapper.callNext(bus.to("echo"), val);
|
||||||
});
|
});
|
||||||
bus.source.addListener((message) {
|
|
||||||
var data = message['data'];
|
ObservableWrapper.subscribe(bus.from("echo"), (message) {
|
||||||
if (identical(data['type'], "echo_response")) {
|
querySelector("#echo_result")
|
||||||
querySelector("#echo_result")
|
.appendHtml("<span class='response'>${message}</span>");
|
||||||
.appendHtml("<span class='response'>${data['value']}</span>");
|
});
|
||||||
} else if (identical(data['type'], "test")) {
|
ObservableWrapper.subscribe(bus.from("result"), (message) {
|
||||||
bus.sink.send({'type': "result", 'id': data['id'], 'value': VALUE});
|
querySelector("#ui_result")
|
||||||
} else if (identical(data['type'], "result")) {
|
.appendHtml("<span class='result'>${message}</span>");
|
||||||
querySelector("#ui_result")
|
});
|
||||||
.appendHtml("<span class='result'>${data['value']}</span>");
|
ObservableWrapper.subscribe(bus.from("test"),
|
||||||
} else if (identical(data['type'], "ready")) {
|
(Map<String, dynamic> message) {
|
||||||
bus.sink.send({'type': "init"});
|
ObservableWrapper.callNext(bus.to("test"),
|
||||||
}
|
{'id': message['id'], 'type': "result", 'value': VALUE});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,29 +1,28 @@
|
|||||||
import {
|
import {
|
||||||
UIMessageBus,
|
PostMessageBus,
|
||||||
UIMessageBusSink,
|
PostMessageBusSink,
|
||||||
UIMessageBusSource
|
PostMessageBusSource
|
||||||
} from "angular2/src/web-workers/ui/application";
|
} from 'angular2/src/web-workers/shared/post_message_bus';
|
||||||
|
import {ObservableWrapper} from 'angular2/src/facade/async';
|
||||||
|
|
||||||
var worker = new Worker("loader.js");
|
var webWorker = new Worker("loader.js");
|
||||||
var bus = new UIMessageBus(new UIMessageBusSink(worker), new UIMessageBusSource(worker));
|
var sink = new PostMessageBusSink(webWorker);
|
||||||
var VALUE = 5;
|
var source = new PostMessageBusSource(webWorker);
|
||||||
|
var bus = new PostMessageBus(sink, source);
|
||||||
|
const VALUE = 5;
|
||||||
|
|
||||||
document.getElementById("send_echo")
|
document.getElementById("send_echo")
|
||||||
.addEventListener("click", (e) => {
|
.addEventListener("click", (e) => {
|
||||||
var val = (<HTMLInputElement>document.getElementById("echo_input")).value;
|
var val = (<HTMLInputElement>document.getElementById("echo_input")).value;
|
||||||
bus.sink.send({type: "echo", value: val});
|
ObservableWrapper.callNext(bus.to("echo"), val);
|
||||||
});
|
});
|
||||||
|
|
||||||
bus.source.addListener((message) => {
|
ObservableWrapper.subscribe(bus.from("echo"), (message) => {
|
||||||
if (message.data.type === "echo_response") {
|
document.getElementById("echo_result").innerHTML = `<span class='response'>${message}</span>`;
|
||||||
document.getElementById("echo_result").innerHTML =
|
});
|
||||||
`<span class='response'>${message.data.value}</span>`;
|
ObservableWrapper.subscribe(bus.from("result"), (message) => {
|
||||||
} else if (message.data.type === "test") {
|
document.getElementById("ui_result").innerHTML = `<span class='result'>${message}</span>`;
|
||||||
bus.sink.send({type: "result", id: message.data.id, value: VALUE});
|
});
|
||||||
} else if (message.data.type == "result") {
|
ObservableWrapper.subscribe(bus.from("test"), (message: StringMap<string, any>) => {
|
||||||
document.getElementById("ui_result").innerHTML =
|
ObservableWrapper.callNext(bus.to("test"), {id: message['id'], type: "result", value: VALUE});
|
||||||
`<span class='result'>${message.data.value}</span>`;
|
|
||||||
} else if (message.data.type == "ready") {
|
|
||||||
bus.sink.send({type: "init"});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
@ -5,19 +5,19 @@ import 'dart:typed_data';
|
|||||||
|
|
||||||
// TODO(jteplitz602) Implement this class #3493
|
// TODO(jteplitz602) Implement this class #3493
|
||||||
class BitmapService {
|
class BitmapService {
|
||||||
ImageData applySepia (ImageData imageData) {
|
ImageData applySepia(ImageData imageData) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String arrayBufferToDataUri (Uint8ClampedList data) {
|
String arrayBufferToDataUri(Uint8ClampedList data) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageData convertToImageData (ByteBuffer buffer) {
|
ImageData convertToImageData(ByteBuffer buffer) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String toDataUri (ImageData imageData) {
|
String toDataUri(ImageData imageData) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user