Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 45 additions & 5 deletions server/context.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,54 @@
const context = {}
import { AsyncLocalStorage } from 'async_hooks'

const internalContext = {}

const contextProxyHandler = {
set(target, name, value, receiver) {
context[name] = value
return Reflect.set(target, name, value, receiver)
const currentContext = asyncLocalStorage.getStore()
if (currentContext) {
currentContext[name] = value
return true
} else {
return Reflect.set(target, name, value, receiver)
}
},
get(target, name, receiver) {
const currentContext = asyncLocalStorage.getStore()
if (currentContext) {
return currentContext[name]
} else {
return Reflect.get(target, name, receiver)
}
}
}

const context = new Proxy(internalContext, contextProxyHandler)

const asyncLocalStorage = new AsyncLocalStorage()

export function generateContext(temporary) {
return new Proxy({ ...context, ...temporary }, contextProxyHandler)
if(temporary) {
Object.assign(context, temporary)
}
return context
}

export function generateCurrentContext(temporary, callback) {
const currentContext = {...internalContext, ...temporary}
asyncLocalStorage.run(currentContext, () => {
callback(currentContext);
});
}

export function getCurrentContext(temporary) {
const currentContext = asyncLocalStorage.getStore()
if (!currentContext) {
return generateContext()
}
if(temporary) {
Object.assign(currentContext, temporary)
}
return currentContext
}

export default context
export default context
10 changes: 3 additions & 7 deletions server/exposeServerFunctions.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,16 @@ import fs from 'fs'
import bodyParser from 'body-parser'
import path from 'path'
import deserialize from '../shared/deserialize'
import { generateContext } from './context'
import { getCurrentContext } from './context'
import printError from './printError'
import registry from './registry'
import reqres from './reqres'

