From 44a028bb95eb4567af54d11d67ef7af33c7a8ba0 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Thu, 14 Jun 2012 21:30:21 -0700 Subject: [PATCH] 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 --- Atom-Linux/native_handler.cpp | 112 ++++++++++++++++++++++++++++++++++ Atom-Linux/native_handler.h | 30 +++++++++ 2 files changed, 142 insertions(+) diff --git a/Atom-Linux/native_handler.cpp b/Atom-Linux/native_handler.cpp index fbb563346..fea5ac3be 100644 --- a/Atom-Linux/native_handler.cpp +++ b/Atom-Linux/native_handler.cpp @@ -1,8 +1,10 @@ #include "native_handler.h" #include "include/cef_base.h" +#include "include/cef_runnable.h" #include "client_handler.h" #include #include +#include #include #include #include @@ -11,9 +13,41 @@ #include #include #include +#include +#include + +#define BUFFER_SIZE 8192 using namespace std; +void *NotifyWatchersCallback(void* pointer) { + NativeHandler* handler = (NativeHandler*) pointer; + handler->NotifyWatchers(); + return NULL; +} + +void ExecuteWatchCallback(NotifyContext notifyContext) { + map callbacks = + notifyContext.callbacks[notifyContext.descriptor]; + map::iterator callback; + for (callback = callbacks.begin(); callback != callbacks.end(); + callback++) { + CallbackContext callbackContext = callback->second; + CefRefPtr context = callbackContext.context; + CefRefPtr function = callbackContext.function; + + context->Enter(); + + CefV8ValueList args; + CefRefPtr retval; + CefRefPtr 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 object, @@ -332,6 +397,49 @@ void NativeHandler::Alert(const CefString& name, CefRefPtr object, gtk_widget_destroy(dialog); } +void NativeHandler::WatchPath(const CefString& name, + CefRefPtr object, const CefV8ValueList& arguments, + CefRefPtr& 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 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 object, const CefV8ValueList& arguments, + CefRefPtr& retval, CefString& exception) { + string path = arguments[0]->GetStringValue().ToString(); + + int descriptor = pathDescriptors[path]; + if (descriptor == -1) + return; + + map 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 object, const CefV8ValueList& arguments, CefRefPtr& retval, CefString& exception) { @@ -369,6 +477,10 @@ bool NativeHandler::Execute(const CefString& name, CefRefPtr 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; diff --git a/Atom-Linux/native_handler.h b/Atom-Linux/native_handler.h index 45e2cc3a1..797850a5f 100644 --- a/Atom-Linux/native_handler.h +++ b/Atom-Linux/native_handler.h @@ -4,6 +4,18 @@ #include "include/cef_base.h" #include "include/cef_v8.h" #include +#include + +struct CallbackContext { + CefRefPtr context; + CefRefPtr function; + CefRefPtr eventTypes; +}; + +struct NotifyContext { + int descriptor; + std::map > callbacks; +}; class NativeHandler: public CefV8Handler { public: @@ -15,10 +27,20 @@ public: std::string path; + int notifyFd; + + unsigned long int idCounter; + + std::map > pathCallbacks; + + std::map pathDescriptors; + virtual bool Execute(const CefString& name, CefRefPtr object, const CefV8ValueList& arguments, CefRefPtr& retval, CefString& exception); + void NotifyWatchers(); + IMPLEMENT_REFCOUNTING(NativeHandler) ; @@ -86,6 +108,14 @@ private: void Alert(const CefString& name, CefRefPtr object, const CefV8ValueList& arguments, CefRefPtr& retval, CefString& exception); + + void WatchPath(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); + + void UnwatchPath(const CefString& name, CefRefPtr object, + const CefV8ValueList& arguments, CefRefPtr& retval, + CefString& exception); }; #endif