Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/maven/fixes/8.1' into maven/rele…
Browse files Browse the repository at this point in the history
…ase/8.1
  • Loading branch information
metaventis-build committed Oct 12, 2023
2 parents 890c216 + 48ea11a commit 59d8153
Show file tree
Hide file tree
Showing 6 changed files with 220 additions and 21 deletions.
9 changes: 7 additions & 2 deletions service/src/main/php/bootstrap.php
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
<?php

use connector\lib\BlockingMiddleware;
use connector\lib\Connector;
use connector\lib\EduRestClient;
use connector\lib\Logger;
use connector\lib\MetadataGenerator;
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
use Slim\App;
use Slim\Container;
use Slim\Views\Twig;

error_reporting(0); //do not change, can cause ajax problems

$container = new \Slim\Container;
$app = new \Slim\App([$container, 'settings' => [
$container = new Container;
$app = new App([$container, 'settings' => [
'displayErrorDetails' => true,
'debug' => true,
'whoops.editor' => 'sublime',
Expand All @@ -31,6 +34,8 @@
return $view;
};

$app->add(new BlockingMiddleware());

$app->get('/', function (Request $request, Response $response) {
$this->get('log')->info($request->getUri());
$connector = new Connector($this->get('log'), $this, $response);
Expand Down
8 changes: 8 additions & 0 deletions service/src/main/php/cacheCleaner.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php declare(strict_types=1);

use connector\lib\CacheCleaner;

require_once 'src/lib/CacheCleaner.php';

$cacheCleaner = new CacheCleaner();
$cacheCleaner->run();
41 changes: 41 additions & 0 deletions service/src/main/php/src/lib/BlockingMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php declare(strict_types=1);

namespace connector\lib;

use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;

/**
* Class BlockingMiddleware
*
* includes logic to block the connector service for the
* duration of the cache cleaning process.
* This is needed in order to prevent potential invalid state creation.
*
* @author Marian Ziegler <[email protected]>
*/
class BlockingMiddleware
{
/**
* Function __invoke
*
* Function to run the middleware as per the Slim PHP documentation
*
* @param Request $request
* @param Response $response
* @param callable $next
* @return Response
*/
public function __invoke(Request $request, Response $response, callable $next): Response
{
$retryCount = 0;
while (file_exists(__DIR__ . '/' . CacheCleaner::LOCK_FILE_NAME) && $retryCount <= 10) {
sleep(1);
$retryCount += 1;
}
if (file_exists(__DIR__ . '/' . CacheCleaner::LOCK_FILE_NAME)) {
return $response->withStatus(503);
}
return $next($request, $response);
}
}
136 changes: 136 additions & 0 deletions service/src/main/php/src/lib/CacheCleaner.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<?php declare(strict_types=1);

namespace connector\lib;

require_once __DIR__ . '/../../vendor/autoload.php';

use connector\tools\h5p\H5P;
use Exception;
use Monolog\Logger as MonoLogger;

/**
* Class CacheCleaner
*
* encapsulates logic for cleaning the connector service H5P cache.
* There is only one public function to be called: run(). Invoke it
* to perform the cleaning process and behold its might!
*
* @author Marian Ziegler <[email protected]>
*/
class CacheCleaner
{
public const LOCK_FILE_NAME = 'LOCK';
private MonoLogger $logger;
private Database $database;
private H5P $h5p;

/**
* CacheCleaner constructor
*/
public function __construct() {
$this->init();
}

/**
* Function init
*
* sets up dependencies
*/
private function init(): void {
$logInitializer = new Logger();
$this->logger = $logInitializer->getLog();
$this->database = new Database();
$this->h5p = new H5P();
}

/**
* Function run
*
* This is the main workhorse of the class
*
* @return void
*/
public function run(): void {
$this->logger->info('### Cache cleaner started ###');
try {
$this->lock();
$this->database->beginTransaction();
$this->clearH5pTables();
$this->clearH5pDirectories();
! $this->database->commit() && throw new Exception('### Database commit failed. Script terminated ###');
} catch (Exception $exception) {
$this->logger->error($exception->getMessage());
$this->logger->error('### Database transaction rollback started. ###');
$this->database->rollBack();
} finally {
try {
$this->unlock();
$this->logger->info('### Cache cleaner ran successfully ###');
} catch (Exception $exception) {
$this->logger->error($exception->getMessage());
}
}
}

/**
* Function clearH5pTables
*
* clears H5P-related tables
*
* @throws Exception
*/
private function clearH5pTables(): void {
$libraryLanguageRes = $this->database->query('TRUNCATE TABLE h5p_libraries_languages');
$contentsLibrariesRes = $this->database->query('TRUNCATE TABLE h5p_contents_libraries');
$contentsRes = $this->database->query('TRUNCATE TABLE h5p_contents');
$librariesRes = $this->database->query('TRUNCATE TABLE h5p_libraries');
$librariesLanguagesRes = $this->database->query('TRUNCATE TABLE h5p_libraries_languages');
$librariesLibrariesRes = $this->database->query('TRUNCATE TABLE h5p_libraries_libraries');
if (in_array(false, [$libraryLanguageRes, $contentsLibrariesRes, $contentsRes, $librariesRes, $librariesLanguagesRes, $librariesLibrariesRes], true)) {
throw new Exception('### Cache cleaner error: Database operation failed. Script will be terminated. ###');
}
}

/**
* Function clearH5pDirectories
*
* deletes all files and folders from the H5P-related directories within the cache directory
*
* @throws Exception
*/
private function clearH5pDirectories(): void {
$directories = ['content', 'exports', 'libraries', 'editor', 'temp'];
try {
foreach ($directories as $directory) {
$this->h5p->rrmdir($this->h5p->H5PFramework->get_h5p_path() . '/' . $directory, true);
}
} catch (Exception $exception) {
throw new Exception('### Cache cleaner error: ' . $exception->getMessage() . '. Script will be terminated. ###');
}
}

/**
* Function lock
*
* creates a lock file in order to lock the connector service
* for the duration of the cache cleaning process
*
* @throws Exception
*/
private function lock(): void {
$lockFile = fopen(static::LOCK_FILE_NAME, "w");
$lockFile === false && throw new Exception('### Cache cleaner error: Cannot create lock file. Script will be terminated. ###');
}

/**
* Function unlock
*
* deletes the lock file in order to unlock the connector service
*
* @throws Exception
*/
private function unlock(): void {
$isFileDeleted = unlink(static::LOCK_FILE_NAME);
! $isFileDeleted && throw new Exception('### Cache cleaner error: Cannot delete lock file. Script will be terminated. ###');
}
}
21 changes: 13 additions & 8 deletions service/src/main/php/src/lib/Logger.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,35 @@

namespace connector\lib;

use Exception;
use Monolog\Handler\RedisHandler;
use Monolog\Formatter\LogstashFormatter;
use Monolog\Handler\RotatingFileHandler;
use Monolog\Handler\StreamHandler;
use Monolog\Logger as MonoLogger;
use Monolog\Processor\IntrospectionProcessor;
use Predis\Client;


class Logger {

private $log;
private MonoLogger $log;

public function __construct() {
$this->log = new \Monolog\Logger('eduConnector');
$this->log->pushProcessor(new \Monolog\Processor\IntrospectionProcessor());
$this->log = new MonoLogger('eduConnector');
$this->log->pushProcessor(new IntrospectionProcessor());

/*
* Log to local file
* */
if(LOG_MODE === 'file') {
$this->log->pushHandler(new \Monolog\Handler\RotatingFileHandler(DATA . DIRECTORY_SEPARATOR . 'log' . DIRECTORY_SEPARATOR . 'error.log', 0, \Monolog\Logger::ERROR));
$this->log->pushHandler(new \Monolog\Handler\RotatingFileHandler(DATA . DIRECTORY_SEPARATOR . 'log' . DIRECTORY_SEPARATOR . 'info.log', 0, \Monolog\Logger::INFO));
$this->log->pushHandler(new RotatingFileHandler(DATA . DIRECTORY_SEPARATOR . 'log' . DIRECTORY_SEPARATOR . 'error.log', 0, MonoLogger::ERROR));
$this->log->pushHandler(new RotatingFileHandler(DATA . DIRECTORY_SEPARATOR . 'log' . DIRECTORY_SEPARATOR . 'info.log', 0, MonoLogger::INFO));
} else if(LOG_MODE === 'stdout') {
$this->log->pushHandler(new \Monolog\Handler\StreamHandler('php://stdout', \Monolog\Logger::INFO));
$this->log->pushHandler(new \Monolog\Handler\StreamHandler('php://stderr', \Monolog\Logger::ERROR));
$this->log->pushHandler(new StreamHandler('php://stdout', MonoLogger::INFO));
$this->log->pushHandler(new StreamHandler('php://stderr', MonoLogger::ERROR));
} else {
throw new \Exception("invalid LOG_MODE: " . LOG_MODE);
throw new Exception("invalid LOG_MODE: " . LOG_MODE);
}
$this->log->info("Logger started in mode " . LOG_MODE);
/*
Expand Down
26 changes: 15 additions & 11 deletions service/src/main/php/src/tools/h5p/H5P.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use connector\lib\Database;
use connector\lib\EduRestClient;
use Dompdf\Exception;
use Exception;
use Slim\Http\Response;

define('MODE_NEW', 'mode_new');
Expand Down Expand Up @@ -140,18 +140,22 @@ private function copyr($source, $dest) {
}


public function rrmdir($dir) {
if (is_dir($dir)) {
$objects = scandir($dir);
foreach ($objects as $object) {
/**
* @throws Exception
*/
public function rrmdir(string $dir, bool $throwException = false): void {
if (is_dir($dir)) {
$objects = scandir($dir);
foreach ($objects as $object) {
if ($object != "." && $object != "..") {
if (is_dir($dir."/".$object))
$this -> rrmdir($dir."/".$object);
else
unlink($dir."/".$object);
}
if (is_dir($dir."/".$object))
$this -> rrmdir($dir."/".$object);
else
unlink($dir."/".$object);
}
}
rmdir($dir);
$isDirDeleted = rmdir($dir);
! $isDirDeleted && $throwException && throw new Exception('Cannot delete directory: ' . $dir . '.');
}
}

Expand Down

0 comments on commit 59d8153

Please sign in to comment.