Skip to content

Commit

Permalink
🎨 structural refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
Petter Andersson committed Nov 11, 2022
1 parent 3305466 commit 2492f48
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 103 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createSmsContentService, formatContent } from '../services/sms-content-service'
import { getContentService, formatContent } from '../services/content-service'

it('returns a templated string with an injected verificationcode', async () => {
expect(await createSmsContentService('<base_path>').build({
expect(await getContentService('<base_path>').build({
number: '+46722334451',
verificationCode: 'dcd77d41-c1fa-4d90-851a-4d5f03d0183a',
isVerified: false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

import { MqEngine } from '../types'
import { createSmsListenerService } from '../services/sms-listener-service'
import { getListenerService } from '../services/listener-service'

const emptyHandler = async () => {
return
Expand All @@ -12,15 +12,15 @@ it('should throw on an unrecoverable connection issue', async () => {
const engine: MqEngine = ({
connect: async () => { throw Error('Connect') },
})
await expect(createSmsListenerService(testParams, engine, false).listen(emptyHandler)).rejects.toThrowError('Connect')
await expect(getListenerService(testParams, engine, emptyHandler, false).listen(emptyHandler)).rejects.toThrowError('Connect')
})

it('should throw on an unrecoverable channel creation issue', async () => {
const engine: MqEngine = ({
connect: async () => Promise.resolve(),
createChannel: async () => { throw Error('CreateChannel')},
})
await expect(createSmsListenerService(testParams, engine, false).listen(emptyHandler)).rejects.toThrowError('CreateChannel')
await expect(getListenerService(testParams, engine, emptyHandler, false).listen(emptyHandler)).rejects.toThrowError('CreateChannel')
})

it('should throw on an unrecoverable assert exchange issue', async () => {
Expand All @@ -29,7 +29,7 @@ it('should throw on an unrecoverable assert exchange issue', async () => {
createChannel: async () => Promise.resolve(),
assertExchange: async () => { throw Error('AssertExchange')},
})
await expect(createSmsListenerService(testParams, engine, false).listen(emptyHandler)).rejects.toThrowError('AssertExchange')
await expect(getListenerService(testParams, engine, emptyHandler, false).listen(emptyHandler)).rejects.toThrowError('AssertExchange')
})

it('should throw on an unrecoverable assert queue issue', async () => {
Expand All @@ -39,7 +39,7 @@ it('should throw on an unrecoverable assert queue issue', async () => {
assertExchange: async () => Promise.resolve(),
assertQueue: async () => { throw Error('AssertQueue') },
})
await expect(createSmsListenerService(testParams, engine, false).listen(emptyHandler)).rejects.toThrowError('AssertQueue')
await expect(getListenerService(testParams, engine, emptyHandler, false).listen(emptyHandler)).rejects.toThrowError('AssertQueue')
})

it('should throw on an unrecoverable bind queue issue', async () => {
Expand All @@ -50,7 +50,7 @@ it('should throw on an unrecoverable bind queue issue', async () => {
assertQueue: async () => Promise.resolve(),
bindQueue: async () => { throw Error('BindQueue') },
})
await expect(createSmsListenerService(testParams, engine, false).listen(emptyHandler)).rejects.toThrowError('BindQueue')
await expect(getListenerService(testParams, engine, emptyHandler, false).listen(emptyHandler)).rejects.toThrowError('BindQueue')
})

describe('should call ack after successful send', () => {
Expand All @@ -73,6 +73,9 @@ describe('should call ack after successful send', () => {
})),
fields: {
routingKey: 'phone.changed',
deliveryTag: 0,
redelivered: false,
exchange: '<exchange>',
},
properties: {},
})
Expand All @@ -83,13 +86,13 @@ describe('should call ack after successful send', () => {

it('should call ack after SUCCESSFUL send', async () => {
success = false
await createSmsListenerService(testParams, engine, false).listen(emptyHandler)
await getListenerService(testParams, engine, emptyHandler, false).listen(emptyHandler)
expect(success).toBeTruthy()
})

it('should call ack after FAILURE to send', async () => {
success = false
await createSmsListenerService(testParams, engine, false).listen(async () => { throw Error('FailToSend') })
await getListenerService(testParams, engine, emptyHandler, false).listen(async () => { throw Error('FailToSend') })
expect(success).toBeTruthy()
})
})
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { Services } from './types'
const services: Services = createServicesFromEnv()

/** Start daemon */
services.smsListenerService.listen(async message => await services.smsSendService.send({
services.listenerService.listen(async message => await services.sendService.send({
receiver: message.number,
message: await services.smsContentService.build(message),
message: await services.contentService.build(message),
})).catch(err => {
console.error(err)
process.exit(1)
Expand Down
12 changes: 6 additions & 6 deletions src/services.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { createSmsContentServiceFromEnv } from './services/sms-content-service'
import { createSmsListenerServiceFromEnv } from './services/sms-listener-service'
import { createSmsSendServiceFromEnv } from './services/sms-send-service'
import { getContentServiceFromEnv } from './services/content-service'
import { getListenerServiceFromEnv } from './services/listener-service'
import { getSendServiceFromEnv } from './services/send-service'
import { Services } from './types'

const createServicesFromEnv = (): Services => ({
smsListenerService: createSmsListenerServiceFromEnv(),
smsContentService: createSmsContentServiceFromEnv(),
smsSendService: createSmsSendServiceFromEnv(),
listenerService: getListenerServiceFromEnv(),
contentService: getContentServiceFromEnv(),
sendService: getSendServiceFromEnv(),
})

export { createServicesFromEnv }
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { getEnv } from '@helsingborg-stad/gdi-api-node'
import { MqMessageBody, SmsContentService } from '../types'
import { MqMessageBody, ContentService } from '../types'

const formatContent = (verificationCode: string, smsBasePath: string): string =>`Hej!
Tack för att du angett ditt telefonnummer på helsingborg.se
För att verifiera att det är ditt nummer, vänligen bekräfta genom
att klicka på denna länk: ${smsBasePath}/${verificationCode}`

const createSmsContentServiceFromEnv = (): SmsContentService => createSmsContentService(
const getContentServiceFromEnv = (): ContentService => getContentService(
getEnv('SMS_BASEPATH')
)

const createSmsContentService = (smsBasePath: string): SmsContentService => ({
const getContentService = (smsBasePath: string): ContentService => ({
build: async (message: MqMessageBody): Promise<string> => formatContent(message.verificationCode, smsBasePath),
})

export { createSmsContentService, createSmsContentServiceFromEnv, formatContent }
export { getContentService, getContentServiceFromEnv, formatContent }
64 changes: 64 additions & 0 deletions src/services/listener-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@

import { ListenerService, MqMessageEnvelope, MqEngine } from '../types'
import { getEnv } from '@helsingborg-stad/gdi-api-node'
import { createAmqpEngine } from '../helpers/amqp-engine'

type ListenerServiceParams = {
uri: string;
exchange: string;
queue: string;
filter: string;
}

const getListenerServiceFromEnv = (): ListenerService => getListenerService({
uri: getEnv('AMQP_URI'),
exchange: getEnv('AMQP_EXCHANGE'),
queue: getEnv('AMQP_QUEUE'),
filter: getEnv('AMQP_FILTER'),
}, createAmqpEngine())

const getListenerService = ({ uri, exchange, queue, filter }: ListenerServiceParams, engine: MqEngine, debug: (data: string) => void = console.debug, infinite = true): ListenerService => ({
listen: async (handler) => {
debug(`Connecting to ${uri}...`)
await engine.connect(uri)
// Assign graceful close on Ctrl+C)
process.once('SIGINT', async () => {
await engine.close()
})

debug('Creating channel...')
await engine.createChannel()

debug(`Asserting durable topic exchange (${exchange}) ...`)
await engine.assertExchange(exchange)

debug(`Asserting durable queue (${queue})...`)
await engine.assertQueue(queue)

debug(`Binding queue with filter (${filter})...`)
await engine.bindQueue(queue, exchange, filter)

debug('waiting for messages. Ctrl-C to exit...')

// Message loop (Breaks on CTRL+C)
let didFail = false
do {
await engine.consume(queue, async (message: MqMessageEnvelope) => {
debug(message.content.toString())

try {
await handler(JSON.parse(message.content.toString()))
}
catch(error) {
debug(`Failed to send message (${error})`)
}
finally {
await engine.ack(message).catch(() => debug('Failed to ack message'))
}
}).catch(() => didFail = true)
} while (infinite && !didFail)
},
})

export { getListenerServiceFromEnv, getListenerService }

Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { SmsSendService } from '../types'
import { SendService } from '../types'
import * as superagent from 'superagent'
import { getEnv } from '@helsingborg-stad/gdi-api-node'
import { v4 as uuidv4 } from 'uuid'

const createSmsSendServiceFromEnv = (): SmsSendService => createSmsSendService(
const getSendServiceFromEnv = (): SendService => getSendService(
getEnv('SMS_PROXY_URL'),
getEnv('SMS_PROXY_KEY')
)

const createSmsSendService = (smsProxyUrl: string, smsProxyKey: string): SmsSendService => ({
const getSendService = (smsProxyUrl: string, smsProxyKey: string): SendService => ({
send: async ({ receiver, message }) => {
const body = {
jsonapi: {
Expand All @@ -31,4 +31,4 @@ const createSmsSendService = (smsProxyUrl: string, smsProxyKey: string): SmsSend
},
})

export { createSmsSendService, createSmsSendServiceFromEnv }
export { getSendService, getSendServiceFromEnv }
70 changes: 0 additions & 70 deletions src/services/sms-listener-service.ts

This file was deleted.

19 changes: 12 additions & 7 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
export interface Services {
smsListenerService: SmsListenerService,
smsContentService: SmsContentService,
smsSendService: SmsSendService,
listenerService: ListenerService,
contentService: ContentService,
sendService: SendService,
}
export interface SmsSendService {
export interface SendService {
send: ({ receiver, message } : SmsMessage) => Promise<void>
}
export interface SmsContentService {
export interface ContentService {
build: (message: MqMessageBody) => Promise<string>
}

export interface SmsListenerService {
export interface ListenerService {
listen: (handler: (message: MqMessageBody) => Promise<void> ) => Promise<void>
}
export interface SmsMessage {
Expand All @@ -25,7 +25,12 @@ export interface MqMessageBody {
}
export interface MqMessageEnvelope {
content: Buffer;
fields: any;
fields: {
routingKey: string;
deliveryTag: number;
redelivered: boolean;
exchange: string;
};
properties: any;
}
export interface MqEngine {
Expand Down

0 comments on commit 2492f48

Please sign in to comment.