UNPKG

10.6 kBJavaScriptView Raw
1"use strict";
2var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3 if (k2 === undefined) k2 = k;
4 Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5}) : (function(o, m, k, k2) {
6 if (k2 === undefined) k2 = k;
7 o[k2] = m[k];
8}));
9var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10 Object.defineProperty(o, "default", { enumerable: true, value: v });
11}) : function(o, v) {
12 o["default"] = v;
13});
14var __importStar = (this && this.__importStar) || function (mod) {
15 if (mod && mod.__esModule) return mod;
16 var result = {};
17 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18 __setModuleDefault(result, mod);
19 return result;
20};
21var __importDefault = (this && this.__importDefault) || function (mod) {
22 return (mod && mod.__esModule) ? mod : { "default": mod };
23};
24Object.defineProperty(exports, "__esModule", { value: true });
25exports.PuppetManager = void 0;
26/**
27 * Wechaty Chatbot SDK - https://github.com/wechaty/wechaty
28 *
29 * @copyright 2016 Huan LI (李卓桓) <https://github.com/huan>, and
30 * Wechaty Contributors <https://github.com/wechaty>.
31 *
32 * Licensed under the Apache License, Version 2.0 (the "License");
33 * you may not use this file except in compliance with the License.
34 * You may obtain a copy of the License at
35 *
36 * http://www.apache.org/licenses/LICENSE-2.0
37 *
38 * Unless required by applicable law or agreed to in writing, software
39 * distributed under the License is distributed on an "AS IS" BASIS,
40 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
41 * See the License for the specific language governing permissions and
42 * limitations under the License.
43 *
44 */
45const path_1 = __importDefault(require("path"));
46const read_pkg_up_1 = __importDefault(require("read-pkg-up"));
47const npm_programmatic_1 = __importDefault(require("npm-programmatic"));
48const pkg_dir_1 = __importDefault(require("pkg-dir"));
49const semver_1 = __importDefault(require("semver"));
50const in_gfw_1 = __importDefault(require("in-gfw"));
51const wechaty_puppet_1 = require("wechaty-puppet");
52const loose_instance_of_class_1 = require("./helper-functions/pure/loose-instance-of-class");
53const config_1 = require("./config");
54const puppet_config_1 = require("./puppet-config");
55/**
56 * Huan(202011):
57 * Create a `looseInstanceOfClass` to check `FileBox` and `Puppet` instances #2090
58 * https://github.com/wechaty/wechaty/issues/2090
59 */
60const looseInstanceOfPuppet = loose_instance_of_class_1.looseInstanceOfClass(wechaty_puppet_1.Puppet);
61class PuppetManager {
62 static async resolve(options) {
63 config_1.log.verbose('PuppetManager', 'resolve({puppet: %s, puppetOptions: %s})', options.puppet, JSON.stringify(options.puppetOptions));
64 let puppetInstance;
65 /**
66 * Huan(202001): (DEPRECATED) When we are developing, we might experiencing we have two version of wechaty-puppet installed,
67 * if `options.puppet` is Puppet v1, but the `Puppet` in Wechaty is v2,
68 * then options.puppet will not instanceof Puppet.
69 * So I changed here to match not a string as a workaround.
70 *
71 * Huan(202020): The wechaty-puppet-xxx must NOT dependencies `wechaty-puppet` so that it can be `instanceof`-ed
72 * wechaty-puppet-xxx should put `wechaty-puppet` in `devDependencies` and `peerDependencies`.
73 */
74 if (looseInstanceOfPuppet(options.puppet)) {
75 puppetInstance = await this.resolveInstance(options.puppet);
76 }
77 else if (typeof options.puppet !== 'string') {
78 config_1.log.error('PuppetManager', 'resolve() %s', `
79 Wechaty Framework must keep only one Puppet instance #1930
80 See: https://github.com/wechaty/wechaty/issues/1930
81 `);
82 throw new Error('Wechaty Framework must keep only one Puppet instance #1930');
83 }
84 else {
85 const MyPuppet = await this.resolveName(options.puppet);
86 /**
87 * We will meet the following error:
88 *
89 * [ts] Cannot use 'new' with an expression whose type lacks a call or construct signature.
90 *
91 * When we have different puppet with different `constructor()` args.
92 * For example: PuppetA allow `constructor()` but PuppetB requires `constructor(options)`
93 *
94 * SOLUTION: we enforce all the PuppetImplementation to have `options` and should not allow default parameter.
95 * Issue: https://github.com/wechaty/wechaty-puppet/issues/2
96 */
97 /**
98 * Huan(20210313) Issue #2151 - https://github.com/wechaty/wechaty/issues/2151
99 * error TS2511: Cannot create an instance of an abstract class.
100 *
101 * Huan(20210530): workaround by "as any"
102 */
103 puppetInstance = new MyPuppet(options.puppetOptions);
104 }
105 return puppetInstance;
106 }
107 static async resolveName(puppetName) {
108 config_1.log.verbose('PuppetManager', 'resolveName(%s)', puppetName);
109 if (!puppetName) {
110 throw new Error('must provide a puppet name');
111 }
112 if (!(puppetName in puppet_config_1.PUPPET_DEPENDENCIES)) {
113 throw new Error([
114 '',
115 'puppet npm module not supported: "' + puppetName + '"',
116 'learn more about supported Wechaty Puppet from our directory at',
117 '<https://github.com/wechaty/wechaty-puppet/wiki/Directory>',
118 '',
119 ].join('\n'));
120 }
121 await this.checkModule(puppetName);
122 const puppetModule = await Promise.resolve().then(() => __importStar(require(puppetName)));
123 if (!puppetModule.default) {
124 throw new Error(`Puppet(${puppetName}) has not provided the default export`);
125 }
126 const MyPuppet = puppetModule.default;
127 return MyPuppet;
128 }
129 static async checkModule(puppetName) {
130 config_1.log.verbose('PuppetManager', 'checkModule(%s)', puppetName);
131 const versionRange = puppet_config_1.PUPPET_DEPENDENCIES[puppetName];
132 /**
133 * 1. Not Installed
134 */
135 if (!this.installed(puppetName)) {
136 config_1.log.silly('PuppetManager', 'checkModule(%s) not installed.', puppetName);
137 await this.install(puppetName, versionRange);
138 return;
139 }
140 const moduleVersion = this.getModuleVersion(puppetName);
141 const satisfy = semver_1.default.satisfies(moduleVersion, versionRange);
142 /**
143 * 2. Installed But Version Not Satisfy
144 */
145 if (!satisfy) {
146 config_1.log.silly('PuppetManager', 'checkModule() %s installed version %s NOT satisfied range %s', puppetName, moduleVersion, versionRange);
147 await this.install(puppetName, versionRange);
148 return;
149 }
150 /**
151 * 3. Installed and Version Satisfy
152 */
153 config_1.log.silly('PuppetManager', 'checkModule() %s installed version %s satisfied range %s', puppetName, moduleVersion, versionRange);
154 }
155 static getModuleVersion(moduleName) {
156 const modulePath = path_1.default.dirname(require.resolve(moduleName));
157 const pkg = read_pkg_up_1.default.sync({ cwd: modulePath }).packageJson;
158 const version = pkg.version;
159 return version;
160 }
161 static async resolveInstance(instance) {
162 config_1.log.verbose('PuppetManager', 'resolveInstance(%s)', instance);
163 // const version = instance.version()
164 // const name = instance.name()
165 // const satisfy = semver.satisfies(
166 // version,
167 // puppetConfig.npm.version,
168 // )
169 // TODO: check the instance version to satisfy semver
170 return instance;
171 }
172 static installed(moduleName) {
173 try {
174 require.resolve(moduleName);
175 return true;
176 }
177 catch (e) {
178 return false;
179 }
180 }
181 static async preInstallPuppeteer() {
182 let gfw = false;
183 try {
184 gfw = await in_gfw_1.default();
185 if (gfw) {
186 config_1.log.verbose('PuppetManager', 'preInstallPuppeteer() inGfw = true');
187 }
188 }
189 catch (e) {
190 config_1.log.verbose('PuppetManager', 'preInstallPuppeteer() exception: %s', e);
191 }
192 // https://github.com/GoogleChrome/puppeteer/issues/1597#issuecomment-351945645
193 if (gfw && !process.env['PUPPETEER_DOWNLOAD_HOST']) {
194 config_1.log.info('PuppetManager', 'preInstallPuppeteer() set PUPPETEER_DOWNLOAD_HOST=https://npm.taobao.org/mirrors/');
195 process.env['PUPPETEER_DOWNLOAD_HOST'] = 'https://npm.taobao.org/mirrors/';
196 }
197 }
198 static async install(puppetModule, puppetVersion = 'latest') {
199 config_1.log.info('PuppetManager', 'install(%s@%s) please wait ...', puppetModule, puppetVersion);
200 if (puppetModule === 'wechaty-puppet-puppeteer') {
201 await this.preInstallPuppeteer();
202 }
203 await npm_programmatic_1.default.install(`${puppetModule}@${puppetVersion}`, {
204 cwd: await pkg_dir_1.default(__dirname),
205 output: true,
206 save: false,
207 });
208 config_1.log.info('PuppetManager', 'install(%s@%s) done', puppetModule, puppetVersion);
209 }
210 /**
211 * Install all `wechaty-puppet-*` modules from `puppet-config.ts`
212 */
213 static async installAll() {
214 config_1.log.info('PuppetManager', 'installAll() please wait ...');
215 const skipList = [
216 '@juzibot/wechaty-puppet-donut',
217 '@juzibot/wechaty-puppet-wxwork', // wxwork puppet
218 ];
219 const moduleList = [];
220 for (const puppetModuleName of Object.keys(puppet_config_1.PUPPET_DEPENDENCIES)) {
221 const version = puppet_config_1.PUPPET_DEPENDENCIES[puppetModuleName];
222 if (version === '0.0.0' || skipList.includes(puppetModuleName)) {
223 continue;
224 }
225 moduleList.push(`${puppetModuleName}@${version}`);
226 }
227 await npm_programmatic_1.default.install(moduleList, {
228 cwd: await pkg_dir_1.default(__dirname),
229 output: true,
230 save: false,
231 });
232 }
233}
234exports.PuppetManager = PuppetManager;
235//# sourceMappingURL=puppet-manager.js.map
\No newline at end of file