86 lines
2.3 KiB
TypeScript
86 lines
2.3 KiB
TypeScript
|
import { Socket } from "socket.io"
|
||
|
import Cookies from "cookies"
|
||
|
import http from "http"
|
||
|
import Koa from "koa"
|
||
|
import { Header } from "@budibase/backend-core"
|
||
|
|
||
|
/**
|
||
|
* Constructs a fake Koa context to use for manually running middlewares in
|
||
|
* sockets
|
||
|
* @param app the Koa app
|
||
|
* @param socket the socket.io socket instance
|
||
|
* @param options additional metadata to populate the context with
|
||
|
*/
|
||
|
export const createContext = (
|
||
|
app: Koa,
|
||
|
socket: Socket,
|
||
|
options?: WebsocketContextOptions
|
||
|
) => {
|
||
|
const res = new http.ServerResponse(socket.request)
|
||
|
const context: WebsocketContext = {
|
||
|
...app.createContext(socket.request, res),
|
||
|
|
||
|
// Additional overrides needed to make our middlewares work with this
|
||
|
// fake koa context
|
||
|
resourceId: options?.resourceId,
|
||
|
path: "/fake",
|
||
|
request: {
|
||
|
url: "/fake",
|
||
|
headers: {
|
||
|
[Header.APP_ID]: options?.appId,
|
||
|
},
|
||
|
},
|
||
|
cookies: new Cookies(socket.request, res),
|
||
|
get: (field: string) => socket.request.headers?.[field] as string,
|
||
|
throw: (...params: any[]) => {
|
||
|
// Throw has a bunch of different signatures, so we'll just stringify
|
||
|
// whatever params we get given
|
||
|
throw new Error(
|
||
|
...(params?.join(" ") || "Unknown error in socket middleware")
|
||
|
)
|
||
|
},
|
||
|
|
||
|
// Needed for koa-useragent middleware
|
||
|
headers: socket.request.headers,
|
||
|
header: socket.request.headers,
|
||
|
}
|
||
|
return context
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Runs a list of middlewares, nesting each callback inside each other mimic
|
||
|
* how the real middlewares run and ensuring that app or tenant context work
|
||
|
* as expected
|
||
|
* @param ctx the Koa context
|
||
|
* @param middlewares the array of middlewares to run
|
||
|
* @param callback a final callback for when all middlewares are completed
|
||
|
*/
|
||
|
export const runMiddlewares = async (
|
||
|
ctx: any,
|
||
|
middlewares: any[],
|
||
|
callback: Function
|
||
|
) => {
|
||
|
if (!middlewares[0]) {
|
||
|
await callback()
|
||
|
} else {
|
||
|
await middlewares[0](ctx, async () => {
|
||
|
await runMiddlewares(ctx, middlewares.slice(1), callback)
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export interface WebsocketContext extends Omit<Koa.Context, "request"> {
|
||
|
request: {
|
||
|
url: string
|
||
|
headers: {
|
||
|
[key: string]: string | undefined
|
||
|
}
|
||
|
}
|
||
|
cookies: Cookies
|
||
|
}
|
||
|
|
||
|
export interface WebsocketContextOptions {
|
||
|
appId?: string
|
||
|
resourceId?: string
|
||
|
}
|