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 { | ||||
|   StreamController<String> _controller; | ||||
|   StreamController<dynamic> _controller; | ||||
| 
 | ||||
|   EventEmitter() { | ||||
|     _controller = new StreamController.broadcast(); | ||||
|   } | ||||
| 
 | ||||
|   StreamSubscription listen(void onData(String line), | ||||
|   StreamSubscription listen(void onData(dynamic line), | ||||
|       {void onError(Error error), void onDone(), bool cancelOnError}) { | ||||
|     return _controller.stream.listen(onData, | ||||
|         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
 | ||||
| /** | ||||
|  * Message Bus is a low level API used to communicate between the UI and the worker. | ||||
|  * It smooths out the differences between Javascript's postMessage and Dart's Isolate | ||||
|  * allowing you to work with one consistent API. | ||||
|  */ | ||||
| export interface MessageBus { | ||||
|   sink: MessageBusSink; | ||||
|   source: MessageBusSource; | ||||
| import {EventEmitter} from 'angular2/src/facade/async'; | ||||
| import {BaseException} from 'angular2/src/facade/lang'; | ||||
| // TODO(jteplitz602): Replace both the interface and the exported class with an abstract class #3683
 | ||||
| 
 | ||||
| function _abstract() { | ||||
|   throw new BaseException("This method is abstract"); | ||||
| } | ||||
| 
 | ||||
| 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 { | ||||
|   /** | ||||
|    * Attaches the SourceListener to this source. | ||||
|    * The SourceListener will get called whenever the bus receives a message | ||||
|    * Returns a listener id that can be passed to {removeListener} | ||||
|    * Returns an {@link EventEmitter} that emits every time a messsage | ||||
|    * is received on the given channel. | ||||
|    */ | ||||
|   addListener(fn: SourceListener): number; | ||||
|   removeListener(index: number); | ||||
|   from(channel: string): EventEmitter; | ||||
| } | ||||
| 
 | ||||
| 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:core'; | ||||
| 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/shared/isolate_message_bus.dart'; | ||||
| 
 | ||||
| /** | ||||
|  * 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 | ||||
|  */ | ||||
| Future<UIMessageBus> spawnWebWorker(Uri uri) { | ||||
| Future<MessageBus> spawnWebWorker(Uri uri) { | ||||
|   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 UIMessageBusSink(sendPort); | ||||
|       return new UIMessageBus(sink, source); | ||||
|       var sink = new IsolateMessageBusSink(sendPort); | ||||
|       return new IsolateMessageBus(sink, source); | ||||
|     }); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| class UIMessageBus extends MessageBus { | ||||
|   final UIMessageBusSink sink; | ||||
|   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(); | ||||
| class UIMessageBusSource extends IsolateMessageBusSource { | ||||
|   UIMessageBusSource(ReceivePort port) : super(port); | ||||
| 
 | ||||
|   Future<SendPort> get sink => rawDataStream.firstWhere((message) { | ||||
|         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 { | ||||
|   MessageBus, | ||||
|   MessageBusSource, | ||||
|   MessageBusSink, | ||||
|   SourceListener | ||||
| } from "angular2/src/web-workers/shared/message_bus"; | ||||
|   PostMessageBus, | ||||
|   PostMessageBusSink, | ||||
|   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/facade/lang"; | ||||
| 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 { | ||||
|   var webWorker: Worker = new Worker(uri); | ||||
|   return new UIMessageBus(new UIMessageBusSink(webWorker), new UIMessageBusSource(webWorker)); | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
|   } | ||||
|   var sink = new PostMessageBusSink(webWorker); | ||||
|   var source = new PostMessageBusSource(webWorker); | ||||
|   return new PostMessageBus(sink, source); | ||||
| } | ||||
|  | ||||
| @ -62,6 +62,11 @@ import { | ||||
| } from 'angular2/src/web-workers/shared/render_view_with_fragments_store'; | ||||
| import {AnchorBasedAppRootUrl} from 'angular2/src/services/anchor_based_app_root_url'; | ||||
| 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; | ||||
| 
 | ||||
| @ -129,13 +134,18 @@ function _injectorBindings(): List<Type | Binding | List<any>> { | ||||
|     Testability, | ||||
|     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(); | ||||
|   _rootBindings.push(bind(NgZone).toValue(zone)); | ||||
|   _rootBindings.push(bind(MessageBus).toValue(bus)); | ||||
|   var injector: Injector = Injector.resolveAndCreate(_rootBindings); | ||||
|   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 { | ||||
|   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 { | ||||
|   RenderViewWithFragmentsStore | ||||
| } from 'angular2/src/web-workers/shared/render_view_with_fragments_store'; | ||||
| 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 {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 {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 | ||||
| @ -49,305 +25,20 @@ export function bootstrapUICommon(bus: MessageBus) { | ||||
|   var zone = createNgZone(); | ||||
|   wtfInit(); | ||||
|   zone.run(() => { | ||||
|     var injector = createInjector(zone); | ||||
|     var webWorkerMain = injector.get(WebWorkerMain); | ||||
|     webWorkerMain.attachToWebWorker(bus); | ||||
|     var injector = createInjector(zone, bus); | ||||
|     // necessary to kick off all the message based components
 | ||||
|     injector.get(WebWorkerMain); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| @Injectable() | ||||
| export class WebWorkerMain { | ||||
|   private _rootUrl: string; | ||||
|   private _bus: MessageBus; | ||||
| 
 | ||||
|   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); }); | ||||
|   } | ||||
|   constructor(public renderCompiler: MessageBasedRenderCompiler, | ||||
|               public renderer: MessageBasedRenderer, public xhr: MessageBasedXHRImpl, | ||||
|               public setup: WebWorkerSetup) {} | ||||
| } | ||||
| 
 | ||||
| class EventDispatcher implements RenderEventDispatcher { | ||||
|   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 { | ||||
| export class ReceivedMessage { | ||||
|   method: string; | ||||
|   args: List<any>; | ||||
|   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; | ||||
| 
 | ||||
| import "package:angular2/src/web-workers/shared/message_bus.dart" | ||||
|     show MessageBus, MessageBusSource, MessageBusSink; | ||||
| import "package:angular2/src/web-workers/shared/isolate_message_bus.dart"; | ||||
| import "package:angular2/src/web-workers/worker/application_common.dart" | ||||
|     show bootstrapWebWorkerCommon; | ||||
| import "package:angular2/src/facade/async.dart" show Future; | ||||
| @ -26,56 +25,15 @@ Future<ApplicationRef> bootstrapWebWorker( | ||||
|     SendPort replyTo, Type appComponentType, | ||||
|     [List<dynamic> componentInjectableBindings = null]) { | ||||
|   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( | ||||
|       appComponentType, bus, componentInjectableBindings); | ||||
| } | ||||
| 
 | ||||
| class WebWorkerMessageBus extends MessageBus { | ||||
|   final WebWorkerMessageBusSink sink; | ||||
|   final WebWorkerMessageBusSource source; | ||||
| 
 | ||||
|   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); | ||||
| class WebWorkerMessageBusSink extends IsolateMessageBusSink { | ||||
|   WebWorkerMessageBusSink(SendPort sPort, ReceivePort rPort) : super(sPort) { | ||||
|     sPort.send(rPort.sendPort); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -1,18 +1,21 @@ | ||||
| import { | ||||
|   MessageBus, | ||||
|   MessageBusSource, | ||||
|   MessageBusSink, | ||||
|   SourceListener | ||||
| } from "angular2/src/web-workers/shared/message_bus"; | ||||
|   PostMessageBus, | ||||
|   PostMessageBusSink, | ||||
|   PostMessageBusSource | ||||
| } from 'angular2/src/web-workers/shared/post_message_bus'; | ||||
| import {Type, BaseException} from "angular2/src/facade/lang"; | ||||
| 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 {ApplicationRef} from "angular2/src/core/application"; | ||||
| import {Injectable} from "angular2/di"; | ||||
| 
 | ||||
| // 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 | ||||
| @ -26,44 +29,12 @@ var _postMessage: (message: any, transferrables?:[ArrayBuffer]) => void = <any>p | ||||
| export function bootstrapWebWorker( | ||||
|     appComponentType: Type, componentInjectableBindings: List<Type | Binding | List<any>> = null): | ||||
|     Promise<ApplicationRef> { | ||||
|   var bus: WebWorkerMessageBus = | ||||
|       new WebWorkerMessageBus(new WebWorkerMessageBusSink(), new WebWorkerMessageBusSource()); | ||||
|   var sink = new PostMessageBusSink({ | ||||
|     postMessage: | ||||
|         (message: any, transferrables?:[ArrayBuffer]) => { _postMessage(message, transferrables); } | ||||
|   }); | ||||
|   var source = new PostMessageBusSource(); | ||||
|   var bus = new PostMessageBus(sink, source); | ||||
| 
 | ||||
|   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 {internalView} from 'angular2/src/core/compiler/view_ref'; | ||||
| 
 | ||||
| import {MessageBroker} from 'angular2/src/web-workers/worker/broker'; | ||||
| import {WebWorkerMessageBus} from 'angular2/src/web-workers/worker/application'; | ||||
| import {MessageBrokerFactory} from 'angular2/src/web-workers/worker/broker'; | ||||
| 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 {ApplicationRef} from 'angular2/src/core/application'; | ||||
| import {createNgZone} from 'angular2/src/core/application_common'; | ||||
| @ -63,6 +63,9 @@ import {RenderProtoViewRefStore} from 'angular2/src/web-workers/shared/render_pr | ||||
| import { | ||||
|   RenderViewWithFragmentsStore | ||||
| } 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; | ||||
| 
 | ||||
| @ -75,7 +78,7 @@ class PrintLogger { | ||||
|   logGroupEnd() {} | ||||
| } | ||||
| 
 | ||||
| function _injectorBindings(appComponentType, bus: WebWorkerMessageBus, | ||||
| function _injectorBindings(appComponentType, bus: MessageBusInterface, | ||||
|                            initData: StringMap<string, any>): List<Type | Binding | List<any>> { | ||||
|   var bestChangeDetection: Type = DynamicChangeDetection; | ||||
|   if (PreGeneratedChangeDetection.isSupported()) { | ||||
| @ -100,10 +103,8 @@ function _injectorBindings(appComponentType, bus: WebWorkerMessageBus, | ||||
|     bind(LifeCycle).toFactory((exceptionHandler) => new LifeCycle(null, assertionsEnabled()), | ||||
|                               [ExceptionHandler]), | ||||
|     Serializer, | ||||
|     bind(WebWorkerMessageBus).toValue(bus), | ||||
|     bind(MessageBroker) | ||||
|         .toFactory((a, b, c) => new MessageBroker(a, b, c), | ||||
|                    [WebWorkerMessageBus, Serializer, NgZone]), | ||||
|     bind(MessageBus).toValue(bus), | ||||
|     MessageBrokerFactory, | ||||
|     WebWorkerRenderer, | ||||
|     bind(Renderer).toAlias(WebWorkerRenderer), | ||||
|     WebWorkerCompiler, | ||||
| @ -136,12 +137,13 @@ function _injectorBindings(appComponentType, bus: WebWorkerMessageBus, | ||||
|     StyleUrlResolver, | ||||
|     DynamicComponentLoader, | ||||
|     Testability, | ||||
|     bind(AppRootUrl).toValue(new AppRootUrl(initData['rootUrl'])) | ||||
|     bind(AppRootUrl).toValue(new AppRootUrl(initData['rootUrl'])), | ||||
|     WebWorkerEventDispatcher | ||||
|   ]; | ||||
| } | ||||
| 
 | ||||
| export function bootstrapWebWorkerCommon( | ||||
|     appComponentType: Type, bus: WebWorkerMessageBus, | ||||
|     appComponentType: Type, bus: MessageBusInterface, | ||||
|     componentInjectableBindings: List<Type | Binding | List<any>> = null): Promise<ApplicationRef> { | ||||
|   var bootstrapProcess: PromiseCompleter<any> = PromiseWrapper.completer(); | ||||
| 
 | ||||
| @ -151,14 +153,12 @@ export function bootstrapWebWorkerCommon( | ||||
|     // 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, | ||||
|                                            message["data"]["value"]); | ||||
|     var subscription: any; | ||||
|     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(() => { | ||||
|         try { | ||||
|           return appInjector.get(APP_COMPONENT_REF_PROMISE); | ||||
| @ -178,17 +178,17 @@ export function bootstrapWebWorkerCommon( | ||||
|       PromiseWrapper.then(compRefToken, tick, | ||||
|                           (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; | ||||
| } | ||||
| 
 | ||||
| function _createAppInjector(appComponentType: Type, bindings: List<Type | Binding | List<any>>, | ||||
|                             zone: NgZone, bus: WebWorkerMessageBus, | ||||
|                             zone: NgZone, bus: MessageBusInterface, | ||||
|                             initData: StringMap<string, any>): Injector { | ||||
|   if (isBlank(_rootInjector)) _rootInjector = Injector.resolveAndCreate(_rootBindings); | ||||
|   var mergedBindings: any[] = | ||||
| @ -197,4 +197,4 @@ function _createAppInjector(appComponentType: Type, bindings: List<Type | Bindin | ||||
|           _injectorBindings(appComponentType, bus, initData); | ||||
|   mergedBindings.push(bind(NgZone).toValue(zone)); | ||||
|   return _rootInjector.resolveAndCreateChild(mergedBindings); | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -1,24 +1,35 @@ | ||||
| /// <reference path="../../../globals.d.ts" />
 | ||||
| import {MessageBus} from "angular2/src/web-workers/shared/message_bus"; | ||||
| 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 {Serializer} from "angular2/src/web-workers/shared/serializer"; | ||||
| import {Injectable} from "angular2/di"; | ||||
| 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() | ||||
| 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 { | ||||
|   private _pending: Map<string, PromiseCompleter<any>> = new Map<string, PromiseCompleter<any>>(); | ||||
|   private _eventDispatchRegistry: Map<RenderViewRef, RenderEventDispatcher> = | ||||
|       new Map<RenderViewRef, RenderEventDispatcher>(); | ||||
|   private _sink: EventEmitter; | ||||
| 
 | ||||
|   constructor(private _messageBus: MessageBus, protected _serializer: Serializer, | ||||
|               private _zone: NgZone) { | ||||
|     this._messageBus.source.addListener((data) => this._handleMessage(data['data'])); | ||||
|   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)); | ||||
|   } | ||||
| 
 | ||||
|   private _generateMessageId(name: string): string { | ||||
| @ -48,7 +59,7 @@ export class MessageBroker { | ||||
|     var id: string = null; | ||||
|     if (returnType != null) { | ||||
|       var completer: PromiseCompleter<any> = PromiseWrapper.completer(); | ||||
|       id = this._generateMessageId(args.type + args.method); | ||||
|       id = this._generateMessageId(args.method); | ||||
|       this._pending.set(id, completer); | ||||
|       PromiseWrapper.catchError(completer.promise, (err, stack?) => { | ||||
|         print(err); | ||||
| @ -66,22 +77,20 @@ export class MessageBroker { | ||||
|       promise = null; | ||||
|     } | ||||
| 
 | ||||
|     // TODO(jteplitz602): Create a class for these messages so we don't keep using StringMap
 | ||||
|     var message = {'type': args.type, 'method': args.method, 'args': fnArgs}; | ||||
|     // TODO(jteplitz602): Create a class for these messages so we don't keep using StringMap #3685
 | ||||
|     var message = {'method': args.method, 'args': fnArgs}; | ||||
|     if (id != null) { | ||||
|       message['id'] = id; | ||||
|     } | ||||
|     this._messageBus.sink.send(message); | ||||
|     ObservableWrapper.callNext(this._sink, message); | ||||
| 
 | ||||
|     return promise; | ||||
|   } | ||||
| 
 | ||||
|   private _handleMessage(message: StringMap<string, any>): void { | ||||
|     var data = new MessageData(message); | ||||
|     // TODO(jteplitz602): replace these strings with messaging constants
 | ||||
|     if (data.type === "event") { | ||||
|       this._dispatchEvent(new RenderEventData(data.value, this._serializer)); | ||||
|     } else if (data.type === "result" || data.type === "error") { | ||||
|     // TODO(jteplitz602): replace these strings with messaging constants #3685
 | ||||
|     if (data.type === "result" || data.type === "error") { | ||||
|       var id = data.id; | ||||
|       if (this._pending.has(id)) { | ||||
|         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 { | ||||
| @ -149,5 +132,5 @@ export class FnArg { | ||||
| } | ||||
| 
 | ||||
| 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 | ||||
| } from 'angular2/src/render/api'; | ||||
| 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 {Injectable} from "angular2/di"; | ||||
| import { | ||||
| @ -21,16 +26,24 @@ import { | ||||
|   WebWorkerRenderViewRef | ||||
| } from 'angular2/src/web-workers/shared/render_view_with_fragments_store'; | ||||
| 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() | ||||
| 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. | ||||
|    */ | ||||
|   compileHost(directiveMetadata: RenderDirectiveMetadata): Promise<ProtoViewDto> { | ||||
|     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); | ||||
|   } | ||||
| 
 | ||||
| @ -41,7 +54,7 @@ export class WebWorkerCompiler implements RenderCompiler { | ||||
|    */ | ||||
|   compile(view: ViewDefinition): Promise<ProtoViewDto> { | ||||
|     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); | ||||
|   } | ||||
| 
 | ||||
| @ -57,7 +70,7 @@ export class WebWorkerCompiler implements RenderCompiler { | ||||
|   mergeProtoViewsRecursively( | ||||
|       protoViewRefs: List<RenderProtoViewRef | List<any>>): Promise<RenderProtoViewMergeMapping> { | ||||
|     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); | ||||
|   } | ||||
| } | ||||
| @ -65,8 +78,12 @@ export class WebWorkerCompiler implements RenderCompiler { | ||||
| 
 | ||||
| @Injectable() | ||||
| export class WebWorkerRenderer implements Renderer { | ||||
|   constructor(private _messageBroker: MessageBroker, | ||||
|               private _renderViewStore: RenderViewWithFragmentsStore) {} | ||||
|   private _messageBroker; | ||||
|   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. | ||||
|    * 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)); | ||||
| 
 | ||||
|     var args = new UiArguments("renderer", method, fnArgs); | ||||
|     var args = new UiArguments(method, fnArgs); | ||||
|     this._messageBroker.runOnUiThread(args, null); | ||||
| 
 | ||||
|     return renderViewWithFragments; | ||||
| @ -119,7 +136,7 @@ export class WebWorkerRenderer implements Renderer { | ||||
|    */ | ||||
|   destroyView(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); | ||||
|   } | ||||
| 
 | ||||
| @ -132,7 +149,7 @@ export class WebWorkerRenderer implements Renderer { | ||||
|       new FnArg(previousFragmentRef, RenderFragmentRef), | ||||
|       new FnArg(fragmentRef, RenderFragmentRef) | ||||
|     ]; | ||||
|     var args = new UiArguments("renderer", "attachFragmentAfterFragment", fnArgs); | ||||
|     var args = new UiArguments("attachFragmentAfterFragment", fnArgs); | ||||
|     this._messageBroker.runOnUiThread(args, null); | ||||
|   } | ||||
| 
 | ||||
| @ -142,7 +159,7 @@ export class WebWorkerRenderer implements Renderer { | ||||
|   attachFragmentAfterElement(elementRef: RenderElementRef, fragmentRef: RenderFragmentRef) { | ||||
|     var fnArgs = | ||||
|         [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); | ||||
|   } | ||||
| 
 | ||||
| @ -151,7 +168,7 @@ export class WebWorkerRenderer implements Renderer { | ||||
|    */ | ||||
|   detachFragment(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); | ||||
|   } | ||||
| 
 | ||||
| @ -161,7 +178,7 @@ export class WebWorkerRenderer implements Renderer { | ||||
|    */ | ||||
|   hydrateView(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); | ||||
|   } | ||||
| 
 | ||||
| @ -171,7 +188,7 @@ export class WebWorkerRenderer implements Renderer { | ||||
|    */ | ||||
|   dehydrateView(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); | ||||
|   } | ||||
| 
 | ||||
| @ -190,7 +207,7 @@ export class WebWorkerRenderer implements Renderer { | ||||
|       new FnArg(propertyName, null), | ||||
|       new FnArg(propertyValue, null) | ||||
|     ]; | ||||
|     var args = new UiArguments("renderer", "setElementProperty", fnArgs); | ||||
|     var args = new UiArguments("setElementProperty", fnArgs); | ||||
|     this._messageBroker.runOnUiThread(args, null); | ||||
|   } | ||||
| 
 | ||||
| @ -203,7 +220,7 @@ export class WebWorkerRenderer implements Renderer { | ||||
|       new FnArg(attributeName, null), | ||||
|       new FnArg(attributeValue, null) | ||||
|     ]; | ||||
|     var args = new UiArguments("renderer", "setElementAttribute", fnArgs); | ||||
|     var args = new UiArguments("setElementAttribute", fnArgs); | ||||
|     this._messageBroker.runOnUiThread(args, null); | ||||
|   } | ||||
| 
 | ||||
| @ -216,7 +233,7 @@ export class WebWorkerRenderer implements Renderer { | ||||
|       new FnArg(className, null), | ||||
|       new FnArg(isAdd, null) | ||||
|     ]; | ||||
|     var args = new UiArguments("renderer", "setElementClass", fnArgs); | ||||
|     var args = new UiArguments("setElementClass", fnArgs); | ||||
|     this._messageBroker.runOnUiThread(args, null); | ||||
|   } | ||||
| 
 | ||||
| @ -229,7 +246,7 @@ export class WebWorkerRenderer implements Renderer { | ||||
|       new FnArg(styleName, null), | ||||
|       new FnArg(styleValue, null) | ||||
|     ]; | ||||
|     var args = new UiArguments("renderer", "setElementStyle", fnArgs); | ||||
|     var args = new UiArguments("setElementStyle", fnArgs); | ||||
|     this._messageBroker.runOnUiThread(args, null); | ||||
|   } | ||||
| 
 | ||||
| @ -243,7 +260,7 @@ export class WebWorkerRenderer implements Renderer { | ||||
|       new FnArg(methodName, null), | ||||
|       new FnArg(args, null) | ||||
|     ]; | ||||
|     var uiArgs = new UiArguments("renderer", "invokeElementMethod", fnArgs); | ||||
|     var uiArgs = new UiArguments("invokeElementMethod", fnArgs); | ||||
|     this._messageBroker.runOnUiThread(uiArgs, null); | ||||
|   } | ||||
| 
 | ||||
| @ -253,7 +270,7 @@ export class WebWorkerRenderer implements Renderer { | ||||
|   setText(viewRef: RenderViewRef, textNodeIndex: number, text: string) { | ||||
|     var fnArgs = | ||||
|         [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); | ||||
|   } | ||||
| 
 | ||||
| @ -262,8 +279,8 @@ export class WebWorkerRenderer implements Renderer { | ||||
|    */ | ||||
|   setEventDispatcher(viewRef: RenderViewRef, dispatcher: RenderEventDispatcher) { | ||||
|     var fnArgs = [new FnArg(viewRef, RenderViewRef)]; | ||||
|     var args = new UiArguments("renderer", "setEventDispatcher", fnArgs); | ||||
|     this._messageBroker.registerEventDispatcher(viewRef, dispatcher); | ||||
|     var args = new UiArguments("setEventDispatcher", fnArgs); | ||||
|     this._eventDispatcher.registerEventDispatcher(viewRef, dispatcher); | ||||
|     this._messageBroker.runOnUiThread(args, null); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -1,7 +1,13 @@ | ||||
| import {Injectable} from 'angular2/di'; | ||||
| import {Promise} from 'angular2/src/facade/async'; | ||||
| 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 | ||||
| @ -9,11 +15,16 @@ import {FnArg, UiArguments, MessageBroker} from 'angular2/src/web-workers/worker | ||||
|  */ | ||||
| @Injectable() | ||||
| 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> { | ||||
|     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); | ||||
|   } | ||||
| } | ||||
|  | ||||
							
								
								
									
										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 {Serializer} from 'angular2/src/web-workers/shared/serializer'; | ||||
| 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 {bind} from 'angular2/di'; | ||||
| import {RenderProtoViewRefStore} from 'angular2/src/web-workers/shared/render_proto_view_ref_store'; | ||||
| @ -23,9 +21,13 @@ import { | ||||
|   WebWorkerRenderViewRef | ||||
| } from 'angular2/src/web-workers/shared/render_view_with_fragments_store'; | ||||
| 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() { | ||||
|   describe("MessageBroker", () => { | ||||
|   describe("EventDispatcher", () => { | ||||
|     beforeEachBindings(() => [ | ||||
|       bind(ON_WEB_WORKER) | ||||
|           .toValue(true), | ||||
| @ -33,47 +35,41 @@ export function main() { | ||||
|       RenderViewWithFragmentsStore | ||||
|     ]); | ||||
| 
 | ||||
|     it("should dispatch events", inject([Serializer, NgZone], (serializer, zone) => { | ||||
|          var bus = new MockMessageBus(new MockMessageBusSink(), new MockMessageBusSource()); | ||||
|          var broker = new MessageBroker(bus, serializer, zone); | ||||
| 
 | ||||
|          var eventDispatcher = new SpyEventDispatcher(); | ||||
|          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); | ||||
|     it("should dispatch events", | ||||
|        inject([Serializer, NgZone, AsyncTestCompleter], (serializer, zone, async) => { | ||||
|          var messageBuses = createPairedMessageBuses(); | ||||
|          var webWorkerEventDispatcher = | ||||
|              new WebWorkerEventDispatcher(messageBuses.worker, serializer, zone); | ||||
| 
 | ||||
|          var elementIndex = 15; | ||||
|          var eventName = 'click'; | ||||
| 
 | ||||
|          bus.source.receive({ | ||||
|            'data': { | ||||
|              'type': 'event', | ||||
|              'value': { | ||||
|                'viewRef': viewRef.serialize(), | ||||
|                'elementIndex': elementIndex, | ||||
|                'eventName': eventName, | ||||
|                'locals': {'$event': {'target': {value: null}}} | ||||
|              } | ||||
|            } | ||||
|          var eventDispatcher = new SpyEventDispatcher((elementIndex, eventName, locals) => { | ||||
|            expect(elementIndex).toEqual(elementIndex); | ||||
|            expect(eventName).toEqual(eventName); | ||||
|            async.done(); | ||||
|          }); | ||||
| 
 | ||||
|          expect(eventDispatcher.wasDispatched).toBeTruthy(); | ||||
|          expect(eventDispatcher.elementIndex).toEqual(elementIndex); | ||||
|          expect(eventDispatcher.eventName).toEqual(eventName); | ||||
|          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); | ||||
|          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 { | ||||
|   wasDispatched: boolean = false; | ||||
|   elementIndex: number; | ||||
|   eventName: string; | ||||
|   constructor(private _callback: Function) {} | ||||
| 
 | ||||
|   dispatchRenderEvent(elementIndex: number, eventName: string, locals: Map<string, any>) { | ||||
|     this.wasDispatched = true; | ||||
|     this.elementIndex = elementIndex; | ||||
|     this.eventName = eventName; | ||||
|     this._callback(elementIndex, eventName, locals); | ||||
|   } | ||||
| } | ||||
| @ -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 {bind} from 'angular2/di'; | ||||
| 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 {isPresent, isBlank, BaseException, Type} from "angular2/src/facade/lang"; | ||||
| 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 {someComponent} from '../../render/dom/dom_renderer_integration_spec'; | ||||
| import {WebWorkerMain} from 'angular2/src/web-workers/ui/impl'; | ||||
| import {AnchorBasedAppRootUrl} from 'angular2/src/services/anchor_based_app_root_url'; | ||||
| import {MockMessageBus, MockMessageBusSink, MockMessageBusSource} from './worker_test_util'; | ||||
| import {MessageBasedRenderCompiler} from 'angular2/src/web-workers/ui/render_compiler'; | ||||
| import {MessageBasedRenderer} from 'angular2/src/web-workers/ui/renderer'; | ||||
| import { | ||||
|   createPairedMessageBuses | ||||
| } from './worker_test_util' | ||||
| 
 | ||||
| export function main() { | ||||
|   function createBroker(workerSerializer: Serializer, uiSerializer: Serializer, tb: DomTestbed, | ||||
|                         uiRenderViewStore: RenderViewWithFragmentsStore, | ||||
|                         workerRenderViewStore: RenderViewWithFragmentsStore): MessageBroker { | ||||
|     // set up the two message buses to pass messages to each other
 | ||||
|     var uiMessageBus = new MockMessageBus(new MockMessageBusSink(), new MockMessageBusSource()); | ||||
|     var workerMessageBus = new MockMessageBus(new MockMessageBusSink(), new MockMessageBusSource()); | ||||
|     uiMessageBus.attachToBus(workerMessageBus); | ||||
|     workerMessageBus.attachToBus(uiMessageBus); | ||||
|     export function | ||||
|     main() { | ||||
|   function createBrokerFactory(workerSerializer: Serializer, uiSerializer: Serializer, | ||||
|                                tb: DomTestbed, uiRenderViewStore: RenderViewWithFragmentsStore, | ||||
|                                workerRenderViewStore: RenderViewWithFragmentsStore): | ||||
|       MessageBrokerFactory { | ||||
|     var messageBuses = createPairedMessageBuses(); | ||||
|     var uiMessageBus = messageBuses.ui; | ||||
|     var workerMessageBus = messageBuses.worker; | ||||
| 
 | ||||
|     // set up the worker side
 | ||||
|     var broker = new MessageBroker(workerMessageBus, workerSerializer, null); | ||||
|     var brokerFactory = new MessageBrokerFactory(workerMessageBus, workerSerializer); | ||||
| 
 | ||||
|     // set up the ui side
 | ||||
|     var webWorkerMain = new WebWorkerMain(tb.compiler, tb.renderer, uiRenderViewStore, uiSerializer, | ||||
|                                           new AnchorBasedAppRootUrl(), null); | ||||
|     webWorkerMain.attachToWebWorker(uiMessageBus); | ||||
|     return broker; | ||||
|     var renderCompiler = new MessageBasedRenderCompiler(uiMessageBus, uiSerializer, tb.compiler); | ||||
|     var renderer = | ||||
|         new MessageBasedRenderer(uiMessageBus, uiSerializer, uiRenderViewStore, tb.renderer); | ||||
|     new WebWorkerMain(renderCompiler, renderer, null, null); | ||||
| 
 | ||||
|     return brokerFactory; | ||||
|   } | ||||
| 
 | ||||
|   function createWorkerRenderer(workerSerializer: Serializer, uiSerializer: Serializer, | ||||
|                                 tb: DomTestbed, uiRenderViewStore: RenderViewWithFragmentsStore, | ||||
|                                 workerRenderViewStore: RenderViewWithFragmentsStore): | ||||
|       WebWorkerRenderer { | ||||
|     var broker = | ||||
|         createBroker(workerSerializer, uiSerializer, tb, uiRenderViewStore, workerRenderViewStore); | ||||
|     return new WebWorkerRenderer(broker, workerRenderViewStore); | ||||
|     var brokerFactory = createBrokerFactory(workerSerializer, uiSerializer, tb, uiRenderViewStore, | ||||
|                                             workerRenderViewStore); | ||||
|     return new WebWorkerRenderer(brokerFactory, workerRenderViewStore, null); | ||||
|   } | ||||
| 
 | ||||
|   function createWorkerCompiler(workerSerializer: Serializer, uiSerializer: Serializer, | ||||
|                                 tb: DomTestbed): WebWorkerCompiler { | ||||
|     var broker = createBroker(workerSerializer, uiSerializer, tb, null, null); | ||||
|     return new WebWorkerCompiler(broker); | ||||
|     var brokerFactory = createBrokerFactory(workerSerializer, uiSerializer, tb, null, null); | ||||
|     return new WebWorkerCompiler(brokerFactory); | ||||
|   } | ||||
| 
 | ||||
|   describe("Web Worker Compiler", function() { | ||||
| @ -1,36 +1,60 @@ | ||||
| import {StringMap, StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection'; | ||||
| import { | ||||
|   MessageBus, | ||||
|   MessageBusSource, | ||||
|   MessageBusInterface, | ||||
|   MessageBusSink, | ||||
|   SourceListener | ||||
| } from "angular2/src/web-workers/shared/message_bus"; | ||||
| import {MapWrapper} from "angular2/src/facade/collection"; | ||||
|   MessageBusSource, | ||||
|   MessageBus | ||||
| } 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 { | ||||
|   private _listenerStore: Map<int, SourceListener> = new Map<int, SourceListener>(); | ||||
|   private _numListeners: number = 0; | ||||
|   constructor(private _channels: StringMap<string, MockEventEmitter>) {} | ||||
| 
 | ||||
|   addListener(fn: SourceListener): int { | ||||
|     this._listenerStore.set(++this._numListeners, fn); | ||||
|     return this._numListeners; | ||||
|   } | ||||
| 
 | ||||
|   removeListener(index: int): void { MapWrapper.delete(this._listenerStore, index); } | ||||
| 
 | ||||
|   receive(message: Object): void { | ||||
|     MapWrapper.forEach(this._listenerStore, (fn: SourceListener, key: int) => { fn(message); }); | ||||
|   from(channel: string): MockEventEmitter { | ||||
|     if (!StringMapWrapper.contains(this._channels, channel)) { | ||||
|       this._channels[channel] = new MockEventEmitter(); | ||||
|     } | ||||
|     return this._channels[channel]; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export class MockMessageBusSink implements MessageBusSink { | ||||
|   private _sendTo: MockMessageBusSource; | ||||
|   constructor(private _channels: StringMap<string, MockEventEmitter>) {} | ||||
| 
 | ||||
|   send(message: Object): void { this._sendTo.receive({'data': message}); } | ||||
| 
 | ||||
|   attachToSource(source: MockMessageBusSource) { this._sendTo = source; } | ||||
|   to(channel: string): MockEventEmitter { | ||||
|     if (!StringMapWrapper.contains(this._channels, channel)) { | ||||
|       this._channels[channel] = new MockEventEmitter(); | ||||
|     } | ||||
|     return this._channels[channel]; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export class MockMessageBus implements MessageBus { | ||||
|   constructor(public sink: MockMessageBusSink, public source: MockMessageBusSource) {} | ||||
|   attachToBus(bus: MockMessageBus) { this.sink.attachToSource(bus.source); } | ||||
| export class MockMessageBus extends MessageBus { | ||||
|   constructor(public sink: MockMessageBusSink, public source: MockMessageBusSource) { super(); } | ||||
| 
 | ||||
| 
 | ||||
|   to(channel: string): MockEventEmitter { return this.sink.to(channel); } | ||||
| 
 | ||||
|   from(channel: string): MockEventEmitter { return this.source.from(channel); } | ||||
| } | ||||
|  | ||||
| @ -11,7 +11,11 @@ import { | ||||
|   proxy | ||||
| } from 'angular2/test_lib'; | ||||
| 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 {PromiseWrapper} from "angular2/src/facade/async"; | ||||
| 
 | ||||
| @ -25,14 +29,13 @@ export function main() { | ||||
|          var messageBroker: any = new SpyMessageBroker(); | ||||
|          messageBroker.spy("runOnUiThread") | ||||
|              .andCallFake((args: UiArguments, returnType: Type) => { | ||||
|                expect(args.type).toEqual("xhr"); | ||||
|                expect(args.method).toEqual("get"); | ||||
|                expect(args.args.length).toEqual(1); | ||||
|                expect(args.args[0].value).toEqual(URL); | ||||
|                return PromiseWrapper.wrap(() => { return RESPONSE; }); | ||||
|              }); | ||||
| 
 | ||||
|          var xhrImpl = new WebWorkerXHRImpl(messageBroker); | ||||
|          var xhrImpl = new WebWorkerXHRImpl(new MockMessageBrokerFactory(messageBroker)); | ||||
|          xhrImpl.get(URL).then((response) => { | ||||
|            expect(response).toEqual(RESPONSE); | ||||
|            async.done(); | ||||
| @ -47,3 +50,8 @@ class SpyMessageBroker extends SpyObject { | ||||
|   constructor() { super(MessageBroker); } | ||||
|   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; | ||||
| 
 | ||||
| import "package:angular2/src/web-workers/worker/application.dart" | ||||
|     show WebWorkerMessageBus; | ||||
| import "package:angular2/src/web-workers/worker/broker.dart" | ||||
|     show MessageBroker, UiArguments; | ||||
| import "package:angular2/src/web-workers/shared/serializer.dart" | ||||
|     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"; | ||||
| 
 | ||||
| main(List<String> args, SendPort replyTo) { | ||||
|   ReceivePort rPort = new ReceivePort(); | ||||
|   WebWorkerMessageBus bus = new WebWorkerMessageBus.fromPorts(replyTo, rPort); | ||||
|   bus.source.addListener((message) { | ||||
|     if (identical(message['data']['type'], "echo")) { | ||||
|       bus.sink | ||||
|           .send({"type": "echo_response", "value": message['data']['value']}); | ||||
|     } | ||||
|   var sink = new WebWorkerMessageBusSink(replyTo, rPort); | ||||
|   var source = new IsolateMessageBusSource(rPort); | ||||
|   IsolateMessageBus bus = new IsolateMessageBus(sink, source); | ||||
| 
 | ||||
|   ObservableWrapper.subscribe(bus.from("echo"), (value) { | ||||
|     ObservableWrapper.callNext(bus.to("echo"), value); | ||||
|   }); | ||||
| 
 | ||||
|   MessageBroker broker = | ||||
|       new MessageBroker(bus, new Serializer(null, null, null), null); | ||||
|   var args = new UiArguments("test", "tester"); | ||||
|       new MessageBroker(bus, new Serializer(null, null, null), "test"); | ||||
|   var args = new UiArguments("tester"); | ||||
|   broker.runOnUiThread(args, String).then((data) { | ||||
|     bus.sink.send({"type": "result", "value": data}); | ||||
|     ObservableWrapper.callNext(bus.to("result"), data); | ||||
|   }); | ||||
| } | ||||
|  | ||||
| @ -1,21 +1,30 @@ | ||||
| import { | ||||
|   WebWorkerMessageBus, | ||||
|   WebWorkerMessageBusSource, | ||||
|   WebWorkerMessageBusSink | ||||
| } from "angular2/src/web-workers/worker/application"; | ||||
|   PostMessageBus, | ||||
|   PostMessageBusSink, | ||||
|   PostMessageBusSource | ||||
| } 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 {Serializer} from "angular2/src/web-workers/shared/serializer"; | ||||
| 
 | ||||
| export function main() { | ||||
|   var bus = new WebWorkerMessageBus(new WebWorkerMessageBusSink(), new WebWorkerMessageBusSource()); | ||||
|   bus.source.addListener((message) => { | ||||
|     if (message.data.type === "echo") { | ||||
|       bus.sink.send({type: "echo_response", 'value': message.data.value}); | ||||
|     } | ||||
|   }); | ||||
| 
 | ||||
|   var broker = new MessageBroker(bus, new Serializer(null, null, null), null); | ||||
|   var args = new UiArguments("test", "tester"); | ||||
|   broker.runOnUiThread(args, String) | ||||
|       .then((data: string) => { bus.sink.send({type: "result", value: data}); }); | ||||
| interface PostMessageInterface { | ||||
|   (message: any, transferrables?:[ArrayBuffer]): void; | ||||
| } | ||||
| var _postMessage: PostMessageInterface = <any>postMessage; | ||||
| 
 | ||||
| export function main() { | ||||
|   var sink = new PostMessageBusSink({ | ||||
|     postMessage: | ||||
|         (message: any, transferrables?:[ArrayBuffer]) => { _postMessage(message, transferrables); } | ||||
|   }); | ||||
|   var source = new PostMessageBusSource(); | ||||
|   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; | ||||
| 
 | ||||
| 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"; | ||||
| 
 | ||||
| main() { | ||||
| @ -10,21 +10,21 @@ main() { | ||||
|   spawnWebWorker(Uri.parse("background_index.dart")).then((bus) { | ||||
|     querySelector("#send_echo").addEventListener("click", (e) { | ||||
|       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']; | ||||
|       if (identical(data['type'], "echo_response")) { | ||||
|         querySelector("#echo_result") | ||||
|             .appendHtml("<span class='response'>${data['value']}</span>"); | ||||
|       } else if (identical(data['type'], "test")) { | ||||
|         bus.sink.send({'type': "result", 'id': data['id'], 'value': VALUE}); | ||||
|       } else if (identical(data['type'], "result")) { | ||||
|         querySelector("#ui_result") | ||||
|             .appendHtml("<span class='result'>${data['value']}</span>"); | ||||
|       } else if (identical(data['type'], "ready")) { | ||||
|         bus.sink.send({'type': "init"}); | ||||
|       } | ||||
| 
 | ||||
|     ObservableWrapper.subscribe(bus.from("echo"), (message) { | ||||
|       querySelector("#echo_result") | ||||
|           .appendHtml("<span class='response'>${message}</span>"); | ||||
|     }); | ||||
|     ObservableWrapper.subscribe(bus.from("result"), (message) { | ||||
|       querySelector("#ui_result") | ||||
|           .appendHtml("<span class='result'>${message}</span>"); | ||||
|     }); | ||||
|     ObservableWrapper.subscribe(bus.from("test"), | ||||
|         (Map<String, dynamic> message) { | ||||
|       ObservableWrapper.callNext(bus.to("test"), | ||||
|           {'id': message['id'], 'type': "result", 'value': VALUE}); | ||||
|     }); | ||||
|   }); | ||||
| } | ||||
|  | ||||
| @ -1,29 +1,28 @@ | ||||
| import { | ||||
|   UIMessageBus, | ||||
|   UIMessageBusSink, | ||||
|   UIMessageBusSource | ||||
| } from "angular2/src/web-workers/ui/application"; | ||||
|   PostMessageBus, | ||||
|   PostMessageBusSink, | ||||
|   PostMessageBusSource | ||||
| } from 'angular2/src/web-workers/shared/post_message_bus'; | ||||
| import {ObservableWrapper} from 'angular2/src/facade/async'; | ||||
| 
 | ||||
| var worker = new Worker("loader.js"); | ||||
| var bus = new UIMessageBus(new UIMessageBusSink(worker), new UIMessageBusSource(worker)); | ||||
| var VALUE = 5; | ||||
| var webWorker = new Worker("loader.js"); | ||||
| var sink = new PostMessageBusSink(webWorker); | ||||
| var source = new PostMessageBusSource(webWorker); | ||||
| var bus = new PostMessageBus(sink, source); | ||||
| const VALUE = 5; | ||||
| 
 | ||||
| document.getElementById("send_echo") | ||||
|     .addEventListener("click", (e) => { | ||||
|       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) => { | ||||
|   if (message.data.type === "echo_response") { | ||||
|     document.getElementById("echo_result").innerHTML = | ||||
|         `<span class='response'>${message.data.value}</span>`; | ||||
|   } else if (message.data.type === "test") { | ||||
|     bus.sink.send({type: "result", id: message.data.id, value: VALUE}); | ||||
|   } else if (message.data.type == "result") { | ||||
|     document.getElementById("ui_result").innerHTML = | ||||
|         `<span class='result'>${message.data.value}</span>`; | ||||
|   } else if (message.data.type == "ready") { | ||||
|     bus.sink.send({type: "init"}); | ||||
|   } | ||||
| ObservableWrapper.subscribe(bus.from("echo"), (message) => { | ||||
|   document.getElementById("echo_result").innerHTML = `<span class='response'>${message}</span>`; | ||||
| }); | ||||
| ObservableWrapper.subscribe(bus.from("result"), (message) => { | ||||
|   document.getElementById("ui_result").innerHTML = `<span class='result'>${message}</span>`; | ||||
| }); | ||||
| ObservableWrapper.subscribe(bus.from("test"), (message: StringMap<string, any>) => { | ||||
|   ObservableWrapper.callNext(bus.to("test"), {id: message['id'], type: "result", value: VALUE}); | ||||
| }); | ||||
|  | ||||
| @ -5,19 +5,19 @@ import 'dart:typed_data'; | ||||
| 
 | ||||
| // TODO(jteplitz602) Implement this class #3493 | ||||
| class BitmapService { | ||||
|   ImageData applySepia (ImageData imageData) { | ||||
|   ImageData applySepia(ImageData imageData) { | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   String arrayBufferToDataUri (Uint8ClampedList data) { | ||||
|   String arrayBufferToDataUri(Uint8ClampedList data) { | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   ImageData convertToImageData (ByteBuffer buffer) { | ||||
|   ImageData convertToImageData(ByteBuffer buffer) { | ||||
|     return null; | ||||
|   } | ||||
| 
 | ||||
|   String toDataUri (ImageData imageData) { | ||||
|   String toDataUri(ImageData imageData) { | ||||
|     return null; | ||||
|   } | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user