| Index: src/FileSystemJsObject.cpp | 
| =================================================================== | 
| --- a/src/FileSystemJsObject.cpp | 
| +++ b/src/FileSystemJsObject.cpp | 
| @@ -18,320 +18,196 @@ | 
| #include <AdblockPlus/FileSystem.h> | 
| #include <stdexcept> | 
| #include <sstream> | 
| #include <vector> | 
|  | 
| #include <AdblockPlus/JsValue.h> | 
| #include "FileSystemJsObject.h" | 
| #include "JsContext.h" | 
| -#include "Thread.h" | 
| #include "Utils.h" | 
|  | 
| using namespace AdblockPlus; | 
| using AdblockPlus::Utils::ThrowExceptionInJS; | 
|  | 
| namespace | 
| { | 
| -  class IoThread : public Thread | 
| -  { | 
| -  public: | 
| -    IoThread(const JsEnginePtr& jsEngine, const JsValue& callback) | 
| -      : Thread(true), jsEngine(jsEngine), fileSystem(jsEngine->GetFileSystem()), | 
| -        callback(callback) | 
| -    { | 
| -    } | 
| - | 
| -  protected: | 
| -    JsEnginePtr jsEngine; | 
| -    FileSystemPtr fileSystem; | 
| -    JsValue callback; | 
| -  }; | 
| - | 
| -  class ReadThread : public IoThread | 
| -  { | 
| -  public: | 
| -    ReadThread(const JsEnginePtr& jsEngine, const JsValue& callback, | 
| -               const std::string& path) | 
| -      : IoThread(jsEngine, callback), path(path) | 
| -    { | 
| -    } | 
| - | 
| -    void Run() | 
| -    { | 
| -      std::string content; | 
| -      std::string error; | 
| -      try | 
| -      { | 
| -        std::shared_ptr<std::istream> stream = fileSystem->Read(path); | 
| -        content = Utils::Slurp(*stream); | 
| -      } | 
| -      catch (std::exception& e) | 
| -      { | 
| -        error = e.what(); | 
| -      } | 
| -      catch (...) | 
| -      { | 
| -        error =  "Unknown error while reading from " + path; | 
| -      } | 
| - | 
| -      const JsContext context(*jsEngine); | 
| -      auto result = jsEngine->NewObject(); | 
| -      result.SetProperty("content", content); | 
| -      result.SetProperty("error", error); | 
| -      JsValueList params; | 
| -      params.push_back(result); | 
| -      callback.Call(params); | 
| -    } | 
| - | 
| -  private: | 
| -    std::string path; | 
| -  }; | 
| - | 
| -  class WriteThread : public IoThread | 
| -  { | 
| -  public: | 
| -    WriteThread(const JsEnginePtr& jsEngine, const JsValue& callback, | 
| -                const std::string& path, const std::string& content) | 
| -      : IoThread(jsEngine, callback), path(path), content(content) | 
| -    { | 
| -    } | 
| - | 
| -    void Run() | 
| -    { | 
| -      std::string error; | 
| -      try | 
| -      { | 
| -        std::stringstream stream; | 
| -        stream << content; | 
| -        fileSystem->Write(path, stream); | 
| -      } | 
| -      catch (std::exception& e) | 
| -      { | 
| -        error = e.what(); | 
| -      } | 
| -      catch (...) | 
| -      { | 
| -        error = "Unknown error while writing to " + path; | 
| -      } | 
| - | 
| -      const JsContext context(*jsEngine); | 
| -      auto errorValue = jsEngine->NewValue(error); | 
| -      JsValueList params; | 
| -      params.push_back(errorValue); | 
| -      callback.Call(params); | 
| -    } | 
| - | 
| -  private: | 
| -    std::string path; | 
| -    std::string content; | 
| -  }; | 
| - | 
| -  class MoveThread : public IoThread | 
| -  { | 
| -  public: | 
| -    MoveThread(const JsEnginePtr& jsEngine, const JsValue& callback, | 
| -               const std::string& fromPath, const std::string& toPath) | 
| -      : IoThread(jsEngine, callback), fromPath(fromPath), toPath(toPath) | 
| -    { | 
| -    } | 
| - | 
| -    void Run() | 
| -    { | 
| -      std::string error; | 
| -      try | 
| -      { | 
| -        fileSystem->Move(fromPath, toPath); | 
| -      } | 
| -      catch (std::exception& e) | 
| -      { | 
| -        error = e.what(); | 
| -      } | 
| -      catch (...) | 
| -      { | 
| -        error = "Unknown error while moving " + fromPath + " to " + toPath; | 
| -      } | 
| - | 
| -      const JsContext context(*jsEngine); | 
| -      auto errorValue = jsEngine->NewValue(error); | 
| -      JsValueList params; | 
| -      params.push_back(errorValue); | 
| -      callback.Call(params); | 
| -    } | 
| - | 
| -  private: | 
| -    std::string fromPath; | 
| -    std::string toPath; | 
| -  }; | 
| - | 
| -  class RemoveThread : public IoThread | 
| -  { | 
| -  public: | 
| -    RemoveThread(const JsEnginePtr& jsEngine, const JsValue& callback, | 
| -                 const std::string& path) | 
| -      : IoThread(jsEngine, callback), path(path) | 
| -    { | 
| -    } | 
| - | 
| -    void Run() | 
| -    { | 
| -      std::string error; | 
| -      try | 
| -      { | 
| -        fileSystem->Remove(path); | 
| -      } | 
| -      catch (std::exception& e) | 
| -      { | 
| -        error = e.what(); | 
| -      } | 
| -      catch (...) | 
| -      { | 
| -        error = "Unknown error while removing " + path; | 
| -      } | 
| - | 
| -      const JsContext context(*jsEngine); | 
| -      auto errorValue = jsEngine->NewValue(error); | 
| -      JsValueList params; | 
| -      params.push_back(errorValue); | 
| -      callback.Call(params); | 
| -    } | 
| - | 
| -  private: | 
| -    std::string path; | 
| -  }; | 
| - | 
| - | 
| -  class StatThread : public IoThread | 
| -  { | 
| -  public: | 
| -    StatThread(const JsEnginePtr& jsEngine, const JsValue& callback, | 
| -               const std::string& path) | 
| -      : IoThread(jsEngine, callback), path(path) | 
| -    { | 
| -    } | 
| - | 
| -    void Run() | 
| -    { | 
| -      std::string error; | 
| -      FileSystem::StatResult statResult; | 
| -      try | 
| -      { | 
| -        statResult = fileSystem->Stat(path); | 
| -      } | 
| -      catch (std::exception& e) | 
| -      { | 
| -        error = e.what(); | 
| -      } | 
| -      catch (...) | 
| -      { | 
| -        error = "Unknown error while calling stat on " + path; | 
| -      } | 
| - | 
| -      const JsContext context(*jsEngine); | 
| -      auto result = jsEngine->NewObject(); | 
| -      result.SetProperty("exists", statResult.exists); | 
| -      result.SetProperty("isFile", statResult.isFile); | 
| -      result.SetProperty("isDirectory", statResult.isDirectory); | 
| -      result.SetProperty("lastModified", statResult.lastModified); | 
| -      result.SetProperty("error", error); | 
| - | 
| -      JsValueList params; | 
| -      params.push_back(result); | 
| -      callback.Call(params); | 
| -    } | 
| - | 
| -  private: | 
| -    std::string path; | 
| -  }; | 
| - | 
| void ReadCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) | 
| { | 
| AdblockPlus::JsEnginePtr jsEngine = AdblockPlus::JsEngine::FromArguments(arguments); | 
| AdblockPlus::JsValueList converted = jsEngine->ConvertArguments(arguments); | 
|  | 
| v8::Isolate* isolate = arguments.GetIsolate(); | 
| if (converted.size() != 2) | 
| return ThrowExceptionInJS(isolate, "_fileSystem.read requires 2 parameters"); | 
| if (!converted[1].IsFunction()) | 
| return ThrowExceptionInJS(isolate, "Second argument to _fileSystem.read must be a function"); | 
| -    ReadThread* const readThread = new ReadThread(jsEngine, converted[1], | 
| -        converted[0].AsString()); | 
| -    readThread->Start(); | 
| + | 
| +    JsValueList values; | 
| +    values.push_back(converted[1]); | 
| +    auto weakCallback = jsEngine->StoreJsValues(values); | 
| +    std::weak_ptr<JsEngine> weakJsEngine = jsEngine; | 
| +    jsEngine->GetAsyncFileSystem()->Read(converted[0].AsString(), | 
| +      [weakJsEngine, weakCallback] | 
| +      (std::string&& content, const std::string& error) | 
| +      { | 
| +        auto jsEngine = weakJsEngine.lock(); | 
| +        if (!jsEngine) | 
| +          return; | 
| + | 
| +        const JsContext context(*jsEngine); | 
| +        auto result = jsEngine->NewObject(); | 
| +        result.SetProperty("content", std::move(content)); | 
| +        if (!error.empty()) | 
| +          result.SetProperty("error", error); | 
| +        jsEngine->TakeJsValues(weakCallback)[0].Call(result); | 
| +      }); | 
| } | 
|  | 
| void WriteCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) | 
| { | 
| AdblockPlus::JsEnginePtr jsEngine = AdblockPlus::JsEngine::FromArguments(arguments); | 
| AdblockPlus::JsValueList converted = jsEngine->ConvertArguments(arguments); | 
|  | 
| v8::Isolate* isolate = arguments.GetIsolate(); | 
| if (converted.size() != 3) | 
| return ThrowExceptionInJS(isolate, "_fileSystem.write requires 3 parameters"); | 
| if (!converted[2].IsFunction()) | 
| return ThrowExceptionInJS(isolate, "Third argument to _fileSystem.write must be a function"); | 
| -    WriteThread* const writeThread = new WriteThread(jsEngine, converted[2], | 
| -        converted[0].AsString(), converted[1].AsString()); | 
| -    writeThread->Start(); | 
| + | 
| +    JsValueList values; | 
| +    values.push_back(converted[2]); | 
| +    auto weakCallback = jsEngine->StoreJsValues(values); | 
| +    std::weak_ptr<JsEngine> weakJsEngine = jsEngine; | 
| +    jsEngine->GetAsyncFileSystem()->Write(converted[0].AsString(), | 
| +      converted[1].AsString(), | 
| +      [weakJsEngine, weakCallback](const std::string& error) | 
| +      { | 
| +        auto jsEngine = weakJsEngine.lock(); | 
| +        if (!jsEngine) | 
| +          return; | 
| + | 
| +        const JsContext context(*jsEngine); | 
| +        JsValueList params; | 
| +        if (!error.empty()) | 
| +          params.push_back(jsEngine->NewValue(error)); | 
| +        jsEngine->TakeJsValues(weakCallback)[0].Call(params); | 
| +      }); | 
| } | 
|  | 
| void MoveCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) | 
| { | 
| AdblockPlus::JsEnginePtr jsEngine = AdblockPlus::JsEngine::FromArguments(arguments); | 
| AdblockPlus::JsValueList converted = jsEngine->ConvertArguments(arguments); | 
|  | 
| v8::Isolate* isolate = arguments.GetIsolate(); | 
| if (converted.size() != 3) | 
| return ThrowExceptionInJS(isolate, "_fileSystem.move requires 3 parameters"); | 
| if (!converted[2].IsFunction()) | 
| return ThrowExceptionInJS(isolate, "Third argument to _fileSystem.move must be a function"); | 
| -    MoveThread* const moveThread = new MoveThread(jsEngine, converted[2], | 
| -        converted[0].AsString(), converted[1].AsString()); | 
| -    moveThread->Start(); | 
| + | 
| +    JsValueList values; | 
| +    values.push_back(converted[2]); | 
| +    auto weakCallback = jsEngine->StoreJsValues(values); | 
| +    std::weak_ptr<JsEngine> weakJsEngine = jsEngine; | 
| +    jsEngine->GetAsyncFileSystem()->Move(converted[0].AsString(), | 
| +      converted[1].AsString(), | 
| +      [weakJsEngine, weakCallback](const std::string& error) | 
| +      { | 
| +        auto jsEngine = weakJsEngine.lock(); | 
| +        if (!jsEngine) | 
| +          return; | 
| + | 
| +        const JsContext context(*jsEngine); | 
| +        JsValueList params; | 
| +        if (!error.empty()) | 
| +          params.push_back(jsEngine->NewValue(error)); | 
| +        jsEngine->TakeJsValues(weakCallback)[0].Call(params); | 
| +      }); | 
| } | 
|  | 
| void RemoveCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) | 
| { | 
| AdblockPlus::JsEnginePtr jsEngine = AdblockPlus::JsEngine::FromArguments(arguments); | 
| AdblockPlus::JsValueList converted = jsEngine->ConvertArguments(arguments); | 
|  | 
| v8::Isolate* isolate = arguments.GetIsolate(); | 
| if (converted.size() != 2) | 
| return ThrowExceptionInJS(isolate, "_fileSystem.remove requires 2 parameters"); | 
| if (!converted[1].IsFunction()) | 
| return ThrowExceptionInJS(isolate, "Second argument to _fileSystem.remove must be a function"); | 
| -    RemoveThread* const removeThread = new RemoveThread(jsEngine, converted[1], | 
| -        converted[0].AsString()); | 
| -    removeThread->Start(); | 
| + | 
| +    JsValueList values; | 
| +    values.push_back(converted[1]); | 
| +    auto weakCallback = jsEngine->StoreJsValues(values); | 
| +    std::weak_ptr<JsEngine> weakJsEngine = jsEngine; | 
| +    jsEngine->GetAsyncFileSystem()->Remove(converted[0].AsString(), | 
| +      [weakJsEngine, weakCallback](const std::string& error) | 
| +      { | 
| +        auto jsEngine = weakJsEngine.lock(); | 
| +        if (!jsEngine) | 
| +          return; | 
| + | 
| +        const JsContext context(*jsEngine); | 
| +        JsValueList params; | 
| +        if (!error.empty()) | 
| +          params.push_back(jsEngine->NewValue(error)); | 
| +        jsEngine->TakeJsValues(weakCallback)[0].Call(params); | 
| +      }); | 
| } | 
|  | 
| void StatCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) | 
| { | 
| AdblockPlus::JsEnginePtr jsEngine = AdblockPlus::JsEngine::FromArguments(arguments); | 
| AdblockPlus::JsValueList converted = jsEngine->ConvertArguments(arguments); | 
|  | 
| v8::Isolate* isolate = arguments.GetIsolate(); | 
| if (converted.size() != 2) | 
| return ThrowExceptionInJS(isolate, "_fileSystem.stat requires 2 parameters"); | 
| if (!converted[1].IsFunction()) | 
| return ThrowExceptionInJS(isolate, "Second argument to _fileSystem.stat must be a function"); | 
| -    StatThread* const statThread = new StatThread(jsEngine, converted[1], | 
| -        converted[0].AsString()); | 
| -    statThread->Start(); | 
| + | 
| +    JsValueList values; | 
| +    values.push_back(converted[1]); | 
| +    auto weakCallback = jsEngine->StoreJsValues(values); | 
| +    std::weak_ptr<JsEngine> weakJsEngine = jsEngine; | 
| +    jsEngine->GetAsyncFileSystem()->Stat(converted[0].AsString(), | 
| +      [weakJsEngine, weakCallback] | 
| +      (const IFileSystem::StatResult& statResult, const std::string& error) | 
| +      { | 
| +        auto jsEngine = weakJsEngine.lock(); | 
| +        if (!jsEngine) | 
| +          return; | 
| + | 
| +        const JsContext context(*jsEngine); | 
| +        auto result = jsEngine->NewObject(); | 
| + | 
| +        result.SetProperty("exists", statResult.exists); | 
| +        result.SetProperty("isFile", statResult.isFile); | 
| +        result.SetProperty("isDirectory", statResult.isDirectory); | 
| +        result.SetProperty("lastModified", statResult.lastModified); | 
| +        if (!error.empty()) | 
| +          result.SetProperty("error", error); | 
| + | 
| +        JsValueList params; | 
| +        params.push_back(result); | 
| +        jsEngine->TakeJsValues(weakCallback)[0].Call(params); | 
| +      }); | 
| } | 
|  | 
| void ResolveCallback(const v8::FunctionCallbackInfo<v8::Value>& arguments) | 
| { | 
| AdblockPlus::JsEnginePtr jsEngine = AdblockPlus::JsEngine::FromArguments(arguments); | 
| AdblockPlus::JsValueList converted = jsEngine->ConvertArguments(arguments); | 
|  | 
| v8::Isolate* isolate = arguments.GetIsolate(); | 
| if (converted.size() != 1) | 
| return ThrowExceptionInJS(isolate, "_fileSystem.resolve requires 1 parameter"); | 
|  | 
| -    std::string resolved = jsEngine->GetFileSystem()->Resolve(converted[0].AsString()); | 
| +    std::string resolved = jsEngine->GetAsyncFileSystem()->Resolve(converted[0].AsString()); | 
| arguments.GetReturnValue().Set(Utils::ToV8String(isolate, resolved)); | 
| } | 
| } | 
|  | 
|  | 
| JsValue& FileSystemJsObject::Setup(JsEngine& jsEngine, JsValue& obj) | 
| { | 
| obj.SetProperty("read", jsEngine.NewCallback(::ReadCallback)); | 
|  |