Skip to content

Commit

Permalink
feat: add additional data to received message, move debugger to decor…
Browse files Browse the repository at this point in the history
…ator (#15)

* feat: add additional data to received message, move debugger to decorator

* test: update subscribe test

* test: update all tests

* test: fix bug when transform data on mock server

* refactor: move subscribe logic to folder
  • Loading branch information
melishev committed Feb 10, 2024
1 parent ddb284f commit 14b7a8c
Show file tree
Hide file tree
Showing 12 changed files with 138 additions and 105 deletions.
14 changes: 14 additions & 0 deletions src/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/** Envelopes the content in a string of a certain length */
export function formatString(text: string, count: number): string {
const spaceString = ' '.repeat(count)
return text + spaceString.substring(text.length)
}

/** Converts milliseconds into a conveniently readable unit */
export function fromMsToUp(ms: number): { value: number; unit: 'ms' | 's' | 'm' | 'h' } {
if (ms < 1000) return { value: ms, unit: 'ms' }
if (ms < 60000) return { value: ms / 1000, unit: 's' }
if (ms < 3600000) return { value: ms / 60000, unit: 'm' }

return { value: ms / 3600000, unit: 'h' }
}
14 changes: 2 additions & 12 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { type WSGOEventName, type WSGOConfig, type WSGOSubscriptions } from './types'

import { type WSGOSubscribeCallback } from './subscribe'

import { send } from './send'
import { subscribe } from './subscribe'
import type { WSGOSubscribeCallback } from './subscribe/types'
import { heartbeatStart, heartbeatStop, listenHeartbeat } from './heartbeat'

/** Method allows you create new WebSocket connection */
Expand Down Expand Up @@ -63,7 +62,7 @@ export default function create(
send(...args, ws, _config)
},
subscribe: (...args) => {
subscribe(subscriptions, ...args)
subscribe(...args, subscriptions, _config)
},
}
}
Expand Down Expand Up @@ -112,15 +111,6 @@ function _listen(ws: WebSocket, subscriptions: WSGOSubscriptions, _config: WSGOC
return
}

if (_config.debugging) {
if (message.event === 'exception') {
console.error(message.data)
} else {
const { event, data, time } = message
console.log(`%c${new Date(time).toLocaleTimeString()}%c`, 'color: gray', '', event, data)
}
}

if (message.event in subscriptions) {
subscriptions[message.event](message)
}
Expand Down
25 changes: 0 additions & 25 deletions src/subscribe.ts

This file was deleted.

52 changes: 52 additions & 0 deletions src/subscribe/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { formatString, fromMsToUp } from '../helpers'
import type { WSGOSubscribeResponse, WSGOSubscribeCallback } from './types'
import type { WSGOEventName, WSGOConfig, WSGOSubscriptions } from '../types'

/** Method allows you to subscribe to listen to a specific event */
export function subscribe<T>(
eventName: WSGOEventName,
callback: WSGOSubscribeCallback<T>,
subscriptions: WSGOSubscriptions,
_config: WSGOConfig,
): void {
if (eventName in subscriptions) return

callback = _subscribeDecoratorTransform<T>(callback, _config)

Object.assign(subscriptions, { [eventName]: callback })
}

/** Decorator adds aditional data to received events */
function _subscribeDecoratorTransform<T>(callback: WSGOSubscribeCallback<T>, _config: WSGOConfig): any {
return (message: Omit<WSGOSubscribeResponse<T>, 'timeReceived'>) => {
const transformedMessage: WSGOSubscribeResponse<T> = {
...message,
timeReceived: Date.now(),
}

_subscribeDebugger(transformedMessage, _config)
callback(transformedMessage)
}
}

