diff --git a/Gruntfile.coffee b/Gruntfile.coffee deleted file mode 100644 index 130de8d..0000000 --- a/Gruntfile.coffee +++ /dev/null @@ -1,26 +0,0 @@ -module.exports = (grunt) -> - grunt.initConfig - pkg: grunt.file.readJSON 'package.json' - - clean: - default: - src: ['lib'] - - - coffee: - compile: - options: - bare: true - join: false - files: [ - expand: true - cwd: 'src' - src: '**/*.coffee' - dest: 'lib' - ext: '.js' - ] - - grunt.loadTasks('tasks') - grunt.loadNpmTasks('grunt-contrib-clean') - grunt.loadNpmTasks('grunt-contrib-coffee') - grunt.registerTask('default', ['clean', 'coffee']) diff --git a/README.md b/README.md index dbc1dbc..0290853 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ Using Messaging is as easy as: return log.info('RESULT', "finished : " + (JSON.stringify(x))); }); }, fail); - + async.series([ function() { return dyn.accounts.create("example@foo.com", "secret", "bar", "1234567890").then(function(x) { @@ -105,7 +105,7 @@ Using Messaging is as easy as: return log.info('RESULT', "finished : " + (JSON.stringify(x))); }); }, fail); - + async.series([ function() { return dyn.recipients.activate("foo@bars.com").then(function(x) { @@ -123,7 +123,7 @@ Using Messaging is as easy as: return log.info('RESULT', "finished : " + (JSON.stringify(x))); }); }, fail); - + async.series([ function() { return dyn.send_mail.create("foo@bars.com", "recipient@destination.com", "hello, new js api", "it works!").then(function(x) { @@ -151,6 +151,10 @@ Using Messaging is as easy as: * See the "examples" folder for more comprehensive examples +## Building + +To compile the coffee-script, first install dev dependencies: `npm install`. Then run `npm run compile`. + ## License (The MIT License) diff --git a/lib/dyn-js.js b/lib/dyn-js.js index fce11be..91d2e4b 100644 --- a/lib/dyn-js.js +++ b/lib/dyn-js.js @@ -1,7 +1,7 @@ -// Generated by CoffeeScript 1.7.1 +// Generated by CoffeeScript 1.10.0 (function() { 'use strict'; - var Dyn, callWithError, crudAccounts, crudGslb, crudGslbRegion, crudHttpRedirect, crudMessaging, crudRecipients, crudRecord, crudReportsBounces, crudReportsClicks, crudReportsComplaints, crudReportsDelivered, crudReportsIssues, crudReportsOpens, crudReportsSentMail, crudSendMail, crudSenders, crudSuppressions, crudTraffic, crudZone, extract, extractData, extractMsgData, extractMsgs, extractRecords, extractZones, failBool, https, identity, isOk, log, makePromise, msgIsOk, okBool, q, qs, throwMessages, throwMsgMessages, _, _request_q; + var Dyn, _, _request_q, callWithError, concat, crudAccounts, crudGslb, crudGslbRegion, crudHttpRedirect, crudJob, crudMessaging, crudNode, crudRecipients, crudRecord, crudReportsBounces, crudReportsClicks, crudReportsComplaints, crudReportsDelivered, crudReportsIssues, crudReportsOpens, crudReportsSentMail, crudSendMail, crudSenders, crudSuppressions, crudTraffic, crudZone, extract, extractData, extractMsgData, extractMsgs, extractRecords, extractZones, failBool, https, identity, isOk, log, makePromise, msgIsOk, okBool, q, qs, safeparse, throwMessages, throwMsgMessages, throwResponse; _ = require('underscore'); @@ -13,10 +13,22 @@ qs = require('querystring'); + concat = require('concat-stream'); + _.templateSettings = { interpolate: /\{\{(.+?)\}\}/g }; + safeparse = function(str) { + var error, ex; + try { + return JSON.parse(str); + } catch (error) { + ex = error; + return str; + } + }; + _request_q = function(dyn, method, path, body, isTraffic) { var cc, defer, headers, host, opts, port, req; log.verbose('dyn', "invoking via https : " + method + " " + path); @@ -59,19 +71,20 @@ }; log.silly('dyn', "request : " + (JSON.stringify(opts))); req = https.request(opts, function(res) { - var data; - data = ''; - res.on('readable', function() { - var chunk; - chunk = res.read(); - return data += chunk.toString('ascii'); - }); - return res.on('end', function() { + var concatStream, handleDone, handleError; + handleError = function(err) { + log.silly('dyn', err.message); + return cc(err); + }; + handleDone = function(buffer) { var response; - log.silly('dyn', "response : " + data); - response = JSON.parse(data); + log.silly('dyn', "response : " + (buffer.toString())); + response = safeparse(buffer); return cc(null, response, res); - }); + }; + concatStream = concat(handleDone); + res.on('error', handleError); + return res.pipe(concatStream); }); req.on('error', function(e) { log.warn('dyn', "error : " + (JSON.stringify(e))); @@ -97,8 +110,8 @@ return _.reduce(_.keys(methods), function(a, x) { a[x] || (a[x] = {}); a[x]._path = function(dyn, data) { - var cpath, _ref; - cpath = (custom != null ? (_ref = custom[x]) != null ? _ref.path : void 0 : void 0) || path; + var cpath, ref; + cpath = (custom != null ? (ref = custom[x]) != null ? ref.path : void 0 : void 0) || path; return _.template(cpath)(data); }; a[x]._call = function(dyn, pathData, bodyData) { @@ -123,15 +136,15 @@ return _.reduce(allKeys, function(a, x) { a[x] || (a[x] = {}); a[x]._path = function(dyn, data) { - var cpath, _ref; - cpath = (custom != null ? (_ref = custom[x]) != null ? _ref.path : void 0 : void 0) || path; + var cpath, ref; + cpath = (custom != null ? (ref = custom[x]) != null ? ref.path : void 0 : void 0) || path; data.e = escape; return _.template(cpath)(data); }; a[x]._call = function(dyn, pathData, bodyData) { - var method, _ref; + var method, ref; log.silly('dyn', "api call : " + x + " -> " + path); - method = (custom != null ? (_ref = custom[x]) != null ? _ref.method : void 0 : void 0) || methods[x]; + method = (custom != null ? (ref = custom[x]) != null ? ref.method : void 0 : void 0) || methods[x]; if (method === 'GET') { return _request_q(dyn, method, a[x]._path(dyn, pathData) + "?" + qs.stringify(bodyData)); } else { @@ -182,6 +195,22 @@ }); }; + crudJob = function() { + return crudTraffic("/Job/", { + _get: { + path: "/Job/{{id}}/" + } + }); + }; + + crudNode = function() { + return crudTraffic("/Node/", { + _destroy: { + path: "/Node/{{zone}}/{{fqdn}}/" + } + }); + }; + crudHttpRedirect = function() { return crudTraffic("/HTTPRedirect/", { _get: { @@ -469,8 +498,8 @@ }; extractMsgData = function(x) { - var _ref; - return x != null ? (_ref = x.response) != null ? _ref.data : void 0 : void 0; + var ref; + return x != null ? (ref = x.response) != null ? ref.data : void 0 : void 0; }; okBool = function() { @@ -485,6 +514,9 @@ if (!(x && x.data)) { return []; } + if (!Array.isArray(x.data)) { + return x.data; + } return _(x.data).map(function(r) { var v; v = r.split("/"); @@ -515,8 +547,12 @@ }; throwMsgMessages = function(x) { - var _ref; - throw (x != null ? (_ref = x.response) != null ? _ref.message : void 0 : void 0) || "unknown exception when calling api"; + var ref; + throw (x != null ? (ref = x.response) != null ? ref.message : void 0 : void 0) || "unknown exception when calling api"; + }; + + throwResponse = function(x) { + return (x != null ? x.response : void 0) || "unknown exception when calling api"; }; Dyn = function(opts) { @@ -591,6 +627,20 @@ thaw: true }), "zone.thaw", isOk, extractData, throwMessages); }; + traffic.job = crudJob(); + traffic.job.get = function(id) { + return callWithError(traffic.job._get._call(traffic, { + zone: traffic.defaults.zone, + id: id + }, {}), "job.get", isOk, extractData, throwMessages); + }; + traffic.node = crudNode(); + traffic.node.destroy = function(fqdn) { + return callWithError(traffic.node._destroy._call(traffic, { + zone: traffic.defaults.zone, + fqdn: fqdn + }, {}), "node.destroy", isOk, extractMsgs, throwMessages); + }; traffic.session = crudTraffic("/Session/"); traffic.session.create = function() { return callWithError(traffic.session._create._call(traffic, {}, _.pick(traffic.defaults, 'customer_name', 'user_name', 'password')), "session.create", isOk, function(x) { @@ -668,7 +718,7 @@ a[type].replace = (function(fqdn, records) { var arg; arg = {}; - arg["" + x + "Records"] = records; + arg[x + "Records"] = records; return callWithError(traffic.record[type]._update._call(traffic, { zone: traffic.defaults.zone, fqdn: fqdn, @@ -851,7 +901,7 @@ emailaddress: email }, { apikey: messaging.defaults.apikey - })), "senders.status", msgIsOk, extractMsgData, throwMsgMessages); + })), "senders.status", msgIsOk, extractMsgData, throwResponse); }; messaging.senders.dkim = function(email, dkim) { return callWithError(messaging.senders._dkim._call(messaging, {}, _.defaults({ diff --git a/package.json b/package.json index b21340b..7ec7752 100644 --- a/package.json +++ b/package.json @@ -25,20 +25,19 @@ "node": ">= 0.8.x" }, "devDependencies": { - "grunt": "~0.4.4", - "grunt-contrib-clean": "~0.5.0", - "grunt-contrib-coffee": "~0.10.1" + "coffee-script": "~1.10.0" }, "bugs": { - "url" : "https://github.com/dyninc/dyn-js/issues" + "url": "https://github.com/dyninc/dyn-js/issues" }, "license": "MIT", "repository": { - "type" : "git", - "url" : "https://github.com/dyninc/dyn-js" + "type": "git", + "url": "https://github.com/dyninc/dyn-js" }, "dependencies": { - "npmlog": "~0.0.6 ", + "concat-stream": "~1.5.2", + "npmlog": "~2.0.4", "q": "~1.0.1", "underscore": "~1.6.0" }, @@ -48,5 +47,7 @@ "dns", "dynamic dns" ], - "main": "lib/dyn-js.js" + "scripts": { + "compile": "coffee -o lib -c src" + } } diff --git a/scripts/compile.rb b/scripts/compile.rb deleted file mode 100644 index 632b908..0000000 --- a/scripts/compile.rb +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/env ruby - -`coffee -o lib -c src` diff --git a/src/dyn-js.coffee b/src/dyn-js.coffee index 026b17e..9d085d5 100644 --- a/src/dyn-js.coffee +++ b/src/dyn-js.coffee @@ -1,13 +1,20 @@ 'use strict' -_ = require 'underscore' -q = require 'q' -https = require 'https' -log = require 'npmlog' -qs = require 'querystring' +_ = require 'underscore' +q = require 'q' +https = require 'https' +log = require 'npmlog' +qs = require 'querystring' +concat = require 'concat-stream' _.templateSettings = { interpolate: /\{\{(.+?)\}\}/g } +safeparse = (str) -> + try + return JSON.parse(str) + catch ex + return str + _request_q = (dyn, method, path, body, isTraffic) -> log.verbose 'dyn', "invoking via https : #{method} #{path}" defer = q.defer() @@ -41,17 +48,20 @@ _request_q = (dyn, method, path, body, isTraffic) -> opts = {hostname:host,port:port,method:method,path:path,headers:headers} log.silly 'dyn', "request : #{JSON.stringify(opts)}" req = https.request opts, (res) -> - # log.silly 'dynres', arguments - data = '' - res.on 'readable', -> - # log.silly 'dynres', arguments - chunk = res.read() - # log.silly 'dyn', "partial : #{chunk}" - data += chunk.toString('ascii') - res.on 'end', -> - log.silly 'dyn', "response : #{data}" - response = JSON.parse(data) + + handleError = (err) -> + log.silly 'dyn', err.message + cc(err) + + handleDone = (buffer) -> + log.silly 'dyn', "response : #{buffer.toString()}" + response = safeparse(buffer) cc(null, response, res) + + concatStream = concat(handleDone) + res.on('error', handleError) + res.pipe(concatStream) + req.on 'error', (e) -> log.warn 'dyn', "error : #{JSON.stringify(e)}" cc(e) @@ -110,6 +120,14 @@ crudZone = -> _update: {path:"/Zone/{{zone}}/"} _destroy: {path:"/Zone/{{zone}}/"} +crudJob = -> + crudTraffic "/Job/", + _get: {path:"/Job/{{id}}/"} + +crudNode = -> + crudTraffic "/Node/", + _destroy: {path:"/Node/{{zone}}/{{fqdn}}/"} + crudHttpRedirect = -> crudTraffic "/HTTPRedirect/", _get: {path:"/HTTPRedirect/{{zone}}/{{fqdn}}"} @@ -157,7 +175,7 @@ crudRecipients = (type) -> _status: {path:"/recipients/status", method: "GET"} crudSendMail = (type) -> - crudMessaging "/send/", + crudMessaging "/send/", _create: {path:"/send"} crudSuppressions = (type) -> @@ -217,8 +235,10 @@ callWithError = (funProm, description, successFilter, successCase, errorCase) -> log.silly 'dyn', "api call returned successfully : #{JSON.stringify(x[1])}" successCase(x[1]) else + log.info 'dyn', "api call returned error : #{JSON.stringify(x[1])}" errorCase x[1] + , (x) -> log.warn 'dyn', "unexpected error : #{JSON.stringify(x[1])}" errorCase x @@ -237,6 +257,7 @@ failBool = -> false extractRecords = (x) -> return [] unless x && x.data + return x.data unless Array.isArray(x.data) _(x.data).map (r) -> v = r.split("/") {type:v[2].replace(/Record$/, ""),zone:v[3],fqdn:v[4],id:v[5]} @@ -249,6 +270,7 @@ extractZones = (x) -> throwMessages = (x) -> throw (x.msgs || "unknown exception when calling api") throwMsgMessages = (x) -> throw (x?.response?.message || "unknown exception when calling api") +throwResponse =(x) -> return x?.response || "unknown exception when calling api" Dyn = (opts) -> traffic_defaults = _.defaults opts?.traffic || {}, { @@ -296,6 +318,18 @@ Dyn = (opts) -> traffic.zone.freeze = -> callWithError traffic.zone._update._call(traffic, {zone:traffic.defaults.zone}, {freeze:true}), "zone.freeze", isOk, extractData, throwMessages traffic.zone.thaw = -> callWithError traffic.zone._update._call(traffic, {zone:traffic.defaults.zone}, {thaw:true}), "zone.thaw", isOk, extractData, throwMessages + traffic.job = crudJob() + traffic.job.get = (id) -> + callWithError traffic.job._get._call(traffic, { + zone:traffic.defaults.zone, + id:id }, {}), + "job.get", isOk, extractData, throwMessages + + traffic.node = crudNode() + traffic.node.destroy = (fqdn) -> callWithError traffic.node._destroy._call(traffic, + {zone:traffic.defaults.zone, fqdn: fqdn}, {}), + "node.destroy", isOk, extractMsgs, throwMessages + traffic.session = crudTraffic "/Session/" traffic.session.create = -> callWithError(traffic.session._create._call(traffic, {}, _.pick(traffic.defaults, 'customer_name', 'user_name', 'password')), "session.create", isOk, (x) -> traffic.defaults.token = x.data.token @@ -361,7 +395,7 @@ Dyn = (opts) -> messaging.senders.create = (email, seeding) -> callWithError messaging.senders._create._call(messaging, {}, _.defaults({emailaddress:email,seeding:seeding||'0'}, {apikey:messaging.defaults.apikey})), "senders.create", msgIsOk, extractMsgData, throwMsgMessages messaging.senders.update = (email, seeding) -> callWithError messaging.senders._update._call(messaging, {}, _.defaults({emailaddress:email}, {apikey:messaging.defaults.apikey})), "senders.update", msgIsOk, extractMsgData, throwMsgMessages messaging.senders.details = (email) -> callWithError messaging.senders._details._call(messaging, {}, _.defaults({emailaddress:email}, {apikey:messaging.defaults.apikey})), "senders.details", msgIsOk, extractMsgData, throwMsgMessages - messaging.senders.status = (email) -> callWithError messaging.senders._status._call(messaging, {}, _.defaults({emailaddress:email}, {apikey:messaging.defaults.apikey})), "senders.status", msgIsOk, extractMsgData, throwMsgMessages + messaging.senders.status = (email) -> callWithError messaging.senders._status._call(messaging, {}, _.defaults({emailaddress:email}, {apikey:messaging.defaults.apikey})), "senders.status", msgIsOk, extractMsgData, throwResponse messaging.senders.dkim = (email, dkim) -> callWithError messaging.senders._dkim._call(messaging, {}, _.defaults({emailaddress:email,dkim:dkim}, {apikey:messaging.defaults.apikey})), "senders.dkim", msgIsOk, extractMsgData, throwMsgMessages messaging.senders.destroy = (email) -> callWithError messaging.senders._destroy._call(messaging, {}, _.defaults({emailaddress:email}, {apikey:messaging.defaults.apikey})), "senders.destroy", msgIsOk, extractMsgData, throwMsgMessages