mirror of
https://github.com/FlareSolverr/FlareSolverr.git
synced 2025-06-08 12:35:30 +00:00
189 lines
5.4 KiB
TypeScript
189 lines
5.4 KiB
TypeScript
const fs = require('fs');
|
|
const os = require('os');
|
|
const path = require('path');
|
|
const process = require('process')
|
|
import log from './log'
|
|
import { createServer, IncomingMessage, ServerResponse } from 'http';
|
|
import { RequestContext } from './types'
|
|
import Router, { BaseAPICall } from './routes'
|
|
import getCaptchaSolver from "./captcha";
|
|
import sessions from "./session";
|
|
import {v1 as UUIDv1} from "uuid";
|
|
|
|
const version: string = "v" + require('../package.json').version
|
|
const serverPort: number = Number(process.env.PORT) || 8191
|
|
const serverHost: string = process.env.HOST || '0.0.0.0'
|
|
let webBrowserUserAgent: string = ""
|
|
|
|
function validateEnvironmentVariables() {
|
|
// ip and port variables are validated by nodejs
|
|
if (process.env.LOG_LEVEL && ['error', 'warn', 'info', 'verbose', 'debug'].indexOf(process.env.LOG_LEVEL) == -1) {
|
|
log.error(`The environment variable 'LOG_LEVEL' is wrong. Check the documentation.`);
|
|
process.exit(1);
|
|
}
|
|
if (process.env.LOG_HTML && ['true', 'false'].indexOf(process.env.LOG_HTML) == -1) {
|
|
log.error(`The environment variable 'LOG_HTML' is wrong. Check the documentation.`);
|
|
process.exit(1);
|
|
}
|
|
if (process.env.HEADLESS && ['true', 'false'].indexOf(process.env.HEADLESS) == -1) {
|
|
log.error(`The environment variable 'HEADLESS' is wrong. Check the documentation.`);
|
|
process.exit(1);
|
|
}
|
|
try {
|
|
getCaptchaSolver();
|
|
} catch (e) {
|
|
log.error(`The environment variable 'CAPTCHA_SOLVER' is wrong. ${e.message}`);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
async function testWebBrowserInstallation() {
|
|
const sessionId = UUIDv1()
|
|
log.debug("Testing web browser installation...")
|
|
const session = await sessions.create(sessionId, {
|
|
oneTimeSession: true
|
|
})
|
|
const page = await session.browser.newPage()
|
|
await page.goto("https://www.google.com")
|
|
webBrowserUserAgent = await page.evaluate(() => navigator.userAgent)
|
|
log.info("FlareSolverr User-Agent: " + webBrowserUserAgent)
|
|
await page.close()
|
|
await sessions.destroy(sessionId)
|
|
log.debug("Test successful")
|
|
}
|
|
|
|
function errorResponse(errorMsg: string, res: ServerResponse, startTimestamp: number) {
|
|
log.error(errorMsg)
|
|
const response = {
|
|
status: 'error',
|
|
message: errorMsg,
|
|
startTimestamp,
|
|
endTimestamp: Date.now(),
|
|
version
|
|
}
|
|
res.writeHead(500, {
|
|
'Content-Type': 'application/json'
|
|
})
|
|
res.write(JSON.stringify(response))
|
|
res.end()
|
|
}
|
|
|
|
function successResponse(successMsg: string, extendedProperties: object, res: ServerResponse, startTimestamp: number) {
|
|
const endTimestamp = Date.now()
|
|
log.info(`Response in ${(endTimestamp - startTimestamp) / 1000} s`)
|
|
if (successMsg) { log.info(successMsg) }
|
|
|
|
const response = Object.assign({
|
|
status: 'ok',
|
|
message: successMsg || '',
|
|
startTimestamp,
|
|
endTimestamp,
|
|
version
|
|
}, extendedProperties || {})
|
|
res.writeHead(200, {
|
|
'Content-Type': 'application/json'
|
|
})
|
|
res.write(JSON.stringify(response))
|
|
res.end()
|
|
}
|
|
|
|
function validateIncomingRequest(ctx: RequestContext, params: BaseAPICall) {
|
|
log.info(`Params: ${JSON.stringify(params)}`)
|
|
|
|
if (ctx.req.method !== 'POST') {
|
|
ctx.errorResponse('Only the POST method is allowed')
|
|
return false
|
|
}
|
|
|
|
if (ctx.req.url !== '/v1') {
|
|
ctx.errorResponse('Only /v1 endpoint is allowed')
|
|
return false
|
|
}
|
|
|
|
if (!params.cmd) {
|
|
ctx.errorResponse("Parameter 'cmd' is mandatory")
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// init
|
|
log.info(`FlareSolverr ${version}`);
|
|
log.debug('Debug log enabled');
|
|
|
|
process.on('SIGTERM', () => {
|
|
// Capture signal on Docker Stop #158
|
|
log.info("Process interrupted")
|
|
process.exit(0)
|
|
})
|
|
|
|
validateEnvironmentVariables();
|
|
|
|
testWebBrowserInstallation()
|
|
.catch(e => {
|
|
log.error("Error starting web browser.", e);
|
|
process.exit(1);
|
|
})
|
|
.then(r =>
|
|
createServer((req: IncomingMessage, res: ServerResponse) => {
|
|
const startTimestamp = Date.now()
|
|
|
|
// health endpoint. this endpoint is special because it doesn't print traces
|
|
if (req.url == '/health') {
|
|
res.writeHead(200, {
|
|
'Content-Type': 'application/json'
|
|
})
|
|
res.write(JSON.stringify({"status": "ok"}))
|
|
res.end()
|
|
return;
|
|
}
|
|
|
|
// count the request for the log prefix
|
|
log.incRequests()
|
|
log.info(`Incoming request: ${req.method} ${req.url}`)
|
|
|
|
// show welcome message
|
|
if (req.url == '/') {
|
|
const extendedProperties = {"userAgent": webBrowserUserAgent};
|
|
successResponse("FlareSolverr is ready!", extendedProperties, res, startTimestamp);
|
|
return;
|
|
}
|
|
|
|
// get request body
|
|
const bodyParts: any[] = []
|
|
req.on('data', chunk => {
|
|
bodyParts.push(chunk)
|
|
}).on('end', () => {
|
|
// parse params
|
|
const body = Buffer.concat(bodyParts).toString()
|
|
let params: BaseAPICall = null
|
|
try {
|
|
params = JSON.parse(body)
|
|
} catch (err) {
|
|
errorResponse('Body must be in JSON format', res, startTimestamp)
|
|
return
|
|
}
|
|
|
|
const ctx: RequestContext = {
|
|
req,
|
|
res,
|
|
startTimestamp,
|
|
errorResponse: (msg) => errorResponse(msg, res, startTimestamp),
|
|
successResponse: (msg, extendedProperties) => successResponse(msg, extendedProperties, res, startTimestamp)
|
|
}
|
|
|
|
// validate params
|
|
if (!validateIncomingRequest(ctx, params)) { return }
|
|
|
|
// process request
|
|
Router(ctx, params).catch(e => {
|
|
console.error(e)
|
|
ctx.errorResponse(e.message)
|
|
})
|
|
})
|
|
}).listen(serverPort, serverHost, () => {
|
|
log.info(`Listening on http://${serverHost}:${serverPort}`);
|
|
})
|
|
)
|