Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Unified Diff: src/FileSystemJsObject.cpp

Issue 10296001: Implement File API (Closed)
Patch Set: Don't pass a blog to _fileSystem.write Created April 12, 2013, 12:10 p.m.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/FileSystemJsObject.cpp
===================================================================
new file mode 100644
--- /dev/null
+++ b/src/FileSystemJsObject.cpp
@@ -0,0 +1,411 @@
+#include <AdblockPlus/FileSystem.h>
+#include <stdexcept>
+#include <sstream>
+#include <vector>
+
+#include "FileSystemJsObject.h"
+#include "Utils.h"
+#include "Thread.h"
+
+using namespace AdblockPlus;
+
+namespace
+{
+ class IoThread : public Thread
+ {
+ public:
+ IoThread(FileSystem& fileSystem, v8::Persistent<v8::Function> callback)
Wladimir Palant 2013/04/12 16:10:35 Passing in callback like this is rather ugly - you
+ : isolate(v8::Isolate::GetCurrent()),
+ context(v8::Persistent<v8::Context>::New(isolate,
+ v8::Context::GetCurrent())),
+ fileSystem(fileSystem), callback(callback)
+ {
+ }
+
+ virtual ~IoThread()
+ {
+ callback.Dispose(isolate);
+ context.Dispose(isolate);
+ }
+
+ protected:
+ v8::Isolate* const isolate;
+ v8::Persistent<v8::Context> context;
+ FileSystem& fileSystem;
+ v8::Persistent<v8::Function> callback;
+ };
+
+ class ReadThread : public IoThread
+ {
+ public:
+ ReadThread(FileSystem& fileSystem, v8::Persistent<v8::Function> callback,
+ const std::string& path)
+ : IoThread(fileSystem, callback), path(path)
+ {
+ }
+
+ void Run()
+ {
+ std::string content;
+ std::string error;
+ try
+ {
+ std::auto_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 v8::Locker locker(isolate);
+ const v8::HandleScope handleScope;
+ const v8::Context::Scope contextScope(context);
+ v8::Handle<v8::Object> result = v8::Object::New();
+ result->Set(v8::String::New("content"), v8::String::New(content.c_str()));
+ result->Set(v8::String::New("error"), v8::String::New(error.c_str()));
Wladimir Palant 2013/04/12 16:10:35 Please always use the string length when convertin
Felix Dahlke 2013/04/15 03:43:34 Will do, I meant to add string conversion function
+ callback->Call(callback, 1,
+ reinterpret_cast<v8::Handle<v8::Value>*>(&result));
+ delete this;
+ }
+
+ private:
+ std::string path;
+ };
+
+ class WriteThread : public IoThread
+ {
+ public:
+ WriteThread(FileSystem& fileSystem, v8::Persistent<v8::Function> callback,
+ const std::string& path, const std::string& content)
+ : IoThread(fileSystem, callback), path(path), content(content)
+ {
+ }
+
+ void Run()
+ {
+ std::string error;
+ try
+ {
+ fileSystem.Write(path, content);
+ }
+ catch (std::exception& e)
+ {
+ error = e.what();
+ }
+ catch (...)
+ {
+ error = "Unknown error while writing to " + path;
+ }
+
+ const v8::Locker locker(isolate);
+ const v8::HandleScope handleScope;
+ const v8::Context::Scope contextScope(context);
+ v8::Handle<v8::Value> errorValue = v8::String::New(error.c_str());
+ callback->Call(callback, 1, &errorValue);
+ delete this;
+ }
+
+ private:
+ std::string path;
+ std::string content;
+ };
+
+ class MoveThread : public IoThread
+ {
+ public:
+ MoveThread(FileSystem& fileSystem, v8::Persistent<v8::Function> callback,
+ const std::string& fromPath, const std::string& toPath)
+ : IoThread(fileSystem, 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 v8::Locker locker(isolate);
+ const v8::HandleScope handleScope;
+ const v8::Context::Scope contextScope(context);
+ v8::Handle<v8::Value> errorValue = v8::String::New(error.c_str());
+ callback->Call(callback, 1, &errorValue);
+ delete this;
+ }
+
+ private:
+ std::string fromPath;
+ std::string toPath;
+ };
+
+ class RemoveThread : public IoThread
+ {
+ public:
+ RemoveThread(FileSystem& fileSystem, v8::Persistent<v8::Function> callback,
+ const std::string& path)
+ : IoThread(fileSystem, 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 v8::Locker locker(isolate);
+ const v8::HandleScope handleScope;
+ const v8::Context::Scope contextScope(context);
+ v8::Handle<v8::Value> errorValue = v8::String::New(error.c_str());
+ callback->Call(callback, 1, &errorValue);
+ delete this;
+ }
+
+ private:
+ std::string path;
+ };
+
+ class StatThread : public IoThread
+ {
+ public:
+ StatThread(FileSystem& fileSystem, v8::Persistent<v8::Function> callback,
+ const std::string& path)
+ : IoThread(fileSystem, 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 v8::Locker locker(isolate);
+ const v8::HandleScope handleScope;
+ const v8::Context::Scope contextScope(context);
+ v8::Handle<v8::Object> result = v8::Object::New();
+ result->Set(v8::String::New("exists"),
+ v8::Boolean::New(statResult.exists));
+ result->Set(v8::String::New("isFile"),
+ v8::Boolean::New(statResult.isFile));
+ result->Set(v8::String::New("isDirectory"),
+ v8::Boolean::New(statResult.isDirectory));
+ result->Set(v8::String::New("lastModified"),
+ v8::Number::New(statResult.lastModified));
+ result->Set(v8::String::New("error"), v8::String::New(error.c_str()));
+ callback->Call(callback, 1,
+ reinterpret_cast<v8::Handle<v8::Value>*>(&result));
+ delete this;
+ }
+
+ private:
+ std::string path;
+ };
+
+ std::string CheckArguments(const v8::Arguments& arguments,
+ const std::string& functionName,
Wladimir Palant 2013/04/12 16:10:35 Will arguments.Callee()->GetName() do as well?
+ const std::vector<std::string> requiredTypes)
+ {
+ const int requiredCount = requiredTypes.size();
+ if (arguments.Length() != requiredCount)
+ {
+ std::stringstream stream;
+ stream << functionName << " requires " << requiredCount
+ << (requiredCount == 1 ? " parameter" : " parameters");
+ return stream.str();
+ }
+
+ for (int i = 0; i < requiredCount; i++)
+ {
+ const v8::Handle<v8::Value> argument = arguments[i];
+ const std::string requiredType = requiredTypes[i];
+ if ((requiredType == "string" && !argument->IsString())
+ || (requiredType == "number" && !argument->IsNumber())
Wladimir Palant 2013/04/12 16:10:35 Please note that a parameter doesn't need to be a
+ || (requiredType == "function" && !argument->IsFunction()))
+ {
+ std::vector<std::string> countWords;
+ countWords.push_back("First");
+ countWords.push_back("Second");
+ countWords.push_back("Third");
+ std::stringstream stream;
+ if (i < countWords.size())
+ stream << countWords[i] << " argument";
+ else
+ stream << "Argument " << i;
Wladimir Palant 2013/04/12 16:10:35 I would opt against unnecessary complexity - pleas
+ stream << " to " << functionName << " must be a " << requiredType;
+ return stream.str();
+ }
+ }
+
+ return "";
+ }
+
+ v8::Handle<v8::Value> ReadCallback(const v8::Arguments& arguments)
+ {
+ std::vector<std::string> requiredTypes;
+ requiredTypes.push_back("string");
+ requiredTypes.push_back("function");
+ const std::string error = CheckArguments(arguments, "_fileSystem.read",
+ requiredTypes);
Wladimir Palant 2013/04/12 16:10:35 Mozilla opted for a more trivial CheckArguments("s
Felix Dahlke 2013/04/15 03:43:34 I mainly introduced this to get the duplication do
+ if (error.length())
+ return v8::ThrowException(v8::String::New(error.c_str()));
+
+ const v8::Handle<const v8::External> external =
+ v8::Handle<const v8::External>::Cast(arguments.Data());
+ FileSystem* const fileSystem = static_cast<FileSystem*>(external->Value());
+ const std::string path = *v8::String::Utf8Value(arguments[0]->ToString());
+ v8::Persistent<v8::Function> callback = v8::Persistent<v8::Function>::New(
+ v8::Isolate::GetCurrent(), v8::Handle<v8::Function>::Cast(arguments[1]));
+ ReadThread* const readThread = new ReadThread(*fileSystem, callback, path);
+ readThread->Start();
+ return v8::Undefined();
+ }
+
+ v8::Handle<v8::Value> WriteCallback(const v8::Arguments& arguments)
+ {
+ std::vector<std::string> requiredTypes;
+ requiredTypes.push_back("string");
+ requiredTypes.push_back("string");
+ requiredTypes.push_back("function");
+ const std::string error = CheckArguments(arguments, "_fileSystem.write",
+ requiredTypes);
+ if (error.length())
+ return v8::ThrowException(v8::String::New(error.c_str()));
+
+ const v8::Handle<const v8::External> external =
+ v8::Handle<const v8::External>::Cast(arguments.Data());
+ FileSystem* const fileSystem = static_cast<FileSystem*>(external->Value());
+ const std::string path = *v8::String::Utf8Value(arguments[0]->ToString());
+ const std::string content =
+ *v8::String::Utf8Value(arguments[1]->ToString());
+ v8::Persistent<v8::Function> callback = v8::Persistent<v8::Function>::New(
+ v8::Isolate::GetCurrent(), v8::Handle<v8::Function>::Cast(arguments[2]));
+ WriteThread* const writeThread = new WriteThread(*fileSystem, callback,
+ path, content);
Wladimir Palant 2013/04/12 16:10:35 Just a thought: with the content parameter being a
+ writeThread->Start();
+ return v8::Undefined();
+ }
+
+ v8::Handle<v8::Value> MoveCallback(const v8::Arguments& arguments)
+ {
+ std::vector<std::string> requiredTypes;
+ requiredTypes.push_back("string");
+ requiredTypes.push_back("string");
+ requiredTypes.push_back("function");
+ const std::string error = CheckArguments(arguments, "_fileSystem.move",
+ requiredTypes);
+ if (error.length())
+ return v8::ThrowException(v8::String::New(error.c_str()));
+
+ const v8::Handle<const v8::External> external =
+ v8::Handle<const v8::External>::Cast(arguments.Data());
+ FileSystem* const fileSystem = static_cast<FileSystem*>(external->Value());
+ const std::string fromPath =
+ *v8::String::Utf8Value(arguments[0]->ToString());
+ const std::string toPath = *v8::String::Utf8Value(arguments[1]->ToString());
+ v8::Persistent<v8::Function> callback = v8::Persistent<v8::Function>::New(
+ v8::Isolate::GetCurrent(), v8::Handle<v8::Function>::Cast(arguments[2]));
+ MoveThread* const moveThread = new MoveThread(*fileSystem, callback,
+ fromPath, toPath);
+ moveThread->Start();
+ return v8::Undefined();
+ }
+
+ v8::Handle<v8::Value> RemoveCallback(const v8::Arguments& arguments)
+ {
+ std::vector<std::string> requiredTypes;
+ requiredTypes.push_back("string");
+ requiredTypes.push_back("function");
+ const std::string error = CheckArguments(arguments, "_fileSystem.remove",
+ requiredTypes);
+ if (error.length())
+ return v8::ThrowException(v8::String::New(error.c_str()));
+
+ const v8::Handle<const v8::External> external =
+ v8::Handle<const v8::External>::Cast(arguments.Data());
+ FileSystem* const fileSystem = static_cast<FileSystem*>(external->Value());
+ const std::string path = *v8::String::Utf8Value(arguments[0]->ToString());
+ v8::Persistent<v8::Function> callback = v8::Persistent<v8::Function>::New(
+ v8::Isolate::GetCurrent(), v8::Handle<v8::Function>::Cast(arguments[1]));
+ RemoveThread* const removeThread = new RemoveThread(*fileSystem, callback,
+ path);
+ removeThread->Start();
+ return v8::Undefined();
+ }
+
+ v8::Handle<v8::Value> StatCallback(const v8::Arguments& arguments)
+ {
+ std::vector<std::string> requiredTypes;
+ requiredTypes.push_back("string");
+ requiredTypes.push_back("function");
+ const std::string error = CheckArguments(arguments, "_fileSystem.stat",
+ requiredTypes);
+ if (error.length())
+ return v8::ThrowException(v8::String::New(error.c_str()));
+
+ const v8::Handle<const v8::External> external =
+ v8::Handle<const v8::External>::Cast(arguments.Data());
+ FileSystem* const fileSystem = static_cast<FileSystem*>(external->Value());
+ const std::string path = *v8::String::Utf8Value(arguments[0]->ToString());
+ v8::Persistent<v8::Function> callback = v8::Persistent<v8::Function>::New(
+ v8::Isolate::GetCurrent(), v8::Handle<v8::Function>::Cast(arguments[1]));
+ StatThread* const statThread = new StatThread(*fileSystem, callback, path);
+ statThread->Start();
+ return v8::Undefined();
+ }
+}
+
+v8::Handle<v8::ObjectTemplate>
+FileSystemJsObject::Create(FileSystem& fileSystem)
+{
+ const v8::Locker locker(v8::Isolate::GetCurrent());
+ v8::HandleScope handleScope;
+ const v8::Handle<v8::ObjectTemplate> file = v8::ObjectTemplate::New();
+ file->Set(v8::String::New("read"),
+ v8::FunctionTemplate::New(ReadCallback, v8::External::New(&fileSystem)));
Wladimir Palant 2013/04/12 16:10:35 How about using the same v8::External instance for
+ file->Set(v8::String::New("write"),
+ v8::FunctionTemplate::New(WriteCallback, v8::External::New(&fileSystem)));
+ file->Set(v8::String::New("move"),
+ v8::FunctionTemplate::New(MoveCallback, v8::External::New(&fileSystem)));
+ file->Set(v8::String::New("remove"),
+ v8::FunctionTemplate::New(RemoveCallback, v8::External::New(&fileSystem)));
+ file->Set(v8::String::New("stat"),
+ v8::FunctionTemplate::New(StatCallback, v8::External::New(&fileSystem)));
+ return handleScope.Close(file);
+}

Powered by Google App Engine
This is Rietveld