Skip to content

Commit

Permalink
Async process members of group (#65)
Browse files Browse the repository at this point in the history
* async on members of group

* example fixed

* fix tests
  • Loading branch information
owens1127 authored Aug 27, 2024
1 parent 4a37d1d commit 4ad1651
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 70 deletions.
2 changes: 1 addition & 1 deletion open-api/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1089,7 +1089,7 @@
"examples": [
{
"id": 1,
"name": "Normal",
"name": "Standard",
"path": "normal",
"associatedActivityId": null,
"isChallengeMode": false
Expand Down
30 changes: 22 additions & 8 deletions src/RaidHubRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,15 @@ export class RaidHubRoute<
private controller: RequestHandler<z.infer<Params>, any, z.infer<Body>, z.infer<Query>> =
async (req, res, next) => {
try {
const result = await this.handler(req)
const result = await this.handler(req, callback => {
res.on("finish", () => {
try {
callback()
} catch (err) {
process.env.NODE_ENV !== "test" && console.error(err)
}
})
})
const response = this.buildResponse(result)
if (result.success) {
res.status(this.successCode).json(response)
Expand Down Expand Up @@ -378,20 +386,26 @@ export class RaidHubRoute<
body?: unknown
headers?: IncomingHttpHeaders
}) {
const res = await this.handler({
params: this.paramsSchema?.parse(req.params) ?? {},
query: this.querySchema?.parse(req.query) ?? {},
body: this.bodySchema?.parse(req.body) ?? {},
headers: req.headers ?? {}
}).then(this.buildResponse)
let after: () => Promise<void> = () => Promise.resolve()
const res = await this.handler(
{
params: this.paramsSchema?.parse(req.params) ?? {},
query: this.querySchema?.parse(req.query) ?? {},
body: this.bodySchema?.parse(req.body) ?? {},
headers: req.headers ?? {}
},
afterCallback => (after = afterCallback)
).then(this.buildResponse)

await after()

// We essentially can use this type to narrow down the type of res in our unit tests
// This will guarantee that we are testing the correct type of response and that
// also the shape matches the schema
if (res.success) {
return {
type: "ok",
parsed: this.responseSchema.parse(res.response)
parsed: this.responseSchema.parse(res.response) as z.infer<ResponseBody>
} as const
} else {
const schema =
Expand Down
15 changes: 9 additions & 6 deletions src/RaidHubRouterTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,15 @@ export type RaidHubHandler<
Body extends ZodType,
T,
ErrorResponse extends ErrorData
> = (req: {
params: z.infer<Params>
query: z.infer<Query>
body: z.infer<Body>
headers: IncomingHttpHeaders
}) => Promise<RaidHubHandlerReturn<T, ErrorResponse>>
> = (
req: {
params: z.infer<Params>
query: z.infer<Query>
body: z.infer<Body>
headers: IncomingHttpHeaders
},
after: (callback: () => Promise<void>) => void
) => Promise<RaidHubHandlerReturn<T, ErrorResponse>>

export type RaidHubHandlerReturn<T, E extends ErrorData> =
| { success: true; response: T }
Expand Down
37 changes: 0 additions & 37 deletions src/middlewares/async.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { beforeAll, beforeEach, describe, expect, spyOn, test } from "bun:test"
import express from "express"
import request from "supertest"
import { clanQueue } from "../services/rabbitmq/queues/clan"
import { playersQueue } from "../services/rabbitmq/queues/player"
import { processClanAsync } from "./processClanAsync"
import { processPlayerAsync } from "./processPlayerAsync"

const app = express()
Expand Down Expand Up @@ -43,38 +41,3 @@ describe("player", () => {
expect(spyPlayersQueueSend).toHaveBeenCalledWith({ membershipId: 4611686018488107374n })
})
})

describe("clan", () => {
beforeAll(() => {
app.use("/clan/200/:groupId", processClanAsync, (req, res) => {
req.params.groupId = BigInt(req.params.groupId)
res.sendStatus(200)
})

app.use("/clan/404/:groupId", processClanAsync, (req, res) => {
req.params.groupId = BigInt(req.params.groupId)
res.sendStatus(404)
})
})

const spyClanQueueSend = spyOn(clanQueue, "send")
beforeEach(() => {
spyClanQueueSend.mockReset()
spyClanQueueSend.mockResolvedValueOnce(true)
})

test("sends on 200", async () => {
const res = await request(app).get("/clan/200/3148408")
expect(res.status).toBe(200)

expect(spyClanQueueSend).toHaveBeenCalledTimes(1)
expect(spyClanQueueSend).toHaveBeenCalledWith({ groupId: 3148408n })
})

test("does not send on 404", async () => {
const res = await request(app).get("/clan/404/3148408")
expect(res.status).toBe(404)

expect(spyClanQueueSend).not.toHaveBeenCalled()
})
})
11 changes: 0 additions & 11 deletions src/middlewares/processClanAsync.ts

This file was deleted.

21 changes: 19 additions & 2 deletions src/routes/clan.test.ts → src/routes/clanStats.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
import { describe, expect, spyOn, test } from "bun:test"
import { beforeEach, describe, expect, spyOn, test } from "bun:test"
import { PlatformErrorCodes } from "bungie-net-core/enums"
import { ErrorCode } from "../schema/errors/ErrorCode"
import { bungiePlatformHttp } from "../services/bungie/client"
import { BungieApiError } from "../services/bungie/error"
import { clanQueue } from "../services/rabbitmq/queues/clan"
import { playersQueue } from "../services/rabbitmq/queues/player"
import { expectErr, expectOk } from "../util.test"
import { clanStatsRoute } from "./clan"
import { clanStatsRoute } from "./clanStats"

describe("clan 200", () => {
const spyClanQueueSend = spyOn(clanQueue, "send")
const spyPlayersQueueSend = spyOn(playersQueue, "send")

beforeEach(() => {
spyClanQueueSend.mockReset()
spyClanQueueSend.mockResolvedValueOnce(true)
spyPlayersQueueSend.mockReset()
spyPlayersQueueSend.mockResolvedValue(true)
})

const t = async (groupId: string) => {
const result = await clanStatsRoute.$mock({ params: { groupId } })
expectOk(result)
expect(spyClanQueueSend).toHaveBeenCalledTimes(1)
if (result.type === "ok") {
console.log("test", result.parsed.members.length)
expect(spyPlayersQueueSend).toHaveBeenCalledTimes(result.parsed.members.length)
}
}

test("Elysium", () => t("3148408"))
Expand Down
18 changes: 15 additions & 3 deletions src/routes/clan.ts → src/routes/clanStats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,22 @@ import { z } from "zod"
import { RaidHubRoute } from "../RaidHubRoute"
import { getClanStats } from "../data/clan"
import { cacheControl } from "../middlewares/cache-control"
import { processClanAsync } from "../middlewares/processClanAsync"
import { zClanStats } from "../schema/components/Clan"
import { ErrorCode } from "../schema/errors/ErrorCode"
import { zBigIntString } from "../schema/util"
import { BungieApiError } from "../services/bungie/error"
import { getClan } from "../services/bungie/getClan"
import { getClanMembers } from "../services/bungie/getClanMembers"
import { clanQueue } from "../services/rabbitmq/queues/clan"
import { playersQueue } from "../services/rabbitmq/queues/player"

export const clanStatsRoute = new RaidHubRoute({
method: "get",
description: "Get the stats for a clan. Data updates weekly.",
params: z.object({
groupId: zBigIntString()
}),
middleware: [cacheControl(30), processClanAsync],
middleware: [cacheControl(30)],
response: {
success: {
statusCode: 200,
Expand All @@ -42,7 +43,7 @@ export const clanStatsRoute = new RaidHubRoute({
}
] as const
},
async handler({ params }) {
async handler({ params }, after) {
const groupId = params.groupId

try {
Expand All @@ -65,6 +66,17 @@ export const clanStatsRoute = new RaidHubRoute({

const stats = await getClanStats(members.map(m => m.destinyUserInfo.membershipId))

after(async () => {
await clanQueue.send({ groupId })
await Promise.all(
members.map(member =>
playersQueue.send({
membershipId: BigInt(member.destinyUserInfo.membershipId)
})
)
)
})

return RaidHubRoute.ok(stats)
}
})
Expand Down
2 changes: 1 addition & 1 deletion src/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { activityRoute } from "./activity"
import { adminRouter } from "./admin"
import { adminAuthorizationRoute } from "./authorize/admin"
import { userAuthorizationRoute } from "./authorize/user"
import { clanStatsRoute } from "./clan"
import { clanStatsRoute } from "./clanStats"
import { leaderboardRouter } from "./leaderboard"
import { manifestRoute } from "./manifest"
import { pgcrRoute } from "./pgcr"
Expand Down
2 changes: 1 addition & 1 deletion src/schema/components/VersionDefinition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const zVersionDefinition = registry.register(
examples: [
{
id: 1,
name: "Normal",
name: "Standard",
path: "normal",
associatedActivityId: null,
isChallengeMode: false
Expand Down

0 comments on commit 4ad1651

Please sign in to comment.