Skip to content

Commit

Permalink
feat: improved http caching
Browse files Browse the repository at this point in the history
  • Loading branch information
tabarra committed Jan 3, 2024
1 parent 76bedcb commit 9d26130
Show file tree
Hide file tree
Showing 19 changed files with 125 additions and 211 deletions.
7 changes: 4 additions & 3 deletions core/components/WebServer/getReactIndex.ts
Expand Up @@ -180,9 +180,10 @@ export default async function getReactIndex(ctx: CtxWithVars | AuthedCtx) {

//If in prod mode and NUI, replace the entry point with the local one
//This is required because of how badly the WebPipe handles "large" files
if (!ctx.txVars.isWebInterface && !convars.isDevMode){
htmlOut = htmlOut.replace(/src="\.\/index.js"/, 'src="nui://monitor/panel/index.js"');
htmlOut = htmlOut.replace(/href="\.\/index.css"/, 'href="nui://monitor/panel/index.css"');
if (!convars.isDevMode){
const base = ctx.txVars.isWebInterface ? `./` : `nui://monitor/panel/`;
htmlOut = htmlOut.replace(/src="\.\/index-(\w+)\.js"/, `src="${base}index-$1.js"`);
htmlOut = htmlOut.replace(/href="\.\/index-(\w+)\.css"/, `href="${base}index-$1.css"`);
}

return htmlOut;
Expand Down
18 changes: 13 additions & 5 deletions core/components/WebServer/index.ts
Expand Up @@ -24,6 +24,7 @@ import ctxVarsMw from './middlewares/ctxVarsMw';
import ctxUtilsMw from './middlewares/ctxUtilsMw';
import { SessionMemoryStorage, koaSessMw, socketioSessMw } from './middlewares/sessionMws';
import checkRateLimit from './middlewares/globalRateLimiterMw';
import cacheControlMw from './middlewares/cacheControlMw';
const console = consoleFactory(modulename);
const nanoid = customAlphabet(dict51, 32);

Expand All @@ -34,6 +35,14 @@ export type WebServerConfigType = {
limiterAttempts: number;
}

const koaServeOptions = {
index: false,
defer: false,
//The resource URLs should already coontain txVer as a query param to bust cache
//so setting to 30m should be fine, except in dev mode
maxage: !convars.isDevMode ? 30 * 60 * 1000 : 0,
};

export default class WebServer {
readonly #txAdmin: TxAdmin;
public isListening = false;
Expand All @@ -52,8 +61,6 @@ export default class WebServer {
constructor(txAdmin: TxAdmin, public config: WebServerConfigType) {
this.#txAdmin = txAdmin;



//Generate cookie key & luaComToken
const pathHash = crypto.createHash('shake256', { outputLength: 6 })
.update(txAdmin.info.serverProfilePath)
Expand Down Expand Up @@ -99,12 +106,13 @@ export default class WebServer {
const panelPublicPath = convars.isDevMode
? path.join(process.env.TXADMIN_DEV_SRC_PATH as string, 'panel/public')
: path.join(txEnv.txAdminResourcePath, 'panel');
this.app.use(KoaServe(path.join(txEnv.txAdminResourcePath, 'web/public'), { index: false, defer: false }));
this.app.use(KoaServe(panelPublicPath, { index: false, defer: false }));
this.app.use(KoaServe(path.join(txEnv.txAdminResourcePath, 'web/public'), koaServeOptions));
this.app.use(KoaServe(panelPublicPath, koaServeOptions));
this.app.use(KoaBodyParser({ jsonLimit }));

//Custom stuff
this.sessionStore = new SessionMemoryStorage();
this.app.use(cacheControlMw);
this.app.use(koaSessMw(this.sessionCookieName, this.sessionStore));
this.app.use(ctxVarsMw(txAdmin));
this.app.use(ctxUtilsMw);
Expand All @@ -119,7 +127,7 @@ export default class WebServer {
ctx.status = 404;
console.verbose.warn(`Request 404 error: ${ctx.path}`);
return ctx.utils.render('standalone/404');
}else if (ctx.path.endsWith('.map')){
} else if (ctx.path.endsWith('.map')) {
ctx.status = 404;
return ctx.send('Not found');
} else {
Expand Down
16 changes: 16 additions & 0 deletions core/components/WebServer/middlewares/cacheControlMw.ts
@@ -0,0 +1,16 @@
import type { CtxWithVars } from "../ctxTypes";
import type { Next } from 'koa';

/**
* Middleware responsible for setting the cache control headers (disabling it entirely)
* Since this comes after the koa-static middleware, it will only apply to the web routes
* This is important because even our react index.html is actually SSR with auth context
*/
export default async function cacheControlMw(ctx: CtxWithVars, next: Next) {
ctx.set('Cache-Control', 'no-cache, no-store, must-revalidate, proxy-revalidate');
ctx.set('Surrogate-Control', 'no-store');
ctx.set('Expires', '0');
ctx.set('Pragma', 'no-cache');

return next();
};
1 change: 0 additions & 1 deletion core/components/WebServer/middlewares/ctxUtilsMw.ts
Expand Up @@ -249,7 +249,6 @@ export default async function ctxUtilsMw(ctx: CtxWithVars, next: Next) {
}

const serveReactIndex = async () => {
//FIXME: no cache, even in prod mode
ctx.body = await getReactIndex(ctx);
ctx.type = 'text/html';
};
Expand Down
1 change: 0 additions & 1 deletion core/components/WebServer/middlewares/ctxVarsMw.ts
@@ -1,5 +1,4 @@
const modulename = 'WebServer:SetupVarsMw';
import { convars } from '@core/globalData';
import TxAdmin from '@core/txAdmin';
import consoleFactory from '@extras/console';
import consts from '@shared/consts';
Expand Down
154 changes: 28 additions & 126 deletions docs/dev_notes.md
@@ -1,22 +1,30 @@
# TODO:
- [x] menu: add x, y int coords to detailed playerlist
- [x] menu: `txcl:plist:setDetailed` should remove any player not in the event data
- [x] menu: `txcl:plist:setDetailed` should request any missing player not in local cache

Processo:
- [x] testar o básico do legacy e api auth
- [x] testar rotas websocket
- [x] corrigir rotas nui iframe
- [x] deal with the nui auth rate limiting (no more middleware)
- [x] pesquisar por `ctx.session.auth`
- [x] aplicar novo tipo e trocar todos os ctx.session e ctx.utils.xxxxx de todas as rotas
- [x] remove all `globals.` in the webroutes folder from typescript files
- [x] test and commit all changed files
- [x] check `playerDatabase.registerAction` expiration type error
- [x] translation fix the `The player was xxxxx` lines in all files
- [x] corrigir comportamento dos profile pictures
- [x] normalize the session.auth creation w/ types
- [x] checar o que fazer com as stats no `core/webroutes/authentication/self.ts`
- [ ][3d] NEW PAGE: Dashboard
- [ ] number callouts from legacy players page
- [ ] warning for dev builds of txadmin
- [ ] warning for top servers
- [ ][1d] NEW PAGEs: Console log + Action log
- [ ][3d] NEW PAGE: Live console
- [ ][3d] NEW PAGE: Players
- [ ][1d] NEW PAGE: History
- [ ][1h] zap hosting advertisement
- [ ][1d] tutorial stepper for the new UI
- [ ][2h] fine tune `panel/vite.config.ts`


Quickies
- [x] apply cache control policies
- [x] do i need to add a input type hidden with the username in the add master and account modal so vaults can save it both?
- [ ] feat(menu): add keymapping for tp to waypoint (PR #886)
- [ ] fix the tsc build
- [ ] put in server name in the login page, to help lost admins notice they are in the wrong txAdmin
- [ ] talk to r* and make sure the new build process wipes the old cache
- [ ] make sure some user input based fields are truncated (server name, player name)
- [ ] layout on 4k and ultrawide screens
- [ ] check again for the need of lazy loading
- [ ] deprecate StatisticsManager.pageViews as its now untrackable?
- [ ] easter egg with some old music? https://www.youtube.com/watch?v=nNoaXej0Jeg
- [ ] make sure the playerlist scroll works if the playergen is stopped (therefore, not re-rendering the component)

=======================================================================

Expand Down Expand Up @@ -87,8 +95,6 @@ await (async () => {
})()
```



```js
import bytes from 'bytes';
import fs from 'node:fs';
Expand Down Expand Up @@ -134,110 +140,6 @@ setTimeout(() => {
//lib 202 -> weird 1gb peak
```



=======================================================================
## v7 RELEASE CHECKLIST
- [x][2d] full router + link parity with legacy pages
- [x] decide on the links/pages for now
- [x] remove tanstack-router
- [x] create new routes with wouter
- [x] add active state to buttons
- [x] on re-click, page should refresh
- [x] remove menu and footer from main template
- [x] add error boundries (global/page)
- [x] refactor auth layer + type koa context
- [x] rewrite the session middlewares
- [x] new auth ui + auth routing
- [x] enforce new password rule
- [x][2d] light/dark theme
- [x][1d] adapt legacy styles to somewhat match shadcn
- SHELL:
- [x][5d] fully responsive layout (show/hide sidebars, login, addMaster, etc)
- [x][2h] merge new shell design into the `txadmin/panel` codebase
- [x][~3d] implement most shell+status features
- [x][1d] socket.io connection for default room
- [x][2h] warning for outdated tx, visible in all pages
- [x][1h] dynamic title
- [x][1h] dynamic favicon
- [x][1d] server status
- [x][4h] update notices via socket.io
- [x][2h] tooltips on everything
- [x][1d] toasts API
- [x] generic toasts
- [x] markdown toasts
- [x] error toasts with discord link
- [x][2h] prompts API
- [x][2d] useBackendApi hook - wrapper around fetch with optional toast management
- [x][2h] server controls
- [x][1h] server scheduled restarts (legacy style)
- [x][3d] "your account" modal
- [x] if isTempPassword change message and disallows closing before changing the password
- [x] give the chance to change modifiers
- [x] remove legacy header + change password code
- [x] admin manager should open "my account" when trying to edit self
- [x] maybe separate the backend routes
- [x][3d] playerlist
- [x][2d] implement new player modal
- [x] legacy pages should open the new modal
- [x] write tsx + handling of data
- [x] all actions
- [x] make sure it is responsive
- [x] check behavior on error (invalid player, 500, etc)
- [x] clean legacy modal and playerlist code
- [x][5d] auth stuff
- [x] password login
- [x] cfx.re login
- [x] error page
- [x] master account pin add page
- [x] master account bkp password page
- [x] disable player modal buttons based on permissions
- [x] flow to refresh the page if invalidated auth
- [x] when logging out, create an effect to close all sheets and dialogs
- [x] disable menu links based on permissions
- [x] flow to refresh the permissions on the client side
- [x][2d] full setup flow (legacy)
- [x][1d] full deployer flow (legacy)
- [x][1d] add the new logos to shell+auth pages
> BETA RELEASE
- [ ][3d] NEW PAGE: Dashboard
- [ ] number callouts from legacy players page
- [ ] warning for dev builds of txadmin
- [ ] warning for top servers
- [ ][1d] NEW PAGEs: Console log + Action log
- [ ][3d] NEW PAGE: Live console
- [ ][3d] NEW PAGE: Players
- [ ][1d] NEW PAGE: History
- [ ][1h] zap hosting advertisement
- [ ][1d] tutorial stepper for the new UI
- [ ][2h] fine tune `panel/vite.config.ts`

Quickies
- [x] fix all legacy cfx.response.redirect (dashboard, setup, deployer, maybe more)
- [x] move the socket.io stuff from mainshell to a dedicated component child of mainshell
- [x] disable testing page in prod build
- [x] check if strict mode is indeed disabled in prod build
- [x] fix the console bg on light mode + command input
- [x] commit the fixes for the player ids and god mode issues
> BETA RELEASE
- [ ] feat(menu): add keymapping for tp to waypoint (PR #886)
- [ ] fix the tsc build
- [x] do i need to add a input type hidden with the username in the add master and account modal so vaults can save it both?
- [ ] put in server name in the login page, to help lost admins notice they are in the wrong txAdmin
- [ ] talk to r* and make sure the new build process wipes the old cache
- [ ] make sure some user input based fields are truncated (server name, player name)
- [ ] layout on 4k and ultrawide screens
- [ ] check again for the need of lazy loading
- [ ] Cache stuff:
- [ ] add `maxage` to `koa-static` config
- [ ] add `cache-control` and/or `vary` to all pages
- [ ] deprecate StatisticsManager.pageViews as its now untrackable?
- [ ] easter egg with some old music? https://www.youtube.com/watch?v=nNoaXej0Jeg
- [ ] make sure the playerlist scroll works if the playergen is stopped (therefore, not re-rendering the component)


=======================================================================

## src
Expand All @@ -264,7 +166,6 @@ Quickies




### Page Changes:
Players:
- list of players in a table
Expand Down Expand Up @@ -310,8 +211,9 @@ Master Actions:
- [ ] Anonymous admin actions (issue #893)
- settings with select box for which options to choose (bans, warns, dms, kicks, restarts, announcements, everything)
- [ ] Change the kick all to require the `control.server` permission (issue #379)
- [ ] create new "Remove Player Data" permission which would allow to delete bans/warns, players and player identifiers

- [ ] maybe use [this lib](https://www.npmjs.com/package/ntp-time-sync) to check for clock skew so i can remove the complexity of dealing with possible desync between core and ui on player modal, scheduler, etc;
- [ ] maybe use [this lib](https://www.npmjs.com/package/ntp-time-sync) to check for clock skew so I can remove the complexity of dealing with possible desync between core and ui on player modal, scheduler, etc;

- [ ] write some automated tests for the auth logic and middlewares
- [ ] instead of showing cfg errors when trying to start server, just show "there are errors in your cfg file" and link the user to the cfg editor page
Expand Down
19 changes: 2 additions & 17 deletions fxmanifest.lua
Expand Up @@ -5,7 +5,7 @@
author 'Tabarra'
description 'Remotely Manage & Monitor your GTA5 FiveM Server'
repository 'https://github.com/tabarra/txAdmin'
version '7.0.0-beta2'
version '7.0.0-beta2-dev'
ui_label 'txAdmin'

rdr3_warning 'I acknowledge that this is a prerelease build of RedM, and I am aware my resources *will* become incompatible once RedM ships.'
Expand Down Expand Up @@ -66,20 +66,5 @@ files {

-- WebPipe optimization:
'panel/**/*',
'web/public/css/coreui.min.css',
'web/public/css/jquery-confirm.min.css',
'web/public/css/txAdmin.css',
'web/public/css/dark.css',
'web/public/js/coreui.bundle.min.js',
'web/public/js/bootstrap-notify.min.js',
'web/public/js/jquery-confirm.min.js',
'web/public/js/socket.io.min.js',
'web/public/js/humanizeDuration.min.js',
'web/public/js/txadmin/base.js',
'web/public/js/txadmin/main.js',
'web/public/xtermjs/xterm.min.css',
'web/public/xtermjs/xterm.min.js',
'web/public/xtermjs/xterm-addon-fit.min.js',
'web/public/xtermjs/xterm-addon-search.js',
'web/public/xtermjs/xterm-addon-search-bar.min.js',
'web/public/**/*',
}
4 changes: 3 additions & 1 deletion nui/vite.config.ts
Expand Up @@ -4,6 +4,7 @@ import react from '@vitejs/plugin-react-swc';
import tsconfigPaths from 'vite-tsconfig-paths';
import { getFxsPaths } from '../scripts/scripts-utils.js';
import config from '../.deploy.config.js';
import { licenseBanner } from '../scripts/scripts-utils.js';


const baseConfig = {
Expand All @@ -16,8 +17,9 @@ const baseConfig = {
sourcemap: false,

rollupOptions: {
//Doing this because fxserver's cicd doesn't wipe the dist folder
output: {
banner: licenseBanner('..'),
//Doing this because fxserver's cicd doesn't wipe the dist folder
entryFileNames: `[name].js`,
chunkFileNames: `[name].js`,
assetFileNames: '[name].[ext]',
Expand Down
11 changes: 6 additions & 5 deletions panel/vite.config.ts
Expand Up @@ -3,7 +3,7 @@ import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
// import tsconfigPaths from 'vite-tsconfig-paths';
import config from '../.deploy.config.js';

import { licenseBanner } from '../scripts/scripts-utils.js';

const baseConfig = {
build: {
Expand All @@ -17,11 +17,12 @@ const baseConfig = {
rollupOptions: {
input: undefined, //placeholder

//Doing this because fxserver's cicd doesn't wipe the dist folder
output: {
entryFileNames: `[name].js`,
chunkFileNames: `[name].js`,
assetFileNames: '[name].[ext]',
banner: licenseBanner('..'),
//Adding hash to help with cache busting
entryFileNames: `[name]-[hash].js`,
chunkFileNames: `[name]-[hash].js`,
assetFileNames: '[name]-[hash].[ext]',
}
},
},
Expand Down
5 changes: 3 additions & 2 deletions scripts/scripts-utils.js
Expand Up @@ -24,8 +24,8 @@ export const txAdminASCII = () => {
* txAdmin + license banner for bundled files
* @returns {String}
*/
export const licenseBanner = () => {
const licensePath = path.join('.', 'LICENSE');
export const licenseBanner = (baseDir = '.') => {
const licensePath = path.join(baseDir, 'LICENSE');
const lineSep = '%'.repeat(80);
const logoPad = ' '.repeat(18);
const contentLines = [
Expand All @@ -35,6 +35,7 @@ export const licenseBanner = () => {
lineSep,
'Author: André Tabarra (https://github.com/tabarra)',
'Repository: https://github.com/tabarra/txAdmin',
'This bundled file includes third party libraries under their respective licenses.',
'txAdmin is a free open source software provided under the license below.',
lineSep,
...fs.readFileSync(licensePath, 'utf8').trim().split('\n'),
Expand Down

0 comments on commit 9d26130

Please sign in to comment.