FileWatcher.hx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. package hide.tools;
  2. typedef FileWatchEvent = {path:String,fun:Void->Void,checkDel:Bool,element:js.html.Element,?ignoreCheck:String};
  3. class FileWatcher {
  4. var ide : hide.Ide;
  5. var watches : Map<String, {
  6. events : Array<FileWatchEvent>,
  7. w : js.node.fs.FSWatcher,
  8. wasChanged : Bool,
  9. changed : Bool,
  10. isDir : Bool,
  11. version : Int
  12. }> = new Map();
  13. var timer : haxe.Timer;
  14. public function new() {
  15. ide = hide.Ide.inst;
  16. }
  17. public function ignorePrevChange( f : FileWatchEvent ) {
  18. f.ignoreCheck = getSignature(f.path);
  19. }
  20. function getSignature( path : String ) {
  21. return try haxe.crypto.Md5.make(sys.io.File.getBytes(ide.getPath(path))).toHex() catch( e : Dynamic ) null;
  22. }
  23. public function dispose() {
  24. if( timer != null ) {
  25. timer.stop();
  26. timer = null;
  27. }
  28. for( w in watches )
  29. if( w.w != null )
  30. w.w.close();
  31. watches = new Map();
  32. }
  33. public function register( path : String, updateFun, ?checkDelete : Bool, ?element : Element ) : FileWatchEvent {
  34. path = ide.getPath(path);
  35. var w = getWatches(path);
  36. var f : FileWatchEvent = { path : path, fun : updateFun, checkDel : checkDelete, element : element == null ? null : element[0] };
  37. w.events.push(f);
  38. if( element != null && timer == null ) {
  39. timer = new haxe.Timer(1000);
  40. timer.run = cleanEvents;
  41. }
  42. return f;
  43. }
  44. public function unregister( path : String, updateFun : Void -> Void ) {
  45. path = ide.getPath(path);
  46. var w = getWatches(path);
  47. for( e in w.events )
  48. if( Reflect.compareMethods(e.fun, updateFun) ) {
  49. w.events.remove(e);
  50. break;
  51. }
  52. if( w.events.length == 0 ) {
  53. watches.remove(path);
  54. if( w.w != null ) w.w.close();
  55. }
  56. }
  57. public function unregisterElement( element : Element ) {
  58. for( path => w in watches ) {
  59. for( e in w.events.copy() )
  60. if( e.element == element[0] )
  61. w.events.remove(e);
  62. if( w.events.length == 0 ) {
  63. watches.remove(path);
  64. if( w.w != null ) w.w.close();
  65. }
  66. }
  67. }
  68. public function getVersion( path : String ) : Int {
  69. var w = watches.get(ide.getPath(path));
  70. if( w == null )
  71. return 0;
  72. return w.version;
  73. }
  74. function cleanEvents() {
  75. for( w in watches )
  76. for( e in w.events.copy() )
  77. isLive(w.events, e);
  78. }
  79. function isLive( events : Array<FileWatchEvent>, e : FileWatchEvent ) {
  80. if( e.element == null ) return true;
  81. var elt = e.element;
  82. while( elt != null ) {
  83. if( elt.nodeName == "BODY" ) return true;
  84. elt = elt.parentElement;
  85. }
  86. events.remove(e);
  87. return false;
  88. }
  89. function getWatches( path : String ) {
  90. var w = watches.get(path);
  91. if( w == null ) {
  92. var fullPath = ide.getPath(path);
  93. w = {
  94. events : [],
  95. w : null,
  96. changed : false,
  97. isDir : try sys.FileSystem.isDirectory(fullPath) catch( e : Dynamic ) false,
  98. wasChanged : false,
  99. version : 0,
  100. };
  101. w.w = try js.node.Fs.watch(fullPath, function(k:String, file:String) {
  102. if( w.isDir && k == "change" ) return;
  103. if( k == "change" ) w.wasChanged = true;
  104. if( w.changed ) return;
  105. w.changed = true;
  106. w.version++;
  107. haxe.Timer.delay(function() {
  108. if( !w.changed ) return;
  109. w.changed = false;
  110. var sign = null;
  111. for( e in w.events.copy() )
  112. if( isLive(w.events,e) && (w.wasChanged || e.checkDel) ) {
  113. if( e.ignoreCheck != null ) {
  114. if( sign == null ) sign = getSignature(path);
  115. if( sign == e.ignoreCheck ) continue;
  116. e.ignoreCheck = null;
  117. }
  118. e.fun();
  119. }
  120. w.wasChanged = false;
  121. }, 100);
  122. }) catch( e : Dynamic ) {
  123. // file does not exists, trigger a delayed event
  124. haxe.Timer.delay(function() {
  125. for( e in w.events.copy() )
  126. if( isLive(w.events,e) && e.checkDel )
  127. e.fun();
  128. }, 0);
  129. return w;
  130. }
  131. watches.set(path, w);
  132. }
  133. return w;
  134. }
  135. }