Merge branch 'nonblockingReindex' into 'master'

reindexing in background and gravity cleanup

Closes #29

See merge request lukas/openmediacenter!20
This commit is contained in:
Lukas Heiligenbrunner 2020-10-21 19:14:46 +00:00
commit 8f7ba53c39
10 changed files with 163 additions and 40 deletions

View File

@ -1,18 +0,0 @@
<?php
$return = new stdClass();
if (file_exists("/tmp/output.log")) {
$out = file_get_contents("/tmp/output.log");
// clear log file
file_put_contents("/tmp/output.log", "");
$return->message = $out;
$return->contentAvailable = true;
if (substr($out, -strlen("-42")) == "-42") {
unlink("/tmp/output.log");
}
} else {
$return->contentAvailable = false;
}
echo json_encode($return);

View File

@ -1,7 +1,7 @@
<?php
require_once './src/Database.php';
require_once './src/TMDBMovie.php';
require_once './src/SSettings.php';
require_once 'Database.php';
require_once 'TMDBMovie.php';
require_once 'SSettings.php';
/**
* Class VideoParser

View File

@ -1,5 +1,5 @@
<?php
require_once 'src/Database.php';
require_once __DIR__.'/../Database.php';
abstract class RequestBase {
protected $conn;

View File

@ -1,5 +1,6 @@
<?php
require_once 'RequestBase.php';
require_once __DIR__ . '/../VideoParser.php';
/**
* Class Settings
@ -9,6 +10,7 @@ class Settings extends RequestBase {
function initHandlers() {
$this->getFromDB();
$this->saveToDB();
$this->reIndexHandling();
}
/**
@ -102,4 +104,57 @@ class Settings extends RequestBase {
}
});
}
/**
* methods for handling reindexing and cleanup of db gravity
*/
private function reIndexHandling() {
$this->addActionHandler("startReindex", function () {
$indexrunning = false;
if (file_exists("/tmp/output.log")) {
$out = file_get_contents("/tmp/output.log");
if (substr($out, -strlen("-42")) == "-42") {
unlink("/tmp/output.log");
} else {
$indexrunning = true;
}
}
if (!$indexrunning) {
// start extraction of video previews in background
$cmd = 'php extractvideopreviews.php';
exec(sprintf("%s > %s 2>&1 & echo $! >> %s", $cmd, '/dev/zero', '/tmp/openmediacenterpid'));
$this->commitMessage('{"success": true}');
} else {
$this->commitMessage('{"success": false}');
}
});
$this->addActionHandler("cleanupGravity", function () {
$vp = new VideoParser();
$vp->cleanUpGravity();
});
$this->addActionHandler("getStatusMessage", function () {
$return = new stdClass();
if (file_exists("/tmp/output.log")) {
$out = file_get_contents("/tmp/output.log");
// clear log file
file_put_contents("/tmp/output.log", "");
$return->message = $out;
$return->contentAvailable = true;
if (substr($out, -strlen("-42")) == "-42") {
unlink("/tmp/output.log");
}
} else {
$return->contentAvailable = false;
}
$this->commitMessage(json_encode($return));
});
}
}

View File

