mirror of
https://github.com/seejohnrun/haste-server.git
synced 2024-11-22 20:51:21 +00:00
remove web app class and fixes
This commit is contained in:
parent
82fd0654e2
commit
fa9d3f98e9
5 changed files with 160 additions and 184 deletions
|
@ -52,7 +52,7 @@ EXPOSE ${PORT}
|
||||||
STOPSIGNAL SIGINT
|
STOPSIGNAL SIGINT
|
||||||
ENTRYPOINT [ "bash", "docker-entrypoint.sh" ]
|
ENTRYPOINT [ "bash", "docker-entrypoint.sh" ]
|
||||||
|
|
||||||
RUN yarn build
|
RUN yarn build:nostatic
|
||||||
COPY static /app/dist/static
|
COPY static /app/dist/static
|
||||||
|
|
||||||
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s \
|
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s \
|
||||||
|
|
22
README.md
22
README.md
|
@ -29,9 +29,25 @@ STDOUT. Check the README there for more details and usages.
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
1. Download the package, and expand it
|
1. Download the package, and expand it
|
||||||
2. Explore the settings inside of config.js, but the defaults should be good
|
3. `yarn install`
|
||||||
3. `npm install`
|
|
||||||
4. `npm start` (you may specify an optional `<config-path>` as well)
|
## Development
|
||||||
|
|
||||||
|
1. Explore the settings inside of config.js, but the defaults should be good
|
||||||
|
2. `yarn install`
|
||||||
|
3. `yarn dev` (you may specify an optional `<config-path>` as well)
|
||||||
|
|
||||||
|
## Production
|
||||||
|
|
||||||
|
1. Explore the settings inside of config.js, but the defaults should be good
|
||||||
|
2. `yarn install`
|
||||||
|
3. `yarn build` to build the package
|
||||||
|
4. `yarn start` to start the server
|
||||||
|
|
||||||
|
## Production with Docker
|
||||||
|
|
||||||
|
1. Explore the settings inside of config.js, but the defaults should be good
|
||||||
|
2. `docker compose up`
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,8 @@
|
||||||
"copy:files": "copyFiles -u 1 static/**/* dist/static",
|
"copy:files": "copyFiles -u 1 static/**/* dist/static",
|
||||||
"clean:files": "rimraf dist",
|
"clean:files": "rimraf dist",
|
||||||
"test": "jest --config config/jest.config.js",
|
"test": "jest --config config/jest.config.js",
|
||||||
"build": "yarn clean:files && tsc --project ./",
|
"build:nostatic": "yarn clean:files && tsc --project ./",
|
||||||
|
"build": "yarn clean:files && yarn copy:files && tsc --project ./",
|
||||||
"dev": "nodemon src/server.ts",
|
"dev": "nodemon src/server.ts",
|
||||||
"start": "node dist/src/server.js",
|
"start": "node dist/src/server.js",
|
||||||
"lint": "eslint src --fix",
|
"lint": "eslint src --fix",
|
||||||
|
|
175
src/app.ts
175
src/app.ts
|
@ -1,175 +0,0 @@
|
||||||
import express, { Router, Express, Request } from 'express'
|
|
||||||
import * as fs from 'fs'
|
|
||||||
import * as winston from 'winston'
|
|
||||||
import uglify from 'uglify-js'
|
|
||||||
import connectSt from 'st'
|
|
||||||
import connectRateLimit from 'connect-ratelimit'
|
|
||||||
import getConfig from './lib/helpers/config'
|
|
||||||
import addLogging from './lib/helpers/log'
|
|
||||||
import build from './lib/document-handler/builder'
|
|
||||||
import DocumentHandler from './lib/document-handler'
|
|
||||||
import { Config } from './types/config'
|
|
||||||
import {
|
|
||||||
getStaticDirectory,
|
|
||||||
getStaticItemDirectory,
|
|
||||||
} from './lib/helpers/directory'
|
|
||||||
|
|
||||||
class App {
|
|
||||||
public server: Express
|
|
||||||
|
|
||||||
public config: Config
|
|
||||||
|
|
||||||
documentHandler?: DocumentHandler
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.config = getConfig()
|
|
||||||
this.server = express()
|
|
||||||
this.setLogging()
|
|
||||||
this.setDocumentHandler()
|
|
||||||
this.compressStaticAssets()
|
|
||||||
this.sendDocumentsToStore()
|
|
||||||
this.middlewares()
|
|
||||||
this.setRateLimits()
|
|
||||||
this.apiCalls()
|
|
||||||
this.staticPages()
|
|
||||||
}
|
|
||||||
|
|
||||||
middlewares() {
|
|
||||||
this.server.use(express.json())
|
|
||||||
}
|
|
||||||
|
|
||||||
setLogging() {
|
|
||||||
if (this.config.logging) {
|
|
||||||
addLogging(this.config)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setDocumentHandler = async () => {
|
|
||||||
this.documentHandler = await build(this.config)
|
|
||||||
}
|
|
||||||
|
|
||||||
apiCalls() {
|
|
||||||
const router = Router()
|
|
||||||
|
|
||||||
// get raw documents - support getting with extension
|
|
||||||
router.get('/raw/:id', async (request, response) =>
|
|
||||||
this.documentHandler?.handleRawGet(request, response),
|
|
||||||
)
|
|
||||||
|
|
||||||
router.head('/raw/:id', (request, response) =>
|
|
||||||
this.documentHandler?.handleRawGet(request, response),
|
|
||||||
)
|
|
||||||
|
|
||||||
// // add documents
|
|
||||||
router.post('/documents', (request, response) =>
|
|
||||||
this.documentHandler?.handlePost(request, response),
|
|
||||||
)
|
|
||||||
|
|
||||||
// get documents
|
|
||||||
router.get('/documents/:id', (request, response) =>
|
|
||||||
this.documentHandler?.handleGet(request, response),
|
|
||||||
)
|
|
||||||
|
|
||||||
router.head('/documents/:id', (request, response) =>
|
|
||||||
this.documentHandler?.handleGet(request, response),
|
|
||||||
)
|
|
||||||
|
|
||||||
this.server.use(router)
|
|
||||||
}
|
|
||||||
|
|
||||||
setRateLimits() {
|
|
||||||
if (this.config.rateLimits) {
|
|
||||||
this.config.rateLimits.end = true
|
|
||||||
this.server.use(connectRateLimit(this.config.rateLimits))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compressStaticAssets() {
|
|
||||||
// Compress the static javascript assets
|
|
||||||
if (this.config.recompressStaticAssets) {
|
|
||||||
const list = fs.readdirSync(getStaticDirectory(__dirname))
|
|
||||||
for (let j = 0; j < list.length; j += 1) {
|
|
||||||
const item = list[j]
|
|
||||||
if (
|
|
||||||
item.indexOf('.js') === item.length - 3 &&
|
|
||||||
item.indexOf('.min.js') === -1
|
|
||||||
) {
|
|
||||||
const dest = `${item.substring(
|
|
||||||
0,
|
|
||||||
item.length - 3,
|
|
||||||
)}.min${item.substring(item.length - 3)}`
|
|
||||||
const origCode = fs.readFileSync(
|
|
||||||
getStaticItemDirectory(__dirname, item),
|
|
||||||
'utf8',
|
|
||||||
)
|
|
||||||
|
|
||||||
fs.writeFileSync(
|
|
||||||
getStaticItemDirectory(__dirname, dest),
|
|
||||||
uglify.minify(origCode).code,
|
|
||||||
'utf8',
|
|
||||||
)
|
|
||||||
winston.info(`compressed ${item} into ${dest}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sendDocumentsToStore() {
|
|
||||||
// Send the static documents into the preferred store, skipping expirations
|
|
||||||
let documentPath
|
|
||||||
let data
|
|
||||||
|
|
||||||
Object.keys(this.config.documents).forEach(name => {
|
|
||||||
documentPath = this.config.documents[name]
|
|
||||||
data = fs.readFileSync(documentPath, 'utf8')
|
|
||||||
winston.info('loading static document', { name, path: documentPath })
|
|
||||||
|
|
||||||
if (data) {
|
|
||||||
this.documentHandler?.store?.set(
|
|
||||||
name,
|
|
||||||
data,
|
|
||||||
cb => {
|
|
||||||
winston.debug('loaded static document', { success: cb })
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
winston.warn('failed to load static document', {
|
|
||||||
name,
|
|
||||||
path: documentPath,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
staticPages() {
|
|
||||||
|
|
||||||
// Otherwise, try to match static files
|
|
||||||
this.server.use(
|
|
||||||
connectSt({
|
|
||||||
path: getStaticDirectory(__dirname),
|
|
||||||
content: { maxAge: this.config.staticMaxAge },
|
|
||||||
passthrough: true,
|
|
||||||
index: false,
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
|
|
||||||
// Then we can loop back - and everything else should be a token,
|
|
||||||
// so route it back to /
|
|
||||||
this.server.get('/:id', (request: Request, response, next) => {
|
|
||||||
request.sturl = '/'
|
|
||||||
next()
|
|
||||||
})
|
|
||||||
|
|
||||||
// And match index
|
|
||||||
this.server.use(
|
|
||||||
connectSt({
|
|
||||||
path: getStaticDirectory(__dirname),
|
|
||||||
content: { maxAge: this.config.staticMaxAge },
|
|
||||||
index: 'index.html',
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default App
|
|
142
src/server.ts
142
src/server.ts
|
@ -1,8 +1,142 @@
|
||||||
|
import express, { Express, Request } from 'express'
|
||||||
|
import * as fs from 'fs'
|
||||||
import * as winston from 'winston'
|
import * as winston from 'winston'
|
||||||
import App from './app'
|
import uglify from 'uglify-js'
|
||||||
|
import connectSt from 'st'
|
||||||
const { server, config } = new App()
|
import connectRateLimit from 'connect-ratelimit'
|
||||||
|
import getConfig from './lib/helpers/config'
|
||||||
|
import addLogging from './lib/helpers/log'
|
||||||
|
import buildDocumenthandler from './lib/document-handler/builder'
|
||||||
|
import DocumentHandler from './lib/document-handler'
|
||||||
|
import { Config } from './types/config'
|
||||||
|
import {
|
||||||
|
getStaticDirectory,
|
||||||
|
getStaticItemDirectory,
|
||||||
|
} from './lib/helpers/directory'
|
||||||
|
|
||||||
server.listen(config.port, config.host, () => {
|
const config: Config = getConfig()
|
||||||
|
|
||||||
|
if (config.logging) {
|
||||||
|
addLogging(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
let documentHandler: DocumentHandler
|
||||||
|
|
||||||
|
buildDocumenthandler(config).then((handler) => {
|
||||||
|
documentHandler = handler
|
||||||
|
})
|
||||||
|
|
||||||
|
// Compress the static javascript assets
|
||||||
|
if (config.recompressStaticAssets) {
|
||||||
|
|
||||||
|
const list = fs.readdirSync(getStaticDirectory(__dirname))
|
||||||
|
for (let j = 0; j < list.length; j += 1) {
|
||||||
|
const item = list[j]
|
||||||
|
if (
|
||||||
|
item.indexOf('.js') === item.length - 3 &&
|
||||||
|
item.indexOf('.min.js') === -1
|
||||||
|
) {
|
||||||
|
const dest = `${item.substring(0, item.length - 3)}.min${item.substring(
|
||||||
|
item.length - 3,
|
||||||
|
)}`
|
||||||
|
const origCode = fs.readFileSync(
|
||||||
|
getStaticItemDirectory(__dirname, item),
|
||||||
|
'utf8',
|
||||||
|
)
|
||||||
|
|
||||||
|
fs.writeFileSync(
|
||||||
|
getStaticItemDirectory(__dirname, dest),
|
||||||
|
uglify.minify(origCode).code,
|
||||||
|
'utf8',
|
||||||
|
)
|
||||||
|
winston.info(`compressed ${item} into ${dest}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the static documents into the preferred store, skipping expirations
|
||||||
|
let documentPath
|
||||||
|
let data
|
||||||
|
|
||||||
|
Object.keys(config.documents).forEach(name => {
|
||||||
|
documentPath = config.documents[name]
|
||||||
|
data = fs.readFileSync(documentPath, 'utf8')
|
||||||
|
winston.info('loading static document', { name, path: documentPath })
|
||||||
|
|
||||||
|
if (data) {
|
||||||
|
documentHandler?.store?.set(
|
||||||
|
name,
|
||||||
|
data,
|
||||||
|
cb => {
|
||||||
|
winston.debug('loaded static document', { success: cb })
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
winston.warn('failed to load static document', {
|
||||||
|
name,
|
||||||
|
path: documentPath,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const app: Express = express()
|
||||||
|
|
||||||
|
// Rate limit all requests
|
||||||
|
if (config.rateLimits) {
|
||||||
|
config.rateLimits.end = true
|
||||||
|
app.use(connectRateLimit(config.rateLimits))
|
||||||
|
}
|
||||||
|
|
||||||
|
// get raw documents - support getting with extension
|
||||||
|
app.get('/raw/:id', async (request, response) =>
|
||||||
|
documentHandler?.handleRawGet(request, response),
|
||||||
|
)
|
||||||
|
|
||||||
|
app.head('/raw/:id', (request, response) =>
|
||||||
|
documentHandler?.handleRawGet(request, response),
|
||||||
|
)
|
||||||
|
|
||||||
|
// // add documents
|
||||||
|
app.post('/documents', (request, response) =>
|
||||||
|
documentHandler?.handlePost(request, response),
|
||||||
|
)
|
||||||
|
|
||||||
|
// get documents
|
||||||
|
app.get('/documents/:id', (request, response) =>
|
||||||
|
documentHandler?.handleGet(request, response),
|
||||||
|
)
|
||||||
|
|
||||||
|
app.head('/documents/:id', (request, response) =>
|
||||||
|
documentHandler?.handleGet(request, response),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Otherwise, try to match static files
|
||||||
|
app.use(
|
||||||
|
connectSt({
|
||||||
|
path: getStaticDirectory(__dirname),
|
||||||
|
content: { maxAge: config.staticMaxAge },
|
||||||
|
passthrough: true,
|
||||||
|
index: false,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
// Then we can loop back - and everything else should be a token,
|
||||||
|
// so route it back to /
|
||||||
|
app.get('/:id', (request: Request, response, next) => {
|
||||||
|
request.sturl = '/'
|
||||||
|
next()
|
||||||
|
})
|
||||||
|
|
||||||
|
// And match index
|
||||||
|
app.use(
|
||||||
|
connectSt({
|
||||||
|
path: getStaticDirectory(__dirname),
|
||||||
|
content: { maxAge: config.staticMaxAge },
|
||||||
|
index: 'index.html',
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
app.listen(config.port, config.host, () => {
|
||||||
winston.info(`listening on ${config.host}:${config.port}`)
|
winston.info(`listening on ${config.host}:${config.port}`)
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue