#6644 -- Allow uploading libStereoTool_x.so files directly.

This commit is contained in:
Buster Neece 2023-10-16 00:56:57 -05:00
parent 36c43289ca
commit c604fbeceb
No known key found for this signature in database
6 changed files with 177 additions and 99 deletions

View File

@ -13,6 +13,7 @@
"php": "^8.2",
"ext-PDO": "*",
"ext-curl": "*",
"ext-ffi": "*",
"ext-fileinfo": "*",
"ext-gd": "*",
"ext-iconv": "*",

15
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "9116f1b4dc2e0cd79df47fe3c493f4fc",
"content-hash": "b992c7b41bfe8482f2c81e001d5cff93",
"packages": [
{
"name": "aws/aws-crt-php",
@ -9519,16 +9519,16 @@
},
{
"name": "codeception/codeception",
"version": "5.0.11",
"version": "5.0.12",
"source": {
"type": "git",
"url": "https://github.com/Codeception/Codeception.git",
"reference": "1998a287a3d7f2771c9591aef1c528d9d44cc4b4"
"reference": "7f528f5fd8cdcd05cd0a85eb1e24d05df989e0c4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/1998a287a3d7f2771c9591aef1c528d9d44cc4b4",
"reference": "1998a287a3d7f2771c9591aef1c528d9d44cc4b4",
"url": "https://api.github.com/repos/Codeception/Codeception/zipball/7f528f5fd8cdcd05cd0a85eb1e24d05df989e0c4",
"reference": "7f528f5fd8cdcd05cd0a85eb1e24d05df989e0c4",
"shasum": ""
},
"require": {
@ -9623,7 +9623,7 @@
],
"support": {
"issues": "https://github.com/Codeception/Codeception/issues",
"source": "https://github.com/Codeception/Codeception/tree/5.0.11"
"source": "https://github.com/Codeception/Codeception/tree/5.0.12"
},
"funding": [
{
@ -9631,7 +9631,7 @@
"type": "open_collective"
}
],
"time": "2023-08-22T06:42:39+00:00"
"time": "2023-10-15T18:04:50+00:00"
},
{
"name": "codeception/lib-asserts",
@ -13815,6 +13815,7 @@
"php": "^8.2",
"ext-pdo": "*",
"ext-curl": "*",
"ext-ffi": "*",
"ext-fileinfo": "*",
"ext-gd": "*",
"ext-iconv": "*",

View File

@ -9,6 +9,11 @@
$gettext('Stereo Tool is a popular, proprietary tool for software audio processing. Using Stereo Tool, you can customize the sound of your stations using preset configuration files.')
}}
</p>
<p class="card-text">
{{
$gettext('Note that Stereo Tool can be resource-intensive for both CPU and Memory. Please ensure you have sufficient resources before proceeding.')
}}
</p>
</template>
<div class="card-body">
@ -20,11 +25,6 @@
{{ $gettext('Instructions') }}
</legend>
<p class="card-text">
{{
$gettext('Stereo Tool can be resource-intensive for both CPU and Memory. Please ensure you have sufficient resources before proceeding.')
}}
</p>
<p class="card-text">
{{
@ -36,35 +36,56 @@
{{ $gettext('In order to install Stereo Tool:') }}
</p>
<ul>
<ol type="1">
<li>
{{
$gettext('Download the appropriate binary from the Stereo Tool downloads page:')
}}
<br>
<a
href="https://www.thimeo.com/stereo-tool/download/"
target="_blank"
>
{{ $gettext('Stereo Tool Downloads') }}
</a>
<p class="card-text">
{{
$gettext('Download the appropriate binary from the Stereo Tool downloads page:')
}}
</p>
<div class="buttons mb-3">
<a
href="https://www.thimeo.com/stereo-tool/download/"
target="_blank"
class="btn btn-sm btn-secondary"
>
{{ $gettext('Stereo Tool Downloads') }}
</a>
</div>
<ul>
<li>
{{
$gettext('For x86/64 installations, choose "x86/64 Linux Thimeo-ST plugin".')
}}
</li>
<li>
{{
$gettext('For ARM (Raspberry Pi, etc.) installations, choose "Raspberry Pi Thimeo-ST plugin".')
}}
</li>
</ul>
</li>
<li>
{{
$gettext('For x86/64 installations, choose "x86/64 Linux Thimeo-ST plugin".')
}}
<li class="mt-3">
<p class="card-text">
{{
$gettext('Upload the file on this page to automatically extract it into the proper directory.')
}}
</p>
<p class="card-text">
{{
$gettext('Any of the following file types are accepted:')
}}
</p>
<ul>
<li>
<code>libStereoTool_*.so</code>
({{ $gettext('Ensure the library matches your system architecture') }})
</li>
<li><code>Stereo_Tool_Generic_plugin.zip</code></li>
<li><code>stereo_tool</code> ({{ $gettext('For the legacy version') }})</li>
</ul>
</li>
<li>
{{
$gettext('For ARM (Raspberry Pi, etc.) installations, choose "Raspberry Pi Thimeo-ST plugin".')
}}
</li>
<li>
{{
$gettext('Upload the file on this page to automatically extract it into the proper directory.')
}}
</li>
</ul>
</ol>
</fieldset>
</div>
<div class="col-md-5">

View File

@ -11,8 +11,10 @@ use App\Http\ServerRequest;
use App\Radio\StereoTool;
use App\Service\Flow;
use App\Utilities\File;
use FFI;
use InvalidArgumentException;
use Psr\Http\Message\ResponseInterface;
use RuntimeException;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Process\Process;
@ -36,54 +38,127 @@ final class PostAction implements SingleActionInterface
File::clearDirectoryContents($libraryPath);
if ('zip' === pathinfo($flowResponse->getClientFilename(), PATHINFO_EXTENSION)) {
$destTempPath = sys_get_temp_dir() . '/uploads/new_stereo_tool';
$fsUtils->remove($destTempPath);
$fsUtils->mkdir($destTempPath);
switch (strtolower(pathinfo($flowResponse->getClientFilename(), PATHINFO_EXTENSION))) {
case 'zip':
$destTempPath = sys_get_temp_dir() . '/uploads/new_stereo_tool';
$fsUtils->remove($destTempPath);
$fsUtils->mkdir($destTempPath);
$process = new Process([
'unzip',
'-o',
$sourceTempPath,
]);
$process->setWorkingDirectory($destTempPath);
$process->setTimeout(600.0);
$process = new Process([
'unzip',
'-o',
$sourceTempPath,
]);
$process->setWorkingDirectory($destTempPath);
$process->setTimeout(600.0);
$process->run();
$process->run();
$flowResponse->delete();
$flowResponse->delete();
$pluginDirs = glob($destTempPath . '/Stereo_Tool_Generic_plugin_*') ?: [];
if (count($pluginDirs) > 0) {
$pluginDir = $pluginDirs[0];
$versionStr = str_replace($destTempPath . '/Stereo_Tool_Generic_plugin_', '', $pluginDir);
$pluginDirs = glob($destTempPath . '/Stereo_Tool_Generic_plugin_*') ?: [];
if (count($pluginDirs) > 0) {
$pluginDir = $pluginDirs[0];
$versionStr = str_replace($destTempPath . '/Stereo_Tool_Generic_plugin_', '', $pluginDir);
$filesToCopy = glob($pluginDir . '/libStereoTool*.so') ?: [];
$filesToCopy = glob($pluginDir . '/libStereoTool*.so') ?: [];
foreach ($filesToCopy as $fileToCopy) {
$fsUtils->rename(
$fileToCopy,
$libraryPath . '/' . basename($fileToCopy),
true
foreach ($filesToCopy as $fileToCopy) {
$fsUtils->rename(
$fileToCopy,
$libraryPath . '/' . basename($fileToCopy),
true
);
}
$fsUtils->dumpFile(
$libraryPath . '/' . StereoTool::VERSION_FILE,
substr($versionStr, 0, 2) . '.' . substr($versionStr, 2),
);
} else {
throw new InvalidArgumentException('Uploaded file not recognized.');
}
$fsUtils->dumpFile(
$libraryPath . '/' . StereoTool::VERSION_FILE,
substr($versionStr, 0, 2) . '.' . substr($versionStr, 2),
);
} else {
throw new InvalidArgumentException('Uploaded file not recognized.');
}
$fsUtils->remove($destTempPath);
break;
$fsUtils->remove($destTempPath);
} else {
$binaryPath = $libraryPath . '/stereo_tool';
$flowResponse->moveTo($libraryPath);
case 'so':
$binaryPath = $libraryPath . '/libStereoTool.so';
$flowResponse->moveTo($binaryPath);
chmod($binaryPath, 0744);
$version = $this->getSharedLibraryVersion($binaryPath);
if (null !== $version) {
$fsUtils->dumpFile(
$libraryPath . '/' . StereoTool::VERSION_FILE,
$version
);
}
break;
default:
$binaryPath = $libraryPath . '/stereo_tool';
$flowResponse->moveTo($binaryPath);
chmod($binaryPath, 0744);
$version = $this->getLegacyVersion($binaryPath);
if (null !== $version) {
$fsUtils->dumpFile(
$libraryPath . '/' . StereoTool::VERSION_FILE,
$version
);
}
break;
}
return $response->withJson(Status::success());
}
private function getLegacyVersion(string $path): ?string
{
$process = new Process([$path, '--help']);
$process->setWorkingDirectory(dirname($path));
$process->setTimeout(5.0);
try {
$process->run();
} catch (RuntimeException) {
return null;
}
if (!$process->isSuccessful()) {
return null;
}
preg_match('/STEREO TOOL ([.\d]+) CONSOLE APPLICATION/i', $process->getErrorOutput(), $matches);
if (!isset($matches[1])) {
return null;
}
return $matches[1];
}
private function getSharedLibraryVersion(string $path): ?string
{
$ffi = FFI::cdef(
<<<'EOH'
extern int stereoTool_GetSoftwareVersion ();
extern int stereoTool_GetApiVersion ();
EOH,
$path
);
/** @phpstan-ignore-next-line */
$version = (int)call_user_func([
$ffi,
'stereoTool_GetSoftwareVersion',
]);
if (0 === $version) {
return null;
}
$majorVersion = (int)round($version / 1000, 2);
return $majorVersion . '.' . (int)(($version - ($majorVersion * 1000)) / 10);
}
}

View File

@ -6,8 +6,6 @@ namespace App\Radio;
use App\Entity\Station;
use App\Environment;
use RuntimeException;
use Symfony\Component\Process\Process;
final class StereoTool
{
@ -50,29 +48,8 @@ final class StereoTool
$binaryPath = $libraryPath . '/stereo_tool';
if (!file_exists($binaryPath)) {
return null;
}
$process = new Process([$binaryPath, '--help']);
$process->setWorkingDirectory(dirname($binaryPath));
$process->setTimeout(5.0);
try {
$process->run();
} catch (RuntimeException) {
return null;
}
if (!$process->isSuccessful()) {
return null;
}
preg_match('/STEREO TOOL ([.\d]+) CONSOLE APPLICATION/i', $process->getErrorOutput(), $matches);
if (!isset($matches[1])) {
return null;
}
return $matches[1] . ' (CLI)';
return file_exists($binaryPath)
? 'Legacy CLI'
: null;
}
}

View File

@ -21,5 +21,8 @@ touch /run/php/php${PHP_VERSION}-fpm.pid
cp /bd_build/web/php/php.ini.tmpl /etc/php/${PHP_VERSION}/fpm/05-azuracast.ini.tmpl
cp /bd_build/web/php/www.conf.tmpl /etc/php/${PHP_VERSION}/fpm/www.conf.tmpl
# Enable FFI (for StereoTool inspection)
echo 'ffi.enable="true"' >> /etc/php/${PHP_VERSION}/mods-available/ffi.ini
# Install Composer
curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/bin --filename=composer