-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.js
100 lines (94 loc) · 3.35 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import config from "./config/index.js"
import * as utils from "./lib/utils.js"
// Initialize express with settings
import express from "express"
export const app = express()
app.set("json spaces", 2)
if (config.proxies && config.proxies.length) {
app.set("trust proxy", config.proxies)
}
app.use((req, res, next) => {
if (req.headers.origin) {
// Allow all origins by returning the request origin in the header
res.setHeader("Access-Control-Allow-Origin", req.headers.origin)
} else {
// Fallback to * if there is no origin in header
res.setHeader("Access-Control-Allow-Origin", "*")
}
res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization")
res.setHeader("Access-Control-Allow-Methods", "GET")
res.setHeader("Access-Control-Expose-Headers", "X-Total-Count, Link")
res.setHeader("Content-Type", "application/json; charset=utf-8")
next()
})
// Load compatible schemes from database
import Database from "better-sqlite3"
const db = new Database(config.database)
let schemes
function updateSchemes() {
const newSchemes = db.prepare("SELECT * FROM schemes").all().map(s => Object.assign({ _key: s.key }, JSON.parse(s.json)))
if (schemes?.length) {
// Detect and print new detected schemes to console
for (const scheme of newSchemes) {
if (!schemes?.find(s => jskos.compare(s, scheme))) {
console.log(`Detected new compatible scheme: ${jskos.notation(scheme)} (${scheme.uri})`)
}
}
}
schemes = newSchemes
}
updateSchemes()
setInterval(updateSchemes, 10000)
import typesense from "./lib/typesense.js"
import jskos from "jskos-tools"
app.get(
"/search",
utils.wrappers.async(async (req) => {
// Check if vocabulary is compatbile
const scheme = schemes.find(s => jskos.compare(s, { uri: req.query.voc }))
if (!scheme) {
throw new Error(`Incompatible scheme: ${req.query.voc}`)
}
if (!req.query.search) {
return []
}
// Get results from Typesense backend
const collection = `${scheme._key}-suggestions`
const limit = parseInt(req.query.limit) || 100
const offset = parseInt(req.query.offset) || 0
const per_page = limit
const page = Math.floor(offset / limit + 1)
if (!await typesense.exists(collection)) {
return []
}
const result = await typesense.search(collection, req.query.search, ["identifier", "prefLabel", "altLabel", "mappingLabelsExactClose", "mappingLabelsNarrowBroad", "notes"], { per_page, page })
// Return concept data only
return result.hits.map(hit => {
const concept = hit.document.concept
// Reduce concept data a bit
// TODO: Maybe do this during import already
delete concept._mappings
delete concept.ancestors
delete concept.narrower
;["broader", "inScheme"].forEach(key => {
if (Array.isArray(concept[key])) {
concept[key] = concept[key].map(({ uri }) => ({ uri }))
}
})
return concept
})
}),
utils.returnJSON,
)
const start = async () => {
// if (config.env == "test") {
// const portfinder = require("portfinder")
// portfinder.basePort = config.port
// config.port = await portfinder.getPortPromise()
// }
app.listen(config.port, () => {
config.log(`Now listening on port ${config.port}`)
})
}
// Start express server immediately even if database is not yet connected
start()