UNPKG

6.5 kBJavaScriptView Raw
1/**
2 * domo dev server
3 */
4
5var fs = require('fs-extra');
6var path = require('path');
7var _ = require('lodash');
8var koa = require('koa');
9var Router = require('koa-router');
10var bs = require('browser-sync').create();
11var request = require('request');
12var Domo = require('ryuu-client-beta');
13var inquirer = require("inquirer");
14var Promise = require('bluebird');
15var body_parser = require('koa-bodyparser');
16var app = koa();
17var api = new Router();
18var portfinder = require('portfinder');
19var serve = require('koa-static');
20var mount = require('koa-mount');
21var proxyaddr = require('proxy-addr');
22var session = require('../util/session');
23var appStructure = require('../util/appStructure');
24
25portfinder.basePort = 3000;
26
27api.get('/', function *(){
28 var isValidSession = yield session.check(app.domo);
29 var isValidContext = true;
30 var hasThumbnail = appStructure.hasThumbnail();
31
32 // TODO: figure out why this is being called twice
33 // console.log("=========here why twice?");
34 var template = _.template(fs.readFileSync(path.resolve(__dirname + '/../server/domodev/index.html')));
35
36 var manifest = fs.readJsonSync(path.resolve(process.cwd() + '/' + (app.options.manifest || 'manifest.json')));
37 var sizeMultiplier = {
38 width: 235,
39 height: 290
40 }
41
42 // sizes consistent with Domo Web
43 var width = 235 * manifest.size.width - 10 + 'px';
44 var height = 290 * manifest.size.height - 40 + 'px';
45 var fullpage = manifest.fullpage;
46
47 var context = yield createContext(manifest.id, manifest.mapping);
48
49 if (!context){
50 isValidContext = false;
51 context = {id: 0};
52 }
53
54 var appData = yield getDomoappsData();
55
56 var userId = app.options.userId || appData.user.id;
57 var customerId = 1 || appData.customer;
58
59 var url = `index.html?userId=${userId}&customer=${customerId}&locale=en-US&platform=desktop&context=${context.id}`;
60
61 this.body = template({
62 manifest,
63 width,
64 height,
65 url,
66 isValidSession,
67 isValidContext,
68 hasThumbnail,
69 fullpage
70 });
71});
72
73// Proxy requests to the correct domoapps service for the environment they're logged into.
74api.all('/data/*', function *(){
75 var manifest = fs.readJsonSync(path.resolve(process.cwd() + '/' + (app.options.manifest || 'manifest.json')));
76 var appData = yield getDomoappsData();
77 var j = request.jar();
78 var url = appData.url + this.request.url;
79 var method = this.request.method;
80
81 var headers = {
82 referer: this.request.headers.referer,
83 accept: this.request.headers.accept,
84 'Content-Type': this.request.headers['content-type'] || this.request.headers['Content-Type'] || 'application/json'
85 };
86
87
88 var body = JSON.stringify(this.request.body);
89
90 if (url.indexOf("dataversions") !== -1){
91 var getRawBody = require('raw-body')
92 body = yield getRawBody(this.req, {
93 length: this.length,
94 limit: '1mb',
95 encoding: this.charset
96 });
97 url = url.replace("/dataversions", "/dataversions/domodev");
98 url += "&designId=" + manifest.id;
99 var alias = url.match(/data\/(v1|v2|v3)\/(.*)\/dataversions/)[2];
100 url += "&datasetId=" + _.find(manifest.mapping, {alias: alias}).dataSetId;
101 }
102
103 this.body = yield app.domo.processRequestRaw({
104 url: url,
105 method: method,
106 jar: j,
107 body: body,
108 headers: headers
109 });
110});
111
112api.all('/domo/*', function *(){
113 var appData = yield getDomoappsData();
114 var j = request.jar();
115 var url = appData.url + this.request.url;
116
117 var headers = {
118 referer: this.request.headers.referer,
119 accept: this.request.headers.accept,
120 'Content-Type': this.request.headers['content-type'] || this.request.headers['Content-Type'] || 'application/json'
121 };
122
123 this.body = yield app.domo.processRequestRaw({url: url, jar: j, headers: headers});
124
125});
126
127app.use(body_parser({
128 detectJSON: function (ctx) {
129 return false;
130 }
131}));
132app.use(api.middleware());
133app.use(mount('/domodev', serve(path.resolve(__dirname + '/../server/domodev'))));
134app.use(mount(serve('.')));
135
136module.exports = {
137 start: function(domo, options){
138 return new Promise(function(resolve, reject){
139
140 portfinder.getPorts(2, function (err, ports) {
141 var assetsPort = ports[0];
142 var dataPort = ports[1];
143 app.domo = domo;
144 app.options = options;
145
146 session.check(app.domo)
147 .then(function() {
148 var external = Boolean(app.options.external);
149 var middleware = external ? [] : getMiddleware();
150
151 app.listen(dataPort)
152
153 bs.init({
154 proxy: "localhost:" + dataPort,
155 port: assetsPort,
156 notify: false,
157 ui: false,
158 logLevel: 'info',
159 logPrefix: 'Domo Dev',
160 online: external,
161 // TODO: add user's ignored files here too?
162 files: ['**/*', '!node_modules/**/*'],
163 middleware: middleware,
164 });
165 bs.instance.logger.info('Instance: ' + app.domo.instance);
166 })
167 .catch(function(e){
168 reject('Session expired. Please login again using domo login.');
169 })
170 });
171
172 });
173 }
174};
175
176function getCustomer(){
177 var regexp = /([\w]+)[\.|-]/;
178 return app.domo.instance.match(regexp)[1];
179}
180
181function getEnv(){
182 var regexp = /([-_\w]+)\.(.*)/;
183 return app.domo.instance.match(regexp)[2];
184}
185
186function getMiddleware() {
187 return [ function(req, res, next) {
188 if (proxyaddr(req, '127.0.0.1') !== '::1') {
189 Error.stackTraceLimit = 0;
190 next(new Error('Access Denied'));
191 } else {
192 next();
193 }
194 }];
195}
196
197/**
198 * Fetch domoapps environment data from maestro.
199 * Fallback to inferring it by the instance URL.
200 */
201function getDomoappsData(){
202 var uuid = Domo.createUUID();
203
204 var options = {
205 url: 'https://' + app.domo.instance + '/api/content/v1/mobile/environment'
206 }
207
208 return app.domo.processRequest(options)
209 .then(function(res) {
210 var data = JSON.parse(res);
211 data.url = 'https://'+uuid+'.' + JSON.parse(res).domoappsDomain;
212 return data;
213 }).catch(function() {
214 var data = {url: 'https://'+uuid+'.domoapps.' + getEnv()};
215 return data;
216 });
217}
218
219function createContext(designId, mapping){
220 var options = {
221 url: 'https://' + app.domo.instance + '/domoapps/apps/v2/contexts',
222 method: 'POST',
223 json: {designId: designId, mapping: mapping}
224 };
225
226 return app.domo.processRequest(options)
227 .then(function(res) {
228 return res[0];
229 }).catch(function(err) {
230 return;
231 })
232}