wechaty-puppet-service
Version:
Puppet Service for Wechaty
152 lines • 7.49 kB
JavaScript
/**
* Wechaty Open Source Software - https://github.com/wechaty
*
* @copyright 2016 Huan LI (李卓桓) <https://github.com/huan>, and
* Wechaty Contributors <https://github.com/wechaty>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import util from 'util';
import { log, } from 'wechaty-puppet';
import { grpc, puppet as grpcPuppet, google as grpcGoogle, } from 'wechaty-grpc';
import { UniformResourceNameRegistry, } from 'file-box';
import { envVars, VERSION, GRPC_OPTIONS, } from '../config.js';
import { authImplToken, } from '../auth/mod.js';
import { TLS_INSECURE_SERVER_CERT, TLS_INSECURE_SERVER_KEY, } from '../auth/ca.js';
import { puppetImplementation, } from './puppet-implementation.js';
import { healthImplementation, } from './health-implementation.js';
import { uuidifyFileBoxLocal, } from '../file-box-helper/uuidify-file-box-local.js';
export class PuppetServer {
options;
grpcServer;
urnRegistry;
constructor(options) {
this.options = options;
log.verbose('PuppetServer', 'constructor({endpoint: "%s", puppet: "%s", token: "%s"})', options.endpoint, options.puppet, options.token);
}
version() {
return VERSION;
}
async start() {
log.verbose('PuppetServer', 'start()');
if (this.grpcServer) {
throw new Error('grpc server existed!');
}
if (!this.urnRegistry) {
log.verbose('PuppetServer', 'start() initializing FileBox UUID URN Registry ...');
this.urnRegistry = new UniformResourceNameRegistry();
await this.urnRegistry.init();
log.verbose('PuppetServer', 'start() initializing FileBox UUID URN Registry ... done');
}
/**
* Connect FileBox with UUID Manager
*/
const FileBoxUuid = uuidifyFileBoxLocal(this.urnRegistry);
log.verbose('PuppetServer', 'start() initializing gRPC Server with options "%s"', JSON.stringify(GRPC_OPTIONS));
this.grpcServer = new grpc.Server(GRPC_OPTIONS);
log.verbose('PuppetServer', 'start() initializing gRPC Server ... done', JSON.stringify(GRPC_OPTIONS));
log.verbose('PuppetServer', 'start() initializing puppet implementation with FileBoxUuid...');
const puppetImpl = puppetImplementation(this.options.puppet, FileBoxUuid);
log.verbose('PuppetServer', 'start() initializing puppet implementation with FileBoxUuid... done');
log.verbose('PuppetServer', 'start() initializing authorization with token ...');
const puppetImplAuth = authImplToken(this.options.token)(puppetImpl);
this.grpcServer.addService(grpcPuppet.PuppetService, puppetImplAuth);
log.verbose('PuppetServer', 'start() initializing authorization with token ... done');
log.verbose('PuppetServer', 'start() initializing gRPC health service ...');
const healthImpl = healthImplementation(this.options.puppet);
this.grpcServer.addService(grpcGoogle.HealthService, healthImpl);
log.verbose('PuppetServer', 'start() initializing gRPC health service ... done');
log.verbose('PuppetServer', 'start() initializing TLS CA ...');
const caCerts = envVars.WECHATY_PUPPET_SERVICE_TLS_CA_CERT();
const caCertBuf = caCerts
? Buffer.from(caCerts)
: null;
const certChain = Buffer.from(envVars.WECHATY_PUPPET_SERVICE_TLS_SERVER_CERT(this.options.tls?.serverCert)
|| TLS_INSECURE_SERVER_CERT);
const privateKey = Buffer.from(envVars.WECHATY_PUPPET_SERVICE_TLS_SERVER_KEY(this.options.tls?.serverKey)
|| TLS_INSECURE_SERVER_KEY);
log.verbose('PuppetServer', 'start() initializing TLS CA ... done');
const keyCertPairs = [{
cert_chain: certChain,
private_key: privateKey,
}];
/**
* Huan(202108): for maximum compatible with the non-tls community servers/clients,
* we introduced the WECHATY_PUPPET_SERVICE_NO_TLS_INSECURE_{SERVER,CLIENT} environment variables.
* if it has been set, then we will run under HTTP instead of HTTPS
*/
log.verbose('PuppetServer', 'start() initializing gRPC server credentials ...');
let credential;
if (envVars.WECHATY_PUPPET_SERVICE_NO_TLS_INSECURE_SERVER(this.options.tls?.disable)) {
log.warn('PuppetServer', 'start() TLS disabled: INSECURE!');
credential = grpc.ServerCredentials.createInsecure();
}
else {
log.verbose('PuppetServer', 'start() TLS enabled.');
credential = grpc.ServerCredentials.createSsl(caCertBuf, keyCertPairs);
}
log.verbose('PuppetServer', 'start() initializing gRPC server credentials ... done');
/***
* Start Grpc Server
*/
log.verbose('PuppetServer', 'start() gRPC server starting ...');
const port = await util.promisify(this.grpcServer.bindAsync
.bind(this.grpcServer))(this.options.endpoint, credential);
if (port === 0) {
throw new Error('grpc server bind fail!');
}
this.grpcServer.start();
log.verbose('PuppetServer', 'start() gRPC server starting ... done');
}
async stop() {
log.verbose('PuppetServer', 'stop()');
if (this.grpcServer) {
const grpcServer = this.grpcServer;
this.grpcServer = undefined;
log.verbose('PuppetServer', 'stop() shuting down gRPC server ...');
// const future = await util.promisify(
// grpcServer.tryShutdown
// .bind(grpcServer),
// )()
try {
await new Promise(resolve => setImmediate(resolve));
grpcServer.forceShutdown();
/**
* Huan(202110) grpc.tryShutdown() never return if client close the connection. #176
* @see https://github.com/wechaty/puppet-service/issues/176
*
* FIXME: even after called `forceShutdown()`, the `tryShutdown()` can not resolved.
* commented out the `await` for now to make it work temporary.
*/
// await future
}
catch (e) {
log.warn('PuppetServer', 'stop() gRPC shutdown rejection: %s', e.message);
}
finally {
log.verbose('PuppetServer', 'stop() shuting down gRPC server ... done');
}
}
else {
log.warn('PuppetServer', 'stop() no grpcServer exist');
}
if (this.urnRegistry) {
log.verbose('PuppetServer', 'stop() destory URN Registry ...');
await this.urnRegistry.destroy();
this.urnRegistry = undefined;
log.verbose('PuppetServer', 'stop() destory URN Registry ... done');
}
}
}
//# sourceMappingURL=puppet-server.js.map