Skip to content

Commit

Permalink
feat: get peering details (#1805)
Browse files Browse the repository at this point in the history
  • Loading branch information
mkurapov authored Sep 1, 2023
1 parent ad8d0de commit 3250663
Show file tree
Hide file tree
Showing 9 changed files with 288 additions and 6 deletions.
38 changes: 33 additions & 5 deletions packages/backend/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ import { createRedisDataStore } from './middleware/cache/data-stores/redis'
import { createRedisLock } from './middleware/lock/redis'
import { CombinedPaymentService } from './open_payments/payment/combined/service'
import { FeeService } from './fee/service'
import { AutoPeeringService } from './auto-peering/service'
import { AutoPeeringRoutes } from './auto-peering/routes'

export interface AppContextData {
logger: Logger
Expand Down Expand Up @@ -203,13 +205,16 @@ export interface AppServices {
redis: Promise<Redis>
combinedPaymentService: Promise<CombinedPaymentService>
feeService: Promise<FeeService>
autoPeeringService: Promise<AutoPeeringService>
autoPeeringRoutes: Promise<AutoPeeringRoutes>
}

export type AppContainer = IocContract<AppServices>

export class App {
private openPaymentsServer!: Server
private adminServer!: Server
private autoPeeringServer!: Server
public apolloServer!: ApolloServer
public closeEmitter!: EventEmitter
public isShuttingDown = false
Expand Down Expand Up @@ -477,19 +482,42 @@ export class App {
this.openPaymentsServer = koa.listen(port)
}

public async startAutoPeeringServer(port: number | string): Promise<void> {
const koa = await this.createKoaServer()

const autoPeeringRoutes = await this.container.use('autoPeeringRoutes')
const router = new Router<DefaultState, AppContext>()

router.use(bodyParser())

router.get('/', autoPeeringRoutes.get)

koa.use(router.routes())

this.autoPeeringServer = koa.listen(port)
}

public async shutdown(): Promise<void> {
return new Promise((resolve): void => {
this.isShuttingDown = true
this.closeEmitter.emit('shutdown')

if (this.openPaymentsServer) {
this.isShuttingDown = true
this.closeEmitter.emit('shutdown')
this.openPaymentsServer.close((): void => {
resolve()
})
}

if (this.adminServer) {
this.adminServer.close((): void => {
resolve()
})
this.openPaymentsServer.close((): void => {
}

if (this.autoPeeringServer) {
this.autoPeeringServer.close((): void => {
resolve()
})
} else {
resolve()
}
})
}
Expand Down
16 changes: 16 additions & 0 deletions packages/backend/src/asset/service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,20 @@ describe('Asset Service', (): void => {
getPage: (pagination?: Pagination) => assetService.getPage(pagination)
})
})

describe('getAll', (): void => {
test('returns all assets', async (): Promise<void> => {
const assets = await Promise.all([
assetService.create(randomAsset()),
assetService.create(randomAsset()),
assetService.create(randomAsset())
])

await expect(assetService.getAll()).resolves.toEqual(assets)
})

test('returns empty array if no assets', async (): Promise<void> => {
await expect(assetService.getAll()).resolves.toEqual([])
})
})
})
8 changes: 7 additions & 1 deletion packages/backend/src/asset/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export interface AssetService {
update(options: UpdateOptions): Promise<Asset | AssetError>
get(id: string): Promise<void | Asset>
getPage(pagination?: Pagination): Promise<Asset[]>
getAll(): Promise<Asset[]>
}

interface ServiceDependencies extends BaseService {
Expand All @@ -48,7 +49,8 @@ export async function createAssetService({
create: (options) => createAsset(deps, options),
update: (options) => updateAsset(deps, options),
get: (id) => getAsset(deps, id),
getPage: (pagination?) => getAssetsPage(deps, pagination)
getPage: (pagination?) => getAssetsPage(deps, pagination),
getAll: () => getAll(deps)
}
}

Expand Down Expand Up @@ -118,3 +120,7 @@ async function getAssetsPage(
): Promise<Asset[]> {
return await Asset.query(deps.knex).getPage(pagination)
}

async function getAll(deps: ServiceDependencies): Promise<Asset[]> {
return await Asset.query(deps.knex)
}
68 changes: 68 additions & 0 deletions packages/backend/src/auto-peering/routes.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { IocContract } from '@adonisjs/fold'
import { initIocContainer } from '..'
import { AppContext, AppServices } from '../app'
import { Config } from '../config/app'
import { createTestApp, TestContainer } from '../tests/app'
import { createAsset } from '../tests/asset'
import { createContext } from '../tests/context'
import { truncateTables } from '../tests/tableManager'
import { AutoPeeringRoutes } from './routes'

describe('Auto Peering Routes', (): void => {
let deps: IocContract<AppServices>
let appContainer: TestContainer
let autoPeeringRoutes: AutoPeeringRoutes

beforeAll(async (): Promise<void> => {
deps = initIocContainer({ ...Config, enableAutoPeering: true })
appContainer = await createTestApp(deps)
autoPeeringRoutes = await deps.use('autoPeeringRoutes')
})

afterEach(async (): Promise<void> => {
await truncateTables(appContainer.knex)
})

afterAll(async (): Promise<void> => {
await appContainer.shutdown()
})

describe('get', (): void => {
test('returns peering details with assets', async (): Promise<void> => {
const assets = await Promise.all([
createAsset(deps),
createAsset(deps),
createAsset(deps)
])

const ctx = createContext<AppContext>({
headers: { Accept: 'application/json' },
url: `/`
})

await expect(autoPeeringRoutes.get(ctx)).resolves.toBeUndefined()
expect(ctx.body).toEqual({
ilpAddress: Config.ilpAddress,
assets: expect.arrayContaining(
assets.map((asset) => ({
code: asset.code,
scale: asset.scale
}))
)
})
})

test('returns peering details without assets', async (): Promise<void> => {
const ctx = createContext<AppContext>({
headers: { Accept: 'application/json' },
url: `/`
})

await expect(autoPeeringRoutes.get(ctx)).resolves.toBeUndefined()
expect(ctx.body).toEqual({
ilpAddress: Config.ilpAddress,
assets: []
})
})
})
})
35 changes: 35 additions & 0 deletions packages/backend/src/auto-peering/routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { AppContext } from '../app'
import { BaseService } from '../shared/baseService'
import { AutoPeeringService } from './service'

export interface ServiceDependencies extends BaseService {
autoPeeringService: AutoPeeringService
}

export interface AutoPeeringRoutes {
get(ctx: AppContext): Promise<void>
}

export async function createAutoPeeringRoutes(
deps_: ServiceDependencies
): Promise<AutoPeeringRoutes> {
const deps: ServiceDependencies = {
...deps_,
logger: deps_.logger.child({
service: 'AutoPeeringRoutes'
})
}

return {
get: (ctx: AppContext) => getPeeringDetails(deps, ctx)
}
}

async function getPeeringDetails(
deps: ServiceDependencies,
ctx: AppContext
): Promise<void> {
const peeringDetails = await deps.autoPeeringService.getPeeringDetails()

ctx.body = peeringDetails
}
55 changes: 55 additions & 0 deletions packages/backend/src/auto-peering/service.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { IocContract } from '@adonisjs/fold'
import { initIocContainer } from '..'
import { AppServices } from '../app'
import { Config } from '../config/app'
import { createTestApp, TestContainer } from '../tests/app'
import { createAsset } from '../tests/asset'
import { truncateTables } from '../tests/tableManager'
import { AutoPeeringService } from './service'

describe('Auto Peering Service', (): void => {
let deps: IocContract<AppServices>
let appContainer: TestContainer
let autoPeeringService: AutoPeeringService

beforeAll(async (): Promise<void> => {
deps = initIocContainer({ ...Config, enableAutoPeering: true })
appContainer = await createTestApp(deps)
autoPeeringService = await deps.use('autoPeeringService')
})

afterEach(async (): Promise<void> => {
await truncateTables(appContainer.knex)
})

afterAll(async (): Promise<void> => {
await appContainer.shutdown()
})

describe('getPeeringDetails', (): void => {
test('returns peering details', async (): Promise<void> => {
const assets = await Promise.all([
createAsset(deps),
createAsset(deps),
createAsset(deps)
])

expect(autoPeeringService.getPeeringDetails()).resolves.toEqual({
ilpAddress: Config.ilpAddress,
assets: expect.arrayContaining(
assets.map((asset) => ({
code: asset.code,
scale: asset.scale
}))
)
})
})

test('returns peering details with no assets', async (): Promise<void> => {
expect(autoPeeringService.getPeeringDetails()).resolves.toEqual({
ilpAddress: Config.ilpAddress,
assets: []
})
})
})
})
46 changes: 46 additions & 0 deletions packages/backend/src/auto-peering/service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { AssetService } from '../asset/service'
import { IAppConfig } from '../config/app'
import { BaseService } from '../shared/baseService'

export interface PeeringDetails {
ilpAddress: string
assets: { code: string; scale: number }[]
}

export interface AutoPeeringService {
getPeeringDetails(): Promise<PeeringDetails>
}

export interface ServiceDependencies extends BaseService {
assetService: AssetService
config: IAppConfig
}

export async function createAutoPeeringService(
deps_: ServiceDependencies
): Promise<AutoPeeringService> {
const deps: ServiceDependencies = {
...deps_,
logger: deps_.logger.child({
service: 'AutoPeeringService'
})
}

return {
getPeeringDetails: () => getPeeringDetails(deps)
}
}

async function getPeeringDetails(
deps: ServiceDependencies
): Promise<PeeringDetails> {
const assets = await deps.assetService.getAll()

return {
ilpAddress: deps.config.ilpAddress,
assets: assets.map((asset) => ({
code: asset.code,
scale: asset.scale
}))
}
}
2 changes: 2 additions & 0 deletions packages/backend/src/config/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ export const Config = {
openPaymentsUrl: envString('OPEN_PAYMENTS_URL', 'http://127.0.0.1:3003'),
openPaymentsPort: envInt('OPEN_PAYMENTS_PORT', 3003),
connectorPort: envInt('CONNECTOR_PORT', 3002),
autoPeeringServerPort: envInt('AUTO_PEERING_SERVER_PORT', 3005),
enableAutoPeering: envBool('ENABLE_AUTO_PEERING', false),
databaseUrl:
process.env.NODE_ENV === 'test'
? `${process.env.DATABASE_URL}_${process.env.JEST_WORKER_ID}`
Expand Down
26 changes: 26 additions & 0 deletions packages/backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ import { createReceiverService } from './open_payments/receiver/service'
import { createRemoteIncomingPaymentService } from './open_payments/payment/incoming_remote/service'
import { createCombinedPaymentService } from './open_payments/payment/combined/service'
import { createFeeService } from './fee/service'
import { createAutoPeeringService } from './auto-peering/service'
import { createAutoPeeringRoutes } from './auto-peering/routes'

BigInt.prototype.toJSON = function () {
return this.toString()
Expand Down Expand Up @@ -416,6 +418,23 @@ export function initIocContainer(
})
})

container.singleton('autoPeeringService', async (deps) => {
return createAutoPeeringService({
logger: await deps.use('logger'),
knex: await deps.use('knex'),
assetService: await deps.use('assetService'),
config: await deps.use('config')
})
})

container.singleton('autoPeeringRoutes', async (deps) => {
return await createAutoPeeringRoutes({
logger: await deps.use('logger'),
knex: await deps.use('knex'),
autoPeeringService: await deps.use('autoPeeringService')
})
})

return container
}

Expand Down Expand Up @@ -507,6 +526,13 @@ export const start = async (
connectorServer = connectorApp.listenPublic(config.connectorPort)
logger.info(`Connector listening on ${config.connectorPort}`)
logger.info('🐒 has 🚀. Get ready for 🍌🍌🍌🍌🍌')

if (config.enableAutoPeering) {
await app.startAutoPeeringServer(config.autoPeeringServerPort)
logger.info(
`Auto-peering server listening on ${config.autoPeeringServerPort}`
)
}
}

// If this script is run directly, start the server
Expand Down

0 comments on commit 3250663

Please sign in to comment.