1 | import { __awaiter } from "tslib";
|
2 | import { Subject } from 'rxjs/Subject';
|
3 | import 'rxjs/add/operator/map';
|
4 | import 'rxjs/add/operator/takeUntil';
|
5 | import 'rxjs/add/operator/take';
|
6 | import * as _ from 'lodash';
|
7 | import { Models } from './models';
|
8 | import { RestHeaders } from './rest-headers';
|
9 | import { Helpers, Level } from 'ng2-logger/browser';
|
10 | import axios from 'axios';
|
11 | import { Resource } from './resource.service';
|
12 | import { Log } from 'ng2-logger/browser';
|
13 | import { isUndefined } from 'util';
|
14 | import { RequestCache } from './request-cache';
|
15 | const log = Log.create('rest-resource', Level.__NOTHING);
|
16 | const jobIDkey = 'jobID';
|
17 |
|
18 |
|
19 | export class RestRequest {
|
20 | constructor() {
|
21 | this.subjectInuUse = {};
|
22 | this.meta = {};
|
23 |
|
24 | this.replaySubjects = {};
|
25 | }
|
26 | handlerResult(options, sourceRequest) {
|
27 | if (isUndefined(options)) {
|
28 | options = {};
|
29 | }
|
30 | const { res, jobid, isArray, method } = options;
|
31 | if (typeof res !== 'object')
|
32 | throw new Error('[ng2-rest] No resposnse for request. ');
|
33 | if (Helpers.isBrowser) {
|
34 | res.headers = RestHeaders.from(res.headers);
|
35 | }
|
36 |
|
37 | if (res.error) {
|
38 | this.subjectInuUse[jobid].error(new Models.HttpResponseError(res.error, res.data, res.headers, res.code));
|
39 | return;
|
40 | }
|
41 | const entity = this.meta[jobid].entity;
|
42 | const circular = this.meta[jobid].circular;
|
43 |
|
44 | this.subjectInuUse[jobid].next(new Models.HttpResponse(sourceRequest, res.data, res.headers, res.code, entity, circular, isArray));
|
45 | return;
|
46 | }
|
47 | checkCache(sourceRequest, jobid) {
|
48 | const existedInCache = RequestCache.findBy(sourceRequest);
|
49 | if (existedInCache) {
|
50 | log.i('cache exists', existedInCache);
|
51 | this.subjectInuUse[jobid].next(existedInCache);
|
52 | return true;
|
53 | }
|
54 | log.i('cache not exists', existedInCache);
|
55 | return false;
|
56 | }
|
57 | req(url, method, headers, body, jobid, isArray = false, mockHttp) {
|
58 | return __awaiter(this, void 0, void 0, function* () {
|
59 | if (this.checkCache({
|
60 | url,
|
61 | body,
|
62 | isArray,
|
63 | method
|
64 | }, jobid)) {
|
65 | return;
|
66 | }
|
67 | var response;
|
68 | if (mockHttp) {
|
69 | if (typeof mockHttp === 'object') {
|
70 | response = {
|
71 | data: mockHttp.data,
|
72 | status: mockHttp.code,
|
73 | headers: mockHttp.headers,
|
74 | statusText: mockHttp.error,
|
75 | config: {}
|
76 | };
|
77 | }
|
78 | else if (typeof mockHttp === 'function') {
|
79 | const r = mockHttp(url, method, headers, body);
|
80 | response = {
|
81 | data: r.data,
|
82 | status: r.code,
|
83 | headers: r.headers,
|
84 | statusText: r.error,
|
85 | config: {}
|
86 | };
|
87 | }
|
88 | }
|
89 | try {
|
90 | if (!response) {
|
91 | response = yield axios({
|
92 | url,
|
93 | method,
|
94 | data: body,
|
95 | responseType: 'text',
|
96 | headers: headers.toJSON()
|
97 | });
|
98 | }
|
99 | this.handlerResult({
|
100 | res: {
|
101 | code: response.status,
|
102 | data: JSON.stringify(response.data),
|
103 | isArray,
|
104 | jobid,
|
105 | headers: RestHeaders.from(response.headers)
|
106 | },
|
107 | method,
|
108 | jobid,
|
109 | isArray
|
110 | }, {
|
111 | url,
|
112 | body,
|
113 | method,
|
114 | isArray,
|
115 | });
|
116 | }
|
117 | catch (catchedError) {
|
118 |
|
119 |
|
120 | if (typeof catchedError === 'object' && catchedError.response && catchedError.response.data) {
|
121 | const err = catchedError.response.data;
|
122 | const msg = catchedError.response.data.message || '';
|
123 | let stack = (err.stack || '').split('\n');
|
124 | Resource['_listenErrors'].next({
|
125 | msg,
|
126 | stack,
|
127 | data: catchedError.response.data
|
128 | });
|
129 | }
|
130 | const error = (catchedError && catchedError.response) ? `[${catchedError.response.statusText}]: ` : '';
|
131 | this.handlerResult({
|
132 | res: {
|
133 | code: (catchedError && catchedError.response) ? catchedError.response.status : undefined,
|
134 | error: `${error}${catchedError.message}`,
|
135 | data: (catchedError && catchedError.response) ? JSON.stringify(catchedError.response.data) : undefined,
|
136 | isArray,
|
137 | jobid,
|
138 | headers: RestHeaders.from(catchedError && catchedError.response && catchedError.response.headers)
|
139 | },
|
140 | method,
|
141 | jobid,
|
142 | isArray
|
143 | }, {
|
144 | url,
|
145 | body,
|
146 | isArray,
|
147 | method
|
148 | });
|
149 | }
|
150 | });
|
151 | }
|
152 | getSubject(method, meta) {
|
153 | if (_.isUndefined(this.replaySubjects[meta.endpoint])) {
|
154 | log.i(`[getSubject][recreate] (${meta.endpoint}) `);
|
155 | this.replaySubjects[meta.endpoint] = {};
|
156 | }
|
157 | if (_.isUndefined(this.replaySubjects[meta.endpoint][meta.path])) {
|
158 | log.i(`[getSubject][recreate] (${meta.endpoint})(${meta.path}) `);
|
159 | this.replaySubjects[meta.endpoint][meta.path] = {};
|
160 | }
|
161 | if (_.isUndefined(this.replaySubjects[meta.endpoint][meta.path][method])) {
|
162 | log.i(`[getSubject][recreate] (${meta.endpoint})(${meta.path})(${method}) `);
|
163 | this.replaySubjects[meta.endpoint][meta.path][method] = {
|
164 | subject: new Subject(),
|
165 | data: undefined,
|
166 | };
|
167 | }
|
168 | const replay = this.replaySubjects[meta.endpoint][meta.path][method];
|
169 | const id = RestRequest.jobId++;
|
170 | replay.id = id;
|
171 | const subject = replay.subject;
|
172 | subject[jobIDkey] = id;
|
173 | this.meta[id] = meta;
|
174 | this.subjectInuUse[id] = subject;
|
175 | return replay;
|
176 | }
|
177 |
|
178 | metaReq(method, url, body, headers, meta, isArray, mockHttp) {
|
179 | const replay = this.getSubject(method, meta);
|
180 | replay.data = { url, body, headers, isArray };
|
181 | setTimeout(() => this.req(url, method, headers, body, replay.id, isArray, mockHttp));
|
182 | const resp = replay.subject.asObservable().take(1).toPromise();
|
183 | resp.observable = replay.subject.asObservable();
|
184 | resp.cache = RequestCache.findBy({
|
185 | body,
|
186 | isArray,
|
187 | method,
|
188 | url
|
189 | });
|
190 | return resp;
|
191 | }
|
192 | get(url, body, headers, meta, isArray, mockHttp) {
|
193 | return this.metaReq('get', url, body, headers, meta, isArray, mockHttp);
|
194 | }
|
195 | head(url, body, headers, meta, isArray, mockHttp) {
|
196 | return this.metaReq('head', url, body, headers, meta, isArray, mockHttp);
|
197 | }
|
198 | delete(url, body, headers, meta, isArray, mockHttp) {
|
199 | return this.metaReq('delete', url, body, headers, meta, isArray, mockHttp);
|
200 | }
|
201 | post(url, body, headers, meta, isArray, mockHttp) {
|
202 | return this.metaReq('post', url, body, headers, meta, isArray, mockHttp);
|
203 | }
|
204 | put(url, body, headers, meta, isArray, mockHttp) {
|
205 | return this.metaReq('put', url, body, headers, meta, isArray, mockHttp);
|
206 | }
|
207 | patch(url, body, headers, meta, isArray, mockHttp) {
|
208 | return this.metaReq('patch', url, body, headers, meta, isArray, mockHttp);
|
209 | }
|
210 | jsonp(url, body, headers, meta, isArray, mockHttp) {
|
211 | const replay = this.getSubject('jsonp', meta);
|
212 | const jobid = replay.id;
|
213 | const method = 'jsonp';
|
214 | setTimeout(() => {
|
215 | if (url.endsWith('/'))
|
216 | url = url.slice(0, url.length - 1);
|
217 | let num = Math.round(10000 * Math.random());
|
218 | let callbackMethodName = "cb_" + num;
|
219 | window[callbackMethodName] = (data) => {
|
220 | if (this.checkCache({
|
221 | url,
|
222 | body,
|
223 | isArray,
|
224 | method
|
225 | }, jobid)) {
|
226 | return;
|
227 | }
|
228 | this.handlerResult({
|
229 | res: {
|
230 | data, isArray
|
231 | },
|
232 | method,
|
233 | jobid,
|
234 | isArray
|
235 | }, {
|
236 | url,
|
237 | body,
|
238 | isArray,
|
239 | method,
|
240 | });
|
241 | };
|
242 | let sc = document.createElement('script');
|
243 | sc.src = `${url}?callback=${callbackMethodName}`;
|
244 | document.body.appendChild(sc);
|
245 | document.body.removeChild(sc);
|
246 | });
|
247 |
|
248 | const resp = replay.subject.asObservable().take(1).toPromise();
|
249 | resp.observable = replay.subject.asObservable();
|
250 | resp.cache = RequestCache.findBy({
|
251 | body,
|
252 | isArray,
|
253 | method,
|
254 | url
|
255 | });
|
256 | return resp;
|
257 | }
|
258 | replay(method, meta) {
|
259 | const replay = this.getSubject(method, meta);
|
260 | if (!replay.data) {
|
261 | console.warn(`Canno replay first ${method} request from ${meta.endpoint}/${meta.path}`);
|
262 | return;
|
263 | }
|
264 | ;
|
265 | if (replay && replay.subject && Array.isArray(replay.subject.observers) &&
|
266 | replay.subject.observers.length == 0) {
|
267 | console.warn(`No observators for ${method} request from ${meta.endpoint}/${meta.path}`);
|
268 | return;
|
269 | }
|
270 | const url = replay.data.url;
|
271 | const headers = replay.data.headers;
|
272 | const body = replay.data.body;
|
273 | const isArray = replay.data.isArray;
|
274 | setTimeout(() => this.req(url, method, headers, body, replay.id, isArray));
|
275 | }
|
276 | }
|
277 | RestRequest.jobId = 0;
|
278 |
|
\ | No newline at end of file |