Skip to content

Commit c89731c

Browse files
committed
Implemented async save API. Fixes nikhilm#23
1 parent 957fbb1 commit c89731c

File tree

4 files changed

+81
-0
lines changed

4 files changed

+81
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ spec/sample-write.mp3
44
.lock-wscript
55
node_modules
66
.DS_Store
7+
spec/sample-write-async.mp3

spec/taglibSpec.js

+21
Original file line numberDiff line numberDiff line change
@@ -189,5 +189,26 @@ vows.describe('taglib bindings')
189189
'should have a silly comment': function(tag) {
190190
assert.equal("Salami Wiglet.", tag.comment);
191191
}
192+
},
193+
194+
'writing Tag to a file asynchronously': {
195+
topic: function() {
196+
var filename = __dirname+'/sample-write-async.mp3';
197+
fs.writeFileSync(filename, fs.readFileSync(__dirname+'/sample.mp3'));
198+
var self = this;
199+
Taglib.tag(filename, function(err, tag) {
200+
if (err) {
201+
self.callback(err);
202+
}
203+
tag.title = 'Something completely different…';
204+
tag.save(function(err) {
205+
self.callback(err, filename);
206+
});
207+
});
208+
},
209+
'should have written `Something completely different…` to title': function (filename) {
210+
var tag = Taglib.tagSync(filename);
211+
assert.equal(tag.title, "Something completely different…");
212+
}
192213
}
193214
}).export(module);

src/tag.cc

+50
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ void Tag::Initialize(Handle<Object> target)
2727
TagTemplate->InstanceTemplate()->SetInternalFieldCount(1);
2828
TagTemplate->SetClassName(String::NewSymbol("Tag"));
2929

30+
NODE_SET_PROTOTYPE_METHOD(TagTemplate, "save", AsyncSaveTag);
3031
NODE_SET_PROTOTYPE_METHOD(TagTemplate, "saveSync", SyncSaveTag);
3132
NODE_SET_PROTOTYPE_METHOD(TagTemplate, "isEmpty", IsEmpty);
3233

@@ -294,4 +295,53 @@ void Tag::AsyncTagReadAfter(uv_work_t *req) {
294295
//delete baton;
295296
}
296297

298+
v8::Handle<v8::Value> Tag::AsyncSaveTag(const v8::Arguments &args) {
299+
HandleScope scope;
300+
301+
if (args.Length() >= 1 && !args[0]->IsFunction())
302+
return ThrowException(String::New("Expected callback function as first argument"));
303+
304+
Local<Function> callback = Local<Function>::Cast(args[0]);
305+
306+
Tag *t = ObjectWrap::Unwrap<Tag>(args.This());
307+
308+
AsyncSaveBaton *baton = new AsyncSaveBaton;
309+
baton->request.data = baton;
310+
baton->tag = t;
311+
baton->callback = Persistent<Function>::New(callback);
312+
baton->success = false;
313+
314+
uv_queue_work(uv_default_loop(), &baton->request, Tag::AsyncSaveTagDo, Tag::AsyncSaveTagAfter);
315+
316+
return Undefined();
317+
}
318+
319+
void Tag::AsyncSaveTagDo(uv_work_t *req) {
320+
AsyncSaveBaton *baton = static_cast<AsyncSaveBaton*>(req->data);
321+
322+
assert(baton->tag->fileRef);
323+
baton->success = baton->tag->fileRef->save();
324+
}
325+
326+
void Tag::AsyncSaveTagAfter(uv_work_t *req) {
327+
HandleScope scope;
328+
329+
AsyncSaveBaton *baton = static_cast<AsyncSaveBaton*>(req->data);
330+
331+
if (baton->success) {
332+
Handle<Value> argv[] = { Null() };
333+
baton->callback->Call(Context::GetCurrent()->Global(), 1, argv);
334+
}
335+
else {
336+
Local<Object> error = Object::New();
337+
error->Set(String::New("message"), String::New("Failed to save file"));
338+
error->Set(String::New("path"), String::New(baton->tag->fileRef->file()->name()));
339+
Handle<Value> argv[] = { error };
340+
baton->callback->Call(Context::GetCurrent()->Global(), 1, argv);
341+
}
342+
343+
baton->callback.Dispose();
344+
delete baton;
345+
}
346+
297347
}

src/tag.h

+9
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,14 @@ class Tag : public node::ObjectWrap {
4242
static void SetGenre(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo& info);
4343

4444
static v8::Handle<v8::Value> IsEmpty(const v8::Arguments &args);
45+
static v8::Handle<v8::Value> AsyncSaveTag(const v8::Arguments &args);
4546
static v8::Handle<v8::Value> SyncSaveTag(const v8::Arguments &args);
4647
static v8::Handle<v8::Value> SyncTag(const v8::Arguments &args);
4748
static v8::Handle<v8::Value> AsyncTag(const v8::Arguments &args);
4849
static void AsyncTagRead(uv_work_t *req);
4950
static void AsyncTagReadAfter(uv_work_t *req);
51+
static void AsyncSaveTagDo(uv_work_t *req);
52+
static void AsyncSaveTagAfter(uv_work_t *req);
5053
};
5154

5255
struct AsyncTagBaton {
@@ -58,6 +61,12 @@ struct AsyncTagBaton {
5861
suseconds_t startTime;
5962
};
6063

64+
struct AsyncSaveBaton {
65+
uv_work_t request;
66+
Tag *tag;
67+
v8::Persistent<v8::Function> callback;
68+
bool success;
69+
};
6170

6271
int CreateFileRef(TagLib::FileName path, TagLib::FileRef **ref);
6372
v8::Handle<v8::String> ErrorToString(int error);

0 commit comments

Comments
 (0)