@ -1,5 +1,5 @@
<?php
require_once 'src/SSettings.php';
require_once __DIR__.'/../SSettings.php';
require_once 'RequestBase.php';
/**

View File

@ -17,7 +17,7 @@
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --reporters=jest-junit --reporters=default",
"test": "react-scripts test --reporters=jest-junit --reporters=default --ci --silent",
"coverage": "react-scripts test --coverage --watchAll=false",
"eject": "react-scripts eject"
},

View File

@ -16,9 +16,6 @@ class MovieSettings extends React.Component {
}
componentDidMount() {
if (this.myinterval) {
clearInterval(this.myinterval);
}
this.myinterval = setInterval(this.updateStatus, 1000);
}
@ -29,9 +26,12 @@ class MovieSettings extends React.Component {
render() {
return (
<>
<button disabled={this.state.startbtnDisabled} className='reindexbtn btn btn-success' onClick={() => {
this.startReindex()
}}>Reindex Movies
<button disabled={this.state.startbtnDisabled}
className='btn btn-success'
onClick={() => {this.startReindex()}}>Reindex Movie
</button>
<button className='btn btn-warning'
onClick={() => {this.cleanupGravity()}}>Cleanup Gravity
</button>
<div className={style.indextextarea}>{this.state.text.map(m => (
<div className='textarea-element'>{m}</div>
@ -50,13 +50,19 @@ class MovieSettings extends React.Component {
this.setState({startbtnDisabled: true});
console.log("starting");
const updateRequest = new FormData();
const request = new FormData();
request.append("action", "startReindex");
// fetch all videos available
fetch('/api/extractvideopreviews.php', {method: 'POST', body: updateRequest})
.then((response) => response.text()
fetch('/api/settings.php', {method: 'POST', body: request})
.then((response) => response.json()
.then((result) => {
// todo 2020-07-4: some kind of return finished handler
console.log("returned");
console.log(result);
if (result.success) {
console.log("started successfully");
} else {
console.log("error, reindex already running");
this.setState({startbtnDisabled: true});
}
}))
.catch(() => {
console.log("no connection to backend");
@ -71,8 +77,10 @@ class MovieSettings extends React.Component {
* This interval function reloads the current status of reindexing from backend
*/
updateStatus = () => {
const updateRequest = new FormData();
fetch('/api/extractionData.php', {method: 'POST', body: updateRequest})
const request = new FormData();
request.append("action", "getStatusMessage");
fetch('/api/settings.php', {method: 'POST', body: request})
.then((response) => response.json()
.then((result) => {
if (result.contentAvailable === true) {
@ -94,6 +102,25 @@ class MovieSettings extends React.Component {
console.log("no connection to backend");
});
};
/**
* send request to cleanup db gravity
*/
cleanupGravity() {
const request = new FormData();
request.append("action", "cleanupGravity");
fetch('/api/settings.php', {method: 'POST', body: request})
.then((response) => response.text()
.then((result) => {
this.setState({
text: ['successfully cleaned up gravity!']
});
}))
.catch(() => {
console.log("no connection to backend");
});
}
}
export default MovieSettings;

View File

@ -9,5 +9,5 @@
overflow-x: auto;
overflow-y: scroll;
padding: 10px;
width: 50%;
width: 40%;
}

View File

@ -22,15 +22,33 @@ describe('<MovieSettings/>', function () {
});
it('test simulate reindex', function () {
global.fetch = global.prepareFetchApi({});
global.fetch = global.prepareFetchApi({success: true});
const wrapper = shallow(<MovieSettings/>);
wrapper.find(".reindexbtn").simulate("click");
wrapper.find("button").findWhere(e => e.text() === "Reindex Movie" && e.type() === "button").simulate("click");
// initial send of reindex request to server
expect(global.fetch).toBeCalledTimes(1);
});
it('test failing reindex start', done => {
global.fetch = global.prepareFetchApi({success: false});
const wrapper = shallow(<MovieSettings/>);
wrapper.find("button").findWhere(e => e.text() === "Reindex Movie" && e.type() === "button").simulate("click");
// initial send of reindex request to server
expect(global.fetch).toBeCalledTimes(1);
process.nextTick(() => {
// reindex already running --> so disable startbdn
expect(wrapper.state()).toMatchObject({startbtnDisabled: true});
global.fetch.mockClear();
done();
});
});
it('content available received and in state', done => {
global.fetch = global.prepareFetchApi({
contentAvailable: true,
@ -51,4 +69,44 @@ describe('<MovieSettings/>', function () {
done();
});
});
it('test reindex with no content available', done=> {
global.fetch = global.prepareFetchApi({
contentAvailable: false
});
global.clearInterval = jest.fn();
const wrapper = shallow(<MovieSettings/>);
wrapper.instance().updateStatus();
process.nextTick(() => {
// expect the refresh interval to be cleared
expect(global.clearInterval).toBeCalledTimes(1);
// expect startbtn to be reenabled
expect(wrapper.state()).toMatchObject({startbtnDisabled: false});
global.fetch.mockClear();
done();
});
});
it('test simulate gravity cleanup', done => {
global.fetch = global.prepareFetchApi("mmi");
const wrapper = shallow(<MovieSettings/>);
wrapper.instance().setState = jest.fn(),
wrapper.find("button").findWhere(e => e.text() === "Cleanup Gravity" && e.type() === "button").simulate("click");
// initial send of reindex request to server
expect(global.fetch).toBeCalledTimes(1);
process.nextTick(() => {
expect(wrapper.instance().setState).toBeCalledTimes(1);
global.fetch.mockClear();
done();
});
});
});

View File

@ -18,6 +18,7 @@ global.prepareFetchApi = (response) => {
const mockJsonPromise = Promise.resolve(response);
const mockFetchPromise = Promise.resolve({
json: () => mockJsonPromise,
text: () => mockJsonPromise
});
return (jest.fn().mockImplementation(() => mockFetchPromise));
}