export default function exposeServerFunctions(server) {
for (const method of ['get', 'post', 'put', 'patch', 'delete', 'all']) {
const original = server[method].bind(server)
server[method] = function (...args) {
if (typeof args[1] === 'function' && args[1].name === '_invoke') {
return original(args[0], bodyParser.text({ limit: server.maximumPayloadSize }), async (request, response) => {
reqres.set(request, response)
const params = {}
for (const key of Object.keys(request.params)) {
params[key] = extractParamValue(request.params[key])
Expand All @@ -27,14 +25,12 @@ export default function exposeServerFunctions(server) {
Object.assign(params, deserialize(payload))
}
try {
const subcontext = generateContext({ request, response, ...params })
const currentContext = getCurrentContext(params)
const exposedFunction = module.hot ? registry[args[1].hash] : args[1]
const result = await exposedFunction(subcontext)
reqres.clear()
const result = await exposedFunction(currentContext)
response.json(result)
} catch (error) {
printError(error)
reqres.clear()
response.status(500).json({})
}
})
Expand Down
7 changes: 4 additions & 3 deletions server/project.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ICONS } from 'nullstack/project'
import environment from './environment'
import reqres from './reqres'
import worker from './worker'
import { getCurrentContext } from './context'

const project = {}

Expand All @@ -21,8 +21,9 @@ project.disallow = []
project.icons = ICONS

function getHost() {
if (reqres.request?.headers?.host) {
return reqres.request.headers.host
const currentContext = getCurrentContext()
if (currentContext.request?.headers?.host) {
return currentContext.request.headers.host
}
if (project.domain === 'localhost') {
return `localhost:${process.env.NULLSTACK_SERVER_PORT}`
Expand Down
8 changes: 3 additions & 5 deletions server/registry.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
const registry = {}
export default registry
import reqres from "./reqres"
import { generateContext } from "./context"
import { getCurrentContext } from "./context"
import Nullstack from '.'
import { load } from "./lazy"

Expand Down Expand Up @@ -34,10 +33,9 @@ function bindStaticProps(klass) {
return klass[propName].call(klass, ...args)
}
const params = args[0] || {}
const { request, response } = reqres
const subcontext = generateContext({ request, response, ...params })
const currentContext = getCurrentContext(params)
await load(klass.hash)
return klass[propName].call(klass, subcontext)
return klass[propName].call(klass, currentContext)
}
if (module.hot) {
_invoke.hash = klass[prop].hash
Expand Down
20 changes: 0 additions & 20 deletions server/reqres.js

This file was deleted.

27 changes: 8 additions & 19 deletions server/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import express from 'express'
import path from 'path'
import deserialize from '../shared/deserialize'
import prefix from '../shared/prefix'
import context, { generateContext } from './context'
import context, { getCurrentContext, generateCurrentContext } from './context'
import emulatePrerender from './emulatePrerender'
import environment from './environment'
import exposeServerFunctions from './exposeServerFunctions'
Expand All @@ -13,7 +13,6 @@ import generateManifest from './manifest'
import { prerender } from './prerender'
import printError from './printError'
import registry from './registry'
import reqres from './reqres'
import generateRobots from './robots'
import template from './template'
import { generateServiceWorker } from './worker'
Expand All @@ -31,7 +30,9 @@ server.use(async (request, response, next) => {
typeof context.start === 'function' && (await context.start())
contextStarted = true
}
next()
generateCurrentContext({request, response}, () => {
next()
})
})

emulatePrerender(server)
Expand Down Expand Up @@ -120,7 +121,6 @@ server.start = function () {

server.all(`/${prefix}/:hash/:methodName.json`, async (request, response) => {
const payload = request.method === 'GET' ? request.query.payload : request.body
reqres.set(request, response)
const args = deserialize(payload)
const { hash, methodName } = request.params
const [invokerHash, boundHash] = hash.split('-')
Expand All @@ -137,25 +137,21 @@ server.start = function () {
const method = registry[key]
if (method !== undefined) {
try {
const subcontext = generateContext({ request, response, ...args })
const result = await method.call(boundKlass, subcontext)
reqres.clear()
const currentContext = getCurrentContext(args)
const result = await method.call(boundKlass, currentContext)
response.json({ result })
} catch (error) {
printError(error)
reqres.clear()
response.status(500).json({})
}
} else {
reqres.clear()
response.status(404).json({})
}
})

if (module.hot) {
server.all(`/${prefix}/:version/:hash/:methodName.json`, async (request, response) => {
const payload = request.method === 'GET' ? request.query.payload : request.body
reqres.set(request, response)
const args = deserialize(payload)
const { version, hash, methodName } = request.params
const [invokerHash, boundHash] = hash.split('-')
Expand All @@ -178,17 +174,14 @@ server.start = function () {
const method = registry[key]
if (method !== undefined) {
try {
const subcontext = generateContext({ request, response, ...args })
const result = await method.call(boundKlass, subcontext)
reqres.clear()
const currentContext = getCurrentContext(args)
const result = await method.call(boundKlass, currentContext)
response.json({ result })
} catch (error) {
printError(error)
reqres.clear()
response.status(500).json({})
}
} else {
reqres.clear()
response.status(404).json({})
}
}
Expand All @@ -210,15 +203,11 @@ server.start = function () {
if (request.originalUrl.split('?')[0].indexOf('.') > -1) {
return next()
}
reqres.set(request, response)
const scope = await prerender(request, response)
if (!response.headersSent) {
const status = scope.context.page.status
const html = template(scope)
reqres.clear()
response.status(status).send(html)
} else {
reqres.clear()
}
})

Expand Down
5 changes: 5 additions & 0 deletions tests/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ context.startIncrementalValue = 0

setExternalRoute(context.server)

context.server.use((request, response, next) => {
context.url = request.originalUrl
next()
})

context.start = async function () {
await ContextProject.start(context)
await ContextSecrets.start(context)
Expand Down
5 changes: 4 additions & 1 deletion tests/src/ServerFunctions.njs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ class ServerFunctions extends Nullstack {
this.count = await this.getCountAsOne()
}

static async getCount({ to }) {
static async getCount(context) {
const { to, url } = context
console.log({url})
setInterval(() => console.log("SERVERF:", context.url), 1000)
return to
}

Expand Down