1 |
|
2 | var assert = require('assert');
|
3 | var norma = require('norma');
|
4 | var debug = require('debug')('waif:service');
|
5 | var _ = require('lodash');
|
6 | var EventEmitter = require('events').EventEmitter;
|
7 | var request = require('request');
|
8 | var express = require('express');
|
9 | var util = require('util');
|
10 |
|
11 | var Uri = require('./state/uri');
|
12 | var Status = require('./state/status');
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 | function 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 | }
|
34 | util.inherits(Service, EventEmitter);
|
35 |
|
36 | Service.prototype.setWaif = function(waif) {
|
37 | this.waif = waif;
|
38 | return this;
|
39 | };
|
40 |
|
41 | Service.prototype.initialize = function() {};
|
42 |
|
43 |
|
44 | Service.prototype.start = function () {
|
45 | debug('start listening on service: %s', this.name);
|
46 |
|
47 |
|
48 | this.server = express();
|
49 |
|
50 |
|
51 | _(this.middleware).each(this.mount, this);
|
52 |
|
53 |
|
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 |
|
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 |
|
71 | Service.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 |
|
77 | Service.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 |
|
95 | Service.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 |
|
102 | Service.prototype.forward = function(url) {
|
103 | console.log("Forward has been deprecated.");
|
104 | console.log("Instead do '.use(pipe, \"http://domain.com\").listen()'");
|
105 | };
|
106 |
|
107 | Service.prototype.listen = function(url) {
|
108 | this.listening = true;
|
109 | this.uri.set(url);
|
110 | return this;
|
111 | };
|
112 |
|
113 | Service.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 |
|
130 |
|
131 |
|
132 |
|
133 | Service.createInstance = function(name, waif) {
|
134 | var _service = new Service(name);
|
135 | _service.setWaif(waif);
|
136 |
|
137 |
|
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 |
|
161 | module.exports = Service;
|