1 | const sipStatus = require('sip-status') ;
|
2 | const debug = require('debug')('connect:dispatcher');
|
3 | const Agent = require('./drachtio-agent') ;
|
4 | const EventEmitter = require('events').EventEmitter ;
|
5 | const delegate = require('delegates') ;
|
6 |
|
7 | const app = module.exports = {};
|
8 |
|
9 | app._init = function() {
|
10 | const client = new Agent(this);
|
11 | for (const prop in this.params) {
|
12 | client.set(prop, this.params[prop]) ;
|
13 | }
|
14 | for (const method in this.routedMethods) {
|
15 | client.route(method) ;
|
16 | }
|
17 |
|
18 |
|
19 | ['connect', 'close', 'error', 'reconnecting', 'listening'].forEach((event) => {
|
20 | client.on(event, (...args) => {
|
21 | EventEmitter.prototype.emit.apply(this, [event].concat(args)) ;
|
22 | }) ;
|
23 | }) ;
|
24 |
|
25 | this._cachedEvents.forEach((event) => {
|
26 | app.on(event);
|
27 | }) ;
|
28 | this._cachedEvents = [] ;
|
29 |
|
30 |
|
31 | delegate(this, 'client')
|
32 | .method('request')
|
33 | .method('disconnect')
|
34 | .method('close')
|
35 | .method('get')
|
36 | .method('set')
|
37 | .getter('idle') ;
|
38 |
|
39 | return client ;
|
40 | };
|
41 |
|
42 | app.connect = function(...args) {
|
43 | const client = this.client = this._init() ;
|
44 | client.connect.apply(client, args);
|
45 | return this ;
|
46 | };
|
47 |
|
48 | app.listen = function(...args) {
|
49 | const client = this.client = this._init() ;
|
50 | const server = client.listen.apply(client, args);
|
51 | return server ;
|
52 | };
|
53 |
|
54 | app.endSession = function(socketHolder) {
|
55 | if (this.client.isListening && socketHolder.socket) {
|
56 | this.client.disconnect(socketHolder.socket);
|
57 | }
|
58 | };
|
59 | app.request = function() {
|
60 | throw new Error('cannot call app#request in unconnected state') ;
|
61 | } ;
|
62 |
|
63 | app.set = function(prop, value) {
|
64 | this.params[prop] = value ;
|
65 | };
|
66 |
|
67 | app.get = function(prop) {
|
68 | return this.params[prop] ;
|
69 | };
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 | app.use = function(fn) {
|
83 | let offset = 0 ;
|
84 | let method = '*' ;
|
85 |
|
86 |
|
87 | if (typeof fn !== 'function') {
|
88 | let arg = fn;
|
89 |
|
90 | while (Array.isArray(arg) && arg.length !== 0) {
|
91 | arg = arg[0];
|
92 | }
|
93 |
|
94 |
|
95 | if (typeof arg !== 'function') {
|
96 | offset = 1;
|
97 | method = fn;
|
98 | }
|
99 | }
|
100 |
|
101 |
|
102 | const fns = [].concat(...Array.prototype.slice.call(arguments, offset));
|
103 |
|
104 | if (fns.length === 0) throw new TypeError('app.use() requires middleware functions');
|
105 |
|
106 | fns.forEach((fn) => {
|
107 |
|
108 | if ('function' === typeof fn.handle) {
|
109 | var server = fn;
|
110 | fn.method = method;
|
111 | fn = function(req, res, next) {
|
112 | server.handle(req, res, next);
|
113 | };
|
114 | }
|
115 |
|
116 | debug('use %s %s', method || '*', fn.name || 'anonymous');
|
117 | this.stack.push({ method: method, handle: fn });
|
118 | }) ;
|
119 |
|
120 | if (typeof method === 'string' && method !== '*' && !(method in this.routedMethods)) {
|
121 | this.routedMethods[method] = true ;
|
122 | if (this.client) { this.client.route(method) ; }
|
123 | }
|
124 |
|
125 | return this;
|
126 | };
|
127 |
|
128 |
|
129 |
|
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 | app.handle = function(req, res, out) {
|
136 | const self = this;
|
137 | const stack = this.stack ;
|
138 | let index = 0;
|
139 |
|
140 | debug(`handling request with method ${req.method}`);
|
141 | req.app = this ;
|
142 |
|
143 | function next(err) {
|
144 | var layer;
|
145 |
|
146 |
|
147 | layer = stack[index++];
|
148 |
|
149 |
|
150 | if (!layer || res.finalResponseSent) {
|
151 |
|
152 | if (out) { return out(err); }
|
153 |
|
154 |
|
155 | if (err) {
|
156 |
|
157 | var finalResponseSent = res.finalResponseSent ;
|
158 |
|
159 | console.error('some layer barfed an error: ', err) ;
|
160 | if (res.status < 400 || !req.status) { res.status = 500; }
|
161 | debug(`default ${res.status}`);
|
162 |
|
163 |
|
164 | if (err.status) { res.status = err.status; }
|
165 |
|
166 |
|
167 | var msg = sipStatus[res.status] ;
|
168 |
|
169 |
|
170 | console.error(err.stack || err.toString());
|
171 | if (finalResponseSent) { return ; }
|
172 | res.send(res.status, msg);
|
173 | } else {
|
174 | if (req.method === 'PRACK') {
|
175 | res.send(200);
|
176 | }
|
177 | else if (req.method !== 'ACK') {
|
178 | res.send(404) ;
|
179 | self.endSession(res);
|
180 | }
|
181 | }
|
182 | return;
|
183 | }
|
184 |
|
185 | try {
|
186 |
|
187 |
|
188 | if (0 !== req.method.toLowerCase().indexOf(layer.method.toLowerCase()) &&
|
189 | layer.method !== '*') { return next(err); }
|
190 |
|
191 | debug('%s %s : %s', layer.handle.name || 'anonymous', layer.method, req.uri);
|
192 | var arity = layer.handle.length;
|
193 | if (err) {
|
194 | if (arity === 4) {
|
195 | layer.handle(err, req, res, next);
|
196 | } else {
|
197 | next(err);
|
198 | }
|
199 | } else if (arity < 4) {
|
200 | layer.handle(req, res, next);
|
201 | } else {
|
202 | next();
|
203 | }
|
204 | } catch (e) {
|
205 | console.error(e.stack) ;
|
206 | next(e);
|
207 | }
|
208 | }
|
209 | next();
|
210 | };
|