exports.id = 'httproute'; exports.title = 'HTTP Route'; exports.group = 'HTTP'; exports.color = '#5D9CEC'; exports.icon = 'globe'; exports.input = false; exports.output = ['#6CAC5A', '#37BC9B']; exports.version = '1.2.3'; exports.author = 'Martin Smola'; exports.cloning = false; exports.options = { method: 'GET', url: '', size: 5, cacheexpire: '5 minutes', cachepolicy: 0, timeout: 5 }; exports.dateupdated = '2021-01-21 18:30d'; exports.readme = `# HTTP route __Outputs__: - first output: raw data (cache is empty or is disabled) - second output: cached data If one of the outputs is disabled then automatic responce with code "503 service unavailable" is sent. When a request comes in bellow object is available at \`flowdata.data\`: \`\`\`javascript { params: { id: '1' }, // params for dynamic routes, e.g. /test/{id} query: { msg: 'Hello' }, // parsed query string, e.g. /test/1?msg=Hello body: { test: 'OK' }, // object if json requests otherwise string headers: {}, // headers data session: {}, // session data user: {}, // user data files: [], // uploaded files url: '/users/', // a relative URL address referrer: '/', // referrer mobile: false, // determines mobile device robot: false, // determines search robots/crawlsers language: 'en' // determines language } \`\`\` See [documentation for flags](https://docs.totaljs.com/latest/en.html#api~HttpRouteOptionsFlags~unauthorize). These method flags are set automatically e.g. \`get, post, put, patch or delete\` --- \`id:ROUTE_ID\` flag cannot be used since it's already used by this component internally`; exports.html = `
@(HTTP method)
@(URL address)
@(Additional flags)
@(Separate flags by comma e.g. json, authorize)
@(Max. request size)
@(In kB kilobytes)
@(Timeout)
@(In seconds.)

@(Automatically respond with 200 OK?)
@(If not checked you need to use HTTP response component to respond to the request.)

@(Custom headers)
@(Cookies)

@(Cache policy)
@(User instance must contain id property.)
@(Expiration)
@(E.g. 5 minutes)
`; exports.install = function(instance) { var route; var uninstall = function(id) { if (F.is4) { route && route.remove(); route = null; } else UNINSTALL('route', id); }; instance.custom.emptyresponse = function(self) { self.plain(); }; instance.reconfigure = function() { var options = instance.options; if (!options.url) { instance.status('Not configured', 'red'); return; } if (typeof(options.flags) === 'string') options.flags = options.flags.split(',').trim(); uninstall('id:' + instance.id); var flags = options.flags || []; flags.push('id:' + instance.id); if (!F.is4) flags.push(options.method.toLowerCase()); options.timeout && flags.push(options.timeout * 1000); // Make unique values flags = flags.filter(function(v, i, a) { if(F.is4 && v.toString().toLowerCase() === options.method.toLowerCase()) return false; // remove method return a.indexOf(v) === i; }); options.flags = flags; var handler = function() { if (instance.paused || (instance.isDisabled && (instance.isDisabled('output', 0) || instance.isDisabled('output', 1)))) { instance.status('503 Service Unavailable'); this.status = 503; this.json(); return; } var key; var self = this; if (instance.options.emptyresponse) { instance.status('200 OK'); setTimeout(instance.custom.emptyresponse, 100, self); if (instance.hasConnection(0)) { var data = instance.make({ query: self.query, body: self.body, session: self.session, user: self.user, files: self.files, headers: self.req.headers, url: self.url, params: self.params }); instance.send2(0, data); } return; } switch (instance.options.cachepolicy) { case 1: // URL key = 'rro' + instance.id + self.url.hash(); break; case 2: // URL + query case 3: // URL + query + user key = self.url; var keys = Object.keys(self.query); keys.sort(); for (var i = 0, length = keys.length; i < length; i++) key += keys[i] + self.query[keys[i]] + '&'; if (instance.options.cachepolicy === 3 && self.user) key += 'iduser' + self.user.id; key = 'rro' + instance.id + key.hash(); break; } if (key && F.cache.get2(key)) { var data = instance.make(F.cache.get2(key)); data.repository.controller = self; instance.send2(1, data); } else { var data = instance.make({ query: self.query, body: self.body, session: self.session, user: self.user, files: self.files, headers: self.req.headers, url: self.url, params: self.params, mobile: self.mobile, robot: self.robot, referrer: self.referrer, language: self.language }); data.repository.controller = self; instance.send2(0, data); key && FINISHED(self.res, () => F.cache.set(key, self.$flowdata.data, instance.options.cacheexpire)); } }; if (F.is4) route = ROUTE(options.method.toUpperCase() + ' ' + options.url, handler, flags, options.size || 5); else F.route(options.url, handler, flags, options.size || 5); instance.status('Listening', 'green'); }; instance.reconfigure(); instance.on('options', instance.reconfigure); instance.on('close', function(){ uninstall('id:' + instance.id); }); }; // check url exists FLOW.trigger('httproutecheckurl', function(next, data) { var url = data.url; var method = data.method; if (url[url.length - 1] !== '/') url += '/'; var exists = F.routes.web.findItem(r => r.urlraw === url && r.method === method); next(exists != null); }); exports.uninstall = function() { FLOW.trigger('httproutecheckurl', null); };