UNPKG

8.08 kBPlain TextView Raw
1import request = require('request');
2import {inject} from 'inversify';
3import {Url} from 'url';
4import path = require('path');
5import fs = require('fs');
6import nodeUrl = require('url');
7import * as _ from 'lodash';
8import {CommandUtil} from "../interfaces/command-util";
9import {ForceErrorImpl} from "./force-error-impl";
10import {SafeJson} from "../interfaces/safe-json";
11import {RemoteCatalogGetter} from "../interfaces/remote-catalog/remote-catalog-getter";
12import {RemoteCatalog} from "../interfaces/remote-catalog/remote-catalog";
13import {RemoteCatalogResource} from "../interfaces/remote-catalog/remote-catalog-resource";
14
15const fileExists = require('file-exists');
16const async = require('async');
17
18export 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 //Now collate results into catalog and send it back
74 remoteCatalog.entries.forEach(entry => {
75 entry.resources =
76 <RemoteCatalogResource[]>_.filter(results, {parentCatalogEntryName: entry.name});
77 });
78 cb(null, remoteCatalog);
79 });
80 });
81 //-->
82 /* remoteCatalog.entries.forEach(entry => {
83 entry.urls.forEach(url => {
84 me.getParsedUrl(url, (err, parsedUrl) => {
85 if (me.commandUtil.callbackIfError(cb, err)) {
86 return;
87 }
88 if (!parsedUrl.protocol) {
89 url = path.isAbsolute(parsedUrl.path) ? parsedUrl.path : `${baseUrl}/${parsedUrl.path}`;
90 }
91 fnArray.push(async.apply(me.getRemoteResource.bind(me), url, entry.name));
92 });
93 });
94 });
95 async.parallel(fnArray, (err, results: RemoteCatalogResource[]) => {
96 //Now collate results into catalog and send it back
97 remoteCatalog.entries.forEach(entry => {
98 entry.resources =
99 <RemoteCatalogResource[]>_.filter(results, {parentCatalogEntryName: entry.name});
100 });
101 cb(null, remoteCatalog);
102 });*/
103 } catch (err) {
104 me.commandUtil.callbackIfError(cb, err);
105 }
106 });
107 });
108 }
109
110 //Right now uri can be a web address (http(s)://somewhere.com/some.json) or an absolute path (/tmp/some.json)
111 //or a path relative to cwd (subdir/some.json)
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 //Let's look on the web
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