Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
fergiemcdowall committed Sep 20, 2024
1 parent d225d78 commit c26beca
Show file tree
Hide file tree
Showing 17 changed files with 766 additions and 87 deletions.
2 changes: 1 addition & 1 deletion build/mirrorUnpkg.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ Promise.all(
files.map(f =>
fetch('https://unpkg.com/swagger-ui-dist@4.5.0/' + f)
.then(res => res.text())
.then(text => writeFile('www_root/api/' + f, text))
.then(text => writeFile('www_root/openapi/' + f, text))
)
)
4 changes: 2 additions & 2 deletions build/openAPIDoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const swaggerDefinition = {
url: '{URL}',
variables: {
URL: {
default: 'http://localhost:3030'
default: 'http://localhost:3030/API'
}
}
}
Expand Down Expand Up @@ -284,7 +284,7 @@ const swaggerDefinition = {
}

writeFileSync(
'www_root/api/openapi-norch-' + version + '.json',
'www_root/openapi/openapi-norch-' + version + '.json',
JSON.stringify(
swaggerJsdoc({
swaggerDefinition,
Expand Down
69 changes: 43 additions & 26 deletions src/API.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
export class API {
constructor (index, sendResponse, events) {
this.index = index
this.sendResponse = sendResponse
constructor(index, sendResponse, events, logResponse) {
this.events = events
this.index = index
this.logResponse = logResponse
this.ready = false
this.sendResponse = sendResponse
events.on('ready', () => (this.ready = true))
}

Expand All @@ -19,10 +20,20 @@ export class API {

param = (req, name) => this.params(req, name)[0]

sendJSONResponse = (body, res) => {
sendJSONResponse = (body, req, res, statusCode) => {
res.setHeader('Content-Type', 'application/json; charset=utf-8')
res.writeHead(200)
res.writeHead(statusCode)
res.end(JSON.stringify(body, null, 2))
this.logResponse(statusCode, req.url)
}

internalServerError = (e, req, res) => {
this.sendJSONResponse(
{ status: 500, error: 'Internal Server Error' },
req,
res,
500
)
}

/**
Expand All @@ -40,7 +51,7 @@ export class API {
ALL_DOCUMENTS = (req, res) =>
this.index
.ALL_DOCUMENTS(+this.params(req, 'LIMIT') || undefined)
.then(ad => this.sendJSONResponse(ad, res))
.then(ad => this.sendJSONResponse(ad, req, res, 200))

/**
* @openapi
Expand All @@ -57,7 +68,7 @@ export class API {
BUCKETS = (req, res) =>
this.index
.BUCKETS(...this.params(req, 'TOKENSPACE'))
.then(b => this.sendJSONResponse(b, res))
.then(b => this.sendJSONResponse(b, req, res, 200))

/**
* @openapi
Expand All @@ -74,7 +85,7 @@ export class API {
DELETE = (req, res) =>
this.index
.DELETE(...this.params(req, 'ID'))
.then(idxRes => this.sendJSONResponse(idxRes, res))
.then(idxRes => this.sendJSONResponse(idxRes, req, res, 200))

// TODO: DELETE_RAW?

Expand All @@ -98,7 +109,7 @@ export class API {
this.index
.DICTIONARY(...this.params(req, 'TOKENSPACE'))
.then(d => d.slice(0, +this.params(req, 'LIMIT')))
.then(d => this.sendJSONResponse(d, res))
.then(d => this.sendJSONResponse(d, req, res, 200))

/**
* @openapi
Expand All @@ -120,7 +131,7 @@ export class API {
this.index
.DISTINCT(...this.params(req, 'TOKENSPACE'))
.then(d => d.slice(0, +this.params(req, 'LIMIT')))
.then(d => this.sendJSONResponse(d, res))
.then(d => this.sendJSONResponse(d, req, res, 200))

/**
* @openapi
Expand All @@ -137,7 +148,7 @@ export class API {
DOCUMENTS = (req, res) =>
this.index
.DOCUMENTS(...this.params(req, 'ID'))
.then(b => this.sendJSONResponse(b, res))
.then(b => this.sendJSONResponse(b, req, res, 200))

// TODO: DOCUMENT_VECTORS?

Expand All @@ -153,7 +164,7 @@ export class API {
* description: A dump of the index
*/
EXPORT = (req, res) =>
this.index.EXPORT().then(exp => this.sendJSONResponse(exp, res))
this.index.EXPORT().then(exp => this.sendJSONResponse(exp, req, res, 200))

/**
* @openapi
Expand All @@ -173,7 +184,7 @@ export class API {
FACETS = (req, res) =>
this.index
.FACETS(...this.params(req, 'TOKENSPACE'))
.then(b => this.sendJSONResponse(b, res))
.then(b => this.sendJSONResponse(b, req, res, 200))

/**
* @openapi
Expand All @@ -186,7 +197,7 @@ export class API {
* description: An array of field names
*/
FIELDS = (req, res) =>
this.index.FIELDS().then(f => this.sendJSONResponse(f, res))
this.index.FIELDS().then(f => this.sendJSONResponse(f, req, res, 200))

/**
* @openapi
Expand All @@ -199,7 +210,9 @@ export class API {
* description: Successfully deleted
*/
FLUSH = (req, res) =>
this.index.FLUSH().then(idxRes => this.sendJSONResponse(idxRes, res))
this.index
.FLUSH()
.then(idxRes => this.sendJSONResponse(idxRes, req, res, 200))

/**
* @openapi
Expand All @@ -225,7 +238,7 @@ export class API {
req.on('end', () =>
this.index
.IMPORT(JSON.parse(body))
.then(idxRes => this.sendJSONResponse(idxRes, res))
.then(idxRes => this.sendJSONResponse(idxRes, req, res, 200))
)
}

Expand All @@ -244,7 +257,7 @@ export class API {
MAX = (req, res) =>
this.index
.MAX(...this.params(req, 'TOKENSPACE'))
.then(m => this.sendJSONResponse(m, res))
.then(m => this.sendJSONResponse(m, req, res, 200))

/**
* @openapi
Expand All @@ -261,7 +274,7 @@ export class API {
MIN = (req, res) =>
this.index
.MIN(JSON.parse(this.params(req, 'TOKENSPACE'))) // TODO: is this right?
.then(m => this.sendJSONResponse(m, res))
.then(m => this.sendJSONResponse(m, req, res, 200))

/**
* @openapi
Expand Down Expand Up @@ -331,12 +344,14 @@ export class API {

// curl -H "Content-Type: application/json" --data @testdata.json http://localhost:8081/put
PUT = (req, res) => {
console.log('I AM HEEEEEREEE IN PUT')
let body = ''
req.on('data', d => (body += d.toString()))
req.on('end', () =>
this.index
.PUT(JSON.parse(body))
.then(idxRes => this.sendJSONResponse(idxRes, res))
.then(idxRes => this.sendJSONResponse(idxRes, req, res, 200))
.catch(e => this.internalServerError(e, req, res))
)
}

Expand Down Expand Up @@ -366,7 +381,7 @@ export class API {
req.on('end', () =>
this.index
.PUT_RAW(JSON.parse(body))
.then(idxRes => this.sendJSONResponse(idxRes, res))
.then(idxRes => this.sendJSONResponse(idxRes, req, res, 200))
)
}

Expand Down Expand Up @@ -462,7 +477,7 @@ export class API {
SCORE: this.param(req, 'SCORE'),
SORT: this.param(req, 'SORT')
})
.then(r => this.sendJSONResponse(r, res))
.then(r => this.sendJSONResponse(r, req, res, 200))

/**
* @openapi
Expand Down Expand Up @@ -497,7 +512,7 @@ export class API {
.SEARCH(this.param(req, 'STRING').trim().split(/\s+/), {
PAGE: this.param(req, 'PAGE')
})
.then(r => this.sendJSONResponse(r, res))
.then(r => this.sendJSONResponse(r, req, res, 200))

/**
* @openapi
Expand All @@ -523,7 +538,9 @@ export class API {
CREATED: new Date(CREATED),
LAST_UPDATED: new Date(LAST_UPDATED)
},
res
req,
res,
200
)
)

Expand All @@ -541,8 +558,8 @@ export class API {
*/
READY = (req, res) =>
this.ready
? this.sendJSONResponse({ READY: true }, res)
? this.sendJSONResponse({ READY: true }, req, res, 200)
: this.events.on('ready', () =>
this.sendJSONResponse({ READY: true }, res)
)
this.sendJSONResponse({ READY: true }, req, res, 200)
)
}
67 changes: 38 additions & 29 deletions src/Norch.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import { API } from './API.js'
import { SearchIndex } from 'search-index'
import { createServer } from 'node:http'
import { fileURLToPath } from 'url'
import { readdirSync, readFileSync } from 'node:fs'
import { createReadStream, readdirSync, readFileSync } from 'node:fs'
import { resolve, dirname } from 'path'
import figlet from 'figlet'

export class Norch {
constructor (ops = {}) {
constructor(ops = {}) {
const defaultConfigFile = JSON.parse(
readFileSync(new URL('../defaultConfig.json', import.meta.url))
)
Expand All @@ -22,7 +22,12 @@ export class Norch {
this.splash(this.index, this.options.port)
.then(() =>
this.createNorchServer(
new API(this.index, this.sendResponse, this.events)
new API(
this.index,
this.sendResponse,
this.events,
this.logResponse
)
)
)
.then(server => {
Expand All @@ -34,6 +39,9 @@ export class Norch {
})
}

logResponse = (statusCode, path) =>
console.info('[' + statusCode + '] ' + path)

readUserConfigFile = location => {
// if no user config defined, simply return an empty object
if (!location) return {}
Expand All @@ -50,7 +58,7 @@ export class Norch {
index.CREATED(),
index.DOCUMENT_COUNT()
]).then(res =>
console.log(
console.info(
`
${figlet
.textSync('NORCH', { font: 'Isometric1', horizontalLayout: 'full' })
Expand All @@ -69,32 +77,26 @@ export class Norch {
)

sendResponse = (body, res, type) => {
res.setHeader('Content-Type', type + '; charset=utf-8')
res.setHeader('Content-Type', type)
res.writeHead(200)
res.end(body)
}

createNorchServer = api =>
createServer((req, res) => {
// strip hostname, protocol, url-params, etc
let pathname = new URL(req.url, `http://${req.headers.host}/`).pathname
console.info(pathname)

if (req.method === 'GET') {
const fileDirs = ['/', '/api/']

// default to index.html when only file-directory is specified
if (fileDirs.includes(pathname)) pathname += 'index.html'

// Serve up static files files
if (this.files(fileDirs).includes(pathname)) {
console.log(dirname(fileURLToPath(import.meta.url)))
return this.sendFileResponse(pathname, res)
}
// Serve up API requests
if (pathname.split('/')[1] === 'API') {
return api[pathname.split('/')[2]]
? api[pathname.split('/')[2]](req, res)
: this._404(res, pathname)
}

return api[pathname.slice(1)]
? api[pathname.slice(1)](req, res)
: this._404(req, res)
// serve up file requests (default to index.html when only file-directory
// is specified)
if (/^\/.*\/$|^\/$/.test(pathname)) pathname += 'index.html'
return this.sendFileResponse(pathname, res)
})

files = dirs => {
Expand All @@ -107,17 +109,24 @@ export class Norch {
return dirs.map(d => getFilesInDir(d)).flat()
}

sendFileResponse = (name, res) =>
this.sendResponse(
readFileSync(
resolve(dirname(fileURLToPath(import.meta.url)), '../www_root' + name)
) + '',
res,
mime.getType(name)
sendFileResponse = (pathname, res) => {
const s = createReadStream(
resolve(dirname(fileURLToPath(import.meta.url)), '../www_root' + pathname)
)
s.on('open', () => {
res.setHeader('Content-Type', mime.getType(pathname))
s.pipe(res)
console.info('[200] ' + pathname)
})
s.on('error', e => {
// TODO: codes other than 404 here.
this._404(res, pathname)
})
}

// ("404: page not found")
_404 = (req, res) => {
_404 = (res, pathname) => {
console.info('[404] ' + pathname)
res.setHeader('Content-Type', 'text/html; charset=utf-8')
res.writeHead(404)
res.end('<html><h1>404</h1>nothing here bro!</html>')
Expand Down
Loading

0 comments on commit c26beca

Please sign in to comment.