Add ServerRequest.withRequestTime, and make body nullable.

This commit is contained in:
Dillon Kearns 2021-12-23 13:34:54 -08:00
parent 4fedf9ee19
commit 6f82aa59f8
5 changed files with 62 additions and 41 deletions

View File

@ -40,6 +40,7 @@
"elm/json": "1.1.3 <= v < 2.0.0",
"elm/parser": "1.1.0 <= v < 2.0.0",
"elm/regex": "1.0.0 <= v < 2.0.0",
"elm/time": "1.0.0 <= v < 2.0.0",
"elm/url": "1.0.0 <= v < 2.0.0",
"elm/virtual-dom": "1.0.2 <= v < 2.0.0",
"elm-community/dict-extra": "2.4.0 <= v < 3.0.0",

View File

@ -119,6 +119,7 @@ exports.handler = render;`
* @param {any} context
*/
async function render(event, context) {
const requestTime = new Date();
console.log(JSON.stringify(event));
global.staticHttpCache = {};
@ -134,7 +135,7 @@ async function render(event, context) {
require(compiledElmPath),
mode,
event.path,
reqToJson(event),
reqToJson(event, renderTime),
addWatcher
);
console.log('@@@renderResult', renderResult);
@ -185,9 +186,10 @@ async function render(event, context) {
/**
* @param {import('aws-lambda').APIGatewayProxyEvent} req
* @param {Date} requestTime
* @returns {{ method: string; hostname: string; query: string; headers: Object; host: string; pathname: string; port: number | null; protocol: string; rawUrl: string; }}
*/
function reqToJson(req) {
function reqToJson(req, requestTime) {
const queryString = req.multiValueQueryStringParameters ? Object.entries(req.multiValueQueryStringParameters).reduce(
(acc, [key, values]) => {
return acc + values.map(value => \`\${encodeURIComponent(key)}=\${encodeURIComponent(value)}\`).join('&')
@ -206,6 +208,7 @@ function reqToJson(req) {
protocol: "https", // TODO
rawUrl: "", // TODO
body: req.body,
requestTime: Math.round(requestTime.getTime()),
};
}
`;

View File