function _subscribeDebugger(message: WSGOSubscribeResponse<any>, _config: WSGOConfig): void {
if (!_config.debugging) return

if (message.event === 'exception') {
console.error(message.data)
return
}

const { event, data, timeSended, timeReceived } = message
const timeDiff = fromMsToUp(timeReceived - timeSended)

// console.log(`%c${new Date(timeReceived).toLocaleTimeString()}%c`, 'color: gray', '', event, data)
// console.log(`%c${new Date(timeReceived).toLocaleTimeString()} %c${timeDiff}ms`, 'color: gray', 'color: green', event, data)
console.log(
`%c${new Date(timeReceived).toLocaleTimeString()} %c${formatString(`${timeDiff.value + timeDiff.unit}`, 5)}%c ${formatString(event, 30)}`,
'color: gray',
'color: green',
'',
data,
)
}
12 changes: 12 additions & 0 deletions src/subscribe/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export interface WSGOSubscribeResponse<T = any> {
/** Event name */
event: string
/** Event data */
data: T
/** Time when the server sent the event */
timeSended: number
/** Time when the client received the event */
timeReceived: number
}

export type WSGOSubscribeCallback<T> = (message: WSGOSubscribeResponse<T>) => any
15 changes: 5 additions & 10 deletions test/close.test.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
import WSGO from '../src/index'
import ws from 'ws'
import { createMockWSServer } from './utils'

