UNPKG

3.82 kBJavaScriptView Raw
1
2var assert = require('assert');
3var norma = require('norma');
4var debug = require('debug')('waif:service');
5var _ = require('lodash');
6var EventEmitter = require('events').EventEmitter;
7var request = require('request');
8var express = require('express');
9var util = require('util');
10
11var Uri = require('./state/uri');
12var Status = require('./state/status');
13
14/**
15* Service constructor.
16*
17* Instances will contain a map to all of the
18* services that have been mounted onto the
19* system.
20*/
21function Service(name) {
22 debug('new service: %s', name);
23 assert(name, "service not supplied with name");
24
25 this.name = name;
26 this.middleware = [];
27 this.uri = new Uri();
28 this.status = new Status();
29
30 this.initialize();
31
32 return this;
33}
34util.inherits(Service, EventEmitter);
35
36Service.prototype.setWaif = function(waif) {
37 this.waif = waif;
38 return this;
39};
40
41Service.prototype.initialize = function() {};
42
43
44Service.prototype.start = function () {
45 debug('start listening on service: %s', this.name);
46
47 // new express server
48 this.server = express();
49
50 // mount middleware
51 _(this.middleware).each(this.mount, this);
52
53 // listen on whatever url we need to
54 if (this.listening) {
55 var listenArgs = this.uri.listenUrl();
56 listenArgs.push(listenFn.bind(this));
57 this.server.listen.apply(this.server, listenArgs);
58 }
59
60 return this;
61
62 //// helpers
63 function listenFn(err) {
64 debug('%s: start listening on %o', this.name, this.uri.get());
65 this.emit('start');
66 this.status.state().go('Running');
67 }
68
69};
70
71Service.prototype.stop = function() {
72 debug('%s: stop forwarding to %s', this.name, this.uri.get());
73 this.emit('stop');
74 this.status.state().go('start');
75};
76
77Service.prototype.mount = function mount(mw) {
78 var _args = [];
79
80 mw.path && _args.push(mw.path);
81 _args.push(_initHandler.call(this, mw));
82
83 this.server.use.apply(this.server, _args);
84
85 function _initHandler(mw) {
86 if (!mw.options) { return mw.handler; }
87 var context = {
88 waif: this.waif,
89 service: this
90 };
91 return mw.handler.apply(context, mw.options);
92 }
93};
94
95Service.prototype.use = function() {
96 var args = norma('{path:s?, handler:f, options:.*}', arguments);
97 this.middleware.push(args);
98 debug('use middlware on service: %s', this.name);
99 return this;
100};
101
102Service.prototype.forward = function(url) {
103 console.log("Forward has been deprecated.");
104 console.log("Instead do '.use(pipe, \"http://domain.com\").listen()'");
105};
106
107Service.prototype.listen = function(url) {
108 this.listening = true;
109 this.uri.set(url);
110 return this;
111};
112
113Service.prototype.request = function() {
114 var args = norma('path:s?, opts:o?, cb:f?', arguments);
115 var cb = args.cb || null;
116 var opts = args.opts || {};
117 var path = args.path || opts.url || opts.uri;
118
119 opts.uri = this.uri.requestUrl(path);
120 opts.url = null;
121
122 _.defaults(opts, { json: true });
123
124 debug('request on service: %s, %o', this.name, args);
125 return request.apply(request, _.compact([opts, cb]));
126};
127
128
129// Each service is also an event emitter,
130// to allow you to get notifications of
131// start, stop and configure.
132
133Service.createInstance = function(name, waif) {
134 var _service = new Service(name);
135 _service.setWaif(waif);
136
137 // called directly
138 var fn = function() {
139 debug('request proxy on service: %s', name);
140 return _service.request.apply(_service, arguments);
141 };
142
143 fn.instance = _service;
144
145 var proxyMethods = [
146 'request', 'listen', 'use', 'start', 'stop', 'on'
147 ];
148
149 _(proxyMethods).each(function(method) {
150 fn[method] = function() {
151 _service[method].apply(_service, arguments);
152 return fn;
153 };
154 });
155
156 fn.requestUrl = _service.uri.requestUrl.bind(_service.uri);
157
158 return fn;
159};
160
161module.exports = Service;