1 module ws.inotify; 2 3 4 import 5 core.sys.linux.sys.inotify, 6 core.sys.posix.sys.time, 7 core.sys.posix.unistd, 8 core.sys.posix.sys.select, 9 core.stdc.errno, 10 std.string, 11 std.stdio, 12 std.algorithm, 13 std.conv, 14 ws.event; 15 16 17 version(Posix): 18 19 __gshared: 20 21 22 class Inotify { 23 24 enum EVENT_BUFFER_LENGTH = (inotify_event.sizeof + 16) * 1024; 25 26 static int inotify = -1; 27 static timeval timeOut; 28 static fd_set descriptorSet; 29 30 static Watcher[int] staticWatchers; 31 32 enum { 33 Add, 34 Remove, 35 Modify 36 } 37 38 39 shared static this(){ 40 if(inotify >= 0) 41 return; 42 inotify = inotify_init; 43 if(inotify < 0) 44 throw new Exception("Failed to initialize inotify: %s".format(errno)); 45 timeOut.tv_sec = 1; 46 timeOut.tv_usec = 0; 47 FD_ZERO(&descriptorSet); 48 } 49 50 51 static class Watcher { 52 this(){ 53 event = new Event!(string, string, int); 54 } 55 string directory; 56 Event!(string, string, int) event; 57 } 58 59 60 static void watch(string directory, void delegate(string, string, int) event){ 61 assert(inotify >= 0); 62 foreach(wd, watcher; staticWatchers){ 63 if(watcher.directory == directory){ 64 watcher.event ~= event; 65 return; 66 } 67 } 68 if(staticWatchers.values.find!(a => a.directory == directory).length){ 69 return; 70 } 71 int wd = inotify_add_watch(inotify, directory.toStringz, IN_CLOSE_WRITE | IN_MOVED_TO | IN_CREATE | IN_MOVED_FROM | IN_DELETE); 72 if(wd < 0) 73 throw new Exception("inotify error in %s: %s".format(directory, errno)); 74 auto watcher = new Watcher; 75 watcher.directory = directory; 76 watcher.event ~= event; 77 staticWatchers[wd] = watcher; 78 } 79 80 static void update(){ 81 FD_SET(inotify, &descriptorSet); 82 int ret = select(inotify + 1, &descriptorSet, null, null, &timeOut); 83 if(ret < 0){ 84 perror("select"); 85 }else if(FD_ISSET(inotify, &descriptorSet)){ 86 ssize_t len, i = 0; 87 byte[EVENT_BUFFER_LENGTH] buff = 0; 88 len = read(inotify, buff.ptr, buff.length); 89 while(i < len){ 90 auto pevent = cast(inotify_event*)&buff[i]; 91 auto watcher = staticWatchers[pevent.wd]; 92 watcher.event( 93 watcher.directory, 94 (cast(char*)&pevent.name).to!string, 95 pevent.mask & IN_CLOSE_WRITE ? Modify 96 : pevent.mask & (IN_MOVED_TO | IN_CREATE) ? Add 97 : pevent.mask & (IN_MOVED_FROM | IN_DELETE) ? Remove 98 : -1); 99 i += inotify_event.sizeof + pevent.len; 100 } 101 } 102 103 } 104 105 } 106