4.3.1r21
[enigma2.git] / usr / include / enigma2 / lib / components / file_monitor.h
1 #ifndef __lib_components_file_watcher_h
2 #define __lib_components_file_watcher_h
3 #include <lib/base/thread.h>
4 #include <lib/base/message.h>
5 #include <lib/base/ebase.h>
6 #include <lib/base/elock.h>
7 #include <lib/base/esignal.h>
8
9 #include <queue>
10 #include <future>
11 #include <sys/inotify.h>
12
13 class eFileEvent {
14         int m_wd;
15         uint32_t m_mask;
16         uint32_t m_cookie;
17         std::string m_name;
18         std::string m_path;
19         std::string m_movedFrom;
20         std::string m_movedTo;
21 #ifdef SWIG
22         eFileEvent();
23 #endif
24 public:
25         enum {
26                 ACCESS = IN_ACCESS,
27                 MODIFY = IN_MODIFY,
28                 ATTRIB = IN_ATTRIB,
29                 CLOSE_WRITE = IN_CLOSE_WRITE,
30                 CLOSE_NOWRITE = IN_CLOSE_NOWRITE,
31                 CLOSE = IN_CLOSE,
32                 OPEN = IN_OPEN,
33                 MOVED_FROM = IN_MOVED_FROM,
34                 MOVED_TO = IN_MOVED_TO,
35                 MOVE = IN_MOVE,
36                 CREATE = IN_CREATE,
37                 DELETE = IN_DELETE,
38                 DELETE_SELF = IN_DELETE_SELF,
39                 MOVE_SELF = IN_MOVE_SELF,
40                 ISDIR = IN_ISDIR,
41         };
42 #ifndef SWIG
43         eFileEvent(struct inotify_event *event, std::string path=std::string(""));
44 #endif
45         int getWd() const { return m_wd; };
46         uint32_t getMask() const { return m_mask; };
47         uint32_t getCookie() const { return m_cookie; };
48         const std::string getName() const { return m_name; };
49         const std::string getPath() const { return m_path; };
50         std::string getFullPath() { return std::string(std::string(m_path) + "/" + std::string(m_name)); };
51         const std::string getMovedFrom() const { return m_movedFrom; };
52         const std::string getMovedTo() const { return m_movedTo; };
53
54 #ifndef SWIG
55         void setWd(int wd){ m_wd = wd; };
56         void setMask(uint32_t mask){ m_mask = mask; };
57         void setCookie(uint32_t cookie){ m_cookie = cookie; };
58         void setName(const std::string &name){ m_name = name; };
59         void setPath(const std::string &path){ m_path = path; };
60         void setMovedFrom(const std::string &movedFrom){ m_movedFrom = movedFrom; };
61         void setMovedTo(const std::string &movedTo){ m_movedTo = movedTo; };
62 #endif
63 };
64
65 /**
66  * Use an eFileWatch to monitor a file or directory (recursively if required) for access/changes
67  * Watches are "self-managed" and do all required interaction with the eFileMonitor instance
68  * Manual interaction with eFileMonitor is not recommended!
69  */
70 class eFileWatch : public sigc::trackable
71 {
72         pthread_mutex_t m_startstop_mutex;
73         pthread_mutex_t m_child_mutex;
74         friend class eFileMonitor;
75
76         int m_wd;
77         uint32_t m_mask;
78         bool m_recursive; //recursivley watch the given directory, all events of siblings will bubble to the very parent eFileWatch and be signalled from there
79         bool m_destroyed;
80         std::string m_directory;
81
82         std::map<std::string, eFileWatch*> m_child_lut;
83         std::vector<eFileWatch*> m_children;
84         std::future<void> m_child_future;
85
86         eFileWatch* m_parent;
87
88         void destroy();
89
90         /**
91          * !! Do not call createDirectChildWatches() twice, it's almost guaranteed to break things
92          */
93         void createDirectChildWatches();
94
95 public:
96         /**
97          * Creates a new FileWatch for a File or Directory
98          * @param directory
99          * @param mask
100          * @param recursive
101          * @param parent
102          */
103         eFileWatch(std::string directory,  bool recursive=false, uint32_t mask = eFileEvent::CLOSE_WRITE | eFileEvent::MOVE | eFileEvent::CREATE | eFileEvent::DELETE | eFileEvent::DELETE_SELF | eFileEvent::MOVE_SELF, eFileWatch* parent=0);
104         ~eFileWatch();
105
106         /**
107          * Start watching the directory of this eFileWatch.
108          * Calls addWatch on eFileMonitor::getInstance() and sets the watch descritpor id (m_wd)
109          * @return true if watch is now running for the eFileWatch instance an all of it's child-Watches, else false
110          */
111         bool startWatching();
112
113         /**
114          * Stop watching the directory of this eFileWatch.
115          * Class removeWatch on eFileMonitor::getInstance() and sets the watch descriptor id to 0
116          * @return
117          */
118         bool stopWatching();
119
120         bool isWatching() const;
121
122 #ifndef SWIG
123         /**
124          * This should only be called for inotify events valid for this eFileWatch.
125          * If the current instance has a non-zero parent no signal will be raised but the event will bubble to the parent.
126          * Event-signals will only be raised on parentless eFileWatches!
127          * @param event
128          */
129         void event(eFileEvent event, bool bubbled=false);
130         void removeChild(eFileWatch* child);
131 #endif
132
133         const int getWd() const { return m_wd; };
134         const std::string getDirectory() const { return m_directory; };
135         const uint32_t getMask() const { return m_mask; };
136
137         void setDirectory(const std::string &dir){ m_directory = dir; };
138
139         eSignal2<void, eFileWatch*, eFileEvent> fileChanged;
140 };
141 SWIG_EXTEND(eFileWatch,
142         bool operator==(const eFileWatch &fw) const { return &fw == self; }
143 );
144
145 #ifndef SWIG
146
147 /**
148  * Monitors the Filesystem for changes (based on inotify).
149  * Do not use this class directly unless you really know why.
150  * Use eFileWatch instances instead, they handle all the tricky stuff properly.
151  */
152 class eFileMonitor: public eMainloop_native, public eThread, public sigc::trackable
153 {
154         int m_fd;
155         uint64_t m_watchcount; //watches total
156         ePtr<eSocketNotifier> m_sn;
157         eSingleLock m_watch_lock, m_queue_lock;
158         std::queue<eFileEvent> m_eventqueue;
159         //lookup-tables
160         std::map<std::string, int> m_dir_wd; //key: directory, value: watch-descriptor-id
161         std::map<int, eFileWatch*> m_wd_watches; //key: watch-descriptor-id, value: related eFileWatch, required for getting all eFileWatches for an event
162         std::map<int, uint64_t> m_wd_watchcount; //key: watch-descriptor-id, value: number of associated watches
163
164         struct Message
165         {
166                 int type;
167                 int count;
168                 enum{
169                         process=0,
170                         quit,
171                 };
172                 Message(int type=0, int count=0): type(type), count(count){};
173         };
174
175         static eFileMonitor *instance;
176
177         eFixedMessagePump<Message> messages_from_thread;
178         eFixedMessagePump<Message> messages_to_thread;
179
180         void gotMessage(const Message &msg);
181         void thread();
182         void readEvents(int what);
183         int processInotifyEvents();
184         void onWatchMoved(eFileWatch *watch, const eFileEvent &event);
185
186 public:
187         eFileMonitor();
188         ~eFileMonitor();
189
190         static eFileMonitor *getInstance();
191
192         int addWatch(eFileWatch *watch);
193         bool removeWatch(eFileWatch *watch);
194         eFileWatch* getWatch(int wd);
195
196         /**
197          * processEvents(bool finished)
198          * emitted when processing of events will start (finished=false) and finish (finished=true).
199          *
200          * Can be used to encapsulate event-based actions into a single database transaction or do some other kind of batch-processing on the receiver-side
201          */
202         Signal1<void, bool> processEvents;
203 };
204
205 #endif
206
207 #endif