1 | import request = require('request');
|
2 | import {inject} from 'inversify';
|
3 | import {Url} from 'url';
|
4 | import path = require('path');
|
5 | import fs = require('fs');
|
6 | import nodeUrl = require('url');
|
7 | import * as _ from 'lodash';
|
8 | import {CommandUtil} from "../interfaces/command-util";
|
9 | import {ForceErrorImpl} from "./force-error-impl";
|
10 | import {SafeJson} from "../interfaces/safe-json";
|
11 | import {RemoteCatalogGetter} from "../interfaces/remote-catalog/remote-catalog-getter";
|
12 | import {RemoteCatalog} from "../interfaces/remote-catalog/remote-catalog";
|
13 | import {RemoteCatalogResource} from "../interfaces/remote-catalog/remote-catalog-resource";
|
14 |
|
15 | const fileExists = require('file-exists');
|
16 | const async = require('async');
|
17 |
|
18 | export class RemoteCatalogGetterImpl extends ForceErrorImpl implements RemoteCatalogGetter {
|
19 | constructor(@inject('CommandUtil') private commandUtil: CommandUtil,
|
20 | @inject('SafeJson') private safeJson: SafeJson) {
|
21 | super();
|
22 | }
|
23 |
|
24 | getCatalogFromUrl(url: Url | string, cb: (err, remoteCatalog) => void) {
|
25 | const me = this;
|
26 | cb = me.checkCallback(cb);
|
27 | if (me.checkForceError('RemoteCatalogGetterImpl.getCatalogFromUrl', cb)) {
|
28 | return;
|
29 | }
|
30 | me.getParsedUrl(url, (err, parsedUrl) => {
|
31 | if (me.commandUtil.callbackIfError(cb, err)) {
|
32 | return;
|
33 | }
|
34 | const baseUrl = (parsedUrl.protocol)
|
35 | ? `${parsedUrl.protocol}//${parsedUrl.hostname}${path.dirname(parsedUrl.path)}`
|
36 | : path.dirname(parsedUrl.path);
|
37 | me.getRemoteResource(parsedUrl, 'root', (err, remoteCatalogResource) => {
|
38 | if (me.commandUtil.callbackIfError(cb, err)) {
|
39 | return;
|
40 | }
|
41 | try {
|
42 | const remoteCatalog: RemoteCatalog = remoteCatalogResource.parsedObject;
|
43 | const fnArray: any[] = [];
|
44 |
|
45 | async.each(remoteCatalog.entries,
|
46 | (entry, cb) => {
|
47 | async.each(entry.urls,
|
48 | (url, cb) => {
|
49 | me.getParsedUrl(url, (err, parsedUrl) => {
|
50 | if (me.commandUtil.callbackIfError(cb, err)) {
|
51 | return;
|
52 | }
|
53 | if (!parsedUrl.protocol) {
|
54 | url = path.isAbsolute(parsedUrl.path) ? parsedUrl.path : `${baseUrl}/${parsedUrl.path}`;
|
55 | }
|
56 | fnArray.push(async.apply(me.getRemoteResource.bind(me), url, entry.name));
|
57 | });
|
58 | cb();
|
59 | },
|
60 | (err) => {
|
61 | me.commandUtil.logError(err);
|
62 | cb();
|
63 | });
|
64 | },
|
65 | (err) => {
|
66 | if (me.commandUtil.callbackIfError(cb, err)) {
|
67 | return;
|
68 | }
|
69 | async.parallel(fnArray, (err, results: RemoteCatalogResource[]) => {
|
70 | if (me.commandUtil.callbackIfError(cb, err)) {
|
71 | return;
|
72 | }
|
73 |
|
74 | remoteCatalog.entries.forEach(entry => {
|
75 | entry.resources =
|
76 | <RemoteCatalogResource[]>_.filter(results, {parentCatalogEntryName: entry.name});
|
77 | });
|
78 | cb(null, remoteCatalog);
|
79 | });
|
80 | });
|
81 |
|
82 | |
83 |
|
84 |
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 |
|
97 |
|
98 |
|
99 |
|
100 |
|
101 |
|
102 |
|
103 | } catch (err) {
|
104 | me.commandUtil.callbackIfError(cb, err);
|
105 | }
|
106 | });
|
107 | });
|
108 | }
|
109 |
|
110 |
|
111 |
|
112 | getRemoteResource(url: Url | string,
|
113 | parentCatalogEntryName: string,
|
114 | cb: (err: Error, remoteCatalogResource?: RemoteCatalogResource) => void) {
|
115 | const me = this;
|
116 | cb = me.checkCallback(cb);
|
117 | if (me.checkForceError('RemoteCatalogGetterImpl.getRemoteResource', cb)) {
|
118 | return;
|
119 | }
|
120 | me.resolveTextResourceFromUrl(url, (err, text, absoluteUrl) => {
|
121 | if (me.commandUtil.callbackIfError(cb, err)) {
|
122 | return;
|
123 | }
|
124 | me.safeJson.safeParse(text, (err, parsedObject) => {
|
125 | const name = path.basename(absoluteUrl);
|
126 | cb(err, {
|
127 | absoluteUrl, name, text, parsedObject, parentCatalogEntryName
|
128 | });
|
129 | });
|
130 | });
|
131 | }
|
132 |
|
133 | resolveJsonObjectFromUrl(url: Url | string, cb: (err: Error, jsonObject: any, absoluteUrl: string) => void) {
|
134 | const me = this;
|
135 | cb = me.checkCallback(cb);
|
136 | if (me.checkForceError('RemoteCatalogGetterImpl.resolveJsonObjectFromUrl', cb)) {
|
137 | return;
|
138 | }
|
139 | me.resolveTextResourceFromUrl(url, (err, text, absoluteUrl) => {
|
140 | if (me.commandUtil.callbackIfError(cb, err, false)) {
|
141 | return;
|
142 | }
|
143 | me.safeJson.safeParse(text, (err, jsonObject) => {
|
144 | cb(err, jsonObject, absoluteUrl);
|
145 | });
|
146 | });
|
147 | }
|
148 |
|
149 | resolveTextResourceFromUrl(url: Url | string, cb: (err: Error, text?: string, absoluteUrl?: string) => void) {
|
150 | const me = this;
|
151 | cb = me.checkCallback(cb);
|
152 | if (me.checkForceError('RemoteCatalogGetterImpl.resolveTextResourceFromUrl', cb)) {
|
153 | return;
|
154 | }
|
155 | me.getParsedUrl(url, (err, parsedUrl) => {
|
156 | if (err) {
|
157 | return cb(err, '', null);
|
158 | }
|
159 | try {
|
160 | if (!parsedUrl.protocol) {
|
161 | const urlString = parsedUrl.path;
|
162 | fileExists(urlString, (err, exists) => {
|
163 | if (me.commandUtil.callbackIfError(cb, err, false)) {
|
164 | return;
|
165 | }
|
166 | if (exists) {
|
167 | fs.readFile(urlString, 'utf8', (err, data) => {
|
168 | if (me.commandUtil.callbackIfError(cb, err)) {
|
169 | return;
|
170 | }
|
171 | cb(null, data.toString(), urlString);
|
172 | });
|
173 | return;
|
174 | }
|
175 | cb(new Error(`Url: '${url}' does not exist`), '', urlString);
|
176 | });
|
177 | return;
|
178 | }
|
179 |
|
180 | request(parsedUrl.href, (err, res, text) => {
|
181 | if (err) {
|
182 | return cb(err, '', parsedUrl.href);
|
183 | }
|
184 | if (res.statusCode !== 200) {
|
185 | return cb(new Error(`Error retrieving '${parsedUrl.href}'`), '', parsedUrl.href);
|
186 | }
|
187 | return cb(null, text.toString(), parsedUrl.href);
|
188 | });
|
189 | }
|
190 | catch (err) {
|
191 | return cb(err, null);
|
192 | }
|
193 | });
|
194 | }
|
195 |
|
196 | getParsedUrl(url: Url | string, cb: (err: Error, parsedUrl?: Url) => void) {
|
197 | const me = this;
|
198 | cb = me.checkCallback(cb);
|
199 | if (me.checkForceError('RemoteCatalogGetterImpl.getParsedUrl', cb)) {
|
200 | return;
|
201 | }
|
202 | try {
|
203 | if (url.constructor.name === 'Url') {
|
204 | return cb(null, <Url>url);
|
205 | }
|
206 | if (url.constructor.name === 'String') {
|
207 | if (!url) {
|
208 | return cb(new Error('Empty string is not a url'));
|
209 | }
|
210 | const parsedUrl = nodeUrl.parse(<string>url);
|
211 | return cb(null, parsedUrl);
|
212 | }
|
213 | } catch (err) {
|
214 | cb(err);
|
215 | }
|
216 | }
|
217 | }
|
218 |
|