PageRenderTime 58ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/src/com/matzmtok/demonsters/debugger/MonsterDebugger.hx

https://code.google.com/p/monsterdebugger4haxe/
Haxe | 515 lines | 468 code | 38 blank | 9 comment | 78 complexity | e8cbbf9ccad1b84131d7fc9fabba9b39 MD5 | raw file
  1. package com.matzmtok.demonsters.debugger;
  2. import com.matzmtok.demonsters.debugger.Command;
  3. import com.matzmtok.demonsters.debugger.errors.ParserError;
  4. import com.matzmtok.demonsters.debugger.errors.ParserError;
  5. import com.matzmtok.demonsters.debugger.monitor.events.MonitorEvent;
  6. import com.matzmtok.demonsters.debugger.monitor.Monitor;
  7. import com.matzmtok.demonsters.debugger.parsers.DisplayObjectContainerParser;
  8. import com.matzmtok.demonsters.debugger.parsers.NumberParser;
  9. import com.matzmtok.demonsters.debugger.parsers.TypeParser;
  10. import com.matzmtok.demonsters.debugger.types.Type;
  11. import com.matzmtok.flash.Utils;
  12. import flash.display.BitmapData;
  13. import flash.display.DisplayObject;
  14. import flash.display.DisplayObjectContainer;
  15. import flash.display.Sprite;
  16. import flash.Error;
  17. import flash.events.AsyncErrorEvent;
  18. import flash.events.SecurityErrorEvent;
  19. import flash.events.StatusEvent;
  20. import flash.geom.Rectangle;
  21. import flash.net.LocalConnection;
  22. import flash.system.System;
  23. import flash.utils.ByteArray;
  24. import flash.utils.Timer;
  25. import flash.xml.XML;
  26. import flash.xml.XMLList;
  27. import flash.xml.XMLNode;
  28. import flash.xml.XMLNodeType;
  29. class MonsterDebugger {
  30. var logger : Dynamic;
  31. private var HIGHLIGHT_BORDER : Int;
  32. private var HIGHLIGHT_COLOR : UInt;
  33. static var COLOR_ERROR : UInt;
  34. static var COLOR_NORMAL : UInt;
  35. static var COLOR_WARNING : UInt;
  36. ////////////////////
  37. //
  38. // static constants
  39. //
  40. ////////////////////
  41. static var VERSION : Float;
  42. static var MAX_BUFFER_SIZE : Int = 500;
  43. static var MAX_PACKAGE_BYTES : Int = 40000;
  44. static var _enabled : Bool = true;
  45. static var LINE_OUT:String = "_debuggerRed";
  46. static var LINE_IN:String = "_debuggerBlue";
  47. static var ALLOWED_DOMAIN:String = "*";
  48. static var _instance:MonsterDebugger;
  49. var _buffer : Array<Dynamic>;
  50. var _root : Dynamic;
  51. var _connected:Bool;
  52. var _lineOut:LocalConnection;
  53. var _lineIn:LocalConnection;
  54. var _monitor:Monitor;
  55. var _highlight : Sprite;
  56. static public function enable():Bool {
  57. if (_instance != null) {
  58. _instance._monitor.enabled = true;
  59. }
  60. return _enabled = true;
  61. }
  62. static public function disable():Bool {
  63. if (_instance != null) {
  64. _instance._monitor.enabled = false;
  65. }
  66. return _enabled = false;
  67. }
  68. static public function isEnabled():Bool {
  69. return _enabled;
  70. }
  71. function new(target:Dynamic = null) {
  72. _buffer = [];
  73. _connected = false;
  74. if (_instance == null) {
  75. _instance = this;
  76. _lineIn = _createLConnection();
  77. _lineIn.allowDomain(ALLOWED_DOMAIN);
  78. _lineIn.client = this;
  79. _lineOut = _createLConnection();
  80. //monitor setup
  81. try {
  82. _lineIn.connect(LINE_IN);
  83. }catch (error:Error) {
  84. trace('Line in connection failed');
  85. }
  86. }
  87. _monitor = new Monitor();
  88. _monitor.addEventListener(MonitorEvent.MOINTOR_UPDATE, monitorUpdateHandler);
  89. _instance._root = target;
  90. _instance._send({text:Command.HELLO, version:VERSION});
  91. }
  92. function _createLConnection():LocalConnection {
  93. var lc:LocalConnection = new LocalConnection();
  94. lc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHanlder );
  95. lc.addEventListener(SecurityErrorEvent.SECURITY_ERROR , securityErrorHandler);
  96. lc.addEventListener(StatusEvent.STATUS, statusHandler);
  97. return lc;
  98. }
  99. function asyncErrorHanlder(event:AsyncErrorEvent):Void {
  100. _connected = false;
  101. }
  102. function securityErrorHandler(event:SecurityErrorEvent):Void {
  103. _connected = false;
  104. }
  105. function statusHandler(event:StatusEvent):Void {
  106. if (event.level == "error" ) {
  107. _connected = false;
  108. }
  109. }
  110. function monitorUpdateHandler(event:MonitorEvent):Void {
  111. var mon:Monitor = cast (event.target, Monitor);
  112. if (mon != null) {
  113. sendCommand({text:Command.MONITOR, memory:mon.memory, fps:mon.fps, time:mon.time, start:mon.monitorStart});
  114. }
  115. }
  116. static public function trace(target : Dynamic, object : Dynamic, ?color : UInt, ?functions : Bool, ?depth : Int) : Void {
  117. if ( !_enabled ) return ;
  118. if (_instance == null) {
  119. _instance = new MonsterDebugger(target);
  120. }
  121. if (_enabled ) {
  122. _instance.traceInternal(target, object, color, functions, depth);
  123. }
  124. }
  125. static public function inspect(target:Dynamic):Void {
  126. if (_instance != null && target != null) {
  127. _instance._root = target;
  128. var obj:Dynamic = _instance.getObject("", 0);
  129. if (obj != null) {
  130. var parser:TypeParser = TypeParser.getParser(Type.getTypeString(obj));
  131. parser.maxDepth = 2;
  132. var xml:XML = parser.parseToXML(obj, "", false);
  133. _instance.sendCommand( { text:Command.INSPECT, xml:xml } );
  134. if (_instance.isDisplayObject(obj)) {
  135. _instance._base(obj, false);
  136. }
  137. }
  138. }
  139. }
  140. static function snapshot(target:DisplayObject, ?color:UInt) : Void {
  141. if (_instance == null) {
  142. _instance = new MonsterDebugger(null);
  143. }
  144. if (MonsterDebugger._enabled) {
  145. _instance.snapshotInternal(target, color);
  146. }
  147. }
  148. function snapshotInternal(target:DisplayObject, ?color:UInt = 0x111111):Void {
  149. if (_enabled ) {
  150. var w:Int = Math.ceil(target.width);
  151. var h:Int = Math.ceil(target.height);
  152. var bitmapData = new BitmapData(w, h);
  153. bitmapData.draw(target);
  154. var bytes:ByteArray = bitmapData.getPixels(new Rectangle(0, 0, w, h));
  155. var memory:UInt = System.totalMemory;
  156. var obj:Dynamic = {
  157. text:Command.SNAPSHOT,
  158. date:Date.now(),
  159. target:target.toString(),
  160. bytes:bytes,
  161. width:w,
  162. height:h,
  163. color:color,
  164. memory:memory };
  165. sendCommand(obj);
  166. bitmapData.dispose();
  167. bytes = null;
  168. }
  169. }
  170. function traceInternal(target : Dynamic, object : Dynamic, ?color : UInt, ?functions : Bool, ?depth : Int) : Void {
  171. var parser:TypeParser = TypeParser.getParser(Type.getTypeString(object));
  172. var xml:XML = parser.parseToXML(object, "", functions);
  173. var memory:UInt = System.totalMemory;
  174. var date:Date = Date.now();
  175. var command:Dynamic = {
  176. text:Command.TRACE,
  177. date:date,
  178. target:target.toString(),
  179. xml:xml,
  180. color:color,
  181. memory:memory
  182. };
  183. sendCommand(command);
  184. }
  185. function sendCommand(data:Dynamic):Void {
  186. if (_connected) {
  187. _send(data);
  188. }else {
  189. _sendToBuffer(data);
  190. }
  191. }
  192. function _send(data:Dynamic):Void {
  193. var item:ByteArray = new ByteArray();
  194. item.writeObject(data);
  195. item.compress();
  196. var dataPackages:Array<Dynamic> = [];
  197. if (item.length > MAX_PACKAGE_BYTES ) {
  198. var bytesAvailable:Int = item.length;
  199. var offset:Int = 0;
  200. var total:Int = Math.ceil(item.length / MAX_PACKAGE_BYTES);
  201. for (i in 0...total) {
  202. var length:Int = bytesAvailable;
  203. if (length > MAX_PACKAGE_BYTES ) {
  204. length = MAX_PACKAGE_BYTES;
  205. }
  206. var tmp:ByteArray = new ByteArray();
  207. tmp.writeBytes(item, offset, length);
  208. dataPackages.push( { total:total, nr:(i + 1), bytes:tmp } );
  209. bytesAvailable -= length;
  210. offset += length;
  211. }
  212. }else {
  213. dataPackages.push({total:1, nr:1, bytes:item});
  214. }
  215. for (i in 0...dataPackages.length) {
  216. try {
  217. _lineOut.send(LINE_OUT, "onReceivedData", dataPackages[i]);
  218. }catch (error:Error) {
  219. trace('error occerd at send');
  220. break;
  221. }
  222. }
  223. }
  224. function _sendToBuffer(data:Dynamic):Void {
  225. _buffer.push(data);
  226. if (_buffer.length > MAX_BUFFER_SIZE ) {
  227. _buffer.shift();
  228. }
  229. }
  230. function _sendBuffer():Void {
  231. if (_buffer.length > 0) {
  232. while (_buffer.length > 0) {
  233. var msg:Dynamic = _buffer.shift();
  234. _send(msg);
  235. }
  236. }
  237. }
  238. static public function clearTraces():Void {
  239. if (_instance == null) {
  240. _instance = new MonsterDebugger(null);
  241. }
  242. if (MonsterDebugger._enabled) {
  243. _instance._clearTracesInternal();
  244. }
  245. }
  246. function _clearTracesInternal():Void {
  247. if (_enabled) {
  248. var command:Dynamic = { text:Command.CLEAR_TRACES };
  249. sendCommand(command);
  250. }
  251. }
  252. public function onReceivedData(data:ByteArray):Void {
  253. if (_enabled ) {
  254. data.uncompress();
  255. var command:Dynamic = data.readObject();
  256. switch(command.text) {
  257. case Command.HELLO:
  258. hello(command);
  259. case Command.HELLO_RESPONSE:
  260. helloResponse(command);
  261. case Command.ROOT:
  262. root(command);
  263. case Command.GET_OBJECT:
  264. get_object(command);
  265. case Command.GET_DISPLAYOBJECT:
  266. get_displayObject(command);
  267. case Command.GET_PROPERTIES:
  268. get_properties(command);
  269. case Command.GET_FUNCTIONS:
  270. get_functions(command);
  271. case Command.SET_PROPERTY:
  272. set_property(command);
  273. case Command.CALL_METHOD:
  274. call_method(command);
  275. case Command.SHOW_HIGHLIGHT:
  276. show_highlight(command);
  277. case Command.HIDE_HIGHLIGHT:
  278. hide_highlight(command);
  279. }
  280. }
  281. }
  282. function hello(command:Dynamic):Void {
  283. _connected = true;
  284. _send({text:Command.HELLO, version:VERSION});
  285. }
  286. function helloResponse(command:Dynamic):Void {
  287. _connected = true;
  288. _sendBuffer();
  289. }
  290. function root(command:Dynamic):Void {
  291. var obj:Dynamic = getObject("", 0);
  292. if (obj != null) {
  293. untyped{
  294. var parser:TypeParser = TypeParser.getParser (Type.getTypeString(obj));
  295. parser.maxDepth = 2;
  296. untyped{
  297. var xml:XML = parser.parseToXML(obj, "", command['functions']);
  298. _send( { text:Command.ROOT, xml:xml } );
  299. }
  300. //base(command);
  301. if (isDisplayObject(obj)) {
  302. base(command);
  303. }
  304. }
  305. }
  306. }
  307. function base(command:Dynamic):Void {
  308. var obj:Dynamic = getObject("", 0);
  309. if (obj != null) {
  310. _base(obj, command.functions);
  311. }
  312. }
  313. function _base(object:Dynamic, functions:Bool):Void {
  314. var p:DisplayObjectContainerParser = new DisplayObjectContainerParser();
  315. try {
  316. untyped {
  317. p.maxDepth = 2;
  318. var xml:XML = p.parseToXML(object, "", functions);
  319. _send( { text:Command.BASE, xml:xml } );
  320. }
  321. }catch (error:ParserError) {
  322. if (error.errorID == ParserError.NOT_FOUND ) {
  323. var msg:XMLNode = createWarningNode("Not found", "Not Found");
  324. sendCommand({text:Command.NOTFOUND, target:error.target, xml:new XML(msg.toString())});
  325. }
  326. throw error;
  327. }
  328. }
  329. function get_object(command:Dynamic):Void {
  330. untyped {
  331. var object:Dynamic = getObject(command.target, 0);
  332. if (object != null) {
  333. var parser:TypeParser = TypeParser.getParser(Type.getTypeString(object));
  334. var xml:XML = parser.parseToXML(object, command.target, command.functions);
  335. _send({text:Command.GET_OBJECT, xml:xml});
  336. }
  337. }
  338. }
  339. function get_displayObject(command:Dynamic):Void {
  340. var object:Dynamic = getObject(command.target, 0);
  341. if (object != null) {
  342. if (isDisplayObject(object)) {
  343. var parser:DisplayObjectContainerParser = new DisplayObjectContainerParser();
  344. parser.maxDepth = 2;
  345. var xml:XML = parser.parseToXML(object, command.target, command.functions);
  346. _send({text:Command.GET_DISPLAYOBJECT, xml:xml});
  347. }
  348. }
  349. }
  350. function get_properties(command:Dynamic):Void {
  351. var object:Dynamic = getObject(command.target, 0);
  352. if (object != null) {
  353. var parser:TypeParser = TypeParser.getParser(Type.getTypeString(object));
  354. parser.maxDepth = 4;
  355. var xml:XML = parser.parseToXML(object, command.target, false);
  356. _send({text:Command.GET_PROPERTIES, xml:xml});
  357. }
  358. }
  359. function get_functions(command:Dynamic):Void {
  360. var object:Dynamic = getObject(command.target, 0);
  361. if (object != null) {
  362. var parser:TypeParser = new TypeParser();
  363. try{
  364. var xml:XML = parser.getFunctions(object, command.target);
  365. _send({text:Command.GET_FUNCTIONS, xml:xml});
  366. }catch (error:ParserError) {
  367. var xml:XML = new XML('<root></root>');
  368. xml.appendChild( createWarningNode("Not found", "Not found"));
  369. sendCommand( { text:Command.NOTFOUND, target:command.target, xml:xml } );
  370. }
  371. }
  372. }
  373. function set_property(command:Dynamic):Void {
  374. var object:Dynamic = getObject(command.target, 1);
  375. if (object != null) {
  376. try {
  377. object[command.name] = command.value;
  378. _send({text:Command.SET_PROPERTY, value:object[command.name]});
  379. } catch (error:Error) {
  380. _send({text:Command.NOTFOUND, target:command.target});
  381. }
  382. }
  383. }
  384. function call_method(command:Dynamic):Void {
  385. var method:Dynamic = getObject(command.target, 0);
  386. if (method != null) {
  387. if (command.returnType == Type.TYPE_VOID) {
  388. method.apply(this, command.arguments);
  389. } else {
  390. var object:Dynamic = method.apply(this, command.arguments);
  391. var parser:TypeParser = TypeParser.getParser(Type.getTypeString(object));
  392. parser.maxDepth = 4;
  393. var xml:XML = parser.parseToXML(object, "", false);
  394. _send({text:Command.CALL_METHOD, id:command.id, xml:xml});
  395. }
  396. }
  397. }
  398. function show_highlight(command:Dynamic):Void {
  399. if (_highlight != null) {
  400. try {
  401. _highlight.parent.removeChild(_highlight);
  402. _highlight = null;
  403. } catch(error:Error) {
  404. //
  405. }
  406. }
  407. var object:Dynamic = getObject(command.target, 0);
  408. if (isDisplayObject(object) && isDisplayObject(object.parent)) {
  409. var bounds:Rectangle = object.getBounds(object.parent);
  410. _highlight = new Sprite();
  411. _highlight.x = 0;
  412. _highlight.y = 0;
  413. _highlight.graphics.beginFill(0, 0);
  414. _highlight.graphics.lineStyle(HIGHLIGHT_BORDER, HIGHLIGHT_COLOR);
  415. _highlight.graphics.drawRect(bounds.x, bounds.y, bounds.width, bounds.height);
  416. _highlight.graphics.endFill();
  417. _highlight.mouseChildren = false;
  418. _highlight.mouseEnabled = false;
  419. try {
  420. object.parent.addChild(_highlight);
  421. } catch(error:Error) {
  422. _highlight = null;
  423. }
  424. }
  425. }
  426. function hide_highlight(command:Dynamic):Void {
  427. if (_highlight != null) {
  428. try {
  429. _highlight.parent.removeChild(_highlight);
  430. _highlight = null;
  431. } catch(error:Error) {
  432. //
  433. }
  434. }
  435. }
  436. function getObject(target:String = "", parent:Int = 0):Dynamic{
  437. var obj:Dynamic = _instance._root;
  438. if (target != "") {
  439. var path:Array < String > = target.split(".");
  440. var len:Int = path.length - parent;
  441. for ( i in 0...len ) {
  442. if (path[i] != "") {
  443. try {
  444. if (path[i] == "children()") {
  445. obj = obj.children();
  446. }else if ( path[i].indexOf("getChildAt(") == 0) {
  447. var j:Int = Std.parseInt(path[i].substr(11, path[i].indexOf(")", 11 - 11)));
  448. obj = obj.getChildAt(j);
  449. }else {
  450. untyped {
  451. obj = obj[path[i]];
  452. }
  453. }
  454. }catch (error:ParserError) {
  455. if (error.errorID == ParserError.NOT_FOUND ) {
  456. var msg:XMLNode = new XMLNode(XMLNodeType.ELEMENT_NODE, "root");
  457. msg.appendChild(createWarningNode("Not found", "Not found"));
  458. sendCommand({text:Command.NOTFOUND, target:target, xml:new XML(msg.toString())});
  459. }
  460. }
  461. }
  462. }
  463. }
  464. return obj;
  465. }
  466. function isDisplayObject(obj:Dynamic):Bool {
  467. return Std.is(obj, DisplayObject);
  468. }
  469. function createWarningNode(label:String, name:String):XMLNode {
  470. var node:XMLNode = new XMLNode(XMLNodeType.ELEMENT_NODE, "node");
  471. node.attributes.icon = Icon.ICON_WARNING;
  472. node.attributes.type = Type.TYPE_WARNING;
  473. node.attributes.label = label;
  474. node.attributes.name = name;
  475. return node;
  476. }
  477. }