1 // Copyright: Hiroshi Ichikawa <http://gimite.net/en/> |
|
2 // License: New BSD License |
|
3 |
|
4 package net.gimite.websocket { |
|
5 |
|
6 import flash.display.Sprite; |
|
7 import flash.external.ExternalInterface; |
|
8 import flash.system.Security; |
|
9 import flash.utils.setTimeout; |
|
10 |
|
11 import mx.utils.URLUtil; |
|
12 |
|
13 /** |
|
14 * Provides JavaScript API of WebSocket. |
|
15 */ |
|
16 public class WebSocketMain extends Sprite implements IWebSocketLogger{ |
|
17 |
|
18 private var callerUrl:String; |
|
19 private var debug:Boolean = false; |
|
20 private var manualPolicyFileLoaded:Boolean = false; |
|
21 private var webSockets:Array = []; |
|
22 private var eventQueue:Array = []; |
|
23 |
|
24 public function WebSocketMain() { |
|
25 ExternalInterface.addCallback("setCallerUrl", setCallerUrl); |
|
26 ExternalInterface.addCallback("setDebug", setDebug); |
|
27 ExternalInterface.addCallback("create", create); |
|
28 ExternalInterface.addCallback("send", send); |
|
29 ExternalInterface.addCallback("close", close); |
|
30 ExternalInterface.addCallback("loadManualPolicyFile", loadManualPolicyFile); |
|
31 ExternalInterface.addCallback("receiveEvents", receiveEvents); |
|
32 ExternalInterface.call("WebSocket.__onFlashInitialized"); |
|
33 } |
|
34 |
|
35 public function setCallerUrl(url:String):void { |
|
36 callerUrl = url; |
|
37 } |
|
38 |
|
39 public function setDebug(val:Boolean):void { |
|
40 debug = val; |
|
41 if (val) { |
|
42 log("debug enabled"); |
|
43 } |
|
44 } |
|
45 |
|
46 private function loadDefaultPolicyFile(wsUrl:String):void { |
|
47 var policyUrl:String = "xmlsocket://" + URLUtil.getServerName(wsUrl) + ":843"; |
|
48 log("policy file: " + policyUrl); |
|
49 Security.loadPolicyFile(policyUrl); |
|
50 } |
|
51 |
|
52 public function loadManualPolicyFile(policyUrl:String):void { |
|
53 log("policy file: " + policyUrl); |
|
54 Security.loadPolicyFile(policyUrl); |
|
55 manualPolicyFileLoaded = true; |
|
56 } |
|
57 |
|
58 public function log(message:String):void { |
|
59 if (debug) { |
|
60 ExternalInterface.call("WebSocket.__log", encodeURIComponent("[WebSocket] " + message)); |
|
61 } |
|
62 } |
|
63 |
|
64 public function error(message:String):void { |
|
65 ExternalInterface.call("WebSocket.__error", encodeURIComponent("[WebSocket] " + message)); |
|
66 } |
|
67 |
|
68 private function parseEvent(event:WebSocketEvent):Object { |
|
69 var webSocket:WebSocket = event.target as WebSocket; |
|
70 var eventObj:Object = {}; |
|
71 eventObj.type = event.type; |
|
72 eventObj.webSocketId = webSocket.getId(); |
|
73 eventObj.readyState = webSocket.getReadyState(); |
|
74 eventObj.protocol = webSocket.getAcceptedProtocol(); |
|
75 if (event.message !== null) { |
|
76 eventObj.message = event.message; |
|
77 } |
|
78 if (event.wasClean) { |
|
79 eventObj.wasClean = event.wasClean; |
|
80 } |
|
81 if (event.code) { |
|
82 eventObj.code = event.code; |
|
83 } |
|
84 if (event.reason !== null) { |
|
85 eventObj.reason = event.reason; |
|
86 } |
|
87 return eventObj; |
|
88 } |
|
89 |
|
90 public function create( |
|
91 webSocketId:int, |
|
92 url:String, protocols:Array, |
|
93 proxyHost:String = null, proxyPort:int = 0, |
|
94 headers:String = null):void { |
|
95 if (!manualPolicyFileLoaded) { |
|
96 loadDefaultPolicyFile(url); |
|
97 } |
|
98 var newSocket:WebSocket = new WebSocket( |
|
99 webSocketId, url, protocols, getOrigin(), proxyHost, proxyPort, |
|
100 getCookie(url), headers, this); |
|
101 newSocket.addEventListener("open", onSocketEvent); |
|
102 newSocket.addEventListener("close", onSocketEvent); |
|
103 newSocket.addEventListener("error", onSocketEvent); |
|
104 newSocket.addEventListener("message", onSocketEvent); |
|
105 webSockets[webSocketId] = newSocket; |
|
106 } |
|
107 |
|
108 public function send(webSocketId:int, encData:String):int { |
|
109 var webSocket:WebSocket = webSockets[webSocketId]; |
|
110 return webSocket.send(encData); |
|
111 } |
|
112 |
|
113 public function close(webSocketId:int):void { |
|
114 var webSocket:WebSocket = webSockets[webSocketId]; |
|
115 webSocket.close(); |
|
116 } |
|
117 |
|
118 public function receiveEvents():Object { |
|
119 var result:Object = eventQueue; |
|
120 eventQueue = []; |
|
121 return result; |
|
122 } |
|
123 |
|
124 private function getOrigin():String { |
|
125 return (URLUtil.getProtocol(this.callerUrl) + "://" + |
|
126 URLUtil.getServerNameWithPort(this.callerUrl)).toLowerCase(); |
|
127 } |
|
128 |
|
129 private function getCookie(url:String):String { |
|
130 if (URLUtil.getServerName(url).toLowerCase() == |
|
131 URLUtil.getServerName(this.callerUrl).toLowerCase()) { |
|
132 return ExternalInterface.call("function(){return document.cookie}"); |
|
133 } else { |
|
134 return ""; |
|
135 } |
|
136 } |
|
137 |
|
138 /** |
|
139 * Socket event handler. |
|
140 */ |
|
141 public function onSocketEvent(event:WebSocketEvent):void { |
|
142 var eventObj:Object = parseEvent(event); |
|
143 eventQueue.push(eventObj); |
|
144 processEvents(); |
|
145 } |
|
146 |
|
147 /** |
|
148 * Process our event queue. If javascript is unresponsive, set |
|
149 * a timeout and try again. |
|
150 */ |
|
151 public function processEvents():void { |
|
152 if (eventQueue.length == 0) return; |
|
153 if (!ExternalInterface.call("WebSocket.__onFlashEvent")) { |
|
154 setTimeout(processEvents, 500); |
|
155 } |
|
156 } |
|
157 |
|
158 } |
|
159 |
|
160 } |
|