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
5 changes: 5 additions & 0 deletions connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ export async function createHsync(config) {
hsyncClient.listeners = initListeners(hsyncClient);
hsyncClient.relays = initRelays(hsyncClient);

// Enable auto-relay for web port (issue #15)
if (port) {
hsyncClient.relays.setWebPort(port);
}

const events = new EventEmitter();

hsyncClient.on = events.on.bind(events);
Expand Down
17 changes: 16 additions & 1 deletion lib/socket-relays.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ export function setNet(netImpl) {

export function initRelays(hsyncClient) {
const cachedRelays = {};
let webPort = null;

function setWebPort(port) {
webPort = port;
debug('web port set for auto-relay:', port);
}

function getSocketRelays() {
const hKeys = Object.keys(cachedRelays);
Expand Down Expand Up @@ -45,8 +51,15 @@ export function initRelays(hsyncClient) {
return `closeRelaySocket no matching socket for ${socketId}`;
});

const relay = cachedRelays['p' + port];
let relay = cachedRelays['p' + port];
debug('connect relay', port, socketId, peer.hostName);

// Auto-create relay if port matches web port (issue #15)
if (!relay && webPort && port === webPort) {
debug('auto-creating relay for web port:', port);
relay = addSocketRelay({ port, targetHost: 'localhost', targetPort: port });
}

if (!relay) {
throw new Error('no relay found for port: ' + port);
}
Expand Down Expand Up @@ -112,11 +125,13 @@ export function initRelays(hsyncClient) {
hsyncClient.addSocketRelay = addSocketRelay;
hsyncClient.getSocketRelays = getSocketRelays;
hsyncClient.connectSocket = connectSocket;
hsyncClient.setWebPort = setWebPort;

return {
// receiveListenerData,
getSocketRelays,
connectSocket,
addSocketRelay,
setWebPort,
};
}
70 changes: 70 additions & 0 deletions test/unit/socket-relays.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,27 @@ describe('socket-relays', () => {
expect(mockHsyncClient.addSocketRelay).toBeTypeOf('function');
expect(mockHsyncClient.getSocketRelays).toBeTypeOf('function');
expect(mockHsyncClient.connectSocket).toBeTypeOf('function');
expect(mockHsyncClient.setWebPort).toBeTypeOf('function');
});

it('should return setWebPort in returned object', () => {
const relays = initRelays(mockHsyncClient);

expect(relays.setWebPort).toBeTypeOf('function');
});
});

describe('setWebPort', () => {
let relays;

beforeEach(() => {
relays = initRelays(mockHsyncClient);
});

it('should store web port for auto-relay', () => {
// setWebPort stores the port internally - no return value
relays.setWebPort(3000);
// No error means success
});
});

Expand Down Expand Up @@ -201,6 +222,55 @@ describe('socket-relays', () => {
).toThrow('no relay found for port: 9999');
});

it('should auto-create relay for web port (issue #15)', async () => {
// Set web port without explicit relay
relays.setWebPort(3000);

// Should NOT throw - should auto-create relay for web port
const result = await relays.connectSocket(mockPeer, {
port: 3000,
socketId: 'auto-relay-socket',
hostName: 'remote.example.com',
});

expect(result.socketId).toBe('auto-relay-socket');
expect(result.targetHost).toBe('localhost');
expect(result.targetPort).toBe(3000);
expect(mockSocket.connect).toHaveBeenCalledWith(3000, 'localhost', expect.any(Function));
});

it('should still throw for non-web ports when web port is set', () => {
relays.setWebPort(3000);

// Different port should still throw
expect(() =>
relays.connectSocket(mockPeer, {
port: 9999,
socketId: 'test-socket',
hostName: 'remote.example.com',
})
).toThrow('no relay found for port: 9999');
});

it('should prefer explicit relay over auto-relay', async () => {
relays.setWebPort(3000);
relays.addSocketRelay({
port: 3000,
targetPort: 4000,
targetHost: 'custom-host.local',
});

const result = await relays.connectSocket(mockPeer, {
port: 3000,
socketId: 'explicit-relay-socket',
hostName: 'remote.example.com',
});

// Should use explicit relay config, not auto-relay
expect(result.targetHost).toBe('custom-host.local');
expect(result.targetPort).toBe(4000);
});

it('should create socket and connect to relay target', async () => {
relays.addSocketRelay({
port: 3000,
Expand Down