feat(WebWorker): Expose MessageBroker API

Closes #3942
This commit is contained in:
Jason Teplitz
2015-09-01 10:55:11 -07:00
parent 6532171997
commit 358908e605
31 changed files with 267 additions and 275 deletions

View File

@ -12,6 +12,7 @@ import {ListWrapper, StringMapWrapper, MapWrapper} from "angular2/src/core/facad
import {Serializer} from "angular2/src/web_workers/shared/serializer";
import {Injectable} from "angular2/di";
import {Type, StringWrapper} from "angular2/src/core/facade/lang";
export {Type} from "angular2/src/core/facade/lang";
@Injectable()
export class ClientMessageBrokerFactory {
@ -29,7 +30,8 @@ export class ClientMessageBroker {
constructor(messageBus: MessageBus, protected _serializer: Serializer, public channel) {
this._sink = messageBus.to(channel);
var source = messageBus.from(channel);
ObservableWrapper.subscribe(source, (message) => this._handleMessage(message));
ObservableWrapper.subscribe(source,
(message: StringMap<string, any>) => this._handleMessage(message));
}
private _generateMessageId(name: string): string {
@ -43,7 +45,7 @@ export class ClientMessageBroker {
return id;
}
runOnUiThread(args: UiArguments, returnType: Type): Promise<any> {
runOnService(args: UiArguments, returnType: Type): Promise<any> {
var fnArgs = [];
if (isPresent(args.args)) {
ListWrapper.forEach(args.args, (argument) => {
@ -128,7 +130,7 @@ class MessageData {
}
export class FnArg {
constructor(public value, public type) {}
constructor(public value, public type: Type) {}
}
export class UiArguments {

View File

@ -5,7 +5,7 @@ import 'dart:async';
import 'dart:core';
import 'package:angular2/src/web_workers/shared/message_bus.dart'
show MessageBus;
import 'package:angular2/src/web_workers/ui/impl.dart' show bootstrapUICommon;
import 'package:angular2/src/web_workers/ui/impl.dart' show bootstrapUICommon, WebWorkerApplication;
import 'package:angular2/src/web_workers/shared/isolate_message_bus.dart';
/**
@ -14,26 +14,24 @@ import 'package:angular2/src/web_workers/shared/isolate_message_bus.dart';
* You instantiate a WebWorker application by calling bootstrap with the URI of your worker's index script
* Note: The WebWorker script must call bootstrapWebworker once it is set up to complete the bootstrapping process
*/
Future<MessageBus> bootstrap(String uri) {
return spawnWebWorker(Uri.parse(uri)).then((bus) {
bootstrapUICommon(bus);
return bus;
});
Future<IsolateInstance> bootstrap(String uri) async {
var instance = await spawnWebWorker(Uri.parse(uri));
instance.app = bootstrapUICommon(instance.bus);
return instance;
}
/**
* To be called from the main thread to spawn and communicate with the worker thread
*/
Future<MessageBus> spawnWebWorker(Uri uri) {
Future<IsolateInstance> spawnWebWorker(Uri uri) async {
var receivePort = new ReceivePort();
var isolateEndSendPort = receivePort.sendPort;
return Isolate.spawnUri(uri, const [], isolateEndSendPort).then((_) {
var source = new UIMessageBusSource(receivePort);
return source.sink.then((sendPort) {
var sink = new IsolateMessageBusSink(sendPort);
return new IsolateMessageBus(sink, source);
});
});
var isolate = await Isolate.spawnUri(uri, const [], isolateEndSendPort);
var source = new UIMessageBusSource(receivePort);
var sendPort = await source.sink;
var sink = new IsolateMessageBusSink(sendPort);
var bus = new IsolateMessageBus(sink, source);
return new IsolateInstance(null, isolate, bus);
}
class UIMessageBusSource extends IsolateMessageBusSource {
@ -43,3 +41,15 @@ class UIMessageBusSource extends IsolateMessageBusSource {
return message is SendPort;
});
}
/**
* Wrapper class that exposes the {@link WebWorkerApplication}
* Isolate instance and underyling {@link MessageBus} for lower level message passing.
*/
class IsolateInstance {
WebWorkerApplication app;
final Isolate isolate;
final MessageBus bus;
IsolateInstance(this.app, this.isolate, this.bus);
}

View File

@ -4,8 +4,9 @@ import {
PostMessageBusSource
} from 'angular2/src/web_workers/shared/post_message_bus';
import {MessageBus} from 'angular2/src/web_workers/shared/message_bus';
import {BaseException} from "angular2/src/core/facade/lang";
import {bootstrapUICommon} from "angular2/src/web_workers/ui/impl";
import {BaseException} from 'angular2/src/core/facade/lang';
import {bootstrapUICommon, WebWorkerApplication} from 'angular2/src/web_workers/ui/impl';
export {WebWorkerApplication} from 'angular2/src/web_workers/ui/impl';
export * from 'angular2/src/web_workers/shared/message_bus';
/**
@ -16,15 +17,24 @@ export * from 'angular2/src/web_workers/shared/message_bus';
* Note: The WebWorker script must call bootstrapWebworker once it is set up to complete the
* bootstrapping process
*/
export function bootstrap(uri: string): MessageBus {
var messageBus = spawnWebWorker(uri);
bootstrapUICommon(messageBus);
return messageBus;
export function bootstrap(uri: string): WebWorkerInstance {
var instance = spawnWebWorker(uri);
instance.app = bootstrapUICommon(instance.bus);
return instance;
}
export function spawnWebWorker(uri: string): MessageBus {
export function spawnWebWorker(uri: string): WebWorkerInstance {
var webWorker: Worker = new Worker(uri);
var sink = new PostMessageBusSink(webWorker);
var source = new PostMessageBusSource(webWorker);
return new PostMessageBus(sink, source);
var bus = new PostMessageBus(sink, source);
return new WebWorkerInstance(null, webWorker, bus);
}
/**
* Wrapper class that exposes the {@link WebWorkerApplication}
* Isolate instance and underyling {@link MessageBus} for lower level message passing.
*/
export class WebWorkerInstance {
constructor(public app: WebWorkerApplication, public worker: Worker, public bus: MessageBus) {}
}

View File

@ -2,7 +2,6 @@
// There should be a way to refactor application so that this file is unnecessary. See #3277
import {Injector, bind, Binding} from "angular2/di";
import {Reflector, reflector} from 'angular2/src/core/reflection/reflection';
import {ListWrapper} from 'angular2/src/core/facade/collection';
import {
Parser,
Lexer,
@ -61,13 +60,14 @@ import {
RenderViewWithFragmentsStore
} from 'angular2/src/web_workers/shared/render_view_with_fragments_store';
import {AnchorBasedAppRootUrl} from 'angular2/src/core/services/anchor_based_app_root_url';
import {WebWorkerMain} from 'angular2/src/web_workers/ui/impl';
import {WebWorkerApplication} from 'angular2/src/web_workers/ui/impl';
import {MessageBus} 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';
import {ServiceMessageBrokerFactory} from 'angular2/src/web_workers/shared/service_message_broker';
import {ClientMessageBrokerFactory} from 'angular2/src/web_workers/shared/client_message_broker';
var _rootInjector: Injector;
@ -134,12 +134,13 @@ function _injectorBindings(): any[] {
Testability,
AnchorBasedAppRootUrl,
bind(AppRootUrl).toAlias(AnchorBasedAppRootUrl),
WebWorkerMain,
WebWorkerApplication,
WebWorkerSetup,
MessageBasedRenderCompiler,
MessageBasedXHRImpl,
MessageBasedRenderer,
ServiceMessageBrokerFactory
ServiceMessageBrokerFactory,
ClientMessageBrokerFactory
];
}

View File

@ -15,25 +15,43 @@ 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';
import {
ClientMessageBrokerFactory,
ClientMessageBroker,
} from 'angular2/src/web_workers/shared/client_message_broker';
import {
ServiceMessageBrokerFactory,
ServiceMessageBroker
} from 'angular2/src/web_workers/shared/service_message_broker';
/**
* Creates a zone, sets up the DI bindings
* And then creates a new WebWorkerMain object to handle messages from the worker
*/
export function bootstrapUICommon(bus: MessageBus) {
export function bootstrapUICommon(bus: MessageBus): WebWorkerApplication {
BrowserDomAdapter.makeCurrent();
var zone = createNgZone();
wtfInit();
zone.run(() => {
return zone.run(() => {
var injector = createInjector(zone, bus);
// necessary to kick off all the message based components
injector.get(WebWorkerMain);
injector.get(MessageBasedRenderCompiler).start();
injector.get(MessageBasedRenderer).start();
injector.get(MessageBasedXHRImpl).start();
injector.get(WebWorkerSetup).start();
return injector.get(WebWorkerApplication);
});
}
@Injectable()
export class WebWorkerMain {
constructor(public renderCompiler: MessageBasedRenderCompiler,
public renderer: MessageBasedRenderer, public xhr: MessageBasedXHRImpl,
public setup: WebWorkerSetup) {}
export class WebWorkerApplication {
constructor(private _clientMessageBrokerFactory: ClientMessageBrokerFactory,
private _serviceMessageBrokerFactory: ServiceMessageBrokerFactory) {}
createClientMessageBroker(channel: string): ClientMessageBroker {
return this._clientMessageBrokerFactory.createMessageBroker(channel);
}
createServiceMessageBroker(channel: string): ServiceMessageBroker {
return this._serviceMessageBrokerFactory.createMessageBroker(channel);
}
}

View File

@ -13,8 +13,11 @@ import {ServiceMessageBrokerFactory} from 'angular2/src/web_workers/shared/servi
@Injectable()
export class MessageBasedRenderCompiler {
constructor(brokerFactory: ServiceMessageBrokerFactory, private _renderCompiler: RenderCompiler) {
var broker = brokerFactory.createMessageBroker(RENDER_COMPILER_CHANNEL);
constructor(private _brokerFactory: ServiceMessageBrokerFactory,
private _renderCompiler: RenderCompiler) {}
start(): void {
var broker = this._brokerFactory.createMessageBroker(RENDER_COMPILER_CHANNEL);
broker.registerMethod("compileHost", [RenderDirectiveMetadata],
bind(this._renderCompiler.compileHost, this._renderCompiler),
ProtoViewDto);

View File

@ -19,11 +19,13 @@ import {ServiceMessageBrokerFactory} from 'angular2/src/web_workers/shared/servi
@Injectable()
export class MessageBasedRenderer {
constructor(brokerFactory: ServiceMessageBrokerFactory, private _bus: MessageBus,
constructor(private _brokerFactory: ServiceMessageBrokerFactory, private _bus: MessageBus,
private _serializer: Serializer,
private _renderViewWithFragmentsStore: RenderViewWithFragmentsStore,
private _renderer: Renderer) {
var broker = brokerFactory.createMessageBroker(RENDERER_CHANNEL);
private _renderer: Renderer) {}
start(): void {
var broker = this._brokerFactory.createMessageBroker(RENDERER_CHANNEL);
broker.registerMethod("createRootHostView",
[RenderProtoViewRef, PRIMITIVE, PRIMITIVE, PRIMITIVE],
bind(this._createRootHostView, this));

View File

@ -7,14 +7,19 @@ import {StringWrapper} from 'angular2/src/core/facade/lang';
@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);
rootUrl: string;
constructor(private _bus: MessageBus, anchorBasedAppRootUrl: AnchorBasedAppRootUrl) {
this.rootUrl = anchorBasedAppRootUrl.value;
}
start(): void {
var sink = this._bus.to(SETUP_CHANNEL);
var source = this._bus.from(SETUP_CHANNEL);
ObservableWrapper.subscribe(source, (message: string) => {
if (StringWrapper.equals(message, "ready")) {
ObservableWrapper.callNext(sink, {"rootUrl": rootUrl});
ObservableWrapper.callNext(sink, {"rootUrl": this.rootUrl});
}
});
}

View File

@ -7,8 +7,10 @@ import {bind} from './bind';
@Injectable()
export class MessageBasedXHRImpl {
constructor(brokerFactory: ServiceMessageBrokerFactory, private _xhr: XHR) {
var broker = brokerFactory.createMessageBroker(XHR_CHANNEL);
constructor(private _brokerFactory: ServiceMessageBrokerFactory, private _xhr: XHR) {}
start(): void {
var broker = this._brokerFactory.createMessageBroker(XHR_CHANNEL);
broker.registerMethod("get", [PRIMITIVE], bind(this._xhr.get, this._xhr), PRIMITIVE);
}
}

View File

@ -44,7 +44,7 @@ export class WebWorkerCompiler implements RenderCompiler {
compileHost(directiveMetadata: RenderDirectiveMetadata): Promise<ProtoViewDto> {
var fnArgs: FnArg[] = [new FnArg(directiveMetadata, RenderDirectiveMetadata)];
var args: UiArguments = new UiArguments("compileHost", fnArgs);
return this._messageBroker.runOnUiThread(args, ProtoViewDto);
return this._messageBroker.runOnService(args, ProtoViewDto);
}
/**
@ -55,7 +55,7 @@ export class WebWorkerCompiler implements RenderCompiler {
compile(view: ViewDefinition): Promise<ProtoViewDto> {
var fnArgs: FnArg[] = [new FnArg(view, ViewDefinition)];
var args: UiArguments = new UiArguments("compile", fnArgs);
return this._messageBroker.runOnUiThread(args, ProtoViewDto);
return this._messageBroker.runOnService(args, ProtoViewDto);
}
/**
@ -71,7 +71,7 @@ export class WebWorkerCompiler implements RenderCompiler {
protoViewRefs: Array<RenderProtoViewRef | any[]>): Promise<RenderProtoViewMergeMapping> {
var fnArgs: FnArg[] = [new FnArg(protoViewRefs, RenderProtoViewRef)];
var args: UiArguments = new UiArguments("mergeProtoViewsRecursively", fnArgs);
return this._messageBroker.runOnUiThread(args, RenderProtoViewMergeMapping);
return this._messageBroker.runOnService(args, RenderProtoViewMergeMapping);
}
}
@ -126,7 +126,7 @@ export class WebWorkerRenderer implements Renderer {
fnArgs.push(new FnArg(startIndex, null));
var args = new UiArguments(method, fnArgs);
this._messageBroker.runOnUiThread(args, null);
this._messageBroker.runOnService(args, null);
return renderViewWithFragments;
}
@ -137,7 +137,7 @@ export class WebWorkerRenderer implements Renderer {
destroyView(viewRef: RenderViewRef) {
var fnArgs = [new FnArg(viewRef, RenderViewRef)];
var args = new UiArguments("destroyView", fnArgs);
this._messageBroker.runOnUiThread(args, null);
this._messageBroker.runOnService(args, null);
this._renderViewStore.remove(viewRef);
}
@ -151,7 +151,7 @@ export class WebWorkerRenderer implements Renderer {
new FnArg(fragmentRef, RenderFragmentRef)
];
var args = new UiArguments("attachFragmentAfterFragment", fnArgs);
this._messageBroker.runOnUiThread(args, null);
this._messageBroker.runOnService(args, null);
}
/**
@ -161,7 +161,7 @@ export class WebWorkerRenderer implements Renderer {
var fnArgs =
[new FnArg(elementRef, WebWorkerElementRef), new FnArg(fragmentRef, RenderFragmentRef)];
var args = new UiArguments("attachFragmentAfterElement", fnArgs);
this._messageBroker.runOnUiThread(args, null);
this._messageBroker.runOnService(args, null);
}
/**
@ -170,7 +170,7 @@ export class WebWorkerRenderer implements Renderer {
detachFragment(fragmentRef: RenderFragmentRef) {
var fnArgs = [new FnArg(fragmentRef, RenderFragmentRef)];
var args = new UiArguments("detachFragment", fnArgs);
this._messageBroker.runOnUiThread(args, null);
this._messageBroker.runOnService(args, null);
}
/**
@ -180,7 +180,7 @@ export class WebWorkerRenderer implements Renderer {
hydrateView(viewRef: RenderViewRef) {
var fnArgs = [new FnArg(viewRef, RenderViewRef)];
var args = new UiArguments("hydrateView", fnArgs);
this._messageBroker.runOnUiThread(args, null);
this._messageBroker.runOnService(args, null);
}
/**
@ -190,7 +190,7 @@ export class WebWorkerRenderer implements Renderer {
dehydrateView(viewRef: RenderViewRef) {
var fnArgs = [new FnArg(viewRef, RenderViewRef)];
var args = new UiArguments("dehydrateView", fnArgs);
this._messageBroker.runOnUiThread(args, null);
this._messageBroker.runOnService(args, null);
}
/**
@ -209,7 +209,7 @@ export class WebWorkerRenderer implements Renderer {
new FnArg(propertyValue, null)
];
var args = new UiArguments("setElementProperty", fnArgs);
this._messageBroker.runOnUiThread(args, null);
this._messageBroker.runOnService(args, null);
}
/**
@ -222,7 +222,7 @@ export class WebWorkerRenderer implements Renderer {
new FnArg(attributeValue, null)
];
var args = new UiArguments("setElementAttribute", fnArgs);
this._messageBroker.runOnUiThread(args, null);
this._messageBroker.runOnService(args, null);
}
/**
@ -235,7 +235,7 @@ export class WebWorkerRenderer implements Renderer {
new FnArg(isAdd, null)
];
var args = new UiArguments("setElementClass", fnArgs);
this._messageBroker.runOnUiThread(args, null);
this._messageBroker.runOnService(args, null);
}
/**
@ -248,7 +248,7 @@ export class WebWorkerRenderer implements Renderer {
new FnArg(styleValue, null)
];
var args = new UiArguments("setElementStyle", fnArgs);
this._messageBroker.runOnUiThread(args, null);
this._messageBroker.runOnService(args, null);
}
/**
@ -262,7 +262,7 @@ export class WebWorkerRenderer implements Renderer {
new FnArg(args, null)
];
var uiArgs = new UiArguments("invokeElementMethod", fnArgs);
this._messageBroker.runOnUiThread(uiArgs, null);
this._messageBroker.runOnService(uiArgs, null);
}
/**
@ -272,7 +272,7 @@ export class WebWorkerRenderer implements Renderer {
var fnArgs =
[new FnArg(viewRef, RenderViewRef), new FnArg(textNodeIndex, null), new FnArg(text, null)];
var args = new UiArguments("setText", fnArgs);
this._messageBroker.runOnUiThread(args, null);
this._messageBroker.runOnService(args, null);
}
/**
@ -282,6 +282,6 @@ export class WebWorkerRenderer implements Renderer {
var fnArgs = [new FnArg(viewRef, RenderViewRef)];
var args = new UiArguments("setEventDispatcher", fnArgs);
this._eventDispatcher.registerEventDispatcher(viewRef, dispatcher);
this._messageBroker.runOnUiThread(args, null);
this._messageBroker.runOnService(args, null);
}
}

View File

@ -25,6 +25,6 @@ export class WebWorkerXHRImpl extends XHR {
get(url: string): Promise<string> {
var fnArgs: FnArg[] = [new FnArg(url, null)];
var args: UiArguments = new UiArguments("get", fnArgs);
return this._messageBroker.runOnUiThread(args, String);
return this._messageBroker.runOnService(args, String);
}
}