Files
tests/ems/src/index.ts
2024-10-25 10:02:40 +09:00

318 lines
9.6 KiB
TypeScript

import express, { Request, Response } from 'express'
import { PrismaClient } from '@prisma/client'
import fs from 'fs'
import path from 'path'
import axios from 'axios'
import multer from 'multer'
import bodyParser from 'body-parser'
import cors from 'cors'
import { Coordinate } from './interfaces/map'
import { generateTilesForZoomLevel } from './utils/tiles'
import { query, validationResult } from 'express-validator'
import { Connection, Request as TediousRequest } from 'tedious'
const tedious = new Connection({
server: 'localhost',
options: {
trustServerCertificate: true,
port: 1433,
database: 'nGeneral'
},
authentication: {
type: 'default',
options: {
userName: 'SA',
password: 'oMhthmsvbYHc'
}
}
})
tedious.on('connect', function (err) {
if (err) {
console.log('Error: ', err)
}
console.log('Connected to General')
})
tedious.connect()
const prisma = new PrismaClient()
const app = express()
const PORT = process.env.EMS_PORT || 5000
const tileFolder = path.join(__dirname, '..', 'public', 'tile_data')
const uploadDir = path.join(__dirname, '..', 'public', 'temp')
app.use(cors())
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({ extended: true }))
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, path.join(__dirname, '..', 'public', 'temp'))
},
filename: function (req, file, cb) {
cb(null, Date.now() + path.extname(file.originalname))
}
})
const upload = multer({ storage: storage })
app.get('/nodes/all', async (req: Request, res: Response) => {
try {
const nodes = await prisma.nodes.findMany()
res.json(nodes)
} catch (error) {
console.error('Error getting node:', error);
res.status(500).json({ error: 'Failed to get node' });
}
})
app.get('/nodes', query('id').isString().isUUID(), async (req: Request, res: Response) => {
try {
const result = validationResult(req)
if (!result.isEmpty()) {
return res.send({ errors: result.array() })
}
const { id } = req.params
const node = await prisma.nodes.findFirst({
where: {
id: id
}
})
res.json(node)
} catch (error) {
console.error('Error getting node:', error);
res.status(500).json({ error: 'Failed to get node' });
}
})
app.post('/nodes', async (req: Request, res: Response) => {
try {
const { coordinates, object_id, type } = req.body;
// Convert the incoming array of coordinates into the shape structure
const shape = coordinates.map((point: number[]) => ({
object_id: object_id || null,
x: point[0],
y: point[1]
}));
console.log(shape)
// Create a new node in the database
const node = await prisma.nodes.create({
data: {
object_id: object_id || null, // Nullable if object_id is not provided
shape_type: type, // You can adjust this dynamically
shape: shape, // Store the shape array as Json[]
label: 'Default'
}
});
res.status(201).json(node);
} catch (error) {
console.error('Error creating node:', error);
res.status(500).json({ error: 'Failed to create node' });
}
})
app.post('/upload', upload.single('file'), async (req: Request, res: Response) => {
const { extentMinX, extentMinY, extentMaxX, extentMaxY, blX, blY, tlX, tlY, trX, trY, brX, brY } = req.body
const bottomLeft: Coordinate = { x: blX, y: blY }
const topLeft: Coordinate = { x: tlX, y: tlY }
const topRight: Coordinate = { x: trX, y: trY }
const bottomRight: Coordinate = { x: brX, y: brY }
if (req.file) {
for (let z = 0; z <= 21; z++) {
await generateTilesForZoomLevel(uploadDir, tileFolder, req.file, [extentMinX, extentMinY, extentMaxX, extentMaxY], bottomLeft, topLeft, topRight, bottomRight, z)
}
}
return res.status(200)
})
const fetchTileFromAPI = async (provider: string, z: string, x: string, y: string): Promise<Buffer> => {
const url = provider === 'google'
? `https://khms2.google.com/kh/v=984?x=${x}&y=${y}&z=${z}`
: `https://core-sat.maps.yandex.net/tiles?l=sat&x=${x}&y=${y}&z=${z}&scale=1&lang=ru_RU`
const response = await axios.get(url, { responseType: 'arraybuffer' })
return response.data
}
app.get('/tile/:provider/:z/:x/:y', async (req: Request, res: Response) => {
const { provider, z, x, y } = req.params
if (!['google', 'yandex', 'custom'].includes(provider)) {
return res.status(400).send('Invalid provider')
}
const tilePath = provider === 'custom' ? path.join(tileFolder, provider, z, x, `${y}.png`) : path.join(tileFolder, provider, z, x, `${y}.jpg`)
if (fs.existsSync(tilePath)) {
return res.sendFile(tilePath)
} else {
if (provider !== 'custom') {
try {
const tileData = await fetchTileFromAPI(provider, z, x, y)
fs.mkdirSync(path.dirname(tilePath), { recursive: true })
fs.writeFileSync(tilePath, tileData)
res.contentType('image/jpeg')
res.send(tileData)
} catch (error) {
console.error('Error fetching tile from API:', error)
res.status(500).send('Error fetching tile from API')
}
} else {
res.status(404).send('Tile is not generated or not provided')
}
}
})
function tediousQuery(query: string) {
// Read all rows from table
const request = new TediousRequest(
query,
(err, rowCount) => {
if (err) {
console.log(`Executing ${query}, ${rowCount} rows.`);
console.error(err.message);
} else {
console.log(`Executing ${query}, ${rowCount} rows.`);
}
}
);
return new Promise((resolve, reject) => {
const result: any = [];
request.on("row", (columns) => {
const entry: any = {};
columns.forEach((column: any) => {
entry[column.metadata.colName] = column.value;
});
result.push(entry);
});
request.on('error', error => reject(error));// some error happened, reject the promise
request.on('requestCompleted', () => resolve(result)); // resolve the promise with the result rows.
tedious.execSql(request);
});
}
app.get('/general/cities/all', async (req: Request, res: Response) => {
try {
const { offset, limit, search, id } = req.query
const result = await tediousQuery(
`
SELECT * FROM nGeneral..Cities
${id ? `WHERE id = '${id}'` : ''}
${search ? `WHERE name LIKE '%${search || ''}%'` : ''}
ORDER BY id
OFFSET ${Number(offset) || 0} ROWS
FETCH NEXT ${Number(limit) || 10} ROWS ONLY;
`
)
res.status(200).json(result)
} catch (err) {
res.status(500)
}
})
app.get('/general/objects/all', async (req: Request, res: Response) => {
try {
const { offset, limit, city_id, id } = req.query
const result = await tediousQuery(
`
SELECT * FROM nGeneral..tObjects
${city_id ? `WHERE id_city = ${city_id}` : ''}
${id ? `WHERE id = '${id}'` : ''}
ORDER BY id
OFFSET ${Number(offset) || 0} ROWS
FETCH NEXT ${Number(limit) || 10} ROWS ONLY;
`
)
res.status(200).json(result)
} catch (err) {
res.status(500)
}
})
app.get('/gis/images/all', async (req: Request, res: Response) => {
try {
const { offset, limit, city_id } = req.query
const result = await tediousQuery(
`
SELECT * FROM New_Gis..images
${city_id ? `WHERE city_id = ${city_id}` : ''}
ORDER BY city_id
OFFSET ${Number(offset) || 0} ROWS
FETCH NEXT ${Number(limit) || 10} ROWS ONLY;
`
)
res.status(200).json(result)
} catch (err) {
res.status(500)
}
})
// Get figures by year and city id
app.get('/gis/figures/all', async (req: Request, res: Response) => {
try {
const { offset, limit, object_id, year, city_id } = req.query
const result = await tediousQuery(
`
SELECT * FROM New_Gis..figures f
JOIN nGeneral..tObjects o ON f.object_id = o.id WHERE o.id_city = ${city_id} AND f.year = ${year}
ORDER BY f.year
OFFSET ${Number(offset) || 0} ROWS
FETCH NEXT ${Number(limit) || 10} ROWS ONLY;
`
)
res.status(200).json(result)
} catch (err) {
res.status(500)
}
})
// Get lines by year and city id
app.get('/gis/lines/all', async (req: Request, res: Response) => {
try {
const { offset, limit, object_id, year, city_id } = req.query
const result = await tediousQuery(
`
SELECT * FROM New_Gis..lines l
JOIN nGeneral..tObjects o ON l.object_id = o.id WHERE o.id_city = ${city_id} AND l.year = ${year}
ORDER BY l.year
OFFSET ${Number(offset) || 0} ROWS
FETCH NEXT ${Number(limit) || 10} ROWS ONLY;
`
)
res.status(200).json(result)
} catch (err) {
res.status(500)
}
})
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));