UNPKG

12.7 kBJavaScriptView Raw
1'use strict';
2var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 return new (P || (P = Promise))(function (resolve, reject) {
4 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6 function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
7 step((generator = generator.apply(thisArg, _arguments || [])).next());
8 });
9};
10const httpx = require('httpx');
11const cheerio = require('cheerio');
12const detectMocha = require('detect-mocha');
13const { red } = require('colors');
14const { Transform } = require('stream');
15const { unrefTimeout } = require('./unref-timeout');
16const _ = require('lodash');
17class FilterChain {
18 constructor(options = {}) {
19 this.processors = [
20 new PuppeteerInvalidPlatformProcessor(options),
21 new DynamicLinkLibraryMissingProcessor(options),
22 new NoSpaceLeftOnDeviceProcessor(options),
23 new MissingAptGetProcessor(options),
24 new DockerNotStartedOrInstalledErrorProcessor(options),
25 new FcServiceNotEnabledProcessor(options),
26 new RamInactiveErrorProcessor(options),
27 new RosStackValidationErrorProcessor(options),
28 new LogInactiveErrorProcessor(options),
29 new ClientTimeoutErrorProcessor(options)
30 ];
31 }
32 process(message, err) {
33 return __awaiter(this, void 0, void 0, function* () {
34 for (const processor of this.processors) {
35 if (!message) {
36 message = '';
37 }
38 if (processor.match(message, err)) {
39 yield processor.process(message, err);
40 yield processor.postProcess();
41 return true;
42 }
43 }
44 });
45 }
46}
47class ErrorProcessor {
48 constructor(options = {}) {
49 this.serviceName = options.serviceName;
50 this.functionName = options.functionName;
51 }
52 match(message, err) { }
53 process(message, err) {
54 return __awaiter(this, void 0, void 0, function* () { });
55 }
56 _autoExist() {
57 process.nextTick(() => {
58 console.log(red('\nFun will auto exit after 3 seconds.\n'));
59 if (!detectMocha()) {
60 unrefTimeout(() => {
61 process.emit('SIGINT');
62 }, 3000);
63 }
64 });
65 }
66 postProcess() {
67 return __awaiter(this, void 0, void 0, function* () {
68 console.log();
69 });
70 }
71}
72class ClientTimeoutErrorProcessor extends ErrorProcessor {
73 match(message, err) {
74 return _.includes(message, 'ReadTimeout(');
75 }
76 process(message) {
77 return __awaiter(this, void 0, void 0, function* () {
78 console.log(red(`The timeout of API request has been detected,you can increase timeout value by 'fun config'.`));
79 });
80 }
81}
82class DockerNotStartedOrInstalledErrorProcessor extends ErrorProcessor {
83 match(message, err) {
84 if (_.includes(message, 'connect ECONNREFUSED /var/run/docker.sock')
85 || _.includes(message, 'Error: connect ENOENT //./pipe/docker_engine')) {
86 return true;
87 }
88 return false;
89 }
90 process(message) {
91 return __awaiter(this, void 0, void 0, function* () {
92 console.log(red('Fun detected that Docker is not installed on your host or not started. Please run \'docker ps\' command to check docker status.'));
93 });
94 }
95}
96class FcServiceNotEnabledProcessor extends ErrorProcessor {
97 match(message, err) {
98 if (_.includes(message, 'FC service is not enabled for current user')) {
99 return true;
100 }
101 return false;
102 }
103 process(message) {
104 return __awaiter(this, void 0, void 0, function* () {
105 console.log(red('FC service is not enabled for current user. Please enable FC service before using fun.\nYou can enable FC service on this page https://www.aliyun.com/product/fc .'));
106 });
107 }
108}
109class RamInactiveErrorProcessor extends ErrorProcessor {
110 match(message, err) {
111 return (_.includes(message, 'Account is inactive to this service') && _.includes(message, 'ram.aliyuncs.com'));
112 }
113 process(message) {
114 return __awaiter(this, void 0, void 0, function* () {
115 console.log(red('Ram service is not enabled for current user. Please enable Ram service before using fun.\nYou can enable Ram service on this page https://www.aliyun.com/product/ram .'));
116 });
117 }
118}
119class RosStackValidationErrorProcessor extends ErrorProcessor {
120 match(message, err) {
121 return _.includes(message, 'Function CodeUri must be an oss bucket, try using package');
122 }
123 process(message) {
124 return __awaiter(this, void 0, void 0, function* () {
125 console.log(red('StackValidationFailed: template syntax mismatch with ROS support. You may be able to solve it by executing the command \'fun package\'.'));
126 });
127 }
128}
129class LogInactiveErrorProcessor extends ErrorProcessor {
130 match(message, err) {
131 return err && err.code === 'InvalidAccessKeyId' && _.includes(message, 'AccessKeyId') && _.includes(message, 'is inactive');
132 }
133 process(message) {
134 return __awaiter(this, void 0, void 0, function* () {
135 console.log(red('\nPlease go to https://sls.console.aliyun.com/ to open the LogServce.'));
136 });
137 }
138}
139// 发生在 fun install 安装依赖,但是依赖包含解决方案,比如 puppeteer,需要使用 apt-get 安装,如果宿主机没有,那就提示使用 fun install -d
140class MissingAptGetProcessor extends ErrorProcessor {
141 match(message) {
142 return _.includes(message, 'touch: /var/cache/apt/pkgcache.bin: No such file or directory');
143 }
144 process(message) {
145 return __awaiter(this, void 0, void 0, function* () {
146 process.nextTick(() => {
147 console.log(red(`Tips: Fun has detected that there is no apt-get installed on the machine, you need use 'fun install --use-docker' to reinstall.
148Type 'fun install -h' for more help.`));
149 });
150 });
151 }
152}
153class NoSpaceLeftOnDeviceProcessor extends ErrorProcessor {
154 match(message) {
155 return _.includes(message, 'no space left on device');
156 }
157 process(message) {
158 return __awaiter(this, void 0, void 0, function* () {
159 process.nextTick(() => {
160 console.log(red(`Tips: Fun has detected that docker is no space left.
161if You are using Docker for Windows/Mac, you can select the Docker icon and then Preferences > Resources > Advanced and increase docker image size.
162Please refer to https://docs.docker.com/docker-for-mac/space/ for more help.
163`));
164 });
165 });
166 }
167}
168class DynamicLinkLibraryMissingProcessor extends ErrorProcessor {
169 constructor(options) {
170 super(options);
171 this.prefix = 'error while loading shared libraries: ';
172 this.suffix = ': cannot open shared object file: No such file or directory';
173 this.debianPakcageUrlPrefix = 'https://packages.debian.org/search?lang=en&suite=jessie&arch=amd64&mode=path&searchon=contents&keywords=';
174 this.libPrefixWhiteList = ['/usr/lib/x86_64-linux-gnu', '/lib/x86_64-linux-gnu', '/usr/local/lib'];
175 }
176 match(message) {
177 return _.includes(message, this.prefix)
178 && _.includes(message, this.suffix);
179 }
180 _findPackageByDlName(lib) {
181 return __awaiter(this, void 0, void 0, function* () {
182 const response = yield httpx.request(`${this.debianPakcageUrlPrefix}${lib}`, { timeout: 10000 });
183 const body = yield httpx.read(response, 'utf8');
184 const $ = cheerio.load(body);
185 const packagesTable = $('#pcontentsres table tbody tr').map((i, element) => ({
186 path: $(element).find('td:nth-of-type(1)').text().trim(),
187 name: $(element).find('td:nth-of-type(2)').text().trim()
188 })).get();
189 const packageInfo = _.find(packagesTable, info => _.some(this.libPrefixWhiteList, (prefix) => info.path.startsWith(prefix)));
190 if (packageInfo) {
191 return packageInfo.name;
192 }
193 return null;
194 });
195 }
196 _fetchDlName(message) {
197 return __awaiter(this, void 0, void 0, function* () {
198 // error while loading shared libraries: libnss3.so: cannot open shared object file: No such file or directory
199 const prefixIdx = message.indexOf(this.prefix);
200 const suffixIdx = message.indexOf(this.suffix);
201 return message.substring(prefixIdx + this.prefix.length, suffixIdx);
202 });
203 }
204 process(message) {
205 return __awaiter(this, void 0, void 0, function* () {
206 const lib = yield this._fetchDlName(message);
207 const packageName = yield this._findPackageByDlName(lib);
208 if (packageName) {
209 process.nextTick(() => {
210 console.log(red(`Tips: Fun has detected that you are missing ${lib} library, you can try to install it like this:
211
212 step1: fun install sbox -f ${this.serviceName}/${this.functionName} -i
213 step2: fun-install apt-get install ${packageName}
214 step3: type 'exit' to exit container and then reRun your function
215
216Also you can install dependencies through one command:
217
218 fun install sbox -f ${this.serviceName}/${this.functionName} --cmd 'fun-install apt-get install ${packageName}'
219`));
220 });
221 }
222 else {
223 console.log(red(`Tips: Fun has detected that you are missing ${lib} library, you can try to install it like this:
224
225 step1: open this page ${this.debianPakcageUrlPrefix}${lib} to find your missing dependency
226 step2: fun install sbox -f ${this.serviceName}/${this.functionName} -i
227 step3: fun-install apt-get install YourPackageName
228 step4: type 'exit' to exit container and then reRun your function
229
230Also you can install dependencies through one command:
231
232 fun install sbox -f ${this.serviceName}/${this.functionName} --cmd 'fun-install apt-get install YourPackageName'
233`));
234 }
235 this._autoExist();
236 });
237 }
238}
239class PuppeteerInvalidPlatformProcessor extends ErrorProcessor {
240 match(message) {
241 return _.includes(message, 'Error: Chromium revision is not downloaded. Run "npm install" or "yarn install"');
242 }
243 process(message) {
244 return __awaiter(this, void 0, void 0, function* () {
245 process.nextTick(() => {
246 console.log(red(`Tips: Fun has detected that your puppeteer installation platform is incorrect.
247Please reinstall it like this:
248
2491. fun install sbox -f ${this.serviceName}/${this.functionName} -i
2502. fun-install npm install puppeteer
2513. type 'exit' to exit container and then reRun your function
252
253Also you can install puppeteer through one command:
254fun install sbox -f puppeteer/html2png --cmd 'fun-install npm install puppeteer'`));
255 this._autoExist();
256 });
257 });
258 }
259}
260class ChunkSplitTransform extends Transform {
261 constructor(options) {
262 super(options);
263 this._buffer = '';
264 this._separator = options.separator || '\n';
265 }
266 _transform(chunk, encoding, done) {
267 let sepPos;
268 this._buffer += chunk.toString();
269 while ((sepPos = this._buffer.indexOf(this._separator)) !== -1) {
270 const portion = this._buffer.substr(0, sepPos);
271 this.push(portion + this._separator);
272 this._buffer = this._buffer.substr(sepPos + this._separator.length);
273 }
274 done();
275 }
276 _flush(done) {
277 this.push(this._buffer);
278 done();
279 }
280}
281class FcErrorTransform extends Transform {
282 constructor(options) {
283 super(options);
284 this.filterChain = new FilterChain(options);
285 }
286 _transform(chunk, encoding, done) {
287 const message = chunk.toString();
288 this.filterChain.process(message).then(() => {
289 this.push(message);
290 done();
291 });
292 }
293}
294function processorTransformFactory({ serviceName, functionName, errorStream }) {
295 const transform = new ChunkSplitTransform({
296 separator: '\n'
297 });
298 transform.pipe(new FcErrorTransform({
299 serviceName: serviceName,
300 functionName: functionName
301 })).pipe(errorStream);
302 return transform;
303}
304module.exports = {
305 processorTransformFactory,
306 FilterChain
307};