UNPKG

tika-server

Version:

Apache Tika Server as a Background Service

208 lines (184 loc) 7.71 kB
/* ** Tika-Server -- Apache Tika Server as a Background Service ** Copyright (c) 2018-2025 Dr. Ralf S. Engelschall <rse@engelschall.com> ** ** Permission is hereby granted, free of charge, to any person obtaining ** a copy of this software and associated documentation files (the ** "Software"), to deal in the Software without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Software, and to ** permit persons to whom the Software is furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be included ** in all copies or substantial portions of the Software. ** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ** SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* internal requirements */ const path = require("path") const childProcess = require("child_process") /* external requirements */ const which = require("which") const findFreePort = require("find-free-port") const EventEmitter = require("eventemitter3") const axios = require("axios") /* the API class */ class TikaServer extends EventEmitter { constructor (options = {}) { super() /* determine options */ this.options = Object.assign({}, { javaBinary: "java", javaOptions: "-server -Xms1G -Xmx1G", tikaBinary: path.join(__dirname, "tika-server-cli.jar"), tikaConfig: path.join(__dirname, "tika-server-cli.xml"), tikaOptions: "", tikaHost: "127.0.0.1", tikaPortMin: 41000, tikaPortMax: 42000 }, options) /* initialize internal state */ this.proc = null this.port = 0 } /* start the Apache Tika Server service */ async start () { /* sanity check usage */ if (this.proc !== null) throw new Error("Apache Tika Server process already running") /* resolve path to Java binary */ const javaBinary = await new Promise((resolve, reject) => { which(this.options.javaBinary).then((filename) => { resolve(filename) }).catch(() => { reject(new Error("unable to find mandatory Java binary " + `"${this.options.javaBinary}" in your $PATH`)) }) }) /* determine free TCP/IP port */ this.port = await findFreePort( this.options.tikaPortMin, this.options.tikaPortMax, this.options.tikaHost) /* spawn the Apache Tika Server process */ this.emit("tika-start") this.emit("debug", "tika: starting") this.proc = childProcess.spawn(javaBinary, [ ...this.options.javaOptions.split(/\s+/), "-jar", this.options.tikaBinary, ...this.options.tikaOptions.split(/\s+/), "--config", this.options.tikaConfig, "--host", this.options.tikaHost, "--port", this.port ], {}) /* detect shutdown of Apache Tika Server process */ this.proc.on("close", (code) => { this.emit("tika-close", code) this.emit("debug", `tika: close (code: ${code})`) this.proc = null }) /* pass-through stdout of Apache Tika Server process */ this.proc.stdout.on("data", (data) => { this.emit("tika-stdout", data) this.emit("debug", `tika: stdout: ${data.toString()})`) }) /* pass-through stderr of Apache Tika Server process and detect when it is finall ready to service requests */ return new Promise((resolve, reject) => { this.proc.stderr.on("data", (data) => { this.emit("tika-stderr", data) this.emit("debug", `tika: stderr: ${data.toString()})`) if (data.toString().match(/Started\s+Apache\s+Tika\s+server/)) { this.emit("tika-started") this.emit("debug", "tika: started") resolve() } }) }) } /* query the Apache Tika Server service */ async query (content, options = {}) { /* sanity check usage */ if (this.proc === null) throw new Error("Apache Tika Server process not running") /* determine options */ options = Object.assign({}, { endpoint: "tika", type: "application/octet-stream", accept: "text/xml", response: "blob", maxlength: 256 * 1024 * 1024, filename: "" }, options) /* query Apache Tika Server process via its HTTP interface */ const request = { method: "PUT", url: `http://${this.options.tikaHost}:${this.port}/${options.endpoint}`, headers: { "Content-Type": options.type, Accept: options.accept }, data: content, responseType: options.response, maxContentLength: options.maxlength } if (options.filename !== "") { const filename = path.basename(options.filename) request.headers["Content-Disposition"] = `attachment; filename=${filename}` } this.emit("tika-query-request", request) this.emit("debug", `tika: query: request=${JSON.stringify(request)}`) return axios(request).then((response) => { this.emit("tika-query-response", response.data) this.emit("debug", `tika: query: response=${JSON.stringify(response.data)}`) return response.data }) } /* query the Apache Tika Server service for meta information only */ async queryMeta (content, options = {}) { /* determine options */ options = Object.assign({}, options, { endpoint: "meta", accept: "application/json", response: "json" }) /* pass-through query */ return this.query(content, options) } /* query the Apache Tika Server service for text extraction only */ async queryText (content, options = {}) { /* determine options */ options = Object.assign({}, options, { endpoint: "tika", accept: "text/plain", response: "text" }) /* pass-through query */ return this.query(content, options) } /* stop the Apache Tika Server service */ async stop () { /* sanity check usage */ if (this.proc === null) throw new Error("Apache Tika Server process not running") /* send process termination signal and await its shutdown */ this.emit("tika-stop") this.emit("debug", "tika: stopping") return new Promise((resolve, reject) => { this.proc.on("close", (code) => { this.emit("tika-stopped") this.emit("debug", "tika: stopped") resolve() }) this.proc.kill("SIGTERM") }) } } /* export API class */ module.exports = TikaServer