Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ghost/admin/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ghost-admin",
"version": "6.44.1-rc.0",
"version": "6.44.2-rc.0",
"description": "Ember.js admin client for Ghost",
"author": "Ghost Foundation",
"homepage": "http://ghost.org",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,44 @@
const logging = require('@tryghost/logging');

module.exports.connectAndSend = (socketAddress, message) => {
import net from 'node:net';
import logging from '@tryghost/logging';
import type {JsonValue} from 'type-fest';

type SocketAddress = Readonly<{
host: string;
port: number;
}>;

type ConnectOptions = Readonly<{
tries: number;
}>;

const getErrorCode = (err: unknown): undefined | string => (
err && typeof err === 'object' && 'code' in err && typeof err.code === 'string'
? err.code
: undefined
);

const isValidPort = (port: unknown): port is number => (
typeof port === 'number' &&
Number.isInteger(port) &&
port >= 1 &&
port <= 65535
);

const hasSocketAddress = (socketAddress?: Partial<SocketAddress>): socketAddress is SocketAddress => (
typeof socketAddress?.host === 'string' && Boolean(socketAddress.host) &&
isValidPort(socketAddress.port)
);

export const connectAndSend = (socketAddress?: Partial<SocketAddress>, message?: JsonValue): Promise<void> => {
// Very basic guard against bad calls
if (!socketAddress || !socketAddress.host || !socketAddress.port || !logging || !logging.info || !logging.warn || !message) {
if (!hasSocketAddress(socketAddress) || !logging || !logging.info || !logging.warn || message === undefined) {
return Promise.resolve();
}

const net = require('net');
const client = new net.Socket();

return new Promise((resolve) => {
const connect = (options = {}) => {
return new Promise((resolve: () => void) => {
const connect = (options: ConnectOptions) => {
let wasResolved = false;

const waitTimeout = setTimeout(() => {
Expand Down Expand Up @@ -51,8 +79,8 @@ module.exports.connectAndSend = (socketAddress, message) => {
}
});

client.on('error', (err) => {
logging.warn(`Can't connect to the bootstrap socket (${socketAddress.host} ${socketAddress.port}) ${err.code}.`);
client.on('error', (err: Error) => {
logging.warn(`Can't connect to the bootstrap socket (${socketAddress.host} ${socketAddress.port}) ${getErrorCode(err)}.`);

client.removeAllListeners();

Expand All @@ -66,10 +94,9 @@ module.exports.connectAndSend = (socketAddress, message) => {
// retry
logging.warn('Retrying...');

options.tries = options.tries + 1;
const retryTimeout = setTimeout(() => {
clearTimeout(retryTimeout);
connect(options);
connect({tries: options.tries + 1});
}, 150);
} else {
if (wasResolved) {
Expand Down
2 changes: 1 addition & 1 deletion ghost/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ghost",
"version": "6.44.1-rc.0",
"version": "6.44.2-rc.0",
"description": "The professional publishing platform",
"author": "Ghost Foundation",
"homepage": "https://ghost.org",
Expand Down
7 changes: 0 additions & 7 deletions ghost/core/test/unit/server/lib/bootstrap-socket.test.js

This file was deleted.

7 changes: 7 additions & 0 deletions ghost/core/test/unit/server/lib/bootstrap-socket.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {connectAndSend} from '../../../../core/server/lib/bootstrap-socket';

describe('Connect and send', function () {
it('Resolves a promise for a bad call', async function () {
await connectAndSend();
});
});
19 changes: 13 additions & 6 deletions ghost/core/test/unit/server/notify.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
const assert = require('node:assert/strict');
const rewire = require('rewire');
const sinon = require('sinon');

const configUtils = require('../../utils/config-utils');
const events = require('../../../core/server/lib/common/events');
const bootstrapSocket = require('../../../core/server/lib/bootstrap-socket');

describe('Notify', function () {
describe('notifyServerStarted', function () {
Expand All @@ -14,22 +14,29 @@ describe('Notify', function () {
beforeEach(function () {
// Have to re-require each time to clear the internal flag
delete require.cache[require.resolve('../../../core/server/notify')];
notify = require('../../../core/server/notify');

socketStub = sinon.stub();
notify = rewire('../../../core/server/notify');
notify.__set__('require', (path) => {
if (path === './lib/bootstrap-socket') {
return {
connectAndSend: socketStub
};
}

return require(path);
});

// process.send isn't set for tests, we can safely override;
process.send = sinon.stub();

// stub socket connectAndSend method
socketStub = sinon.stub(bootstrapSocket, 'connectAndSend');

// Spy for the events that get called
eventSpy = sinon.spy(events, 'emit');
});

afterEach(async function () {
process.send = undefined;
await configUtils.restore();
socketStub.restore();
eventSpy.restore();
});

Expand Down
Loading