rats-search/src/background/background.js
2018-02-11 13:54:45 +03:00

364 lines
9.3 KiB
JavaScript

// This is main process of Electron, started as first thing when your
// app starts. It runs through entire life of your application.
// It doesn't have any windows which you can see on screen, but we can open
// window from here.
import path from "path";
import url from "url";
import { app, Menu, ipcMain, Tray, dialog } from "electron";
import createWindow from "./helpers/window";
import { autoUpdater } from 'electron-updater'
import { devMenuTemplate } from "./menu/dev_menu_template";
import { editMenuTemplate } from "./menu/edit_menu_template";
import { settingsMenuTemplate } from "./menu/config_menu_template";
import { aboutMenuTemplate } from "./menu/about_menu_template";
// Special module holding environment variables which you declared
// in config/env_xxx.json file.
import env from "env";
const { spawn, exec } = require('child_process')
const fs = require('fs')
const iconv = require('iconv-lite');
// plugins and dev tool
require('electron-context-menu')({})
const setApplicationMenu = () => {
const menus = [editMenuTemplate, settingsMenuTemplate, aboutMenuTemplate];
if (env.name !== "production") {
menus.push(devMenuTemplate);
}
Menu.setApplicationMenu(Menu.buildFromTemplate(menus));
};
// Save userData in separate folders for each environment.
// Thanks to this you can use production and development versions of the app
// on same machine like those are two separate apps.
if (env.name !== "production") {
const userDataPath = app.getPath("userData");
app.setPath("userData", `${userDataPath} (${env.name})`);
}
const resourcesPath = env.name === "production" ? process.resourcesPath : 'resources'
const spiderCall = require('./spider')
const appConfig = require('./config')
let sphinx = undefined
let spider = undefined
const util = require('util');
if (!fs.existsSync(app.getPath("userData"))){
fs.mkdirSync(app.getPath("userData"));
}
const logFile = fs.createWriteStream(app.getPath("userData") + '/rats.log', {flags : 'w'});
const logStdout = process.stdout;
console.log = (...d) => {
logFile.write(util.format(...d) + '\n');
logStdout.write(util.format(...d) + '\n');
};
const getSphinxPath = () => {
if (fs.existsSync('./searchd')) {
return './searchd'
}
if (/^win/.test(process.platform) && fs.existsSync('./searchd.exe')) {
return './searchd.exe'
}
if (fs.existsSync(fs.realpathSync(__dirname) + '/searchd')) {
return fs.realpathSync(__dirname) + '/searchd'
}
if (fs.existsSync(fs.realpathSync(path.join(__dirname, '/../../..')) + '/searchd')) {
return fs.realpathSync(path.join(__dirname, '/../../..')) + '/searchd'
}
try {
if (process.platform === 'darwin' && fs.existsSync(fs.realpathSync(path.join(__dirname, '/../../../MacOS')) + '/searchd')) {
return fs.realpathSync(path.join(__dirname, '/../../../MacOS')) + '/searchd'
}
} catch (e) {}
if (/^win/.test(process.platform) && fs.existsSync('imports/win/searchd.exe')) {
return 'imports/win/searchd.exe'
}
if (process.platform === 'linux' && fs.existsSync('imports/linux/searchd')) {
return 'imports/linux/searchd'
}
if (process.platform === 'darwin' && fs.existsSync('imports/darwin/searchd')) {
return 'imports/darwin/searchd'
}
return 'searchd'
}
const writeSphinxConfig = (path, dbPath) => {
let config = `
index torrents
{
type = rt
path = ${dbPath}/database/torrents
rt_attr_string = hash
rt_attr_string = name
rt_field = nameIndex
rt_attr_bigint = size
rt_attr_uint = files
rt_attr_uint = piecelength
rt_attr_timestamp = added
rt_attr_string = ipv4
rt_attr_uint = port
rt_attr_string = contentType
rt_attr_string = contentCategory
rt_attr_uint = seeders
rt_attr_uint = leechers
rt_attr_uint = completed
rt_attr_timestamp = trackersChecked
rt_attr_uint = good
rt_attr_uint = bad
}
index files
{
type = rt
path = ${dbPath}/database/files
rt_attr_string = path
rt_field = pathIndex
rt_attr_string = hash
rt_attr_bigint = size
}
index statistic
{
type = rt
path = ${dbPath}/database/statistic
rt_attr_bigint = size
rt_attr_bigint = files
rt_attr_uint = torrents
}
searchd
{
listen = 9312
listen = 9306:mysql41
read_timeout = 5
max_children = 30
seamless_rotate = 1
preopen_indexes = 1
unlink_old = 1
workers = threads # for RT to work
pid_file = ${path}/searchd.pid
log = ${path}/searchd.log
query_log = ${path}/query.log
binlog_path = ${path}
}
`;
// clear dir in test env
if(env.name === 'test')
{
if (fs.existsSync(`${dbPath}/database`)) {
fs.readdirSync(`${dbPath}/database`).forEach(function(file, index){
const curPath = `${dbPath}/database` + "/" + file;
if (!fs.lstatSync(curPath).isDirectory()) {
fs.unlinkSync(curPath);
}
});
fs.readdirSync(path).forEach(function(file, index){
if(!file.startsWith('binlog'))
return;
const curPath = path + "/" + file;
if (!fs.lstatSync(curPath).isDirectory()) {
fs.unlinkSync(curPath);
}
});
}
}
if (!fs.existsSync(`${dbPath}/database`)){
fs.mkdirSync(`${dbPath}/database`);
}
if(/^win/.test(process.platform))
config = iconv.encode(config, 'win1251')
fs.writeFileSync(`${path}/sphinx.conf`, config)
console.log(`writed sphinx config to ${path}`)
console.log('db path:', dbPath)
}
const sphinxPath = path.resolve(getSphinxPath())
console.log('Sphinx Path:', sphinxPath)
const startSphinx = (callback) => {
const sphinxConfigDirectory = app.getPath("userData")
appConfig['dbPath'] = appConfig.dbPath && appConfig.dbPath.length > 0 ? appConfig.dbPath : sphinxConfigDirectory;
writeSphinxConfig(sphinxConfigDirectory, appConfig.dbPath)
const config = `${sphinxConfigDirectory}/sphinx.conf`
const options = ['--config', config]
if(!(/^win/.test(process.platform)))
{
options.push('--nodetach')
}
sphinx = spawn(sphinxPath, options)
sphinx.stdout.on('data', (data) => {
console.log(`sphinx: ${data}`)
if (data.includes('accepting connections')) {
console.log('catched sphinx start')
if(callback)
callback()
}
})
sphinx.on('close', (code, signal) => {
console.log(`sphinx closed with code ${code} and signal ${signal}`)
app.quit()
})
sphinx.stop = () => {
exec(`${sphinxPath} --config "${config}" --stopwait`)
}
}
autoUpdater.on('update-downloaded', () => {
console.log('update-downloaded lats quitAndInstall');
if (env.name === "production") {
dialog.showMessageBox({
type: 'info',
title: 'Found Updates',
message: 'Found updates, do you want update now?',
buttons: ['Sure', 'No']
}, (buttonIndex) => {
if (buttonIndex === 0) {
const isSilent = true;
const isForceRunAfter = true;
autoUpdater.quitAndInstall(isSilent, isForceRunAfter);
}
})
}
})
let tray = undefined
app.on("ready", () => {
startSphinx(() => {
setApplicationMenu();
const mainWindow = createWindow("main", {
width: 1000,
height: 600
});
mainWindow.loadURL(
url.format({
pathname: path.join(__dirname, "app.html"),
protocol: "file:",
slashes: true
})
);
if (env.name === "development") {
mainWindow.openDevTools();
}
tray = new Tray(`${resourcesPath}/icons/512x512.png`)
tray.on('click', () => {
mainWindow.isVisible() ? mainWindow.hide() : mainWindow.show()
})
mainWindow.on('show', () => {
tray.setHighlightMode('always')
})
mainWindow.on('hide', () => {
tray.setHighlightMode('never')
})
mainWindow.on('minimize', (event) => {
event.preventDefault();
mainWindow.hide();
});
var contextMenu = Menu.buildFromTemplate([
{ label: 'Show', click: function(){
mainWindow.show();
} },
{ label: 'Quit', click: function(){
app.isQuiting = true;
if (sphinx)
stop()
else
app.quit()
} }
]);
tray.setContextMenu(contextMenu)
tray.setToolTip('Rats on The Boat search')
mainWindow.webContents.on('will-navigate', e => { e.preventDefault() })
mainWindow.webContents.on('new-window', (event, url, frameName) => {
if(frameName == '_self')
{
event.preventDefault()
mainWindow.loadURL(url)
}
})
if (env.name === "production") { autoUpdater.checkForUpdates() }
spider = spiderCall((...data) => mainWindow.webContents.send(...data), (message, callback) => {
ipcMain.on(message, (event, arg) => {
if(Array.isArray(arg) && typeof arg[arg.length - 1] === 'object' && arg[arg.length - 1].callback)
{
const id = arg[arg.length - 1].callback
arg[arg.length - 1] = (responce) => {
mainWindow.webContents.send('callback', id, responce)
}
}
callback.apply(null, arg)
})
})
})
});
let stopProtect = false
const stop = () => {
if(stopProtect)
return
stopProtect = true
if(tray)
tray.destroy()
if(spider)
{
spider.stop(() => sphinx.stop())
}
else
{
sphinx.stop()
}
}
app.on("window-all-closed", () => {
if (sphinx)
stop()
else
app.quit()
});
app.on('before-quit', () => {
if (sphinx)
stop()
})