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

Side by Side 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.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 #include <AdblockPlus/FileSystem.h>
2 #include <stdexcept>
3 #include <sstream>
4 #include <vector>
5
6 #include "FileSystemJsObject.h"
7 #include "Utils.h"
8 #include "Thread.h"
9
10 using namespace AdblockPlus;
11
12 namespace
13 {
14 class IoThread : public Thread
15 {
16 public:
17 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
18 : isolate(v8::Isolate::GetCurrent()),
19 context(v8::Persistent<v8::Context>::New(isolate,
20 v8::Context::GetCurrent())),
21 fileSystem(fileSystem), callback(callback)
22 {
23 }
24
25 virtual ~IoThread()
26 {
27 callback.Dispose(isolate);
28 context.Dispose(isolate);
29 }
30
31 protected:
32 v8::Isolate* const isolate;
33 v8::Persistent<v8::Context> context;
34 FileSystem& fileSystem;
35 v8::Persistent<v8::Function> callback;
36 };
37
38 class ReadThread : public IoThread
39 {
40 public:
41 ReadThread(FileSystem& fileSystem, v8::Persistent<v8::Function> callback,
42 const std::string& path)
43 : IoThread(fileSystem, callback), path(path)
44 {
45 }
46
47 void Run()
48 {
49 std::string content;
50 std::string error;
51 try
52 {
53 std::auto_ptr<std::istream> stream = fileSystem.Read(path);
54 content = Utils::Slurp(*stream);
55 }
56 catch (std::exception& e)
57 {
58 error = e.what();
59 }
60 catch (...)
61 {
62 error = "Unknown error while reading from " + path;
63 }
64
65 const v8::Locker locker(isolate);
66 const v8::HandleScope handleScope;
67 const v8::Context::Scope contextScope(context);
68 v8::Handle<v8::Object> result = v8::Object::New();
69 result->Set(v8::String::New("content"), v8::String::New(content.c_str()));
70 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
71 callback->Call(callback, 1,
72 reinterpret_cast<v8::Handle<v8::Value>*>(&result));
73 delete this;
74 }
75
76 private:
77 std::string path;
78 };
79
80 class WriteThread : public IoThread
81 {
82 public:
83 WriteThread(FileSystem& fileSystem, v8::Persistent<v8::Function> callback,
84 const std::string& path, const std::string& content)
85 : IoThread(fileSystem, callback), path(path), content(content)
86 {
87 }
88
89 void Run()
90 {
91 std::string error;
92 try
93 {
94 fileSystem.Write(path, content);
95 }
96 catch (std::exception& e)
97 {
98 error = e.what();
99 }
100 catch (...)
101 {
102 error = "Unknown error while writing to " + path;
103 }
104
105 const v8::Locker locker(isolate);
106 const v8::HandleScope handleScope;
107 const v8::Context::Scope contextScope(context);
108 v8::Handle<v8::Value> errorValue = v8::String::New(error.c_str());
109 callback->Call(callback, 1, &errorValue);
110 delete this;
111 }
112
113 private:
114 std::string path;
115 std::string content;
116 };
117
118 class MoveThread : public IoThread
119 {
120 public:
121 MoveThread(FileSystem& fileSystem, v8::Persistent<v8::Function> callback,
122 const std::string& fromPath, const std::string& toPath)
123 : IoThread(fileSystem, callback), fromPath(fromPath), toPath(toPath)
124 {
125 }
126
127 void Run()
128 {
129 std::string error;
130 try
131 {
132 fileSystem.Move(fromPath, toPath);
133 }
134 catch (std::exception& e)
135 {
136 error = e.what();
137 }
138 catch (...)
139 {
140 error = "Unknown error while moving " + fromPath + " to " + toPath;
141 }
142
143 const v8::Locker locker(isolate);
144 const v8::HandleScope handleScope;
145 const v8::Context::Scope contextScope(context);
146 v8::Handle<v8::Value> errorValue = v8::String::New(error.c_str());
147 callback->Call(callback, 1, &errorValue);
148 delete this;
149 }
150
151 private:
152 std::string fromPath;
153 std::string toPath;
154 };
155
156 class RemoveThread : public IoThread
157 {
158 public:
159 RemoveThread(FileSystem& fileSystem, v8::Persistent<v8::Function> callback,
160 const std::string& path)
161 : IoThread(fileSystem, callback), path(path)
162 {
163 }
164
165 void Run()
166 {
167 std::string error;
168 try
169 {
170 fileSystem.Remove(path);
171 }
172 catch (std::exception& e)
173 {
174 error = e.what();
175 }
176 catch (...)
177 {
178 error = "Unknown error while removing " + path;
179 }
180
181 const v8::Locker locker(isolate);
182 const v8::HandleScope handleScope;
183 const v8::Context::Scope contextScope(context);
184 v8::Handle<v8::Value> errorValue = v8::String::New(error.c_str());
185 callback->Call(callback, 1, &errorValue);
186 delete this;
187 }
188
189 private:
190 std::string path;
191 };
192
193 class StatThread : public IoThread
194 {
195 public:
196 StatThread(FileSystem& fileSystem, v8::Persistent<v8::Function> callback,
197 const std::string& path)
198 : IoThread(fileSystem, callback), path(path)
199 {
200 }
201
202 void Run()
203 {
204 std::string error;
205 FileSystem::StatResult statResult;
206 try
207 {
208 statResult = fileSystem.Stat(path);
209 }
210 catch (std::exception& e)
211 {
212 error = e.what();
213 }
214 catch (...)
215 {
216 error = "Unknown error while calling stat on " + path;
217 }
218
219 const v8::Locker locker(isolate);
220 const v8::HandleScope handleScope;
221 const v8::Context::Scope contextScope(context);
222 v8::Handle<v8::Object> result = v8::Object::New();
223 result->Set(v8::String::New("exists"),
224 v8::Boolean::New(statResult.exists));
225 result->Set(v8::String::New("isFile"),
226 v8::Boolean::New(statResult.isFile));
227 result->Set(v8::String::New("isDirectory"),
228 v8::Boolean::New(statResult.isDirectory));
229 result->Set(v8::String::New("lastModified"),
230 v8::Number::New(statResult.lastModified));
231 result->Set(v8::String::New("error"), v8::String::New(error.c_str()));
232 callback->Call(callback, 1,
233 reinterpret_cast<v8::Handle<v8::Value>*>(&result));
234 delete this;
235 }
236
237 private:
238 std::string path;
239 };
240
241 std::string CheckArguments(const v8::Arguments& arguments,
242 const std::string& functionName,
Wladimir Palant 2013/04/12 16:10:35 Will arguments.Callee()->GetName() do as well?
243 const std::vector<std::string> requiredTypes)
244 {
245 const int requiredCount = requiredTypes.size();
246 if (arguments.Length() != requiredCount)
247 {
248 std::stringstream stream;
249 stream << functionName << " requires " << requiredCount
250 << (requiredCount == 1 ? " parameter" : " parameters");
251 return stream.str();
252 }
253
254 for (int i = 0; i < requiredCount; i++)
255 {
256 const v8::Handle<v8::Value> argument = arguments[i];
257 const std::string requiredType = requiredTypes[i];
258 if ((requiredType == "string" && !argument->IsString())
259 || (requiredType == "number" && !argument->IsNumber())
Wladimir Palant 2013/04/12 16:10:35 Please note that a parameter doesn't need to be a
260 || (requiredType == "function" && !argument->IsFunction()))
261 {
262 std::vector<std::string> countWords;
263 countWords.push_back("First");
264 countWords.push_back("Second");
265 countWords.push_back("Third");
266 std::stringstream stream;
267 if (i < countWords.size())
268 stream << countWords[i] << " argument";
269 else
270 stream << "Argument " << i;
Wladimir Palant 2013/04/12 16:10:35 I would opt against unnecessary complexity - pleas
271 stream << " to " << functionName << " must be a " << requiredType;
272 return stream.str();
273 }
274 }
275
276 return "";
277 }
278
279 v8::Handle<v8::Value> ReadCallback(const v8::Arguments& arguments)
280 {
281 std::vector<std::string> requiredTypes;
282 requiredTypes.push_back("string");
283 requiredTypes.push_back("function");
284 const std::string error = CheckArguments(arguments, "_fileSystem.read",
285 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
286 if (error.length())
287 return v8::ThrowException(v8::String::New(error.c_str()));
288
289 const v8::Handle<const v8::External> external =
290 v8::Handle<const v8::External>::Cast(arguments.Data());
291 FileSystem* const fileSystem = static_cast<FileSystem*>(external->Value());
292 const std::string path = *v8::String::Utf8Value(arguments[0]->ToString());
293 v8::Persistent<v8::Function> callback = v8::Persistent<v8::Function>::New(
294 v8::Isolate::GetCurrent(), v8::Handle<v8::Function>::Cast(arguments[1]));
295 ReadThread* const readThread = new ReadThread(*fileSystem, callback, path);
296 readThread->Start();
297 return v8::Undefined();
298 }
299
300 v8::Handle<v8::Value> WriteCallback(const v8::Arguments& arguments)
301 {
302 std::vector<std::string> requiredTypes;
303 requiredTypes.push_back("string");
304 requiredTypes.push_back("string");
305 requiredTypes.push_back("function");
306 const std::string error = CheckArguments(arguments, "_fileSystem.write",
307 requiredTypes);
308 if (error.length())
309 return v8::ThrowException(v8::String::New(error.c_str()));
310
311 const v8::Handle<const v8::External> external =
312 v8::Handle<const v8::External>::Cast(arguments.Data());
313 FileSystem* const fileSystem = static_cast<FileSystem*>(external->Value());
314 const std::string path = *v8::String::Utf8Value(arguments[0]->ToString());
315 const std::string content =
316 *v8::String::Utf8Value(arguments[1]->ToString());
317 v8::Persistent<v8::Function> callback = v8::Persistent<v8::Function>::New(
318 v8::Isolate::GetCurrent(), v8::Handle<v8::Function>::Cast(arguments[2]));
319 WriteThread* const writeThread = new WriteThread(*fileSystem, callback,
320 path, content);
Wladimir Palant 2013/04/12 16:10:35 Just a thought: with the content parameter being a
321 writeThread->Start();
322 return v8::Undefined();
323 }
324
325 v8::Handle<v8::Value> MoveCallback(const v8::Arguments& arguments)
326 {
327 std::vector<std::string> requiredTypes;
328 requiredTypes.push_back("string");
329 requiredTypes.push_back("string");
330 requiredTypes.push_back("function");
331 const std::string error = CheckArguments(arguments, "_fileSystem.move",
332 requiredTypes);
333 if (error.length())
334 return v8::ThrowException(v8::String::New(error.c_str()));
335
336 const v8::Handle<const v8::External> external =
337 v8::Handle<const v8::External>::Cast(arguments.Data());
338 FileSystem* const fileSystem = static_cast<FileSystem*>(external->Value());
339 const std::string fromPath =
340 *v8::String::Utf8Value(arguments[0]->ToString());
341 const std::string toPath = *v8::String::Utf8Value(arguments[1]->ToString());
342 v8::Persistent<v8::Function> callback = v8::Persistent<v8::Function>::New(
343 v8::Isolate::GetCurrent(), v8::Handle<v8::Function>::Cast(arguments[2]));
344 MoveThread* const moveThread = new MoveThread(*fileSystem, callback,
345 fromPath, toPath);
346 moveThread->Start();
347 return v8::Undefined();
348 }
349
350 v8::Handle<v8::Value> RemoveCallback(const v8::Arguments& arguments)
351 {
352 std::vector<std::string> requiredTypes;
353 requiredTypes.push_back("string");
354 requiredTypes.push_back("function");
355 const std::string error = CheckArguments(arguments, "_fileSystem.remove",
356 requiredTypes);
357 if (error.length())
358 return v8::ThrowException(v8::String::New(error.c_str()));
359
360 const v8::Handle<const v8::External> external =
361 v8::Handle<const v8::External>::Cast(arguments.Data());
362 FileSystem* const fileSystem = static_cast<FileSystem*>(external->Value());
363 const std::string path = *v8::String::Utf8Value(arguments[0]->ToString());
364 v8::Persistent<v8::Function> callback = v8::Persistent<v8::Function>::New(
365 v8::Isolate::GetCurrent(), v8::Handle<v8::Function>::Cast(arguments[1]));
366 RemoveThread* const removeThread = new RemoveThread(*fileSystem, callback,
367 path);
368 removeThread->Start();
369 return v8::Undefined();
370 }
371
372 v8::Handle<v8::Value> StatCallback(const v8::Arguments& arguments)
373 {
374 std::vector<std::string> requiredTypes;
375 requiredTypes.push_back("string");
376 requiredTypes.push_back("function");
377 const std::string error = CheckArguments(arguments, "_fileSystem.stat",
378 requiredTypes);
379 if (error.length())
380 return v8::ThrowException(v8::String::New(error.c_str()));
381
382 const v8::Handle<const v8::External> external =
383 v8::Handle<const v8::External>::Cast(arguments.Data());
384 FileSystem* const fileSystem = static_cast<FileSystem*>(external->Value());
385 const std::string path = *v8::String::Utf8Value(arguments[0]->ToString());
386 v8::Persistent<v8::Function> callback = v8::Persistent<v8::Function>::New(
387 v8::Isolate::GetCurrent(), v8::Handle<v8::Function>::Cast(arguments[1]));
388 StatThread* const statThread = new StatThread(*fileSystem, callback, path);
389 statThread->Start();
390 return v8::Undefined();
391 }
392 }
393
394 v8::Handle<v8::ObjectTemplate>
395 FileSystemJsObject::Create(FileSystem& fileSystem)
396 {
397 const v8::Locker locker(v8::Isolate::GetCurrent());
398 v8::HandleScope handleScope;
399 const v8::Handle<v8::ObjectTemplate> file = v8::ObjectTemplate::New();
400 file->Set(v8::String::New("read"),
401 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
402 file->Set(v8::String::New("write"),
403 v8::FunctionTemplate::New(WriteCallback, v8::External::New(&fileSystem)));
404 file->Set(v8::String::New("move"),
405 v8::FunctionTemplate::New(MoveCallback, v8::External::New(&fileSystem)));
406 file->Set(v8::String::New("remove"),
407 v8::FunctionTemplate::New(RemoveCallback, v8::External::New(&fileSystem)));
408 file->Set(v8::String::New("stat"),
409 v8::FunctionTemplate::New(StatCallback, v8::External::New(&fileSystem)));
410 return handleScope.Close(file);
411 }
OLDNEW

Powered by Google App Engine
This is Rietveld