add linting, do more type hinting
This commit is contained in:
parent
46f3fc7480
commit
d4f02c10df
29 changed files with 3353 additions and 1354 deletions
|
|
@ -13,11 +13,12 @@ const log = logger('Db.ts')
|
|||
* {name: 1}, // then by name ascending
|
||||
* ]
|
||||
*/
|
||||
type OrderBy = Array<any>
|
||||
type Data = Record<string, any>
|
||||
type WhereRaw = Record<string, any>
|
||||
type Params = Array<any>
|
||||
|
||||
export type WhereRaw = Record<string, any>
|
||||
export type OrderBy = Array<Record<string, 1|-1>>
|
||||
|
||||
interface Where {
|
||||
sql: string
|
||||
values: Array<any>
|
||||
|
|
@ -88,7 +89,7 @@ class Db {
|
|||
let prop = '$nin'
|
||||
if (where[k][prop]) {
|
||||
if (where[k][prop].length > 0) {
|
||||
wheres.push(k + ' NOT IN (' + where[k][prop].map((_: any) => '?') + ')')
|
||||
wheres.push(k + ' NOT IN (' + where[k][prop].map(() => '?') + ')')
|
||||
values.push(...where[k][prop])
|
||||
}
|
||||
continue
|
||||
|
|
@ -96,7 +97,7 @@ class Db {
|
|||
prop = '$in'
|
||||
if (where[k][prop]) {
|
||||
if (where[k][prop].length > 0) {
|
||||
wheres.push(k + ' IN (' + where[k][prop].map((_: any) => '?') + ')')
|
||||
wheres.push(k + ' IN (' + where[k][prop].map(() => '?') + ')')
|
||||
values.push(...where[k][prop])
|
||||
}
|
||||
continue
|
||||
|
|
@ -191,7 +192,7 @@ class Db {
|
|||
const values = keys.map(k => data[k])
|
||||
const sql = 'INSERT INTO '+ table
|
||||
+ ' (' + keys.join(',') + ')'
|
||||
+ ' VALUES (' + keys.map(k => '?').join(',') + ')'
|
||||
+ ' VALUES (' + keys.map(() => '?').join(',') + ')'
|
||||
return this.run(sql, values).lastInsertRowid
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import GameCommon, { Game, ScoreMode, Timestamp } from './../common/GameCommon'
|
||||
import GameCommon from './../common/GameCommon'
|
||||
import { Change, Game, Input, ScoreMode, Timestamp } from './../common/Types'
|
||||
import Util from './../common/Util'
|
||||
import { Rng } from './../common/Rng'
|
||||
import GameLog from './GameLog'
|
||||
|
|
@ -10,7 +11,7 @@ async function createGameObject(
|
|||
gameId: string,
|
||||
targetTiles: number,
|
||||
image: PuzzleCreationImageInfo,
|
||||
ts: number,
|
||||
ts: Timestamp,
|
||||
scoreMode: ScoreMode
|
||||
): Promise<Game> {
|
||||
const seed = Util.hash(gameId + ' ' + ts)
|
||||
|
|
@ -29,7 +30,7 @@ async function createGame(
|
|||
gameId: string,
|
||||
targetTiles: number,
|
||||
image: PuzzleCreationImageInfo,
|
||||
ts: number,
|
||||
ts: Timestamp,
|
||||
scoreMode: ScoreMode
|
||||
): Promise<void> {
|
||||
const gameObject = await createGameObject(
|
||||
|
|
@ -63,9 +64,9 @@ function addPlayer(gameId: string, playerId: string, ts: Timestamp): void {
|
|||
function handleInput(
|
||||
gameId: string,
|
||||
playerId: string,
|
||||
input: any,
|
||||
ts: number
|
||||
): Array<Array<any>> {
|
||||
input: Input,
|
||||
ts: Timestamp
|
||||
): Array<Change> {
|
||||
const idx = GameCommon.getPlayerIndexById(gameId, playerId)
|
||||
const diff = ts - GameCommon.getStartTs(gameId)
|
||||
GameLog.log(gameId, Protocol.LOG_HANDLE_INPUT, idx, input, diff)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import fs from 'fs'
|
||||
import GameCommon, { Piece, ScoreMode } from './../common/GameCommon'
|
||||
import GameCommon from './../common/GameCommon'
|
||||
import { Piece, ScoreMode } from './../common/Types'
|
||||
import Util, { logger } from './../common/Util'
|
||||
import { Rng } from './../common/Rng'
|
||||
import { DATA_DIR } from './Dirs'
|
||||
|
|
@ -7,12 +8,12 @@ import Time from './../common/Time'
|
|||
|
||||
const log = logger('GameStorage.js')
|
||||
|
||||
const DIRTY_GAMES = {} as any
|
||||
const dirtyGames: Record<string, boolean> = {}
|
||||
function setDirty(gameId: string): void {
|
||||
DIRTY_GAMES[gameId] = true
|
||||
dirtyGames[gameId] = true
|
||||
}
|
||||
function setClean(gameId: string): void {
|
||||
delete DIRTY_GAMES[gameId]
|
||||
delete dirtyGames[gameId]
|
||||
}
|
||||
|
||||
function loadGames(): void {
|
||||
|
|
@ -63,14 +64,19 @@ function loadGame(gameId: string): void {
|
|||
}
|
||||
|
||||
function persistGames(): void {
|
||||
for (const gameId of Object.keys(DIRTY_GAMES)) {
|
||||
for (const gameId of Object.keys(dirtyGames)) {
|
||||
persistGame(gameId)
|
||||
}
|
||||
}
|
||||
|
||||
function persistGame(gameId: string): void {
|
||||
const game = GameCommon.get(gameId)
|
||||
if (game.id in DIRTY_GAMES) {
|
||||
if (!game) {
|
||||
log.error(`[ERROR] unable to persist non existing game ${gameId}`)
|
||||
return
|
||||
}
|
||||
|
||||
if (game.id in dirtyGames) {
|
||||
setClean(game.id)
|
||||
}
|
||||
fs.writeFileSync(`${DATA_DIR}/${game.id}.json`, JSON.stringify({
|
||||
|
|
|
|||
|
|
@ -4,10 +4,32 @@ import exif from 'exif'
|
|||
import sharp from 'sharp'
|
||||
|
||||
import {UPLOAD_DIR, UPLOAD_URL} from './Dirs'
|
||||
import Db from './Db'
|
||||
import Db, { OrderBy, WhereRaw } from './Db'
|
||||
import { Dim } from '../common/Geometry'
|
||||
import { logger } from '../common/Util'
|
||||
import { Timestamp } from '../common/Types'
|
||||
|
||||
const resizeImage = async (filename: string) => {
|
||||
const log = logger('Images.ts')
|
||||
|
||||
interface Tag
|
||||
{
|
||||
id: number
|
||||
slug: string
|
||||
title: string
|
||||
}
|
||||
|
||||
interface ImageInfo
|
||||
{
|
||||
id: number
|
||||
filename: string
|
||||
file: string
|
||||
url: string
|
||||
title: string
|
||||
tags: Tag[]
|
||||
created: Timestamp,
|
||||
}
|
||||
|
||||
const resizeImage = async (filename: string): Promise<void> => {
|
||||
if (!filename.toLowerCase().match(/\.(jpe?g|webp|png)$/)) {
|
||||
return
|
||||
}
|
||||
|
|
@ -30,33 +52,39 @@ const resizeImage = async (filename: string) => {
|
|||
[150, 100],
|
||||
[375, 210],
|
||||
]
|
||||
for (let [w,h] of sizes) {
|
||||
console.log(w, h, imagePath)
|
||||
await sharpImg.resize(w, h, { fit: 'contain' }).toFile(`${imageOutPath}-${w}x${h}.webp`)
|
||||
for (const [w,h] of sizes) {
|
||||
log.info(w, h, imagePath)
|
||||
await sharpImg
|
||||
.resize(w, h, { fit: 'contain' })
|
||||
.toFile(`${imageOutPath}-${w}x${h}.webp`)
|
||||
}
|
||||
}
|
||||
|
||||
async function getExifOrientation(imagePath: string) {
|
||||
return new Promise((resolve, reject) => {
|
||||
new exif.ExifImage({ image: imagePath }, function (error, exifData) {
|
||||
async function getExifOrientation(imagePath: string): Promise<number> {
|
||||
return new Promise((resolve) => {
|
||||
new exif.ExifImage({ image: imagePath }, (error, exifData) => {
|
||||
if (error) {
|
||||
resolve(0)
|
||||
} else {
|
||||
resolve(exifData.image.Orientation)
|
||||
resolve(exifData.image.Orientation || 0)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const getTags = (db: Db, imageId: number) => {
|
||||
const getTags = (db: Db, imageId: number): Tag[] => {
|
||||
const query = `
|
||||
select * from categories c
|
||||
inner join image_x_category ixc on c.id = ixc.category_id
|
||||
where ixc.image_id = ?`
|
||||
return db._getMany(query, [imageId])
|
||||
return db._getMany(query, [imageId]).map(row => ({
|
||||
id: parseInt(row.number, 10) || 0,
|
||||
slug: row.slug,
|
||||
title: row.tittle,
|
||||
}))
|
||||
}
|
||||
|
||||
const imageFromDb = (db: Db, imageId: number) => {
|
||||
const imageFromDb = (db: Db, imageId: number): ImageInfo => {
|
||||
const i = db.get('images', { id: imageId })
|
||||
return {
|
||||
id: i.id,
|
||||
|
|
@ -64,21 +92,25 @@ const imageFromDb = (db: Db, imageId: number) => {
|
|||
file: `${UPLOAD_DIR}/${i.filename}`,
|
||||
url: `${UPLOAD_URL}/${encodeURIComponent(i.filename)}`,
|
||||
title: i.title,
|
||||
tags: getTags(db, i.id) as any[],
|
||||
tags: getTags(db, i.id),
|
||||
created: i.created * 1000,
|
||||
}
|
||||
}
|
||||
|
||||
const allImagesFromDb = (db: Db, tagSlugs: string[], sort: string) => {
|
||||
const sortMap = {
|
||||
const allImagesFromDb = (
|
||||
db: Db,
|
||||
tagSlugs: string[],
|
||||
orderBy: string
|
||||
): ImageInfo[] => {
|
||||
const orderByMap = {
|
||||
alpha_asc: [{filename: 1}],
|
||||
alpha_desc: [{filename: -1}],
|
||||
date_asc: [{created: 1}],
|
||||
date_desc: [{created: -1}],
|
||||
} as Record<string, any>
|
||||
} as Record<string, OrderBy>
|
||||
|
||||
// TODO: .... clean up
|
||||
const wheresRaw: Record<string, any> = {}
|
||||
const wheresRaw: WhereRaw = {}
|
||||
if (tagSlugs.length > 0) {
|
||||
const c = db.getMany('categories', {slug: {'$in': tagSlugs}})
|
||||
if (!c) {
|
||||
|
|
@ -96,7 +128,7 @@ inner join images i on i.id = ixc.image_id ${where.sql};
|
|||
}
|
||||
wheresRaw['id'] = {'$in': ids}
|
||||
}
|
||||
const images = db.getMany('images', wheresRaw, sortMap[sort])
|
||||
const images = db.getMany('images', wheresRaw, orderByMap[orderBy])
|
||||
|
||||
return images.map(i => ({
|
||||
id: i.id as number,
|
||||
|
|
@ -104,12 +136,15 @@ inner join images i on i.id = ixc.image_id ${where.sql};
|
|||
file: `${UPLOAD_DIR}/${i.filename}`,
|
||||
url: `${UPLOAD_URL}/${encodeURIComponent(i.filename)}`,
|
||||
title: i.title,
|
||||
tags: getTags(db, i.id) as any[],
|
||||
tags: getTags(db, i.id),
|
||||
created: i.created * 1000,
|
||||
}))
|
||||
}
|
||||
|
||||
const allImagesFromDisk = (tags: string[], sort: string) => {
|
||||
const allImagesFromDisk = (
|
||||
tags: string[],
|
||||
sort: string
|
||||
): ImageInfo[] => {
|
||||
let images = fs.readdirSync(UPLOAD_DIR)
|
||||
.filter(f => f.toLowerCase().match(/\.(jpe?g|webp|png)$/))
|
||||
.map(f => ({
|
||||
|
|
@ -118,7 +153,7 @@ const allImagesFromDisk = (tags: string[], sort: string) => {
|
|||
file: `${UPLOAD_DIR}/${f}`,
|
||||
url: `${UPLOAD_URL}/${encodeURIComponent(f)}`,
|
||||
title: f.replace(/\.[a-z]+$/, ''),
|
||||
tags: [] as any[],
|
||||
tags: [] as Tag[],
|
||||
created: fs.statSync(`${UPLOAD_DIR}/${f}`).mtime.getTime(),
|
||||
}))
|
||||
|
||||
|
|
@ -152,7 +187,7 @@ const allImagesFromDisk = (tags: string[], sort: string) => {
|
|||
}
|
||||
|
||||
async function getDimensions(imagePath: string): Promise<Dim> {
|
||||
let dimensions = sizeOf(imagePath)
|
||||
const dimensions = sizeOf(imagePath)
|
||||
const orientation = await getExifOrientation(imagePath)
|
||||
// when image is rotated to the left or right, switch width/height
|
||||
// https://jdhao.github.io/2019/07/31/image_rotation_exif_info/
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import Util from './../common/Util'
|
||||
import { Rng } from './../common/Rng'
|
||||
import Images from './Images'
|
||||
import { EncodedPiece, EncodedPieceShape, PieceShape, Puzzle } from '../common/GameCommon'
|
||||
import { EncodedPiece, EncodedPieceShape, PieceShape, Puzzle } from '../common/Types'
|
||||
import { Dim, Point } from '../common/Geometry'
|
||||
|
||||
export interface PuzzleCreationImageInfo {
|
||||
|
|
@ -9,7 +9,7 @@ export interface PuzzleCreationImageInfo {
|
|||
url: string
|
||||
}
|
||||
|
||||
interface PuzzleCreationInfo {
|
||||
export interface PuzzleCreationInfo {
|
||||
width: number
|
||||
height: number
|
||||
tileSize: number
|
||||
|
|
@ -40,16 +40,16 @@ async function createPuzzle(
|
|||
}
|
||||
const info: PuzzleCreationInfo = determinePuzzleInfo(dim, targetTiles)
|
||||
|
||||
let tiles = new Array(info.tiles)
|
||||
for (let i = 0; i < tiles.length; i++) {
|
||||
tiles[i] = { idx: i }
|
||||
const rawPieces = new Array(info.tiles)
|
||||
for (let i = 0; i < rawPieces.length; i++) {
|
||||
rawPieces[i] = { idx: i }
|
||||
}
|
||||
const shapes = determinePuzzleTileShapes(rng, info)
|
||||
|
||||
let positions: Point[] = new Array(info.tiles)
|
||||
for (let tile of tiles) {
|
||||
const coord = Util.coordByTileIdx(info, tile.idx)
|
||||
positions[tile.idx] = {
|
||||
for (const piece of rawPieces) {
|
||||
const coord = Util.coordByPieceIdx(info, piece.idx)
|
||||
positions[piece.idx] = {
|
||||
// instead of info.tileSize, we use info.tileDrawSize
|
||||
// to spread the tiles a bit
|
||||
x: coord.x * info.tileSize * 1.5,
|
||||
|
|
@ -61,7 +61,7 @@ async function createPuzzle(
|
|||
const tableHeight = info.height * 3
|
||||
|
||||
const off = info.tileSize * 1.5
|
||||
let last: Point = {
|
||||
const last: Point = {
|
||||
x: info.width - (1 * off),
|
||||
y: info.height - (2 * off),
|
||||
}
|
||||
|
|
@ -71,7 +71,7 @@ async function createPuzzle(
|
|||
let diffX = off
|
||||
let diffY = 0
|
||||
let index = 0
|
||||
for (let pos of positions) {
|
||||
for (const pos of positions) {
|
||||
pos.x = last.x
|
||||
pos.y = last.y
|
||||
last.x+=diffX
|
||||
|
|
@ -98,9 +98,9 @@ async function createPuzzle(
|
|||
// then shuffle the positions
|
||||
positions = rng.shuffle(positions)
|
||||
|
||||
const pieces: Array<EncodedPiece> = tiles.map(tile => {
|
||||
const pieces: Array<EncodedPiece> = rawPieces.map(piece => {
|
||||
return Util.encodePiece({
|
||||
idx: tile.idx, // index of tile in the array
|
||||
idx: piece.idx, // index of tile in the array
|
||||
group: 0, // if grouped with other tiles
|
||||
z: 0, // z index of the tile
|
||||
|
||||
|
|
@ -113,7 +113,7 @@ async function createPuzzle(
|
|||
// physical current position of the tile (x/y in pixels)
|
||||
// this position is the initial position only and is the
|
||||
// value that changes when moving a tile
|
||||
pos: positions[tile.idx],
|
||||
pos: positions[piece.idx],
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -171,7 +171,7 @@ function determinePuzzleTileShapes(
|
|||
|
||||
const shapes: Array<PieceShape> = new Array(info.tiles)
|
||||
for (let i = 0; i < info.tiles; i++) {
|
||||
let coord = Util.coordByTileIdx(info, i)
|
||||
const coord = Util.coordByPieceIdx(info, i)
|
||||
shapes[i] = {
|
||||
top: coord.y === 0 ? 0 : shapes[i - info.tilesX].bottom * -1,
|
||||
right: coord.x === info.tilesX - 1 ? 0 : rng.choice(tabs),
|
||||
|
|
|
|||
|
|
@ -14,17 +14,17 @@ config = {
|
|||
*/
|
||||
|
||||
class EvtBus {
|
||||
private _on: any
|
||||
private _on: Record<string, Function[]>
|
||||
constructor() {
|
||||
this._on = {} as any
|
||||
this._on = {}
|
||||
}
|
||||
|
||||
on(type: string, callback: Function) {
|
||||
on (type: string, callback: Function): void {
|
||||
this._on[type] = this._on[type] || []
|
||||
this._on[type].push(callback)
|
||||
}
|
||||
|
||||
dispatch(type: string, ...args: Array<any>) {
|
||||
dispatch (type: string, ...args: Array<any>): void {
|
||||
(this._on[type] || []).forEach((cb: Function) => {
|
||||
cb(...args)
|
||||
})
|
||||
|
|
@ -43,13 +43,13 @@ class WebSocketServer {
|
|||
this.evt = new EvtBus()
|
||||
}
|
||||
|
||||
on(type: string, callback: Function) {
|
||||
on (type: string, callback: Function): void {
|
||||
this.evt.on(type, callback)
|
||||
}
|
||||
|
||||
listen() {
|
||||
listen (): void {
|
||||
this._websocketserver = new WebSocket.Server(this.config)
|
||||
this._websocketserver.on('connection', (socket: WebSocket, request: Request) => {
|
||||
this._websocketserver.on('connection', (socket: WebSocket, request: Request): void => {
|
||||
const pathname = new URL(this.config.connectstring).pathname
|
||||
if (request.url.indexOf(pathname) !== 0) {
|
||||
log.log('bad request url: ', request.url)
|
||||
|
|
@ -66,13 +66,13 @@ class WebSocketServer {
|
|||
})
|
||||
}
|
||||
|
||||
close() {
|
||||
close (): void {
|
||||
if (this._websocketserver) {
|
||||
this._websocketserver.close()
|
||||
}
|
||||
}
|
||||
|
||||
notifyOne(data: any, socket: WebSocket) {
|
||||
notifyOne (data: any, socket: WebSocket): void {
|
||||
socket.send(JSON.stringify(data))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import multer from 'multer'
|
|||
import Protocol from './../common/Protocol'
|
||||
import Util, { logger } from './../common/Util'
|
||||
import Game from './Game'
|
||||
import bodyParser from 'body-parser'
|
||||
import v8 from 'v8'
|
||||
import fs from 'fs'
|
||||
import GameLog from './GameLog'
|
||||
|
|
@ -19,7 +18,8 @@ import {
|
|||
PUBLIC_DIR,
|
||||
UPLOAD_DIR,
|
||||
} from './Dirs'
|
||||
import GameCommon, { Game as GameType, GameSettings, ScoreMode } from '../common/GameCommon'
|
||||
import GameCommon from '../common/GameCommon'
|
||||
import { Game as GameType, GameSettings, ScoreMode } from '../common/Types'
|
||||
import GameStorage from './GameStorage'
|
||||
import Db from './Db'
|
||||
|
||||
|
|
@ -144,7 +144,7 @@ const setImageTags = (db: Db, imageId: number, tags: string[]) => {
|
|||
})
|
||||
}
|
||||
|
||||
app.post('/api/save-image', bodyParser.json(), (req, res) => {
|
||||
app.post('/api/save-image', express.json(), (req, res) => {
|
||||
const data = req.body as SaveImageRequestData
|
||||
db.update('images', {
|
||||
title: data.title,
|
||||
|
|
@ -189,7 +189,7 @@ app.post('/api/upload', (req, res) => {
|
|||
})
|
||||
})
|
||||
|
||||
app.post('/newgame', bodyParser.json(), async (req, res) => {
|
||||
app.post('/newgame', express.json(), async (req, res) => {
|
||||
const gameSettings = req.body as GameSettings
|
||||
log.log(gameSettings)
|
||||
const gameId = Util.uniqId()
|
||||
|
|
@ -212,8 +212,7 @@ app.use('/', express.static(PUBLIC_DIR))
|
|||
const wss = new WebSocketServer(config.ws);
|
||||
|
||||
const notify = (data: any, sockets: Array<WebSocket>) => {
|
||||
// TODO: throttle?
|
||||
for (let socket of sockets) {
|
||||
for (const socket of sockets) {
|
||||
wss.notifyOne(data, socket)
|
||||
}
|
||||
}
|
||||
|
|
@ -221,7 +220,7 @@ const notify = (data: any, sockets: Array<WebSocket>) => {
|
|||
wss.on('close', async ({socket} : {socket: WebSocket}) => {
|
||||
try {
|
||||
const proto = socket.protocol.split('|')
|
||||
const clientId = proto[0]
|
||||
// const clientId = proto[0]
|
||||
const gameId = proto[1]
|
||||
GameSockets.removeSocket(gameId, socket)
|
||||
} catch (e) {
|
||||
|
|
@ -244,7 +243,11 @@ wss.on('message', async ({socket, data} : { socket: WebSocket, data: any }) => {
|
|||
const ts = Time.timestamp()
|
||||
Game.addPlayer(gameId, clientId, ts)
|
||||
GameSockets.addSocket(gameId, socket)
|
||||
const game: GameType = GameCommon.get(gameId)
|
||||
|
||||
const game: GameType|null = GameCommon.get(gameId)
|
||||
if (!game) {
|
||||
throw `[game ${gameId} does not exist (anymore)... ]`
|
||||
}
|
||||
notify(
|
||||
[Protocol.EV_SERVER_INIT, Util.encodeGame(game)],
|
||||
[socket]
|
||||
|
|
@ -269,7 +272,10 @@ wss.on('message', async ({socket, data} : { socket: WebSocket, data: any }) => {
|
|||
sendGame = true
|
||||
}
|
||||
if (sendGame) {
|
||||
const game: GameType = GameCommon.get(gameId)
|
||||
const game: GameType|null = GameCommon.get(gameId)
|
||||
if (!game) {
|
||||
throw `[game ${gameId} does not exist (anymore)... ]`
|
||||
}
|
||||
notify(
|
||||
[Protocol.EV_SERVER_INIT, Util.encodeGame(game)],
|
||||
[socket]
|
||||
|
|
@ -299,7 +305,7 @@ wss.listen()
|
|||
|
||||
const memoryUsageHuman = () => {
|
||||
const totalHeapSize = v8.getHeapStatistics().total_available_size
|
||||
let totalHeapSizeInGB = (totalHeapSize / 1024 / 1024 / 1024).toFixed(2)
|
||||
const totalHeapSizeInGB = (totalHeapSize / 1024 / 1024 / 1024).toFixed(2)
|
||||
|
||||
log.log(`Total heap size (bytes) ${totalHeapSize}, (GB ~${totalHeapSizeInGB})`)
|
||||
const used = process.memoryUsage().heapUsed / 1024 / 1024
|
||||
|
|
@ -340,10 +346,10 @@ process.once('SIGUSR2', function () {
|
|||
gracefulShutdown('SIGUSR2')
|
||||
})
|
||||
|
||||
process.once('SIGINT', function (code) {
|
||||
process.once('SIGINT', function () {
|
||||
gracefulShutdown('SIGINT')
|
||||
})
|
||||
|
||||
process.once('SIGTERM', function (code) {
|
||||
process.once('SIGTERM', function () {
|
||||
gracefulShutdown('SIGTERM')
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue