Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ $ clara --apiToken <apiToken> --username <username> scenes:get <sceneId>
* scenes:delete <sceneId> Delete a scene
* scenes:clone <sceneId> Clone a scene
* scenes:import [options] <sceneId> Import a file into the scene
* scenes:importOptimized [options] <sceneId> Import a file into the scene, taking care to not reupload shared assets
* scenes:export <sceneId> <extension> Export a scene
* scenes:render [options] <sceneId> Render an image
* scenes:command [options] <sceneId> <plugin> <command> Run a command
Expand Down Expand Up @@ -130,7 +131,17 @@ $ clara set apiToken your-api-token
$ clara set username your-username
$ clara scenes:get scene-uuid
```
### Configuration Variables

Available configuration and their defaults:

```
apiToken: null,
dryRun: false,
host: 'https://clara.io',
logLevel: 'info', // silly, verbose, info, warn, error, silent
username: null
```

## Development

Expand Down
11 changes: 9 additions & 2 deletions lib/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ var mapIndexed = R.addIndex(R.map);
var fs = require('fs');
var jsonQuery = require('json-query');
var log = require('npmlog');
var Progress = require('progress');

var config = require('../lib/config');
var conf = config();
Expand Down Expand Up @@ -66,7 +67,7 @@ function buildCommand(info, key, section) {
R.forEach(R.curry(addOption)(query), R.keys(query));
if (info.body) addOption(info, 'body');

if (info.async) {
if (info.async || info.sse) {
cmd.option('--url', 'Return the URL of the result');
}

Expand Down Expand Up @@ -103,6 +104,12 @@ function buildCommand(info, key, section) {

var resource = resources[section][key];

var progress = new Progress(':status [:bar] :message', { total : 80, width: 40 });

opts.progressCallback = function(job) {
if (job.progress) progress.update(job.progress, job);
};

claraApi[section][key](Object.assign({}, args, queryArgs, {url: cmd.url}), opts, function(err, result) {
if (err) return fail(err, result);

Expand All @@ -123,7 +130,7 @@ function buildCommand(info, key, section) {

if (program.output) {
fs.writeFileSync(program.output, output, resource.isBinary ? 'binary' : 'utf8');
} else {
} else if (output) {
process.stdout.write(output);
}
}).catch(fail);
Expand Down
68 changes: 63 additions & 5 deletions lib/method.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ module.exports = function(data, key) {
queryArgs[key] = JSON.stringify(parseJSON(queryArgs[key]));
}, data.jsonQueryKeys);
var qs = R.keys(queryArgs).length ? '?'+queryString.stringify(queryArgs) : '';
var onlyLocation = data.async && queryOptions.url;
var onlyLocation = (data.async || data.sse) && queryOptions.url;

var opts;

Expand All @@ -91,7 +91,6 @@ module.exports = function(data, key) {
}, data.jsonKeys);
}


var errors = [];
function checkRequired(fromObj, obj, key) {
if (fromObj[key].required && obj[key] === undefined) {
Expand All @@ -113,7 +112,10 @@ module.exports = function(data, key) {
function done(err, res) {
var result;

if (!data.isBinary) {
if (!res) {
callback(null, res);
resolve(res);
} else if (!data.isBinary) {
result = data.isJSON ? res.body : res.text;
callback(null, result);
resolve(result);
Expand Down Expand Up @@ -164,7 +166,8 @@ module.exports = function(data, key) {
}

var req = superagent[data.method](url);
if (data.output === 'json') req.set('Accept', 'application/json')
if (data.output === 'json') req.set('Accept', 'application/json');
if (data.sse) req.set('Accept', 'text/event-stream');
if (conf.get('apiToken')) req.auth(conf.get('username'), conf.get('apiToken'));

R.forEach(function(fileKey) {
Expand All @@ -179,7 +182,62 @@ module.exports = function(data, key) {

if (data.method !== 'get') {
log.debug('sending: ', JSON.stringify(opts, null, ' '));
req.send(opts)
req.send(opts);
}


if (data.sse) {
var stream = require('stream').Writable();
var buf = '';
var failed = false;
var job = { status: 'starting', message: '', progress: 0};
stream._write = function(chunk, enc, next) {
buf = buf + chunk.toString('utf8');
var lines = buf.split('\n');
buf = lines[lines.length-1];
for (var i = 0; i < lines.length-1; i++) {
var line = lines[i];
if (line === '') continue;
var match = line.match(/^data: (.*)$/);
if (!match) {
log.debug('unmatched line', line);
continue;
}
job = R.merge(job, JSON.parse(match[1]));
if (job.message === null) job.message = '';
if (opts.progressCallback) opts.progressCallback(job);
}

next();
};

stream.on('error', function(err) {
if (failed) return;
done(err);
failed = true;
});

stream.on('finish', function() {
if (failed) return;
if (!job.files || !job.files.length || !job.files[0].url) return done(null);
if (onlyLocation) {
callback(null, job.files[0].url);
return resolve(job.files[0].url);
}
var req2 = superagent.get(job.files[0].url);
req2.end(done);
});

// https://github.com/visionmedia/superagent/issues/565
req.on('end', function(err, res) {
if (err || this.res.statusCode >= 400) {
fail(err || this.res.statusCode);
failed = true;
}
});

req.pipe(stream);
return;
}

req.end(function(err, res) {
Expand Down
14 changes: 11 additions & 3 deletions lib/resources/scenes.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,14 @@ module.exports = {
description: 'Import files into the scene',
method: 'post',
path: '/scenes/{sceneId}/import',
sse: true,
query: {
async: {type: Boolean},
data: {type: 'json', as: 'filename', description: 'Optional data for import'},
fileIds: {type: Array, description: 'Array of existing file ids'}
},
options: {
progressCallback: {type: Function, description: "Called regularly with job information"},
file: {type: 'File', description: 'A File', required: false},
files: {type: 'Files', description: 'An array of files ', required: false}
}
Expand Down Expand Up @@ -107,14 +109,19 @@ module.exports = {
method: 'post',
path: '/scenes/{sceneId}/export/{extension}',
output: 'binary',
async: true
async: false,
sse: true,
options: {
progressCallback: {type: Function, description: "Called regularly with job information"}
}
},

render: {
description: 'Render an image',
method: 'post',
path: '/scenes/{sceneId}/render',
async: true,
async: false,
sse: true,
query: {
time: {type: Number, description: 'Frame number to render'},
width: {type: Number, description: 'Width in pixels of the desired image'},
Expand All @@ -129,7 +136,8 @@ module.exports = {
},
options: {
setupCommand: {type: String, as: 'string', description: 'Command to be executed before render'},
data: {type: 'json', as: 'filename', description: 'Optional data for setupCommand'}
data: {type: 'json', as: 'filename', description: 'Optional data for setupCommand'},
progressCallback: {type: Function, description: "Called regularly with job information"}
},
output: 'binary'
},
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "clara",
"version": "0.4.4",
"version": "0.4.5",
"description": "Clara.io API wrapper",
"main": "lib/index.js",
"bin": "bin/clara.js",
Expand Down Expand Up @@ -35,6 +35,7 @@
"md5-file": "^2.0.4",
"npmlog": "^2.0.0",
"osenv": "^0.1.3",
"progress": "git+https://github.com/visionmedia/node-progress.git#d47913502ba5b551fcaad9e94fe7b2f5876a7939",
"query-string": "^3.0.0",
"ramda": "^0.18.0",
"superagent": "^1.5.0",
Expand Down