1 | const Emitter = require('events').EventEmitter ;
|
2 | const sip = require('drachtio-sip') ;
|
3 | const delegate = require('delegates') ;
|
4 | const assert = require('assert') ;
|
5 | const noop = require('node-noop').noop;
|
6 | const debug = require('debug')('drachtio:request');
|
7 |
|
8 | class Request extends Emitter {
|
9 |
|
10 | constructor(msg, meta) {
|
11 | super() ;
|
12 |
|
13 | if (msg) {
|
14 | assert(msg instanceof sip.SipMessage) ;
|
15 | this.msg = msg ;
|
16 | this.meta = meta ;
|
17 | }
|
18 | }
|
19 |
|
20 | get res() {
|
21 | return this._res ;
|
22 | }
|
23 | set res(res) {
|
24 | this._res = res ;
|
25 | return this ;
|
26 | }
|
27 |
|
28 | get isNewInvite() {
|
29 | const to = this.getParsedHeader('to') ;
|
30 | return this.method === 'INVITE' && !('tag' in to.params) ;
|
31 | }
|
32 |
|
33 | get url() {
|
34 | return this.uri ;
|
35 | }
|
36 |
|
37 | set agent(agent) {
|
38 | this._agent = agent ;
|
39 | }
|
40 | get agent() {
|
41 | return this._agent ;
|
42 | }
|
43 |
|
44 | set meta(meta) {
|
45 | debug(`Request#set meta ${JSON.stringify(meta)}`);
|
46 | this.source = meta.source ;
|
47 | this.source_address = meta.address ;
|
48 | this.source_port = meta.port ? parseInt(meta.port) : 5060 ;
|
49 | this.protocol = meta.protocol ;
|
50 | this.stackTime = meta.time ;
|
51 | this.stackTxnId = meta.transactionId ;
|
52 | this.stackDialogId = meta.dialogId ;
|
53 | if (meta.server) this.server = meta.server;
|
54 | if (meta.receivedOn) this.receivedOn = meta.receivedOn;
|
55 | }
|
56 |
|
57 | get meta() {
|
58 | return {
|
59 | source: this.source,
|
60 | source_address: this.source_address,
|
61 | source_port: this.source_port,
|
62 | protocol: this.protocol,
|
63 | time: this.stackTime,
|
64 | transactionId: this.stackTxnId,
|
65 | dialogId: this.stackDialogId
|
66 | } ;
|
67 | }
|
68 |
|
69 | |
70 |
|
71 |
|
72 |
|
73 |
|
74 | cancel(opts, callback) {
|
75 | opts = opts || {};
|
76 | if (typeof opts === 'function') {
|
77 | callback = opts;
|
78 | opts = {};
|
79 | }
|
80 | if (!this._agent || this.source !== 'application') {
|
81 | throw new Error('Request#cancel can only be used for uac Request') ;
|
82 | }
|
83 | this._agent.request(Object.assign(
|
84 | {
|
85 | _socket: this.socket,
|
86 | uri: this.uri,
|
87 | method: 'CANCEL',
|
88 | stackTxnId: this.stackTxnId
|
89 | }, opts),
|
90 | callback) ;
|
91 | }
|
92 | |
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 | |
100 |
|
101 |
|
102 |
|
103 |
|
104 |
|
105 | proxy(opts, callback) {
|
106 | if (this.source !== 'network') {
|
107 | throw new Error('Request#proxy can only be used for incoming requests') ;
|
108 | }
|
109 | opts = opts || {} ;
|
110 |
|
111 |
|
112 | const destination = opts.destination || this.uri ;
|
113 | if (typeof destination === 'string') { opts.destination = [destination] ; }
|
114 |
|
115 | Object.assign(opts, {
|
116 | stackTxnId: this.stackTxnId,
|
117 | remainInDialog: opts.remainInDialog || opts.path || opts.recordRoute || false,
|
118 | provisionalTimeout: opts.provisionalTimeout || '',
|
119 | finalTimeout: opts.finalTimeout || '',
|
120 | followRedirects: opts.followRedirects || false,
|
121 | simultaneous: opts.forking === 'simultaneous',
|
122 | fullResponse: true
|
123 | }) ;
|
124 |
|
125 |
|
126 | opts.destination.forEach((value, index, array) => {
|
127 | const token = value.split(':') ;
|
128 | if (token[0] !== 'sip' && token[0] !== 'tel') {
|
129 | array[index] = 'sip:' + value ;
|
130 | }
|
131 | }) ;
|
132 |
|
133 | const result = {
|
134 | connected: false,
|
135 | responses: []
|
136 | } ;
|
137 |
|
138 | const __x = (callback) => {
|
139 | this._agent.proxy(this, opts, (token, rawMsg, meta) => {
|
140 | if ('NOK' === token[0]) {
|
141 | return callback(token[1]) ;
|
142 | }
|
143 | if ('done' === token[1]) {
|
144 | result.connected = (200 === result.finalStatus) ;
|
145 | return callback(null, result) ;
|
146 | }
|
147 | else {
|
148 |
|
149 | const address = meta.address ;
|
150 | const port = +meta.port;
|
151 | const msg = new sip.SipMessage(rawMsg) ;
|
152 | const obj = {
|
153 | time: meta.time,
|
154 | status: msg.status,
|
155 | msg: msg
|
156 | } ;
|
157 | let len = result.responses.length ;
|
158 | if (len === 0 || address !== result.responses[len - 1].address || port === result.responses[len - 1].port) {
|
159 | result.responses.push({
|
160 | address: address,
|
161 | port: port,
|
162 | msgs:[]
|
163 | }) ;
|
164 | len++ ;
|
165 | }
|
166 | result.responses[len - 1].msgs.push(obj) ;
|
167 | result.finalStatus = msg.status ;
|
168 | result.finalResponse = obj ;
|
169 | }
|
170 | }) ;
|
171 | };
|
172 |
|
173 | if (callback) {
|
174 | __x(callback);
|
175 | return this;
|
176 | }
|
177 |
|
178 | return new Promise((resolve, reject) => {
|
179 | __x((err, results) => {
|
180 | if (err) return reject(err);
|
181 | resolve(results);
|
182 | });
|
183 | });
|
184 | }
|
185 |
|
186 | |
187 |
|
188 |
|
189 |
|
190 |
|
191 |
|
192 |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 |
|
201 | |
202 |
|
203 |
|
204 |
|
205 |
|
206 |
|
207 |
|
208 |
|
209 | logIn(user, options, done) {
|
210 | if (typeof options === 'function') {
|
211 | done = options;
|
212 | options = {};
|
213 | }
|
214 | options = options || {};
|
215 | done = done || noop ;
|
216 |
|
217 | let property = 'user';
|
218 | if (this._passport && this._passport.instance) {
|
219 | property = this._passport.instance._userProperty || 'user';
|
220 | }
|
221 | const session = (options.session === undefined) ? true : options.session;
|
222 |
|
223 | this[property] = user;
|
224 | if (session) {
|
225 | if (!this._passport) { throw new Error('passport.initialize() middleware not in use'); }
|
226 | if (typeof done !== 'function') { throw new Error('req#login requires a callback function'); }
|
227 |
|
228 | this._passport.instance.serializeUser(user, this, (err, obj) => {
|
229 | if (err) { this[property] = null; return done(err); }
|
230 | if (!this._passport.session) {
|
231 | this._passport.session = {};
|
232 | }
|
233 | this._passport.session.user = obj;
|
234 | this.session = this.session || {};
|
235 | this.session[this._passport.instance._key] = this._passport.session;
|
236 | done();
|
237 | });
|
238 | } else {
|
239 | done();
|
240 | }
|
241 | }
|
242 |
|
243 |
|
244 | logOut() {
|
245 | let property = 'user';
|
246 | if (this._passport && this._passport.instance) {
|
247 | property = this._passport.instance._userProperty || 'user';
|
248 | }
|
249 |
|
250 | this[property] = null;
|
251 | if (this._passport && this._passport.session) {
|
252 | delete this._passport.session.user;
|
253 | }
|
254 | }
|
255 |
|
256 | isAuthenticated() {
|
257 | let property = 'user';
|
258 | if (this._passport && this._passport.instance) {
|
259 | property = this._passport.instance._userProperty || 'user';
|
260 | }
|
261 |
|
262 | return (this[property]) ? true : false;
|
263 | }
|
264 |
|
265 |
|
266 | isUnauthenticated() {
|
267 | return !this.isAuthenticated();
|
268 | }
|
269 | }
|
270 |
|
271 | module.exports = Request ;
|
272 |
|
273 | delegate(Request.prototype, 'msg')
|
274 | .method('get')
|
275 | .method('has')
|
276 | .method('getParsedHeader')
|
277 | .method('set')
|
278 | .access('method')
|
279 | .access('uri')
|
280 | .access('headers')
|
281 | .access('body')
|
282 | .access('payload')
|
283 | .getter('type')
|
284 | .getter('raw')
|
285 | .getter('callingNumber')
|
286 | .getter('calledNumber')
|
287 | .getter('canFormDialog') ;
|
288 |
|
289 |
|
290 |
|
291 |
|
292 |
|
293 |
|