diff --git a/src/main.ts b/src/main.ts index 5c7a411..cba998d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -24,10 +24,13 @@ import { database, OmnisearchCache } from './database' import * as NotesIndex from './notes-index' import { searchEngine } from './search/omnisearch' import { cacheManager } from './cache-manager' +import getServer from './tools/api-server' export default class OmnisearchPlugin extends Plugin { private ribbonButton?: HTMLElement + public apiHttpServer = getServer() + async onload(): Promise { await loadSettings(this) this.addSettingTab(new SettingsTab(this)) @@ -112,6 +115,10 @@ export default class OmnisearchPlugin extends Plugin { this.executeFirstLaunchTasks() await this.populateIndex() + + if (settings.httpApiEnabled) { + this.apiHttpServer.listen(settings.httpApiPort) + } }) } @@ -137,6 +144,7 @@ export default class OmnisearchPlugin extends Plugin { if (process.env.NODE_ENV === 'production') { await database.clearCache() } + this.apiHttpServer.close() } addRibbonButton(): void { diff --git a/src/settings.ts b/src/settings.ts index 938ad67..cda0217 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -58,6 +58,8 @@ export interface OmnisearchSettings extends WeightingSettings { verboseLogging: boolean vimLikeNavigationShortcut: boolean fuzziness: '0' | '1' | '2' + httpApiEnabled: boolean + httpApiPort: string } /** @@ -284,10 +286,12 @@ export class SettingsTab extends PluginSettingTab { 'Navigate down the results with Ctrl/⌘ + J/N, or navigate up with Ctrl/⌘ + K/P' ) .addToggle(toggle => - toggle.setValue(settings.vimLikeNavigationShortcut).onChange(async v => { - settings.vimLikeNavigationShortcut = v - await saveSettings(this.plugin) - }) + toggle + .setValue(settings.vimLikeNavigationShortcut) + .onChange(async v => { + settings.vimLikeNavigationShortcut = v + await saveSettings(this.plugin) + }) ) // Fuzziness @@ -454,7 +458,52 @@ export class SettingsTab extends PluginSettingTab { }) ) - //#endregion Debugginh + //#endregion Debugging + + //#region HTTP Server + + const httpServerDesc = new DocumentFragment() + httpServerDesc.createSpan({}, span => { + span.innerHTML = `Omnisearch can be used through a simple HTTP server (more information).` + }) + new Setting(containerEl) + .setName('API Access Through HTTP') + .setHeading() + .setDesc(httpServerDesc) + + new Setting(containerEl) + .setName('Enable the HTTP server') + .addToggle(toggle => + toggle.setValue(settings.httpApiEnabled).onChange(async v => { + settings.httpApiEnabled = v + if (v) { + this.plugin.apiHttpServer.listen(settings.httpApiPort) + } else { + this.plugin.apiHttpServer.close() + } + await saveSettings(this.plugin) + }) + ) + + new Setting(containerEl).setName('HTTP Port').addText(component => { + component + .setValue(settings.httpApiPort) + .setPlaceholder('51361') + .onChange(async v => { + if (parseInt(v) > 65535) { + v = settings.httpApiPort + component.setValue(settings.httpApiPort) + } + settings.httpApiPort = v + if (settings.httpApiEnabled) { + this.plugin.apiHttpServer.close() + this.plugin.apiHttpServer.listen(settings.httpApiPort) + } + await saveSettings(this.plugin) + }) + }) + + //#endregion HTTP Server //#region Danger Zone new Setting(containerEl).setName('Danger Zone').setHeading() @@ -479,6 +528,7 @@ export class SettingsTab extends PluginSettingTab { }) ) + // Disable Omnisearch const disableDesc = new DocumentFragment() disableDesc.createSpan({}, span => { span.innerHTML = `Disable Omnisearch on this device only.
@@ -498,6 +548,7 @@ export class SettingsTab extends PluginSettingTab { }) ) + // Clear cache data if (isCacheEnabled()) { const resetCacheDesc = new DocumentFragment() resetCacheDesc.createSpan({}, span => { @@ -522,7 +573,7 @@ export class SettingsTab extends PluginSettingTab { cb.setLimits(1, 5, 0.1) .setValue(settings[key]) .setDynamicTooltip() - .onChange(async (v) => { + .onChange(async v => { settings[key] = v await saveSettings(this.plugin) }) @@ -557,6 +608,9 @@ export const DEFAULT_SETTINGS: OmnisearchSettings = { weightH3: 1.1, weightUnmarkedTags: 1.1, + httpApiEnabled: false, + httpApiPort: '51361', + welcomeMessage: '', verboseLogging: false, } as const diff --git a/src/tools/api-server.ts b/src/tools/api-server.ts new file mode 100644 index 0000000..6f65152 --- /dev/null +++ b/src/tools/api-server.ts @@ -0,0 +1,61 @@ +import * as http from 'http' +import * as url from 'url' +import api from './api' +import { Notice } from 'obsidian' + +export function getServer() { + const server = http.createServer(async function (req, res) { + res.setHeader('Access-Control-Allow-Origin', '*') + res.setHeader( + 'Access-Control-Allow-Methods', + 'GET, HEAD, POST, OPTIONS, PUT, PATCH, DELETE' + ) + res.setHeader( + 'Access-Control-Allow-Headers', + 'Access-Control-Allow-Headers, Origin, Authorization,Accept,x-client-id, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers, hypothesis-client-version' + ) + res.setHeader('Access-Control-Allow-Credentials', 'true') + + try { + if (req.url) { + // parse URL + const parsedUrl = url.parse(req.url, true) + console.log(parsedUrl) + if (parsedUrl.pathname === '/search') { + const q = parsedUrl.query.q as string + console.log(q) + const results = await api.search(q) + res.statusCode = 200 + res.setHeader('Content-Type', 'application/json') + res.end(JSON.stringify(results)) + } + else { + res.end() + } + } + } catch (e) { + res.statusCode = 500 + res.end(e) + } + }) + + return { + listen(port: string) { + console.log(`Omnisearch - Starting HTTP server on port ${port}`) + server.listen({ + port: parseInt(port), + host: 'localhost', + }) + console.log(`Omnisearch - Started HTTP server on port ${port}`) + new Notice(`Omnisearch - Started HTTP server on port ${port}`) + }, + close() { + server.close() + console.log(`Omnisearch - Terminated HTTP server`) + new Notice(`Omnisearch - Terminated HTTP server`) + }, + } +} + +export default getServer +export type StaticServer = ReturnType diff --git a/src/tools/api.ts b/src/tools/api.ts index eae2d7b..711253c 100644 --- a/src/tools/api.ts +++ b/src/tools/api.ts @@ -6,6 +6,7 @@ import { refreshIndex } from '../notes-index' type ResultNoteApi = { score: number + vault: string path: string basename: string foundWords: string[] @@ -33,6 +34,7 @@ function mapResults(results: ResultNote[]): ResultNoteApi[] { const res: ResultNoteApi = { score, + vault: app.vault.getName(), path, basename, foundWords,