@ -14,6 +14,7 @@ import Pages.PageUrl exposing (PageUrl)
import Pages.Url
import ServerResponse
import Shared
import Time
import View exposing (View)
@ -41,17 +42,16 @@ page =
data : ServerRequest.IsAvailable -> RouteParams -> DataSource (PageServerResponse Data)
data serverRequestKey routeParams =
let
serverReq : ServerRequest (Maybe String)
serverReq : ServerRequest ( Maybe String, Time.Posix )
serverReq =
ServerRequest.init identity
ServerRequest.init Tuple.pair
|> ServerRequest.optionalHeader "cookie"
|> ServerRequest.withRequestTime
in
serverReq
|> ServerRequest.toDataSource serverRequestKey
|> DataSource.andThen
(\cookies ->
--DataSource.succeed (PageServerResponse.ServerResponse (ServerResponse.temporaryRedirect "/"))
--DataSource.succeed (PageServerResponse.ServerResponse (ServerResponse.stringBody (foo |> Maybe.withDefault "NOT FOUND")))
(\( cookies, requestTime ) ->
case
cookies
|> Maybe.withDefault ""
@ -60,23 +60,14 @@ data serverRequestKey routeParams =
of
Just username ->
DataSource.succeed
(PageServerResponse.RenderPage { username = username })
(PageServerResponse.RenderPage { username = username, requestTime = requestTime })
--(PageServerResponse.ServerResponse
-- (ServerResponse.stringBody
-- "Alright, here's the secret! This is all running with elm-pages serverless :D"
-- )
--)
Nothing ->
DataSource.succeed
(PageServerResponse.ServerResponse (ServerResponse.temporaryRedirect "/login"))
)
--DataSource.succeed (PageServerResponse.RenderPage {})
head :
StaticPayload Data RouteParams
-> List Head.Tag
@ -98,7 +89,9 @@ head static =
type alias Data =
{ username : String }
{ username : String
, requestTime : Time.Posix
}
view :
@ -110,6 +103,7 @@ view maybeUrl sharedModel static =
{ title = "Hello!"
, body =
[ Html.text <| "Hello " ++ static.data.username ++ "!"
, Html.text <| "Requested page at " ++ String.fromInt (Time.posixToMillis static.data.requestTime)
, Html.div []
[ Html.form
[ Attr.method "post"

View File

@ -346,19 +346,20 @@ async function start(options) {
return;
}
let body = "";
const requestTime = new Date();
/** @type {string | null} */
let body = null;
req.on("data", function (data) {
if (!body) {
body = "";
}
body += data;
// Too much POST data, kill the connection!
// 1e6 === 1 * Math.pow(10, 6) === 1 * 1000000 ~~~ 1MB
if (body.length > 1e6) req.connection.destroy();
});
req.on("end", async function () {
await runRenderThread(
reqToJson(req, body),
reqToJson(req, body, requestTime),
pathname,
function (renderResult) {
const is404 = renderResult.is404;
@ -594,7 +595,12 @@ async function ensureRequiredExecutables() {
}
}
function reqToJson(req, body) {
/**
* @param {http.IncomingMessage} req
* @param {string | null} body
* @param {Date} requestTime
*/
function reqToJson(req, body, requestTime) {
const url = new URL(req.url, "http://localhost:1234");
return {
method: req.method,
@ -607,6 +613,7 @@ function reqToJson(req, body) {
protocol: url.protocol,
rawUrl: req.url,
body: body,
requestTime: Math.round(requestTime.getTime()),
};
}

View File

@ -1,13 +1,22 @@
module DataSource.ServerRequest exposing
( IsAvailable
, ServerRequest, expectHeader, init, optionalHeader, staticData, toDataSource, withFormData, withCookies, withBody, withHost, withAllHeaders, withMethod, withProtocol, Method(..), withQueryParams
( ServerRequest, IsAvailable
, Method(..)
, init
, expectHeader, optionalHeader, withFormData, withCookies, withBody, withHost, withAllHeaders, withMethod, withProtocol, withQueryParams, withRequestTime
, toDataSource
)
{-|
@docs IsAvailable
@docs ServerRequest, IsAvailable
@docs ServerRequest, expectHeader, init, optionalHeader, staticData, toDataSource, withFormData, withCookies, withBody, withHost, withAllHeaders, withMethod, withProtocol, Method, withQueryParams
@docs Method
@docs init
@docs expectHeader, optionalHeader, withFormData, withCookies, withBody, withHost, withAllHeaders, withMethod, withProtocol, withQueryParams, withRequestTime
@docs toDataSource
-}
@ -20,6 +29,7 @@ import Internal.ServerRequest
import OptimizedDecoder
import QueryParams exposing (QueryParams)
import Secrets
import Time
import Url
@ -34,15 +44,6 @@ init constructor =
ServerRequest (OptimizedDecoder.succeed constructor)
{-| -}
staticData : DataSource.DataSource String
staticData =
DataSource.Http.get (Secrets.succeed "$$elm-pages$$headers")
(OptimizedDecoder.field "headers"
(OptimizedDecoder.field "accept-language" OptimizedDecoder.string)
)
{-| In order to access the ServerRequest data, you first need to turn it into a DataSource.
Note that you can only access it in the context of a serverless request because there is no request
@ -70,6 +71,17 @@ expectHeader headerName (ServerRequest decoder) =
|> ServerRequest
{-| -}
withRequestTime : ServerRequest (Time.Posix -> value) -> ServerRequest value
withRequestTime (ServerRequest decoder) =
decoder
|> OptimizedDecoder.andMap
(OptimizedDecoder.field "requestTime"
(OptimizedDecoder.int |> OptimizedDecoder.map Time.millisToPosix)
)
|> ServerRequest
{-| -}
withAllHeaders : ServerRequest (Dict String String -> value) -> ServerRequest value
withAllHeaders (ServerRequest decoder) =
@ -165,11 +177,15 @@ withCookies (ServerRequest decoder) =
withBody : ServerRequest (Maybe String -> value) -> ServerRequest value
withBody (ServerRequest decoder) =
decoder
|> OptimizedDecoder.andMap
(OptimizedDecoder.optionalField "body" OptimizedDecoder.string)
|> OptimizedDecoder.andMap bodyDecoder
|> ServerRequest
bodyDecoder : OptimizedDecoder.Decoder (Maybe String)
bodyDecoder =
OptimizedDecoder.field "body" (OptimizedDecoder.nullable OptimizedDecoder.string)
{-| -}
withFormData :
ServerRequest
@ -197,7 +213,7 @@ withFormData (ServerRequest decoder) =
OptimizedDecoder.string
|> OptimizedDecoder.field "headers"
)
(OptimizedDecoder.optionalField "body" OptimizedDecoder.string)
bodyDecoder
)
|> ServerRequest