link-server-class
Version:
Provides a class that runs an http server with paths addressing processes that run search queries, many of which may be common database type of search queries.
244 lines (204 loc) • 7.78 kB
JavaScript
// data server under ....<app name>
// viewing data server
//
const fs = require('fs')
const polka = require('polka');
const send = require('@polka/send-type');
const bodyParser = require('body-parser');
const cors = require('cors')
// create application/json parser
const jsonParser = bodyParser.json()
// create application/x-www-form-urlencoded parser
const urlencodedParser = bodyParser.urlencoded({ extended: false })
//
const {ObjFileDirLoader, SearchesByUser} = require('copious-little-searcher')
const EntryWatcher = require('./app_dir_watcher.js')
const RecordSearchApp = require('./the_record_searcher_app.js')
// ---- ---- ---- ---- ---- ---- ---- ---- ----
//
const TIMEOUT_THRESHOLD = 8*60*60 // in seconds
class GeneralLinkServer {
constructor(conf) {
//
this.conf = conf
this.app = false
// now to be a parameter of the class
const AppSearching = require(this.conf.application_searcher) // the definer of this data type
this.search_app = new RecordSearchApp(this.conf,SearchesByUser,AppSearching,EntryWatcher,ObjFileDirLoader)
this._port = false
this._items_loader = false
this._search_interface = false
//
if ( conf.timeout_threshold ) {
this.timeout_threshold = parseInt(conf.timeout_threshold)
} else {
this.timeout_threshold = TIMEOUT_THRESHOLD
}
//
}
/**
* initialize
*/
async initialize(prune_timeout) {
//
const app = polka();
app.use(cors())
app.use(jsonParser)
app.use(urlencodedParser)
this.app = app
this.html_paths()
// ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
//
this._port = this.search_app.port()
this._items_loader = this.search_app.items_loader()
this._search_interface = this.search_app.search_interface()
this._dir_watcher = this.search_app.dir_watcher()
this._link_manager = this._dir_watcher._link_manager
this._link_manager.add_instance_target("data-server",this) // tell the link manager to look for this LMTP server for path use
//
// ---- ---- ---- ---- MESSAGE RELAY....(for publishing assets)
// had a message relay here for publishing that a new entry came in... leave it up to data supplier to publish
// ---- ---- ---- ---- WATCH SUBDIRECTORY.... // Get new data as files. Files may contain one (dedicated file) or more entries (JSON array)
this.search_app.start_watching_files()
//
// ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
// ---- ---- ---- ---- RUN ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- ----
// // //
//
this._items_loader.load_directory()
this._search_interface.restore_searches()
let self = this
this._prune_timeout = setInterval(() => {
self.prune_searches()
},prune_timeout)
//
}
/**
* prune_searches
*/
prune_searches() {
console.log("pruning searches")
let count = this._search_interface.prune(this.timeout_threshold)
console.log(`searches pruned: ${count}`)
}
/**
* start
*/
async start() {
try {
this.app.listen(this._port, () => {
console.log(`[contact searcher] Application Listening on Port ${this._port}`);
})
} catch (err) {
this.app.log.error(err)
process.exit(1)
}
}
shutdown() {
console.log('shutdown');
if ( this._prune_timeout !== null ) {
clearInterval(this._prune_timeout)
}
if ( this._search_interface ) {
this._search_interface.backup_searches(true)
} else {
process.exit(0)
}
}
// ---- ---- ---- ---- HTML APPLICATION PATHWAYS ---- ---- ---- ---- ---- ---- ----
/**
* html_paths
*/
html_paths() {
if( this.app === false ) {
throw new Error("could not initialize basic html paths")
}
this.app.get('/',(req, res) => {
try {
if ( this.conf && this.conf.index_file ) {
const data = fs.readFileSync(this.conf.index_file)
send(res,200,data)
} else {
const data = fs.readFileSync("./index.html")
send(res,200,data)
}
} catch (e) {
send(res,404,"what")
}
})
/**
* /:uid/:query/:bcount/:offset
*
* GET
* /:uid - USER ID -- a ccwid of the caller --- check on rate limit if implemented
* /:query - SYNTACTICALLY APPROPRIATE QUERY
* /:bcount - THE NUMBER OF QUERY RESULTS TO RETURN
* /:offset - THE OFFSET (starting point) in the query data
*
*/
this.app.get('/:uid/:query/:bcount/:offset', async (req, res) => {
let data = await this.search_app.rated_search_processing(req,res)
send(res,200,data)
})
/**
* /custom/:owner/:query/:bcount/:offset
* GET
*
* /:uid - USER ID -- a ccwid
* /:owner --
* /:query - SYNTACTICALLY APPROPRIATE QUERY
* /:bcount - THE NUMBER OF QUERY RESULTS TO RETURN
* /:offset - THE OFFSET (starting point) in the query data
*
*/
this.app.get('/custom/:owner/:query/:bcount/:offset', async (req, res) => {
let data = await this.search_app.rated_custom_search_processing(req,res)
send(res,200,data)
})
this.app.post('/custom/:op/:owner', async (req, res) => {
let data = await this.search_app.rated_custom_search_ops(req,res)
send(res,200,data)
})
// // put these into an endpoint that can be managed by the tool.
// this.app.get('/cycle/:halt', (req, res) => {
// // requires admin permission
// let do_halt = req.params.halt
// this._search_interface.backup_searches(do_halt)
// send(res,200,"OK")
// })
// this.app.get('/reload',(req, res) => {
// // requires admin permission
// this._items_loader.load_directory()
// send(res,200,"OK")
// })
// this.app.get('/persistence/add-publisher/:plink', (req, res) => {
// // requires admin permission
// let persistence_link = req.params.plink
// persistence_link = decodeURIComponent(persistence_link)
// // check that this publisher is OK. This will give us a link making
// // this service be a client for subcription to publication...
// this.search_app.add_persistence_service(persistence_link,'admin-contacts')
// send(res,200,{ "status" : "OK" })
// })
}
// now admin comes from a tool that connects to this application's link_manager endpoint
//
async external_op_request(conf) {
switch ( conf.command ) {
case "cycle": {
let do_halt = ((conf.halt !== undefined) ? conf.halt : false)
this._search_interface.backup_searches(do_halt)
break
}
case "reload" : {
this._items_loader.load_directory()
break;
}
default : {
break;
}
}
}
}
module.exports = GeneralLinkServer