-
Notifications
You must be signed in to change notification settings - Fork 0
/
posterus.js
68 lines (57 loc) · 1.64 KB
/
posterus.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
'use strict'
/**
* Version of koa-ring with support for Posterus futures and fibers,
* as well as automatic cancelation on client disconnect.
*/
const f = require('fpx')
const {Future, isFuture} = require('posterus')
const {fiber} = require('posterus/fiber')
const u = require('./utils')
/**
* Public
*/
exports.toKoaMiddleware = toKoaMiddleware
function toKoaMiddleware(handler) {
return async function koaRingMiddleware(ctx, next) {
const request = u.toPlainRequest(ctx)
request.koaNext = next
const future = toFuture(handler(request))
// If the request ends prematurely, this future wins the race.
const requestLifetime = trackRequestLifetime(ctx.req)
// If this future loses the race, it's automatically deinited. This also
// deinits user futures (if any), potentially avoiding unnecessary work.
const handlerFuture = future.mapResult(function sendResponseIfRelevant(response) {
if (u.isAwaitingResponse(ctx)) u.assignResponseToContext(ctx, response)
})
await Future.race([requestLifetime, handlerFuture])
}
}
// Undocumented
exports.runKoaNext = runKoaNext
function* runKoaNext(request) {
const {ctx, koaNext} = request || {}
if (ctx && koaNext) {
yield Future.fromPromise(koaNext())
return u.toPlainResponse(ctx)
}
return undefined
}
/**
* Internal
*/
function toFuture(value) {
return (
isFuture(value)
? value
: f.isIterator(value)
? fiber(value)
: f.isPromise(value)
? Future.fromPromise(value)
: Future.fromResult(value)
)
}
function trackRequestLifetime(req) {
const future = new Future()
req.once('close', () => future.settle())
return future
}