Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

- added unix sockets for file transfer

- refactored requests

capturing preview pictures and normal capture are now both done with takePicture.
  • Loading branch information...
commit 8a370d05e9e19d0ffd7ee79f2a95a2f491bdec31 1 parent 55f3585
@lwille authored
View
5 package.json
@@ -2,7 +2,7 @@
"author": "Leonhardt Wille <hallo@leonhardt-wille.de>",
"name": "gphoto2",
"description": "Node.js wrapper for libgphoto2",
- "version": "0.1.0alpha1",
+ "version": "0.1.0alpha2",
"homepage": "https://www.riverlabs.de",
"repository": {
"type": "git",
@@ -22,7 +22,8 @@
"superagent": "0.4.x",
"mocha": "1.0.x",
"should": "0.6.x",
- "sinon": "1.3.x"
+ "sinon": "1.3.x",
+ "async": "0.1.x"
},
"scripts": {
"preinstall": "make",
View
143 src/camera.cc
@@ -39,7 +39,6 @@ GPCamera::Initialize(Handle<Object> target) {
ADD_PROTOTYPE_METHOD(camera, getConfig, GetConfig);
ADD_PROTOTYPE_METHOD(camera, setConfigValue, SetConfigValue);
ADD_PROTOTYPE_METHOD(camera, takePicture, TakePicture);
- ADD_PROTOTYPE_METHOD(camera, getPreview, GetPreview);
ADD_PROTOTYPE_METHOD(camera, downloadPicture, DownloadPicture);
target->Set(String::NewSymbol("Camera"), constructor_template->GetFunction());
}
@@ -50,18 +49,28 @@ GPCamera::TakePicture(const Arguments& args) {
GPCamera *camera = ObjectWrap::Unwrap<GPCamera>(args.This());
camera->Ref();
take_picture_request *picture_req = new take_picture_request();
+ picture_req->preview = false;
+
if(args.Length() >= 2){
REQ_OBJ_ARG(0, options);
REQ_FUN_ARG(1, cb);
picture_req->cb = Persistent<Function>::New(cb);
Local<Value> dl = options->Get(String::New("download"));
Local<Value> target = options->Get(String::New("targetPath"));
+ Local<Value> preview = options->Get(String::New("preview"));
+ Local<Value> socket = options->Get(String::New("socket"));
if(target->IsString()){
picture_req->target_path = cv::CastFromJS<std::string>(target);
}
+ if(socket->IsString()){
+ picture_req->socket_path = cv::CastFromJS<std::string>(socket);
+ }
if(dl->IsBoolean()){
picture_req->download = dl->ToBoolean()->Value();
}
+ if(preview->IsBoolean()){
+ picture_req->preview = preview->ToBoolean()->Value();
+ }
}else{
REQ_FUN_ARG(0, cb);
picture_req->cb = Persistent<Function>::New(cb);
@@ -71,20 +80,63 @@ GPCamera::TakePicture(const Arguments& args) {
picture_req->cameraObject = camera;
picture_req->context = gp_context_new();
- DO_ASYNC(picture_req, EIO_TakePicture, EIO_CapturePreviewCb);
- // eio_custom(EIO_TakePicture, EIO_PRI_DEFAULT, EIO_TakePictureCb, picture_req);
- // ev_ref(EV_DEFAULT_UC);
+ DO_ASYNC(picture_req, EIO_Capture, EIO_CaptureCb);
return Undefined();
}
+
void
-GPCamera::EIO_TakePicture(uv_work_t *_req){
+GPCamera::EIO_Capture(uv_work_t *_req){
take_picture_request *req = (take_picture_request *)_req->data;
-
req->cameraObject->lock();
- takePicture(req);
+ if(req->preview){
+ capturePreview(req);
+ }else{
+ takePicture(req);
+ }
req->cameraObject->unlock();
}
+void GPCamera::EIO_CaptureCb(uv_work_t *req){
+ HandleScope scope;
+ take_picture_request *capture_req = (take_picture_request*) req->data;
+
+ Handle<Value> argv[2];
+ int argc = 1;
+ argv[0] = Undefined();
+ if(capture_req->ret < GP_OK){
+ argv[0] = Integer::New(capture_req->ret);
+ }
+ else if(capture_req->download && !capture_req->target_path.empty()){
+ argc=2;
+ argv[1] = String::New(capture_req->target_path.c_str());
+ }
+ else if(capture_req->data && capture_req->download) {
+ argc = 2;
+ node::Buffer* slowBuffer = node::Buffer::New(capture_req->length);
+ if(capture_req->length){
+ memmove(Buffer::Data(slowBuffer), capture_req->data, capture_req->length);
+ Local<Object> globalObj = Context::GetCurrent()->Global();
+ Local<Function> bufferConstructor = Local<Function>::Cast(globalObj->Get(String::New("Buffer")));
+ Handle<Value> constructorArgs[3] = { slowBuffer->handle_, Integer::New(capture_req->length), Integer::New(0) };
+ Local<Object> actualBuffer = bufferConstructor->NewInstance(3, constructorArgs);
+ argv[1] = actualBuffer;
+ }
+ }else{
+ argc = 2;
+ argv[1] = cv::CastToJS(capture_req->path);
+ }
+
+ capture_req->cb->Call(Context::GetCurrent()->Global(), argc, argv);
+ capture_req->cb.Dispose();
+ if(capture_req->ret == GP_OK) gp_file_free(capture_req->file);
+ capture_req->cameraObject->Unref();
+ gp_context_unref(capture_req->context);
+// gp_camera_unref(capture_req->camera);
+
+ delete capture_req;
+}
+
+
Handle<Value>
GPCamera::DownloadPicture(const Arguments& args){
HandleScope scope;
@@ -110,7 +162,7 @@ GPCamera::DownloadPicture(const Arguments& args){
picture_req->path = cv::CastFromJS<std::string>(source);
gp_camera_ref(picture_req->camera);
- DO_ASYNC(picture_req, EIO_DownloadPicture, EIO_CapturePreviewCb);
+ DO_ASYNC(picture_req, EIO_DownloadPicture, EIO_CaptureCb);
return Undefined();
}
@@ -303,81 +355,6 @@ Camera* GPCamera::getCamera(){
return this->camera_;
};
-
-Handle<Value>
-GPCamera::GetPreview(const Arguments& args) {
- HandleScope scope;
- GPCamera *camera = ObjectWrap::Unwrap<GPCamera>(args.This());
- camera->Ref();
- REQ_FUN_ARG(0, cb);
- take_picture_request *preview_req = new take_picture_request();
-
- preview_req->cb = Persistent<Function>::New(cb);
- preview_req->camera = camera->getCamera();
- gp_camera_ref(preview_req->camera);
- preview_req->context = gp_context_new();
- preview_req->cameraObject = camera;
- preview_req->download = true;
- DO_ASYNC(preview_req, EIO_CapturePreview, EIO_CapturePreviewCb);
-// eio_custom(EIO_CapturePreview, EIO_PRI_DEFAULT, EIO_CapturePreviewCb, preview_req);
-// ev_ref(EV_DEFAULT_UC);
- return scope.Close(Undefined());
-
-}
-void GPCamera::EIO_CapturePreview(uv_work_t *req){
- take_picture_request *preview_req = (take_picture_request*) req->data;
-
- RETURN_ON_ERROR(preview_req, gp_file_new, (&preview_req->file), {});
-
- preview_req->cameraObject->lock();
- RETURN_ON_ERROR(preview_req, gp_camera_capture_preview, (preview_req->camera, preview_req->file, preview_req->context), {gp_file_free(preview_req->file);preview_req->cameraObject->unlock();});
- preview_req->cameraObject->unlock();
-
- unsigned long int length;
- RETURN_ON_ERROR(preview_req, gp_file_get_data_and_size, (preview_req->file, &preview_req->data, &length), {gp_file_free(preview_req->file);});
- preview_req->length = (size_t)length;
-}
-
-void GPCamera::EIO_CapturePreviewCb(uv_work_t *req){
- HandleScope scope;
- take_picture_request *preview_req = (take_picture_request*) req->data;
-
- Handle<Value> argv[2];
- int argc = 1;
- argv[0] = Undefined();
- if(preview_req->ret < GP_OK){
- argv[0] = Integer::New(preview_req->ret);
- }
- else if(preview_req->download && !preview_req->target_path.empty()){
- argc=2;
- argv[1] = String::New(preview_req->target_path.c_str());
- }
- else if(preview_req->data && preview_req->download) {
- argc = 2;
- node::Buffer* slowBuffer = node::Buffer::New(preview_req->length);
- if(preview_req->length){
- memmove(Buffer::Data(slowBuffer), preview_req->data, preview_req->length);
- Local<Object> globalObj = Context::GetCurrent()->Global();
- Local<Function> bufferConstructor = Local<Function>::Cast(globalObj->Get(String::New("Buffer")));
- Handle<Value> constructorArgs[3] = { slowBuffer->handle_, Integer::New(preview_req->length), Integer::New(0) };
- Local<Object> actualBuffer = bufferConstructor->NewInstance(3, constructorArgs);
- argv[1] = actualBuffer;
- }
- }else{
- argc = 2;
- argv[1] = cv::CastToJS(preview_req->path);
- }
-
- preview_req->cb->Call(Context::GetCurrent()->Global(), argc, argv);
- preview_req->cb.Dispose();
- if(preview_req->ret == GP_OK) gp_file_free(preview_req->file);
- preview_req->cameraObject->Unref();
- gp_context_unref(preview_req->context);
-// gp_camera_unref(preview_req->camera);
-
- delete preview_req;
-}
-
bool
GPCamera::close(){
// this->gphoto_->Unref();
View
11 src/camera.h
@@ -29,7 +29,6 @@
static Persistent<String> camera_getConfigValue_symbol;
static Persistent<String> camera_setConfigValue_symbol;
static Persistent<String> camera_takePicture_symbol;
- static Persistent<String> camera_getPreview_symbol;
static Persistent<String> camera_downloadPicture_symbol;
class GPCamera : public node::ObjectWrap {
pthread_mutex_t cameraMutex;
@@ -54,8 +53,10 @@
size_t length;
int ret;
bool download;
+ bool preview;
std::string path;
std::string target_path;
+ std::string socket_path;
};
struct get_config_request {
Persistent<Function> cb;
@@ -83,7 +84,9 @@
static int getConfigWidget(get_config_request *req, std::string name, CameraWidget **child, CameraWidget **rootconfig);
static int setWidgetValue(set_config_request *req);
static void takePicture(take_picture_request *req);
+ static void capturePreview(take_picture_request *req);
static void downloadPicture(take_picture_request *req);
+ static int getCameraFile(take_picture_request *req, CameraFile **file);
bool close();
public:
@@ -97,16 +100,14 @@
static Handle<Value> GetConfigValue(const Arguments &args);
static Handle<Value> SetConfigValue(const Arguments &args);
static Handle<Value> TakePicture(const Arguments &args);
- static Handle<Value> GetPreview(const Arguments& args);
static Handle<Value> DownloadPicture(const Arguments& args);
ASYNC_FN(EIO_GetConfig);
ASYNC_CB(EIO_GetConfigCb);
ASYNC_FN(EIO_SetConfigValue);
ASYNC_CB(EIO_SetConfigValueCb);
- ASYNC_FN(EIO_TakePicture);
ASYNC_FN(EIO_DownloadPicture);
- ASYNC_FN(EIO_CapturePreview);
- ASYNC_CB(EIO_CapturePreviewCb);
+ ASYNC_FN(EIO_Capture);
+ ASYNC_CB(EIO_CaptureCb);
std::string getPort(){return this->port_;};
std::string getModel(){return this->model_;};
void setCamera(Camera *camera){this->camera_=camera;};
View
142 src/camera_helpers.cc
@@ -4,6 +4,9 @@
#include <cstring>
#include <errno.h>
#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
namespace cv = cvv8;
Handle<Value> GPCamera::getWidgetValue(GPContext *context, CameraWidget *widget) {
HandleScope scope;
@@ -226,62 +229,104 @@ int GPCamera::enumConfig(get_config_request* req, CameraWidget *root, A<TreeNode
return GP_OK;
}
+int
+GPCamera::getCameraFile(take_picture_request *req, CameraFile **file){
+ int retval = GP_OK;
+ int fd;
+ if(!req->target_path.empty()){
+ char *tmpname = strdup(req->target_path.c_str());
+ fd = mkstemp(tmpname);
+ req->target_path = tmpname;
+ }else if(!req->socket_path.empty()){
+ struct sockaddr_un serv_addr;
+ bzero((char *)&serv_addr,sizeof(serv_addr));
+ serv_addr.sun_family = AF_UNIX;
+ strcpy(serv_addr.sun_path, "/tmp/preview.sock");// req->socket_path.c_str());
+
+ if ((fd = socket(AF_UNIX, SOCK_STREAM,0)) < 0)
+ perror("Creating socket");
+
+ if (connect(fd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0){
+ perror(serv_addr.sun_path);
+ }
+ }else{
+ return gp_file_new(file);
+ }
+
+ if (fd == -1) {
+ if (errno == EACCES) {
+ gp_context_error (req->context, "Permission denied");
+ }
+ return retval;
+ }
+ if(fd>=0){
+ retval = gp_file_new_from_fd(file, fd);
+ if (retval < GP_OK) {
+ ::close(fd);
+ }
+ }
+ return retval;
+}
+
void
GPCamera::downloadPicture(take_picture_request *req){
CameraFile *file;
- int fd,retval;
- retval = gp_file_new(&file);
-
+ int retval;
+ CameraFileType type;
std::ostringstream folder;
std::string name;
- if(retval == GP_OK){
- char *component = strtok((char*)req->path.c_str(),"/");
- while(component){
- char *next =strtok(NULL, "/");
- if(next)
- folder << "/" << component;
- else
- name = component;
- component = next;
- }
- if(folder.str().length() == 0)
- folder<<"/";
-
- if(!req->target_path.empty()){
- char *tmpname = strdup(req->target_path.c_str());
- fd = mkstemp(tmpname);
- req->target_path = tmpname;
- if (fd == -1) {
- if (errno == EACCES) {
- gp_context_error (req->context, "Permission denied");
- }
- req->ret = errno;
- return;
- }
- retval = gp_file_new_from_fd (&file, fd);
- if (retval < GP_OK) {
- ::close(fd);
- req->ret=retval;
- return;
- }
- }
+
+ char *component = strtok((char*)req->path.c_str(),"/");
+ while(component){
+ char *next =strtok(NULL, "/");
+ if(next)
+ folder << "/" << component;
+ else
+ name = component;
+ component = next;
+ }
+ if(folder.str().length() == 0)
+ folder<<"/";
- retval = gp_camera_file_get ( req->camera, folder.str().c_str(), name.c_str(), GP_FILE_TYPE_NORMAL, file, req->context);
-
- // Fallback to downloading into buffer
- if(retval == GP_OK && req->target_path.empty()){
- retval = gp_file_get_data_and_size (file, &req->data, &req->length);
- }
-
- if(retval == GP_OK){
- retval = gp_camera_file_delete(req->camera, folder.str().c_str(), name.c_str(), req->context);
- }
+ retval = getCameraFile(req, &file);
+
+ if(retval == GP_OK){
+ retval = gp_camera_file_get ( req->camera, folder.str().c_str(), name.c_str(), GP_FILE_TYPE_NORMAL, file, req->context);
+ }
+
+ // Fallback to downloading into buffer
+ if(retval == GP_OK && req->target_path.empty()){
+ retval = gp_file_get_data_and_size (file, &req->data, &req->length);
+ }
+
+ if(retval == GP_OK){
+ retval = gp_camera_file_delete(req->camera, folder.str().c_str(), name.c_str(), req->context);
}
- if(fd > 0){
- ::close(fd);
+
+ if(gp_file_get_type(file, &type) == GP_OK && type == GP_FILE_ACCESSTYPE_FD){
+ gp_file_free(file);
}
req->ret=retval;
}
+
+void
+GPCamera::capturePreview(take_picture_request *req){
+ int retval;
+ CameraFileType type;
+
+ CameraFile *file;
+
+ retval = getCameraFile(req, &file);
+
+ if(retval == GP_OK){
+ retval = gp_camera_capture_preview(req->camera, file, req->context);
+ }
+ if(retval == GP_OK && gp_file_get_type(file, &type) == GP_OK && type == GP_FILE_ACCESSTYPE_FD){
+ gp_file_free(file);
+ }
+ req->ret = retval;
+}
+
void
GPCamera::takePicture(take_picture_request *req) {
int retval;
@@ -290,8 +335,8 @@ GPCamera::takePicture(take_picture_request *req) {
/* NOP: This gets overridden in the library to /capt0000.jpg */
strcpy(camera_file_path.folder, "/");
strcpy(camera_file_path.name, "foo.jpg");
-
retval = gp_camera_capture(req->camera, GP_CAPTURE_IMAGE, &camera_file_path, req->context);
+
std::ostringstream path;
if(std::string(camera_file_path.folder).compare("/") != 0)
path << camera_file_path.folder;
@@ -299,7 +344,8 @@ GPCamera::takePicture(take_picture_request *req) {
path << camera_file_path.name;
req->path = path.str();
req->ret = retval;
- if(req->download){
+
+ if(retval == GP_OK && req->download){
downloadPicture(req);
}
}
View
93 test/camera.test.coffee
@@ -4,8 +4,10 @@ global[id] ?= require name for id, name of {
"fs"
"GPhoto":"../main"
"child_process"
+ "net"
+ "async"
}
-
+log = console.log
should = require "should"
{exec} = child_process
@@ -35,43 +37,62 @@ describe "node-gphoto2", ()->
done()
it 'should allow saving camera settings', (done)->
- cameras[0].setConfigValue 'capturetarget', 1, (er)->
- should.not.exist er
- done()
+ async.series [
+ (cb)->cameras[0].setConfigValue "capturetarget", 0, cb
+ (cb)->cameras[0].setConfigValue "eosviewfinder", 0, cb
+ (cb)->cameras[0].setConfigValue "uilock", 1, cb
+ ], done
+
describe 'should be able to take a picture', ()->
- it 'without downloading', (done)->
- cameras[0].takePicture download:false, (er, file)->
- should.not.exist er
- file.should.be.a('string')
- cameras[0].firstPicture = file
- done()
- it 'and download it to a buffer', (done)->
- # @timeout 5000
- cameras[0].takePicture download:true, (er, data)->
- should.not.exist er
- data.should.be.an.instanceOf Buffer
- done()
+ it 'without downloading', (done)->
+ cameras[0].takePicture download:false, (er, file)->
+ should.not.exist er
+ file.should.be.a('string')
+ cameras[0].firstPicture = file
+ done()
+ it 'and download it to a buffer', (done)->
+ # @timeout 5000
+ cameras[0].takePicture download:true, (er, data)->
+ should.not.exist er
+ data.should.be.an.instanceOf Buffer
+ done()
+
+ it 'and download it to the file system', (done)->
+ cameras[0].takePicture download:true, targetPath: '/tmp/foo.XXXXXXX', (er, file)->
+ should.not.exist er
+ file.should.be.a('string')
+ path.exists file, (exists)->
+ if exists
+ tempfiles.push file
+ done()
+ else
+ done "#{file} does not exist."
+ it 'and download it later', (done)->
+ cameras[0].downloadPicture cameraPath:cameras[0].firstPicture, targetPath: '/tmp/foo.XXXXXXX', (er, file)->
+ should.not.exist er
+ file.should.be.a('string')
+ path.exists file, (exists)->
+ if exists
+ tempfiles.push file
+ done()
+ else
+ done "#{file} does not exist."
+
+ describe 'should be able to take a preview picture', ()->
+ it 'and send it over a socket', (done)->
+ @timeout 25000
+ server = net.createServer (c)->
+ c.on 'end', ()->
+ server.close()
+ done()
+
+ server.listen '/tmp/preview.sock'
+ server.on 'error', ()->
+ log arguments
+ server.on 'listening', ()->
+ cameras[0].takePicture preview:true, socket:'/tmp/preview.sock', (er)->
+ should.not.exist er
- it 'and download it to the file system', (done)->
- cameras[0].takePicture download:true, targetPath: '/tmp/foo.XXXXXXX', (er, file)->
- should.not.exist er
- file.should.be.a('string')
- path.exists file, (exists)->
- if exists
- tempfiles.push file
- done()
- else
- done "#{file} does not exist."
- it 'and download it later', (done)->
- cameras[0].downloadPicture cameraPath:cameras[0].firstPicture, targetPath: '/tmp/foo.XXXXXXX', (er, file)->
- should.not.exist er
- file.should.be.a('string')
- path.exists file, (exists)->
- if exists
- tempfiles.push file
- done()
- else
- done "#{file} does not exist."
# clean up our mess :)
after ()->
tempfiles.forEach (file)->
View
2  wscript
@@ -4,7 +4,7 @@ from os.path import exists, lexists
srcdir = "."
blddir = "build"
-VERSION = "0.1.0alpha1"
+VERSION = "0.1.0alpha2"
def set_options(opt):
opt.tool_options("compiler_cxx")
Please sign in to comment.
Something went wrong with that request. Please try again.