Skip to content

Commit

Permalink
chore: 1.4 backports (#2176)
Browse files Browse the repository at this point in the history
  • Loading branch information
shumkov authored Sep 27, 2024
2 parents 69a350b + 394c702 commit 75a933e
Show file tree
Hide file tree
Showing 12 changed files with 187 additions and 55 deletions.
36 changes: 25 additions & 11 deletions packages/dapi/lib/externalApis/tenderdash/BlockchainListener.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,12 @@ class BlockchainListener extends EventEmitter {
*/
constructor(tenderdashWsClient) {
super();

this.wsClient = tenderdashWsClient;

this.processLogger = logger.child({
process: 'BlockchainListener',
});
}

/**
Expand All @@ -30,14 +35,7 @@ class BlockchainListener extends EventEmitter {
* Subscribe to blocks and transaction results
*/
start() {
const processLogger = logger.child({
process: 'BlockchainListener',
});

processLogger.info('Subscribed to state transition results');

// Emit transaction results
this.wsClient.subscribe(TX_QUERY);
this.wsClient.on(TX_QUERY, (message) => {
const [hashString] = (message.events || []).map((event) => {
const hashAttribute = event.attributes.find((attribute) => attribute.key === 'hash');
Expand All @@ -53,15 +51,31 @@ class BlockchainListener extends EventEmitter {
return;
}

processLogger.trace(`received transaction result for ${hashString}`);
this.processLogger.trace(`Received transaction result for ${hashString}`);

this.emit(BlockchainListener.getTransactionEventName(hashString), message);
});

// TODO: It's not using
// Emit blocks and contained transactions
// this.wsClient.subscribe(NEW_BLOCK_QUERY);
// this.wsClient.on(NEW_BLOCK_QUERY, (message) => this.emit(EVENTS.NEW_BLOCK, message));
this.wsClient.on(NEW_BLOCK_QUERY, (message) => {
this.processLogger.trace('Received new platform block');

this.emit(EVENTS.NEW_BLOCK, message);
});

this.wsClient.on('connect', () => {
this.#subscribe();
});

if (this.wsClient.isConnected) {
this.#subscribe();
}
}

#subscribe() {
this.wsClient.subscribe(TX_QUERY);
this.wsClient.subscribe(NEW_BLOCK_QUERY);
this.processLogger.debug('Subscribed to platform blockchain events');
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const {
} = require('@dashevo/dapi-grpc');

const BlockchainListener = require('../../../externalApis/tenderdash/BlockchainListener');
const logger = require('../../../logger');

/**
* @param {BlockchainListener} blockchainListener
Expand All @@ -17,12 +18,23 @@ const BlockchainListener = require('../../../externalApis/tenderdash/BlockchainL
* @return {getStatusHandler}
*/
function getStatusHandlerFactory(blockchainListener, driveClient, tenderdashRpcClient) {
// Clean cache when new platform block committed
let cachedResponse = null;
let cleanCacheTimeout = null;

blockchainListener.on(BlockchainListener.EVENTS.NEW_BLOCK, () => {
function cleanCache() {
cachedResponse = null;
});

// cancel scheduled cache cleanup
if (cleanCacheTimeout !== null) {
clearTimeout(cleanCacheTimeout);
cleanCacheTimeout = null;
}

logger.trace({ endpoint: 'getStatus' }, 'cleanup cache');
}

// Clean cache when new platform block committed
blockchainListener.on(BlockchainListener.EVENTS.NEW_BLOCK, cleanCache);

// DAPI Software version
const packageJsonPath = path.resolve(__dirname, '..', '..', '..', '..', 'package.json');
Expand Down Expand Up @@ -210,6 +222,15 @@ function getStatusHandlerFactory(blockchainListener, driveClient, tenderdashRpcC
cachedResponse = new GetStatusResponse();
cachedResponse.setV0(v0);

// Cancel any existing scheduled cache cleanup
if (cleanCacheTimeout !== null) {
clearTimeout(cleanCacheTimeout);
cleanCacheTimeout = null;
}

// Clean cache in 3 minutes
cleanCacheTimeout = setTimeout(cleanCache, 3 * 60 * 1000);

return cachedResponse;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ describe('BlockchainListener', () => {
({ sinon } = this);
wsClientMock = new EventEmitter();
wsClientMock.subscribe = sinon.stub();

blockchainListener = new BlockchainListener(wsClientMock);
blockchainListener.start();

sinon.spy(blockchainListener, 'on');
sinon.spy(blockchainListener, 'off');
Expand Down Expand Up @@ -84,19 +84,23 @@ describe('BlockchainListener', () => {
});

describe('#start', () => {
it('should subscribe to transaction events from WS client', () => {
// TODO: We don't use it for now
// expect(wsClientMock.subscribe).to.be.calledTwice();
expect(wsClientMock.subscribe).to.be.calledOnce();
it('should subscribe to transaction events from WS client if it is connected', () => {
wsClientMock.isConnected = true;

blockchainListener.start();

expect(wsClientMock.subscribe).to.be.calledTwice();
expect(wsClientMock.subscribe.firstCall).to.be.calledWithExactly(
BlockchainListener.TX_QUERY,
);
// expect(wsClientMock.subscribe.secondCall).to.be.calledWithExactly(
// BlockchainListener.NEW_BLOCK_QUERY,
// );
expect(wsClientMock.subscribe.secondCall).to.be.calledWithExactly(
BlockchainListener.NEW_BLOCK_QUERY,
);
});

it.skip('should emit block when new block is arrived', (done) => {
it('should emit block when new block is arrived', (done) => {
blockchainListener.start();

blockchainListener.on(BlockchainListener.EVENTS.NEW_BLOCK, (message) => {
expect(message).to.be.deep.equal(blockMessageMock);

Expand All @@ -107,6 +111,8 @@ describe('BlockchainListener', () => {
});

it('should emit transaction when transaction is arrived', (done) => {
blockchainListener.start();

const topic = BlockchainListener.getTransactionEventName(transactionHash);

blockchainListener.on(topic, (message) => {
Expand Down
16 changes: 13 additions & 3 deletions packages/dashmate/src/docker/DockerCompose.js
Original file line number Diff line number Diff line change
Expand Up @@ -487,13 +487,23 @@ export default class DockerCompose {
* Logs
*
* @param {Config} config
* @return {Promise<void>}
* @param {string[]} services
* @param {Object} options
* @param {number} options.tail
* @return {Promise<{exitCode: number | null, out: string, err: string}>}
*/
async logs(config, services = []) {
async logs(config, services = [], options = {}) {
await this.throwErrorIfNotInstalled();

const args = [...services];
if (options.tail) {
args.unshift('--tail', options.tail.toString());
}

const commandOptions = this.#createOptions(config);

try {
return dockerCompose.logs(services, this.#createOptions(config));
return await dockerCompose.logs(args, commandOptions);
} catch (e) {
throw new DockerComposeError(e);
}
Expand Down
4 changes: 4 additions & 0 deletions packages/dashmate/src/doctor/analyse/analyseConfigFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ and revoke the previous certificate in the ZeroSSL dashboard`,
description: chalk`ZeroSSL certificate is not valid.`,
solution: chalk`Please run {bold.cyanBright dashmate ssl zerossl obtain} to get a new one.`,
},
[ERRORS.ZERO_SSL_API_ERROR]: {
description: ssl?.data?.error?.message,
solution: chalk`Please contact ZeroSSL support if needed.`,
},
}[ssl.error] ?? {};

if (description) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ export default function collectSamplesTaskFactory(
services.map(async (service) => {
const [inspect, logs] = (await Promise.allSettled([
dockerCompose.inspectService(config, service.name),
dockerCompose.logs(config, [service.name]),
dockerCompose.logs(config, [service.name], { tail: 300000 }),
])).map((e) => e.value || e.reason);

if (logs?.out) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ export default function obtainZeroSSLCertificateTaskFactory(
case ERRORS.CERTIFICATE_ID_IS_NOT_SET:
// eslint-disable-next-line no-param-reassign
task.output = 'Certificate is not configured yet, creating a new one';

// We need to create a new certificate
ctx.certificate = null;
break;
case ERRORS.PRIVATE_KEY_IS_NOT_PRESENT:
// If certificate exists but private key does not, then we can't set up TLS connection
Expand All @@ -85,6 +88,9 @@ export default function obtainZeroSSLCertificateTaskFactory(
case ERRORS.CERTIFICATE_EXPIRES_SOON:
// eslint-disable-next-line no-param-reassign
task.output = `Certificate exists but expires in less than ${ctx.expirationDays} days at ${ctx.certificate.expires}. Obtain a new one`;

// We need to create a new certificate
ctx.certificate = null;
break;
case ERRORS.CERTIFICATE_IS_NOT_VALIDATED:
// eslint-disable-next-line no-param-reassign
Expand All @@ -93,7 +99,12 @@ export default function obtainZeroSSLCertificateTaskFactory(
case ERRORS.CERTIFICATE_IS_NOT_VALID:
// eslint-disable-next-line no-param-reassign
task.output = 'Certificate is not valid. Create a new one';

// We need to create a new certificate
ctx.certificate = null;
break;
case ERRORS.ZERO_SSL_API_ERROR:
throw ctx.error;
default:
throw new Error(`Unknown error: ${error}`);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const ERRORS = {
CERTIFICATE_EXPIRES_SOON: 'CERTIFICATE_EXPIRES_SOON',
CERTIFICATE_IS_NOT_VALIDATED: 'CERTIFICATE_IS_NOT_VALIDATED',
CERTIFICATE_IS_NOT_VALID: 'CERTIFICATE_IS_NOT_VALID',
ZERO_SSL_API_ERROR: 'ZERO_SSL_API_ERROR',
};

/**
Expand Down Expand Up @@ -68,9 +69,22 @@ export default function validateZeroSslCertificateFactory(homeDir, getCertificat
data.isBundleFilePresent = fs.existsSync(data.bundleFilePath);

// This function will throw an error if certificate with specified ID is not present
const certificate = await getCertificate(data.apiKey, certificateId);
try {
data.certificate = await getCertificate(data.apiKey, certificateId);
} catch (e) {
if (e.code) {
data.error = e;

data.isExpiresSoon = certificate.isExpiredInDays(expirationDays);
return {
error: ERRORS.ZERO_SSL_API_ERROR,
data,
};
}

throw e;
}

data.isExpiresSoon = data.certificate.isExpiredInDays(expirationDays);

// If certificate exists but private key does not, then we can't setup TLS connection
// In this case we need to regenerate a certificate or put back this private key
Expand All @@ -82,17 +96,16 @@ export default function validateZeroSslCertificateFactory(homeDir, getCertificat
}

// We need to make sure that external IP and certificate IP match
if (certificate.common_name !== data.externalIp) {
if (data.certificate.common_name !== data.externalIp) {
return {
error: ERRORS.EXTERNAL_IP_MISMATCH,
data,
};
}

if (['pending_validation', 'draft'].includes(certificate.status)) {
if (['pending_validation', 'draft'].includes(data.certificate.status)) {
// Certificate is already created, so we just need to pass validation
// and download certificate file
data.certificate = certificate;

// We need to download new certificate bundle
data.isBundleFilePresent = false;
Expand All @@ -103,7 +116,7 @@ export default function validateZeroSslCertificateFactory(homeDir, getCertificat
};
}

if (certificate.status !== 'issued' || data.isExpiresSoon) {
if (data.certificate.status !== 'issued' || data.isExpiresSoon) {
// Certificate is going to expire soon, or current certificate is not valid
// we need to obtain a new one

Expand All @@ -128,8 +141,6 @@ export default function validateZeroSslCertificateFactory(homeDir, getCertificat
}

// Certificate is valid, so we might need only to download certificate bundle
data.certificate = certificate;

return {
data,
};
Expand Down
Loading

0 comments on commit 75a933e

Please sign in to comment.