Skip to content

Commit

Permalink
Broken response streams (#901)
Browse files Browse the repository at this point in the history
response objects in ccc are being consumed more than once without being cloned
first. If we are using the response body multiple times, which is a stream, it can't
be read again, so we have an issue.

this changes a-to-z, contacts, dict, faq, hours, streams, transport
this does not change calendar, jobs, menu, news, orgs, routes
  • Loading branch information
drewvolz authored Dec 7, 2024
1 parent d38f832 commit 17c9ee7
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 56 deletions.
5 changes: 5 additions & 0 deletions scripts/smoke-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ for route in $(curl -s localhost:3000/v1/routes | jq -r '.[].path'); do
continue
;;

"/v1/news/named/oleville")
echo "skip because oleville tends to break often and isn't worth testing"
continue
;;

*"/:"*)
echo "skip because of parameter placeholders"
continue
Expand Down
24 changes: 15 additions & 9 deletions source/ccci-stolaf-college/v1/a-z.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import {GH_PAGES} from './gh-pages.js'
import type {Context} from '../../ccc-server/context.js'
import {z} from 'zod'

const GET = mem(get, {maxAge: ONE_DAY})

type StOlafAzResponseType = z.infer<typeof StOlafAzResponseSchema>
const StOlafAzResponseSchema = z.object({
az_nav: z.object({
Expand All @@ -29,14 +27,22 @@ const AllAboutOlafExtraAzResponseSchema = z.object({
),
})

async function getOlafAtoZ() {
let url = 'https://wp.stolaf.edu/wp-json/site-data/sidebar/a-z'
return StOlafAzResponseSchema.parse(await GET(url).json())
}
const getOlafAtoZ = mem(
async () => {
let url = 'https://wp.stolaf.edu/wp-json/site-data/sidebar/a-z'
const response = await get(url)
return StOlafAzResponseSchema.parse(await response.json())
},
{maxAge: ONE_DAY},
)

async function getPagesAtoZ() {
return AllAboutOlafExtraAzResponseSchema.parse(await GET(GH_PAGES('a-to-z.json')).json())
}
const getPagesAtoZ = mem(
async () => {
const response = await get(GH_PAGES('a-to-z.json'))
return AllAboutOlafExtraAzResponseSchema.parse(await response.json())
},
{maxAge: ONE_DAY},
)

// merge custom entries defined on GH pages with the fetched WP-JSON
function combineResponses(
Expand Down
14 changes: 7 additions & 7 deletions source/ccci-stolaf-college/v1/contacts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import mem from 'memoize'
import {GH_PAGES} from './gh-pages.js'
import type {Context} from '../../ccc-server/context.js'

const GET = mem(get, {maxAge: ONE_DAY})

let url = GH_PAGES('contact-info.json')

export function getContacts() {
return GET(url).json()
}
const getContacts = mem(
async () => {
const response = await get(GH_PAGES('contact-info.json'))
return response.json()
},
{maxAge: ONE_DAY},
)

export async function contacts(ctx: Context) {
ctx.cacheControl(ONE_DAY)
Expand Down
14 changes: 7 additions & 7 deletions source/ccci-stolaf-college/v1/dictionary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import mem from 'memoize'
import {GH_PAGES} from './gh-pages.js'
import type {Context} from '../../ccc-server/context.js'

const GET = mem(get, {maxAge: ONE_DAY})

let url = GH_PAGES('dictionary.json')

export function getDictionary() {
return GET(url).json()
}
const getDictionary = mem(
async () => {
const response = await get(GH_PAGES('dictionary.json'))
return response.json()
},
{maxAge: ONE_DAY},
)

export async function dictionary(ctx: Context) {
ctx.cacheControl(ONE_DAY)
Expand Down
14 changes: 7 additions & 7 deletions source/ccci-stolaf-college/v1/faqs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import mem from 'memoize'
import {GH_PAGES} from './gh-pages.js'
import type {Context} from '../../ccc-server/context.js'

const GET = mem(get, {maxAge: ONE_DAY})

let url = GH_PAGES('faqs.json')

export function getFaqs() {
return GET(url).json()
}
const getFaqs = mem(
async () => {
const response = await get(GH_PAGES('faqs.json'))
return response.json()
},
{maxAge: ONE_DAY},
)

export async function faqs(ctx: Context) {
ctx.cacheControl(ONE_DAY)
Expand Down
14 changes: 7 additions & 7 deletions source/ccci-stolaf-college/v1/hours.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import mem from 'memoize'
import {GH_PAGES} from './gh-pages.js'
import type {Context} from '../../ccc-server/context.js'

const GET = mem(get, {maxAge: ONE_HOUR})

let url = GH_PAGES('building-hours.json')

export function getBuildingHours() {
return GET(url).json()
}
const getBuildingHours = mem(
async () => {
const response = await get(GH_PAGES('building-hours.json'))
return response.json()
},
{maxAge: ONE_HOUR},
)

export async function buildingHours(ctx: Context) {
ctx.cacheControl(ONE_HOUR)
Expand Down
30 changes: 19 additions & 11 deletions source/ccci-stolaf-college/v1/streams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {ONE_HOUR} from '../../ccc-lib/constants.js'
import moment from 'moment-timezone'
import type {Context} from '../../ccc-server/context.js'
import {z} from 'zod'
import mem from 'memoize'

const StreamEntry = z.object({
starttime: z.string(),
Expand Down Expand Up @@ -40,18 +41,25 @@ const StOlafStreamsParamsSchema = z.object({
class: z.enum(['current', 'archived']),
})

export async function getStreams(params: StOlafStreamsParamsType) {
const url = 'https://www.stolaf.edu/multimedia/api/collection'
const data = StreamEntryCollection.parse(await get(url, {searchParams: params}).json())
const getStreams = mem(
async (params: StOlafStreamsParamsType) => {
const url = 'https://www.stolaf.edu/multimedia/api/collection'
const response = await get(url, {searchParams: params})
const json = (await response.clone().json()) as Promise<
(z.infer<typeof StreamEntry> & {starttime: string})[]
>
const data = StreamEntryCollection.parse(json)

return data.results.map((stream) => {
let {starttime} = stream
return {
...stream,
starttime: moment.tz(starttime, 'YYYY-MM-DD HH:mm', 'America/Chicago').toISOString(),
}
})
}
return data.results.map((stream) => {
let {starttime} = stream
return {
...stream,
starttime: moment.tz(starttime, 'YYYY-MM-DD HH:mm', 'America/Chicago').toISOString(),
}
})
},
{maxAge: ONE_HOUR},
)

export async function upcoming(ctx: Context) {
ctx.cacheControl(ONE_HOUR)
Expand Down
22 changes: 14 additions & 8 deletions source/ccci-stolaf-college/v1/transit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,27 @@ import mem from 'memoize'
import {GH_PAGES} from './gh-pages.js'
import type {Context} from '../../ccc-server/context.js'

const GET = mem(get, {maxAge: ONE_HOUR})

export function getBus() {
return GET(GH_PAGES('bus-times.json')).json()
}
const getBus = mem(
async () => {
const response = await get(GH_PAGES('bus-times.json'))
return response.json()
},
{maxAge: ONE_HOUR},
)

export async function bus(ctx: Context) {
ctx.cacheControl(ONE_HOUR)

ctx.body = await getBus()
}

export function getModes() {
return GET(GH_PAGES('transportation.json')).json()
}
const getModes = mem(
async () => {
const response = await get(GH_PAGES('transportation.json'))
return response.json()
},
{maxAge: ONE_HOUR},
)

export async function modes(ctx: Context) {
ctx.cacheControl(ONE_HOUR)
Expand Down

0 comments on commit 17c9ee7

Please sign in to comment.