UNPKG

6.67 kBJavaScriptView Raw
1'use strict';
2
3var https = require('https');
4var http = require('http');
5var jsonStatus = require('./statusmsgs.json');
6var url = require('url');
7
8module.exports = Plotly;
9
10function Plotly(username,apiKey) {
11 if (!(this instanceof Plotly)) return new Plotly(username,apiKey);
12
13 var opts = {};
14
15 if (typeof username === 'object') {
16 opts = username;
17 this.username = opts.username;
18 this.apiKey = opts.apiKey;
19 this.host = opts.host || 'plot.ly';
20 this.port = opts.port || 443;
21 } else {
22 this.username = username;
23 this.apiKey = apiKey;
24 this.host = 'plot.ly';
25 this.port = 443;
26 }
27 this.streamHost = '';
28 this.version='0.0.2';
29 this.platform='nodejs';
30 this.origin='plot';
31}
32
33Plotly.prototype.plot = function(data, graphOptions, callback) {
34 var self = this;
35 if (!callback) { callback = function() {}; }
36
37 // allow users to just pass in an object for the data, data = {x:[],y:[]}
38 if (!Array.isArray(data)) data = [data];
39
40 var urlencoded = '';
41 var pack = {
42 'platform': self.platform,
43 'version': self.version,
44 'args': JSON.stringify(data),
45 'kwargs': JSON.stringify(graphOptions),
46 'un': self.username,
47 'key': self.apiKey,
48 'origin': self.origin
49 };
50
51 for (var key in pack) {
52 urlencoded += key + '=' + pack[key] + '&';
53 }
54
55 // trim off last ambersand
56 urlencoded = urlencoded.substring(0, urlencoded.length - 1);
57
58 var options = {
59 host: self.host,
60 port: self.port,
61 path: '/clientresp',
62 method: 'POST',
63 headers: {
64 'Content-Type': 'application/x-www-form-urlencoded',
65 'Content-Length': urlencoded.length
66 },
67 withCredentials: false
68 };
69
70 var req = https.request(options, function (res) {
71 parseRes(res, function (err, body) {
72 body = JSON.parse(body);
73
74 if ( body['stream-status'] != undefined) {
75 self.streamHost = url.parse(body['stream-host']).hostname;
76 }
77
78 if ( body.error.length > 0 ) {
79 var error = new Error(body.error);
80 error.body = body;
81 error.statusCode = res.statusCode;
82 callback(error);
83 } else {
84 callback(null, {
85 streamstatus : body['stream-status'],
86 url: body.url,
87 message: body.message,
88 warning: body.warning,
89 filename: body.filename,
90 error: body.error
91 });
92 }
93 });
94 });
95
96 req.on('error', function(err) {
97 callback(err);
98 });
99
100 req.write(urlencoded);
101 req.end();
102};
103
104Plotly.prototype.stream = function(token, callback) {
105 var self = this;
106 var opts = {};
107
108 if (typeof token === 'object') {
109 opts = token;
110 token = opts.token;
111 var host = opts.streamHost || self.streamHost;
112 var port = opts.port || 80;
113 }
114
115 var options = {
116 host: host || self.streamHost || 'stream.plot.ly',
117 port: port || 80,
118 path: '/',
119 method: 'POST',
120 agent: false,
121 headers: { 'plotly-streamtoken' : token }
122 };
123
124 if (!callback) { callback = function() {}; }
125
126 var stream = http.request(options, function (res) {
127 var message = jsonStatus[res.statusCode];
128
129 if (res.statusCode !== 200) {
130 var error = new Error(message);
131 error.statusCode = res.statusCode;
132 callback(error);
133 } else {
134 callback(null, {msg : message, statusCode: res.statusCode});
135 }
136 });
137
138 if (stream.setTimeout) stream.setTimeout(Math.pow(2, 32) * 1000);
139
140 return stream;
141};
142
143
144Plotly.prototype.getFigure = function (fileOwner, fileId, callback) {
145 var self = this;
146
147 if (!callback) { callback = function() {}; }
148
149 var headers = {
150 'plotly-username': this.username,
151 'plotly-apikey': this.apiKey,
152 'plotly-version': this.version,
153 'plotly-platform': this.platform
154 };
155
156 var resource = '/apigetfile/'+fileOwner+'/'+fileId;
157
158 var options = {
159 host: self.host,
160 path: resource,
161 port: self.port,
162 headers: headers,
163 method: 'GET'
164 };
165
166 var req = https.get(options, function (res) {
167 parseRes(res, function (err, body) {
168 if (JSON.parse(body).error) {
169 err = JSON.parse(body).error;
170 callback(err);
171 } else {
172 var figure = JSON.parse(body).payload.figure;
173 callback(null, figure);
174 }
175 });
176 });
177
178 req.end();
179};
180
181Plotly.prototype.getImage = function (figure, opts, callback) {
182 callback = callback || function () {};
183 if (!figure) return new Error('no figure provided!');
184
185 var self = this;
186 var payload = JSON.stringify({
187 figure: figure,
188 format: opts.format || 'png',
189 width: opts.width || 700,
190 height: opts.height || 500
191 });
192
193 var headers = {
194 'plotly-username': self.username,
195 'plotly-apikey': self.apiKey,
196 'plotly-version': self.version,
197 'plotly-platform': self.platform,
198 'Content-Type': 'application/x-www-form-urlencoded',
199 'Content-Length': payload.length
200 };
201
202 var options = {
203 hostname: self.host,
204 path : '/apigenimage/',
205 port: self.port,
206 headers: headers,
207 method: 'POST',
208 agent: false
209 };
210
211 function handleResponse(res) {
212 parseRes(res, function (err, body) {
213 if (res.statusCode !== 200) {
214 var error = new Error('Bad response status code ' + res.statusCode);
215 error.msg = body;
216 return callback(error, null);
217 }
218 var imageData = JSON.parse(body).payload;
219 callback(null, imageData);
220 });
221 }
222
223 var req = https.request(options, handleResponse);
224 req.write(payload);
225 req.end();
226};
227
228// response parse helper fn
229function parseRes (res, cb) {
230 var body = '';
231 if ('setEncoding' in res) res.setEncoding('utf-8');
232
233 res.on('data', function (data) {
234 body += data;
235 if (body.length > 1e10) {
236 // FLOOD ATTACK OR FAULTY CLIENT, NUKE REQ
237 res.connection.destroy();
238 res.writeHead(413, {'Content-Type': 'text/plain'});
239 res.end('req body too large');
240 return cb(new Error('body overflow'));
241 }
242 });
243
244 res.on('end', function () {
245 cb(null, body);
246 });
247
248}