describe('close', () => {
let port = 0
let port: number = 0
let server: ws.Server

beforeAll(() => {
server = new ws.WebSocketServer({ port })
const mockWSServer = createMockWSServer(port)

server.on('connection', (ws) => {
ws.on('message', (data, isBinary) => {
const message = isBinary ? data : data.toString()
ws.send(message)
})
})

port = (server.address() as ws.AddressInfo).port
server = mockWSServer.server
port = mockWSServer.port
})

afterAll(() => {
Expand Down
17 changes: 7 additions & 10 deletions test/create.test.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
import WSGO from '../src/index'
import ws from 'ws'
import { createMockWSServer } from './utils'

describe('create', () => {
let port = 0
let port: number = 0
let server: ws.Server

beforeAll(() => {
server = new ws.WebSocketServer({ port })
const mockWSServer = createMockWSServer(port)

server.on('connection', (ws) => {
ws.on('message', (data, isBinary) => {
const message = isBinary ? data : data.toString()
ws.send(message)
})
})

port = (server.address() as ws.AddressInfo).port
server = mockWSServer.server
port = mockWSServer.port
})

afterAll(() => {
Expand Down Expand Up @@ -52,4 +47,6 @@ describe('create', () => {
// Assert
expect(wsgo.ws).toBeUndefined()
})

// TODO: write tests for options
})
4 changes: 2 additions & 2 deletions test/heartbeat.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import WSGO from '../src/index'
import ws from 'ws'
import { createMockWSServer } from './utils'

describe('open', () => {
describe('heartbeat', () => {
const date = new Date(2000, 1, 1)

let port: number = 0
Expand Down Expand Up @@ -50,7 +50,7 @@ describe('open', () => {
)

// Assert
expect(event).toStrictEqual({ event: eventName, timeSended: Date.now() })
expect(event).toStrictEqual({ event: eventName, timeSended: Date.now(), timeReceived: Date.now() })
})

it.todo('must close the connection if no response is received from the server')
Expand Down
17 changes: 7 additions & 10 deletions test/open.test.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,17 @@
import { describe, it, expect, beforeAll, afterAll } from 'vitest'
import WSGO from '../src/index'
import ws from 'ws'
import { createMockWSServer } from './utils'

describe('open', () => {
let port = 0
let port: number = 0
let server: ws.Server

beforeAll(() => {
server = new ws.WebSocketServer({ port })
const mockWSServer = createMockWSServer(port)

server.on('connection', (ws) => {
ws.on('message', (data, isBinary) => {
const message = isBinary ? data : data.toString()
ws.send(message)
})
})

port = (server.address() as ws.AddressInfo).port
server = mockWSServer.server
port = mockWSServer.port
})

afterAll(() => {
Expand All @@ -38,4 +33,6 @@ describe('open', () => {
// check source data
expect(wsgo.ws?.url).toBe(`ws://localhost:${port}/`)
})

it.todo('should open new Websocket, after closing old', () => {})
})
36 changes: 18 additions & 18 deletions test/send.test.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,51 @@
import { describe, it, expect, vitest, beforeAll, afterAll } from 'vitest'
import { describe, it, expect, vi, beforeAll, afterAll } from 'vitest'
import WSGO from '../src/index'
import ws from 'ws'
import { createMockWSServer } from './utils'

describe('send', () => {
let port = 0
const date = new Date(2000, 1, 1)

let port: number = 0
let server: ws.Server

beforeAll(() => {
server = new ws.WebSocketServer({ port })

server.on('connection', (ws) => {
ws.on('message', (data, isBinary) => {
const message = isBinary ? data : data.toString()
ws.send(message)
})
})
const mockWSServer = createMockWSServer(port)

port = (server.address() as ws.AddressInfo).port
server = mockWSServer.server
port = mockWSServer.port
})

afterAll(() => {
server.close()
})

it('should send an event to the server', async () => {
const eventName = 'eventName'
const eventData = { text: 'Hello World!' }

let event: any

// Arrange
const wsgo = WSGO(`ws://localhost:${port}`)
await vitest.waitFor(() => {
await vi.waitFor(() => {
vi.setSystemTime(date)
if (wsgo.ws?.readyState !== window.WebSocket.OPEN) {
throw new Error()
}
})

// Act
wsgo.subscribe('eventName', (ev) => (event = ev))
wsgo.send('eventName', { text: 'Hello World!' })
await vitest.waitFor(() => {
wsgo.subscribe(eventName, (ev) => (event = ev))
wsgo.send(eventName, eventData)
await vi.waitFor(() => {
vi.setSystemTime(date)
if (event === undefined) {
throw new Error('Message not received back')
}
})

// Assert
expect(wsgo.ws).toBeInstanceOf(window.WebSocket)
expect(wsgo.ws?.readyState).toBe(window.WebSocket.OPEN)
expect(event).toStrictEqual({ event: 'eventName', data: { text: 'Hello World!' } })
expect(event).toStrictEqual({ event: eventName, data: eventData, timeSended: Date.now(), timeReceived: Date.now() })
})
})
35 changes: 18 additions & 17 deletions test/subscribe.test.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,52 @@
import { describe, it, expect, vitest, beforeAll, afterAll } from 'vitest'
import { describe, it, expect, vi, beforeAll, afterAll } from 'vitest'
import WSGO from '../src/index'
import ws from 'ws'
import { createMockWSServer } from './utils'

describe('subscribe', () => {
let port = 0
const date = new Date(2000, 1, 1)

let port: number = 0
let server: ws.Server

beforeAll(() => {
server = new ws.WebSocketServer({ port })

server.on('connection', (ws) => {
ws.on('message', (data, isBinary) => {
const message = isBinary ? data : data.toString()
ws.send(message)
})
})
const mockWSServer = createMockWSServer(port)

port = (server.address() as ws.AddressInfo).port
server = mockWSServer.server
port = mockWSServer.port
})

afterAll(() => {
server.close()
})

it('should subscribe to event', async () => {
const eventName = 'eventName'
const eventData = { text: 'Hello World!' }

let event: any

// Arrange
const wsgo = WSGO(`ws://localhost:${port}`)
await vitest.waitFor(() => {
await vi.waitFor(() => {
vi.setSystemTime(date)
if (wsgo.ws?.readyState !== window.WebSocket.OPEN) {
throw new Error()
}
})

// Act
wsgo.subscribe('eventName', (ev) => (event = ev))
wsgo.send('eventName', { text: 'Hello World!' })
await vitest.waitFor(() => {
wsgo.subscribe(eventName, (ev) => (event = ev))
wsgo.send(eventName, eventData)
await vi.waitFor(() => {
vi.setSystemTime(date)
if (event === undefined) {
throw new Error()
}
})
wsgo.close()

// Assert
expect(event).toStrictEqual({ event: 'eventName', data: { text: 'Hello World!' } })
expect(event).toStrictEqual({ event: eventName, data: eventData, timeSended: Date.now(), timeReceived: Date.now() })
})

it.todo('should work once', () => {})
Expand Down
Loading

0 comments on commit 14b7a8c

Please sign in to comment.