Map caching, clickhouse test service

This commit is contained in:
cracklesparkle
2024-08-26 16:11:37 +09:00
parent 579bbf7764
commit ab88fd5ea5
20 changed files with 737 additions and 220 deletions

View File

@ -1,119 +1,48 @@
import express, { Request, Response } from 'express'
import { Redis } from 'ioredis'
import dotenv from 'dotenv'
import bodyParser from 'body-parser'
import { SatelliteMapsProvider } from './interfaces/map'
const axios = require('axios');
import express, { Request, Response } from 'express';
import fs from 'fs';
import path from 'path';
import axios from 'axios';
const cors = require('cors')
const app = express();
const PORT = process.env.EMS_PORT;
const redis = new Redis({
port: Number(process.env.REDIS_PORT) || 6379,
host: process.env.REDIS_HOST,
password: process.env.REDIS_PASSWORD,
})
const tileFolder = path.join(__dirname, '..', 'tiles');
dotenv.config()
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 app = express()
const port = process.env.EMS_PORT
const response = await axios.get(url, { responseType: 'arraybuffer' });
return response.data;
};
// Middleware to parse JSON requests
app.use(bodyParser.json())
app.get('/tile/:provider/:z/:x/:y', async (req: Request, res: Response) => {
const { provider, z, x, y } = req.params;
const getTileUrl = (provider: string, x: string, y: string, z: string) => {
if (provider === 'google') {
return `https://khms2.google.com/kh/v=984?x=${x}&y=${y}&z=${z}`;
} else if (provider === 'yandex') {
return `https://core-sat.maps.yandex.net/tiles?l=sat&x=${x}&y=${y}&z=${z}&scale=1&lang=ru_RU`;
if (!['google', 'yandex'].includes(provider)) {
return res.status(400).send('Invalid provider');
}
throw new Error('Invalid provider');
}
app.get('/tile/:provider/:z/:x/:y', async (req, res) => {
const { provider, x, y, z } = req.params;
const cacheKey = `${provider}:${z}:${x}:${y}`;
const tilePath = path.join(tileFolder, provider, z, x, `${y}.jpg`);
if (fs.existsSync(tilePath)) {
return res.sendFile(tilePath);
}
try {
// Check if tile is in cache
redis.get(cacheKey, async (err, cachedTile) => {
if (err) {
console.error('Redis GET error:', err);
return res.status(500).send('Server error');
}
const tileData = await fetchTileFromAPI(provider, z, x, y);
if (cachedTile) {
// If cached, return tile
console.log('Tile served from cache');
const imgBuffer = Buffer.from(cachedTile, 'base64');
res.writeHead(200, {
'Content-Type': 'image/png',
'Content-Length': imgBuffer.length,
});
return res.end(imgBuffer);
} else {
// Fetch tile from provider
const tileUrl = getTileUrl(provider, x, y, z);
const response = await axios.get(tileUrl, {
responseType: 'arraybuffer',
});
fs.mkdirSync(path.dirname(tilePath), { recursive: true });
// Cache the tile in Redis
const base64Tile = Buffer.from(response.data).toString('base64');
redis.setex(cacheKey, 3600 * 24 * 30, base64Tile); // Cache for 1 hour
fs.writeFileSync(tilePath, tileData);
// Return the tile to the client
res.writeHead(200, {
'Content-Type': 'image/png',
'Content-Length': response.data.length,
});
return res.end(response.data);
}
});
res.contentType('image/jpeg');
res.send(tileData);
} catch (error) {
console.error('Error fetching tile:', error);
res.status(500).send('Error fetching tile');
console.error('Error fetching tile from API:', error);
res.status(500).send('Error fetching tile from API');
}
})
});
app.get('/hello', cors(), (req: Request, res: Response) => {
res.send('Hello, World!')
})
// Route to store GeoJSON data
app.post('/geojson', cors(), async (req: Request, res: Response) => {
const geoJSON = req.body
if (!geoJSON || !geoJSON.features) {
return res.status(400).send('Invalid GeoJSON')
}
const id = `geojson:${Date.now()}`;
redis.set(id, JSON.stringify(geoJSON), (err, reply) => {
if (err) {
return res.status(500).send('Error saving GeoJSON to Redis');
}
res.send({ status: 'success', id });
})
})
// Route to fetch GeoJSON data
app.get('/geojson/:id', cors(), async (req: Request, res: Response) => {
const id = req.params.id;
redis.get(id, (err, data) => {
if (err) {
return res.status(500).send('Error fetching GeoJSON from Redis');
}
if (data) {
res.send(JSON.parse(data));
} else {
res.status(404).send('GeoJSON not found');
}
})
})
app.listen(port, () => {
console.log(`Server running on http://localhost:${port}`);
})
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));