use fastify
parent
17eefa24ad
commit
99dc3adb05
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
|
@ -4,6 +4,7 @@
|
|||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "tsc --project tsconfig.server.json",
|
||||
"build_server": "tsc --project tsconfig.server.json",
|
||||
"start": "cross-env NODE_ENV=production node dist/server/index.js"
|
||||
},
|
||||
|
@ -18,15 +19,14 @@
|
|||
},
|
||||
"homepage": "https://github.com/qwertyforce/ambience#readme",
|
||||
"dependencies": {
|
||||
"@types/express": "^4.17.11",
|
||||
"@types/http-proxy": "^1.17.6",
|
||||
"@types/multer": "^1.4.5",
|
||||
"@types/node": "^15.3.0",
|
||||
"axios": "^0.21.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"express": "^4.17.1",
|
||||
"fastify": "^3.20.1",
|
||||
"fastify-formbody": "^5.1.0",
|
||||
"fastify-multipart": "^4.0.7",
|
||||
"fastify-reply-from": "^6.0.1",
|
||||
"form-data": "^4.0.0",
|
||||
"http-proxy": "^1.18.1",
|
||||
"multer": "^1.4.2"
|
||||
"json-schema-to-ts": "^1.6.4"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
import config from "../../config/config"
|
||||
import FormData from 'form-data'
|
||||
import axios from 'axios'
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
async function calculate_phash_features(image_id: number, image: Buffer) {
|
||||
const form = new FormData();
|
||||
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
||||
form.append('image_id', image_id.toString())
|
||||
const status = await axios.post(`${config.phash_microservice_url}/calculate_phash_features`, form.getBuffer(), {
|
||||
maxContentLength: Infinity,
|
||||
maxBodyLength: Infinity,
|
||||
headers: {
|
||||
...form.getHeaders()
|
||||
}
|
||||
})
|
||||
return status.data
|
||||
}
|
||||
|
||||
async function calculate_akaze_features(image_id: number, image: Buffer) {
|
||||
const form = new FormData();
|
||||
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
||||
form.append('image_id', image_id.toString())
|
||||
const status = await axios.post(`${config.akaze_microservice_url}/calculate_akaze_features`, form.getBuffer(), {
|
||||
maxContentLength: Infinity,
|
||||
maxBodyLength: Infinity,
|
||||
headers: {
|
||||
...form.getHeaders()
|
||||
}
|
||||
})
|
||||
return status.data
|
||||
}
|
||||
async function calculate_nn_features(image_id: number, image: Buffer) {
|
||||
const form = new FormData();
|
||||
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
||||
form.append('image_id', image_id.toString())
|
||||
const status = await axios.post(`${config.nn_microservice_url}/calculate_nn_features`, form.getBuffer(), {
|
||||
maxContentLength: Infinity,
|
||||
maxBodyLength: Infinity,
|
||||
headers: {
|
||||
...form.getHeaders()
|
||||
}
|
||||
})
|
||||
return status.data
|
||||
}
|
||||
|
||||
async function calculate_hist_features(image_id: number, image: Buffer) {
|
||||
const form = new FormData();
|
||||
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
||||
form.append('image_id', image_id.toString())
|
||||
const status = await axios.post(`${config.hist_microservice_url}/calculate_hist_features`, form.getBuffer(), {
|
||||
maxContentLength: Infinity,
|
||||
maxBodyLength: Infinity,
|
||||
headers: {
|
||||
...form.getHeaders()
|
||||
}
|
||||
})
|
||||
return status.data
|
||||
}
|
||||
|
||||
async function phash_reverse_search(image: Buffer) {
|
||||
try {
|
||||
const form = new FormData();
|
||||
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
||||
const status = await axios.post(`${config.phash_microservice_url}/phash_reverse_search`, form.getBuffer(), {
|
||||
maxContentLength: Infinity,
|
||||
maxBodyLength: Infinity,
|
||||
headers: {
|
||||
...form.getHeaders()
|
||||
}
|
||||
})
|
||||
return status.data
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
async function akaze_reverse_search(image: Buffer) {
|
||||
try {
|
||||
const form = new FormData();
|
||||
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
||||
const status = await axios.post(`${config.akaze_microservice_url}/akaze_reverse_search`, form.getBuffer(), {
|
||||
maxContentLength: Infinity,
|
||||
maxBodyLength: Infinity,
|
||||
headers: {
|
||||
...form.getHeaders()
|
||||
}
|
||||
})
|
||||
return status.data
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
return []
|
||||
}
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
async function delete_akaze_features_by_id(image_id: number) {
|
||||
const status = await axios.post(`${config.akaze_microservice_url}/delete_akaze_features`, { image_id: image_id })
|
||||
return status.data
|
||||
}
|
||||
|
||||
async function delete_nn_features_by_id(image_id: number) {
|
||||
const status = await axios.post(`${config.nn_microservice_url}/delete_nn_features`, { image_id: image_id })
|
||||
return status.data
|
||||
}
|
||||
|
||||
async function delete_hist_features_by_id(image_id: number) {
|
||||
const status = await axios.post(`${config.hist_microservice_url}/delete_hist_features`, { image_id: image_id })
|
||||
return status.data
|
||||
}
|
||||
|
||||
async function delete_phash_features_by_id(image_id: number) {
|
||||
const status = await axios.post(`${config.phash_microservice_url}/delete_phash_features`, { image_id: image_id })
|
||||
return status.data
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
async function calculate_all_image_features(image_id: number, image_buffer: Buffer) {
|
||||
return Promise.allSettled([
|
||||
calculate_akaze_features(image_id, image_buffer),
|
||||
calculate_nn_features(image_id, image_buffer),
|
||||
calculate_hist_features(image_id, image_buffer),
|
||||
calculate_phash_features(image_id, image_buffer),
|
||||
])
|
||||
}
|
||||
|
||||
async function delete_all_image_features(image_id: number) {
|
||||
return Promise.allSettled([
|
||||
delete_akaze_features_by_id(image_id),
|
||||
delete_nn_features_by_id(image_id),
|
||||
delete_hist_features_by_id(image_id),
|
||||
delete_phash_features_by_id(image_id)
|
||||
])
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
export default { calculate_all_image_features, delete_all_image_features, phash_reverse_search, akaze_reverse_search }
|
246
server/index.ts
246
server/index.ts
|
@ -1,224 +1,76 @@
|
|||
import express from 'express'
|
||||
import { Request, Response } from 'express';
|
||||
import bodyParser from 'body-parser';
|
||||
import multer from 'multer'
|
||||
import config from './../config/config'
|
||||
import httpProxy from 'http-proxy'
|
||||
import axios from 'axios'
|
||||
import FormData from 'form-data'
|
||||
|
||||
const app = express()
|
||||
// app.use(bodyParser.json())
|
||||
app.disable('x-powered-by')
|
||||
const apiProxy = httpProxy.createProxyServer()
|
||||
import fastifyMultipart from 'fastify-multipart'
|
||||
import fastify from 'fastify'
|
||||
import formBodyPlugin from 'fastify-formbody'
|
||||
import fastifyReplyFrom from 'fastify-reply-from'
|
||||
const server = fastify()
|
||||
server.register(formBodyPlugin)
|
||||
server.register(fastifyReplyFrom)
|
||||
const port = config.server_port
|
||||
const storage = multer.memoryStorage()
|
||||
const upload_100MB = multer({ storage: storage, limits: { files: 1, fileSize: 100000000 } }) //100MB
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
async function calculate_phash_features(image_id: number, image: Buffer) {
|
||||
const form = new FormData();
|
||||
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
||||
form.append('image_id', image_id.toString())
|
||||
const status = await axios.post(`${config.phash_microservice_url}/calculate_phash_features`, form.getBuffer(), {
|
||||
maxContentLength: Infinity,
|
||||
maxBodyLength: Infinity,
|
||||
headers: {
|
||||
...form.getHeaders()
|
||||
}
|
||||
})
|
||||
return status.data
|
||||
}
|
||||
|
||||
async function calculate_akaze_features(image_id: number, image: Buffer) {
|
||||
const form = new FormData();
|
||||
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
||||
form.append('image_id', image_id.toString())
|
||||
const status = await axios.post(`${config.akaze_microservice_url}/calculate_akaze_features`, form.getBuffer(), {
|
||||
maxContentLength: Infinity,
|
||||
maxBodyLength: Infinity,
|
||||
headers: {
|
||||
...form.getHeaders()
|
||||
}
|
||||
})
|
||||
return status.data
|
||||
}
|
||||
async function calculate_nn_features(image_id: number, image: Buffer) {
|
||||
const form = new FormData();
|
||||
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
||||
form.append('image_id', image_id.toString())
|
||||
const status = await axios.post(`${config.nn_microservice_url}/calculate_nn_features`, form.getBuffer(), {
|
||||
maxContentLength: Infinity,
|
||||
maxBodyLength: Infinity,
|
||||
headers: {
|
||||
...form.getHeaders()
|
||||
}
|
||||
})
|
||||
return status.data
|
||||
}
|
||||
|
||||
async function calculate_hist_features(image_id: number, image: Buffer) {
|
||||
const form = new FormData();
|
||||
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
||||
form.append('image_id', image_id.toString())
|
||||
const status = await axios.post(`${config.hist_microservice_url}/calculate_hist_features`, form.getBuffer(), {
|
||||
maxContentLength: Infinity,
|
||||
maxBodyLength: Infinity,
|
||||
headers: {
|
||||
...form.getHeaders()
|
||||
}
|
||||
})
|
||||
return status.data
|
||||
}
|
||||
|
||||
async function phash_reverse_search(image: Buffer) {
|
||||
try {
|
||||
const form = new FormData();
|
||||
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
||||
const status = await axios.post(`${config.phash_microservice_url}/phash_reverse_search`, form.getBuffer(), {
|
||||
maxContentLength: Infinity,
|
||||
maxBodyLength: Infinity,
|
||||
headers: {
|
||||
...form.getHeaders()
|
||||
}
|
||||
})
|
||||
return status.data
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
return []
|
||||
server.register(fastifyMultipart, {
|
||||
attachFieldsToBody: true,
|
||||
sharedSchemaId: '#mySharedSchema',
|
||||
limits: {
|
||||
fieldNameSize: 100, // Max field name size in bytes
|
||||
fieldSize: 1000, // Max field value size in bytes
|
||||
fields: 10, // Max number of non-file fields
|
||||
fileSize: 50000000, // For multipart forms, the max file size in bytes //50MB
|
||||
files: 1, // Max number of file fields
|
||||
headerPairs: 2000 // Max number of header key=>value pairs
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
async function akaze_reverse_search(image: Buffer) {
|
||||
try {
|
||||
const form = new FormData();
|
||||
form.append('image', image, { filename: 'document' }) //hack to make nodejs buffer work with form-data
|
||||
const status = await axios.post(`${config.akaze_microservice_url}/akaze_reverse_search`, form.getBuffer(), {
|
||||
maxContentLength: Infinity,
|
||||
maxBodyLength: Infinity,
|
||||
headers: {
|
||||
...form.getHeaders()
|
||||
}
|
||||
})
|
||||
return status.data
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
return []
|
||||
}
|
||||
}
|
||||
import calculate_all_image_features from "./routes/calculate_all_image_features"
|
||||
import delete_all_image_features from "./routes/delete_all_image_features"
|
||||
import reverse_search from "./routes/reverse_search"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
async function delete_akaze_features_by_id(image_id: number) {
|
||||
const status = await axios.post(`${config.akaze_microservice_url}/delete_akaze_features`, { image_id: image_id })
|
||||
return status.data
|
||||
}
|
||||
|
||||
async function delete_nn_features_by_id(image_id: number) {
|
||||
const status = await axios.post(`${config.nn_microservice_url}/delete_nn_features`, { image_id: image_id })
|
||||
return status.data
|
||||
}
|
||||
|
||||
async function delete_hist_features_by_id(image_id: number) {
|
||||
const status = await axios.post(`${config.hist_microservice_url}/delete_hist_features`, { image_id: image_id })
|
||||
return status.data
|
||||
}
|
||||
|
||||
async function delete_phash_features_by_id(image_id: number) {
|
||||
const status = await axios.post(`${config.phash_microservice_url}/delete_phash_features`, { image_id: image_id })
|
||||
return status.data
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
async function calculate_all_image_features(image_id: number, image_buffer: Buffer) {
|
||||
return Promise.allSettled([
|
||||
calculate_akaze_features(image_id, image_buffer),
|
||||
calculate_nn_features(image_id, image_buffer),
|
||||
calculate_hist_features(image_id, image_buffer),
|
||||
calculate_phash_features(image_id, image_buffer),
|
||||
])
|
||||
}
|
||||
|
||||
async function delete_image_features(image_id: number) {
|
||||
return Promise.allSettled([
|
||||
delete_akaze_features_by_id(image_id),
|
||||
delete_nn_features_by_id(image_id),
|
||||
delete_hist_features_by_id(image_id),
|
||||
delete_phash_features_by_id(image_id)
|
||||
])
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////ALL
|
||||
app.post('/calculate_all_image_features', [upload_100MB.single('image')], async (req: Request, res: Response) => {
|
||||
const image_id = parseInt(req.body.image_id)
|
||||
if (req.file && typeof image_id === "number") {
|
||||
const results = await calculate_all_image_features(image_id, req.file.buffer)
|
||||
console.log(results)
|
||||
res.send(results)
|
||||
} else {
|
||||
return res.sendStatus(403)
|
||||
}
|
||||
})
|
||||
|
||||
app.post('/delete_all_image_features',[bodyParser.json()], async (req: Request, res: Response) => {
|
||||
const image_id = parseInt(req.body.image_id)
|
||||
if (typeof image_id === "number") {
|
||||
const results = await delete_image_features(image_id)
|
||||
console.log(results)
|
||||
res.send(results)
|
||||
} else {
|
||||
return res.sendStatus(403)
|
||||
}
|
||||
})
|
||||
|
||||
app.post('/reverse_search', [upload_100MB.single('image')], async (req: Request, res: Response) => {
|
||||
if (req.file) {
|
||||
const phash_found=await phash_reverse_search(req.file.buffer)
|
||||
if(phash_found.length!==0){
|
||||
res.json(phash_found)
|
||||
}else{
|
||||
const akaze_found=await akaze_reverse_search(req.file.buffer)
|
||||
res.json(akaze_found)
|
||||
}
|
||||
} else {
|
||||
return res.sendStatus(403)
|
||||
}
|
||||
})
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
server.post("/calculate_all_image_features",calculate_all_image_features)
|
||||
server.post("/delete_all_image_features",delete_all_image_features)
|
||||
server.post("/reverse_search",reverse_search)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////PROXY
|
||||
app.post(['/akaze_reverse_search','/calculate_akaze_features','/delete_akaze_features'], async (req, res) => {
|
||||
const akaze_routes = ['/akaze_reverse_search', '/calculate_akaze_features', '/delete_akaze_features']
|
||||
akaze_routes.forEach((r) => server.post(r, async (_req, res) => {
|
||||
try {
|
||||
apiProxy.web(req, res, { target: config.akaze_microservice_url });
|
||||
res.from(config.akaze_microservice_url)
|
||||
} catch (err) {
|
||||
res.status(500).send('Akaze microservice is down')
|
||||
}
|
||||
})
|
||||
}))
|
||||
|
||||
app.post(['/nn_get_similar_images_by_image_buffer','/nn_get_similar_images_by_text',
|
||||
'/nn_get_similar_images_by_id','/calculate_nn_features','/delete_nn_features','/nn_get_image_tags_by_image_buffer'], async (req, res) => {
|
||||
const nn_routes = ['/nn_get_similar_images_by_image_buffer', '/nn_get_similar_images_by_text',
|
||||
'/nn_get_similar_images_by_id', '/calculate_nn_features', '/delete_nn_features', '/nn_get_image_tags_by_image_buffer']
|
||||
nn_routes.forEach((r) => server.post(r, async (_req, res) => {
|
||||
try {
|
||||
apiProxy.web(req, res, { target: config.nn_microservice_url });
|
||||
res.from(config.nn_microservice_url)
|
||||
} catch (err) {
|
||||
res.status(500).send('NN microservice is down')
|
||||
}
|
||||
})
|
||||
app.post(['/hist_get_similar_images_by_image_buffer','/hist_get_similar_images_by_id','/calculate_hist_features','/delete_hist_features'], async (req, res) => {
|
||||
}))
|
||||
|
||||
const hist_routes = ['/hist_get_similar_images_by_image_buffer', '/hist_get_similar_images_by_id', '/calculate_hist_features', '/delete_hist_features']
|
||||
hist_routes.forEach((r) => server.post(r, async (_req, res) => {
|
||||
try {
|
||||
apiProxy.web(req, res, { target: config.hist_microservice_url });
|
||||
res.from(config.hist_microservice_url)
|
||||
} catch (err) {
|
||||
res.status(500).send('HIST microservice is down')
|
||||
}
|
||||
})
|
||||
}))
|
||||
|
||||
app.post(['/phash_reverse_search','/calculate_phash_features','/delete_phash_features'], async (req, res) => {
|
||||
const phash_routes = ['/phash_reverse_search', '/calculate_phash_features', '/delete_phash_features']
|
||||
phash_routes.forEach((r) => server.post(r, async (_req, res) => {
|
||||
try {
|
||||
apiProxy.web(req, res, { target: config.phash_microservice_url });
|
||||
res.from(config.phash_microservice_url)
|
||||
} catch (err) {
|
||||
res.status(500).send('Phash microservice is down')
|
||||
}
|
||||
})
|
||||
|
||||
}))
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Server is listening on port ${port}`);
|
||||
});
|
||||
server.listen(port, "127.0.0.1", function (err, address) {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
}
|
||||
console.log(`server listening on ${address}`)
|
||||
})
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
import { FastifyRequest, FastifyReply } from "fastify"
|
||||
import { FromSchema } from "json-schema-to-ts";
|
||||
import image_ops from "./../helpers/image_ops"
|
||||
const body_schema_calculate_all_image_features = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
image: { $ref: '#mySharedSchema' },
|
||||
image_id: {
|
||||
type: "object",
|
||||
properties: {
|
||||
value: { type: 'string' }
|
||||
}
|
||||
},
|
||||
},
|
||||
required: ['image', 'image_id'],
|
||||
} as const;
|
||||
|
||||
async function calculate_all_image_features(req: FastifyRequest<{ Body: FromSchema<typeof body_schema_calculate_all_image_features> }>, res: FastifyReply) {
|
||||
let image_buffer: Buffer;
|
||||
try {
|
||||
image_buffer = await (req as any).body.image.toBuffer()
|
||||
} catch (err) {
|
||||
return res.status(500).send()
|
||||
}
|
||||
if (req.body.image_id.value) {
|
||||
const image_id = parseInt(req.body.image_id.value)
|
||||
const results = await image_ops.calculate_all_image_features(image_id, image_buffer)
|
||||
console.log(results)
|
||||
res.send(results)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
schema: {
|
||||
body: body_schema_calculate_all_image_features
|
||||
},
|
||||
handler: calculate_all_image_features
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import { FastifyRequest, FastifyReply } from "fastify"
|
||||
import { FromSchema } from "json-schema-to-ts";
|
||||
import image_ops from "./../helpers/image_ops"
|
||||
const body_schema_delete_all_image_features = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
image_id: { type: "number" }
|
||||
},
|
||||
required: ['image_id'],
|
||||
} as const;
|
||||
|
||||
async function delete_all_image_features(req: FastifyRequest<{ Body: FromSchema<typeof body_schema_delete_all_image_features> }>, res: FastifyReply) {
|
||||
const results = await image_ops.delete_all_image_features(req.body.image_id)
|
||||
console.log(results)
|
||||
res.send(results)
|
||||
}
|
||||
|
||||
export default {
|
||||
schema: {
|
||||
body: body_schema_delete_all_image_features
|
||||
},
|
||||
handler: delete_all_image_features
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
import { FastifyRequest, FastifyReply } from "fastify"
|
||||
import { FromSchema } from "json-schema-to-ts";
|
||||
import image_ops from "./../helpers/image_ops"
|
||||
const body_schema_reverse_search = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
image: { $ref: '#mySharedSchema' },
|
||||
},
|
||||
required: ['image'],
|
||||
} as const;
|
||||
|
||||
async function reverse_search(req: FastifyRequest<{ Body: FromSchema<typeof body_schema_reverse_search> }>, res: FastifyReply) {
|
||||
let image_buffer: Buffer;
|
||||
try {
|
||||
image_buffer = await (req as any).body.image.toBuffer()
|
||||
} catch (err) {
|
||||
return res.status(500).send()
|
||||
}
|
||||
const phash_found = await image_ops.phash_reverse_search(image_buffer)
|
||||
if (phash_found.length !== 0) {
|
||||
res.send(phash_found)
|
||||
} else {
|
||||
const akaze_found = await image_ops.akaze_reverse_search(image_buffer)
|
||||
res.send(akaze_found)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
schema: {
|
||||
body: body_schema_reverse_search
|
||||
},
|
||||
handler: reverse_search
|
||||
}
|
Loading…
Reference in New Issue