Add support for watchPath and unwatchPath

Use inotify to read a stream of events to one or more
watched paths on a separate background pthread
This commit is contained in:
Kevin Sawicki
2012-06-14 21:30:21 -07:00
parent b8cf8355ba
commit 44a028bb95
2 changed files with 142 additions and 0 deletions

View File

@@ -1,8 +1,10 @@
#include "native_handler.h"
#include "include/cef_base.h"
#include "include/cef_runnable.h"
#include "client_handler.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
@@ -11,9 +13,41 @@
#include <stdlib.h>
#include <vector>
#include <gtk/gtk.h>
#include <sys/inotify.h>
#include <pthread.h>
#define BUFFER_SIZE 8192
using namespace std;
void *NotifyWatchersCallback(void* pointer) {
NativeHandler* handler = (NativeHandler*) pointer;
handler->NotifyWatchers();
return NULL;
}
void ExecuteWatchCallback(NotifyContext notifyContext) {
map<string, CallbackContext> callbacks =
notifyContext.callbacks[notifyContext.descriptor];
map<string, CallbackContext>::iterator callback;
for (callback = callbacks.begin(); callback != callbacks.end();
callback++) {
CallbackContext callbackContext = callback->second;
CefRefPtr<CefV8Context> context = callbackContext.context;
CefRefPtr<CefV8Value> function = callbackContext.function;
context->Enter();
CefV8ValueList args;
CefRefPtr<CefV8Value> retval;
CefRefPtr<CefV8Exception> e;
args.push_back(callbackContext.eventTypes);
function->ExecuteFunction(function, args, retval, e, true);
context->Exit();
}
}
NativeHandler::NativeHandler() :
CefV8Handler() {
object = CefV8Value::CreateObject(NULL, NULL);
@@ -31,6 +65,37 @@ NativeHandler::NativeHandler() :
functionName, this);
object->SetValue(functionName, function, V8_PROPERTY_ATTRIBUTE_NONE);
}
notifyFd = inotify_init();
if (notifyFd != -1) {
pthread_t thread;
pthread_create(&thread, NULL, NotifyWatchersCallback, this);
}
}
void NativeHandler::NotifyWatchers() {
char buffer[BUFFER_SIZE];
ssize_t bufferRead;
size_t eventSize;
ssize_t bufferIndex;
struct inotify_event *event;
bufferRead = read(notifyFd, buffer, BUFFER_SIZE);
while (bufferRead > 0) {
bufferIndex = 0;
while (bufferIndex < bufferRead) {
event = (struct inotify_event *) &buffer[bufferIndex];
eventSize = offsetof (struct inotify_event, name) + event->len;
NotifyContext context;
context.descriptor = event->wd;
context.callbacks = pathCallbacks;
CefPostTask(TID_UI,
NewCefRunnableFunction(&ExecuteWatchCallback, context));
bufferIndex += eventSize;
}
bufferRead = read(notifyFd, buffer, BUFFER_SIZE);
}
}
void NativeHandler::Exists(const CefString& name, CefRefPtr<CefV8Value> object,
@@ -332,6 +397,49 @@ void NativeHandler::Alert(const CefString& name, CefRefPtr<CefV8Value> object,
gtk_widget_destroy(dialog);
}
void NativeHandler::WatchPath(const CefString& name,
CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval, CefString& exception) {
string path = arguments[0]->GetStringValue().ToString();
int descriptor = inotify_add_watch(notifyFd, path.c_str(),
IN_ALL_EVENTS & ~(IN_CLOSE | IN_OPEN | IN_ACCESS));
if (descriptor == -1)
return;
CallbackContext callbackContext;
callbackContext.context = CefV8Context::GetCurrentContext();
callbackContext.function = arguments[1];
CefRefPtr<CefV8Value> eventTypes = CefV8Value::CreateObject(NULL, NULL);
eventTypes->SetValue("modified", CefV8Value::CreateBool(true),
V8_PROPERTY_ATTRIBUTE_NONE);
callbackContext.eventTypes = eventTypes;
stringstream idStream;
idStream << "counter";
idStream << idCounter;
string id = idStream.str();
idCounter++;
pathDescriptors[path] = descriptor;
pathCallbacks[descriptor][id] = callbackContext;
retval = CefV8Value::CreateString(id);
}
void NativeHandler::UnwatchPath(const CefString& name,
CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval, CefString& exception) {
string path = arguments[0]->GetStringValue().ToString();
int descriptor = pathDescriptors[path];
if (descriptor == -1)
return;
map<string, CallbackContext> callbacks = pathCallbacks[descriptor];
string id = arguments[1]->GetStringValue().ToString();
callbacks.erase(id);
if (callbacks.empty())
inotify_rm_watch(notifyFd, descriptor);
}
bool NativeHandler::Execute(const CefString& name, CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
CefString& exception) {
@@ -369,6 +477,10 @@ bool NativeHandler::Execute(const CefString& name, CefRefPtr<CefV8Value> object,
Remove(name, object, arguments, retval, exception);
else if (name == "alert")
Alert(name, object, arguments, retval, exception);
else if (name == "watchPath")
WatchPath(name, object, arguments, retval, exception);
else if (name == "unwatchPath")
UnwatchPath(name, object, arguments, retval, exception);
else
cout << "Unhandled -> " + name.ToString() << " : "
<< arguments[0]->GetStringValue().ToString() << endl;

View File

@@ -4,6 +4,18 @@
#include "include/cef_base.h"
#include "include/cef_v8.h"
#include <string>
#include <map>
struct CallbackContext {
CefRefPtr<CefV8Context> context;
CefRefPtr<CefV8Value> function;
CefRefPtr<CefV8Value> eventTypes;
};
struct NotifyContext {
int descriptor;
std::map<int, std::map<std::string, CallbackContext> > callbacks;
};
class NativeHandler: public CefV8Handler {
public:
@@ -15,10 +27,20 @@ public:
std::string path;
int notifyFd;
unsigned long int idCounter;
std::map<int, std::map<std::string, CallbackContext> > pathCallbacks;
std::map<std::string, int> pathDescriptors;
virtual bool Execute(const CefString& name, CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
CefString& exception);
void NotifyWatchers();
IMPLEMENT_REFCOUNTING(NativeHandler)
;
@@ -86,6 +108,14 @@ private:
void Alert(const CefString& name, CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
CefString& exception);
void WatchPath(const CefString& name, CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
CefString& exception);
void UnwatchPath(const CefString& name, CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval,
CefString& exception);
};
#endif