mirror of
https://github.com/r4sas/recastin-panel
synced 2025-03-12 13:21:14 +00:00
Added rtmp stats for users, fixes #5
This commit is contained in:
parent
37f9d7dad8
commit
8d78961074
@ -36,11 +36,11 @@ services:
|
||||
class: App\Component\ServiceManager
|
||||
arguments: [!tagged recast.service]
|
||||
|
||||
App\Component\NginxConfigGenerator:
|
||||
class: App\Component\NginxConfigGenerator
|
||||
App\Component\Nginx\ConfigGenerator:
|
||||
class: App\Component\Nginx\ConfigGenerator
|
||||
autowire: true
|
||||
bind:
|
||||
$nginxFolder: '%nginxConfigFolder%'
|
||||
$nginxConfigFolder: '%nginxConfigFolder%'
|
||||
$appHost: '%appHost%'
|
||||
|
||||
# add more service definitions when explicit configuration is needed
|
||||
|
File diff suppressed because one or more lines are too long
@ -8,6 +8,19 @@
|
||||
<fg-input label="URL" v-model="stream.streamUrl" disabled="true"></fg-input>
|
||||
<fg-input label="Stream Key" v-model="stream.streamKey" disabled="true"></fg-input>
|
||||
|
||||
<div v-if="stats.active">
|
||||
<h3>Stream Statistics</h3>
|
||||
|
||||
<p>
|
||||
<strong>Bytes received</strong> {{ stats.bytes_in / 1048576 | toNumber }} MiB<br>
|
||||
<strong>Bytes sent</strong> {{ stats.bytes_out / 1048576 | toNumber }} MiB<br>
|
||||
<strong>Current bandwidth in</strong> {{ stats.bw_in / 1000000 | toNumber }} Mb/s<br>
|
||||
<strong>Current bandwidth out</strong> {{ stats.bw_out / 1000000 | toNumber }} Mb/s<br>
|
||||
<strong>Res: </strong> {{ stats.meta.video.width }}x{{ stats.meta.video.height }}<br>
|
||||
<strong>FPS: </strong> {{ stats.meta.video.frame_rate }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h4>OBS</h4>
|
||||
|
||||
<ul>
|
||||
@ -26,13 +39,23 @@
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
stream: {}
|
||||
stream: {},
|
||||
stats: {}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.axios.get('/streams/one?id=' + this.$route.params.id).then(response => {
|
||||
this.stream = response.data;
|
||||
});
|
||||
|
||||
this.axios.get(`/streams/${this.$route.params.id}/stats`).then(response => {
|
||||
this.stats = response.data;
|
||||
})
|
||||
},
|
||||
filters: {
|
||||
toNumber: function (value) {
|
||||
return value.toFixed(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use App\Component\NginxConfigGenerator;
|
||||
use App\Component\Nginx\ConfigGenerator;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
@ -23,8 +23,9 @@ class CronRunnerCommand extends Command implements ContainerAwareInterface
|
||||
* @var Connection
|
||||
*/
|
||||
private $connection;
|
||||
|
||||
/**
|
||||
* @var NginxConfigGenerator
|
||||
* @var ConfigGenerator
|
||||
*/
|
||||
private $configGenerator;
|
||||
|
||||
@ -32,10 +33,10 @@ class CronRunnerCommand extends Command implements ContainerAwareInterface
|
||||
* CronRunnerCommand constructor.
|
||||
* @param null|string $name
|
||||
* @param Connection $connection
|
||||
* @param NginxConfigGenerator $configGenerator
|
||||
* @param ConfigGenerator $configGenerator
|
||||
* @author Soner Sayakci <shyim@posteo.de>
|
||||
*/
|
||||
public function __construct(?string $name = null, Connection $connection, NginxConfigGenerator $configGenerator)
|
||||
public function __construct(?string $name = null, Connection $connection, ConfigGenerator $configGenerator)
|
||||
{
|
||||
parent::__construct($name);
|
||||
$this->connection = $connection;
|
||||
|
@ -4,7 +4,7 @@
|
||||
namespace App\Command;
|
||||
|
||||
|
||||
use App\Component\NginxConfigGenerator;
|
||||
use App\Component\Nginx\ConfigGenerator;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
@ -17,17 +17,17 @@ use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
class GenerateConfigCommand extends Command
|
||||
{
|
||||
/**
|
||||
* @var NginxConfigGenerator
|
||||
* @var ConfigGenerator
|
||||
*/
|
||||
private $configGenerator;
|
||||
|
||||
/**
|
||||
* GenerateConfigCommand constructor.
|
||||
* @param null|string $name
|
||||
* @param NginxConfigGenerator $configGenerator
|
||||
* @param ConfigGenerator $configGenerator
|
||||
* @author Soner Sayakci <shyim@posteo.de>
|
||||
*/
|
||||
public function __construct(?string $name = null, NginxConfigGenerator $configGenerator)
|
||||
public function __construct(?string $name = null, ConfigGenerator $configGenerator)
|
||||
{
|
||||
parent::__construct($name);
|
||||
$this->configGenerator = $configGenerator;
|
||||
|
@ -1,16 +1,17 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Component;
|
||||
namespace App\Component\Nginx;
|
||||
|
||||
use App\Component\ServiceManager;
|
||||
use App\Entity\Endpoint;
|
||||
use App\Repository\StreamsRepository;
|
||||
|
||||
/**
|
||||
* Class NginxConfigGenerator
|
||||
* Class ConfigGenerator
|
||||
* @author Soner Sayakci <shyim@posteo.de>
|
||||
*/
|
||||
class NginxConfigGenerator
|
||||
class ConfigGenerator
|
||||
{
|
||||
private const VHOST = "\t\tapplication %s {
|
||||
\t\t\tlive on;
|
||||
@ -31,6 +32,15 @@ rtmp {
|
||||
%s
|
||||
\t}
|
||||
}
|
||||
|
||||
http {
|
||||
\tserver {
|
||||
\t\tlisten 127.0.0.1:26765;
|
||||
\t\tlocation /stat {
|
||||
\t\t\trtmp_stat all;
|
||||
\t\t}
|
||||
\t}
|
||||
}
|
||||
";
|
||||
|
||||
/**
|
||||
@ -45,7 +55,7 @@ rtmp {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $nginxFolder;
|
||||
private $nginxConfigFolder;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
@ -53,18 +63,18 @@ rtmp {
|
||||
private $appHost;
|
||||
|
||||
/**
|
||||
* NginxConfigGenerator constructor.
|
||||
* ConfigGenerator constructor.
|
||||
* @param StreamsRepository $repository
|
||||
* @param ServiceManager $manager
|
||||
* @param string $nginxFolder
|
||||
* @param string $nginxConfigFolder
|
||||
* @param string $appHost
|
||||
* @author Soner Sayakci <shyim@posteo.de>
|
||||
*/
|
||||
public function __construct(StreamsRepository $repository, ServiceManager $manager, string $nginxFolder, string $appHost)
|
||||
public function __construct(StreamsRepository $repository, ServiceManager $manager, string $nginxConfigFolder, string $appHost)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
$this->manager = $manager;
|
||||
$this->nginxFolder = $nginxFolder;
|
||||
$this->nginxConfigFolder = $nginxConfigFolder;
|
||||
$this->appHost = $appHost;
|
||||
}
|
||||
|
||||
@ -74,9 +84,9 @@ rtmp {
|
||||
*/
|
||||
public function generate(): void
|
||||
{
|
||||
if (!file_exists($this->nginxFolder)) {
|
||||
if (!mkdir($this->nginxFolder, 7777, true) && !is_dir($this->nginxFolder)) {
|
||||
throw new \RuntimeException(sprintf('Directory "%s" was not created', $this->nginxFolder));
|
||||
if (!file_exists($this->nginxConfigFolder)) {
|
||||
if (!mkdir($this->nginxConfigFolder, 7777, true) && !is_dir($this->nginxConfigFolder)) {
|
||||
throw new \RuntimeException(sprintf('Directory "%s" was not created', $this->nginxConfigFolder));
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,7 +110,7 @@ rtmp {
|
||||
}
|
||||
}
|
||||
|
||||
file_put_contents($this->nginxFolder . '/nginx.conf', sprintf(self::NGINX_CONF, $vhost));
|
||||
file_put_contents($this->nginxConfigFolder . '/nginx.conf', sprintf(self::NGINX_CONF, $vhost));
|
||||
}
|
||||
|
||||
/**
|
45
src/Component/Nginx/Stats.php
Normal file
45
src/Component/Nginx/Stats.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Component\Nginx;
|
||||
use App\Entity\Streams;
|
||||
|
||||
/**
|
||||
* Class Stats
|
||||
* @author Soner Sayakci <shyim@posteo.de>
|
||||
*/
|
||||
class Stats
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $data;
|
||||
|
||||
/**
|
||||
* Stats constructor.
|
||||
* @author Soner Sayakci <shyim@posteo.de>
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$stats = file_get_contents('http://127.0.0.1:26765/stat');
|
||||
$xml = simplexml_load_string($stats, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||
$this->data = json_decode(json_encode($xml), true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Streams $stream
|
||||
* @author Soner Sayakci <shyim@posteo.de>
|
||||
* @return array
|
||||
*/
|
||||
public function getStatsForStream(Streams $stream): array
|
||||
{
|
||||
$appKey = $stream->getUser()->getUsername() . '/' . $stream->getName();
|
||||
|
||||
foreach ($this->data['server']['application'] as $application) {
|
||||
if ($application['name'] === $appKey && isset($application['live']['stream'])) {
|
||||
return $application['live']['stream'];
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Component\Nginx\Stats;
|
||||
use App\Component\ServiceManager;
|
||||
use App\Entity\Endpoint;
|
||||
use App\Entity\User;
|
||||
@ -48,7 +49,7 @@ class Streams extends Controller
|
||||
* @Route(path="/list")
|
||||
* @author Soner Sayakci <shyim@posteo.de>
|
||||
*/
|
||||
public function streams() : Response
|
||||
public function streams(): Response
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = $this->getUser();
|
||||
@ -62,7 +63,7 @@ class Streams extends Controller
|
||||
* @return \Symfony\Component\HttpFoundation\RedirectResponse|Response
|
||||
* @author Soner Sayakci <shyim@posteo.de>
|
||||
*/
|
||||
public function one(Request $request) : Response
|
||||
public function one(Request $request): Response
|
||||
{
|
||||
$stream = $this->repository->find($request->query->get('id'));
|
||||
|
||||
@ -85,7 +86,7 @@ class Streams extends Controller
|
||||
* @throws \Doctrine\ORM\OptimisticLockException
|
||||
* @author Soner Sayakci <shyim@posteo.de>
|
||||
*/
|
||||
public function update(Request $request) : Response
|
||||
public function update(Request $request): Response
|
||||
{
|
||||
$requestBody = $request->request->all();
|
||||
|
||||
@ -105,7 +106,7 @@ class Streams extends Controller
|
||||
|
||||
$manager = $this->get('doctrine.orm.entity_manager');
|
||||
|
||||
try {
|
||||
try {
|
||||
$manager->persist($stream);
|
||||
$manager->flush();
|
||||
} catch (UniqueConstraintViolationException $e) {
|
||||
@ -124,7 +125,7 @@ class Streams extends Controller
|
||||
* @throws \Doctrine\ORM\OptimisticLockException
|
||||
* @throws \Doctrine\ORM\TransactionRequiredException
|
||||
*/
|
||||
public function regenerate(Request $request) : Response
|
||||
public function regenerate(Request $request): Response
|
||||
{
|
||||
$manager = $this->get('doctrine.orm.entity_manager');
|
||||
$streams = $manager->find(\App\Entity\Streams::class, $request->request->get('id'));
|
||||
@ -147,7 +148,7 @@ class Streams extends Controller
|
||||
* @throws \Doctrine\ORM\OptimisticLockException
|
||||
* @throws \Doctrine\ORM\TransactionRequiredException
|
||||
*/
|
||||
public function delete(Request $request) : Response
|
||||
public function delete(Request $request): Response
|
||||
{
|
||||
$manager = $this->get('doctrine.orm.entity_manager');
|
||||
$streams = $manager->find(\App\Entity\Streams::class, $request->request->get('id'));
|
||||
@ -171,6 +172,24 @@ class Streams extends Controller
|
||||
return new JsonResponse($manager->getTemplateData());
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route(path="/{id}/stats")
|
||||
* @param int $id
|
||||
* @param Stats $nginxStats
|
||||
* @return JsonResponse
|
||||
* @author Soner Sayakci <shyim@posteo.de>
|
||||
*/
|
||||
public function stats(Stats $nginxStats, int $id): JsonResponse
|
||||
{
|
||||
$stream = $this->repository->find($id);
|
||||
|
||||
if ($stream === null || $stream->getUserId() !== $this->getUser()->getId()) {
|
||||
return new JsonResponse([]);
|
||||
}
|
||||
|
||||
return new JsonResponse($nginxStats->getStatsForStream($stream));
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route(path="/{id}/endpoints/")
|
||||
* @author Soner Sayakci <shyim@posteo.de>
|
||||
@ -188,7 +207,7 @@ class Streams extends Controller
|
||||
* @param int $id
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function endpoint(int $id)
|
||||
public function endpoint(int $id): JsonResponse
|
||||
{
|
||||
return new JsonResponse($this->endpointRepository->find($id));
|
||||
}
|
||||
@ -249,7 +268,7 @@ class Streams extends Controller
|
||||
* @throws \Doctrine\ORM\OptimisticLockException
|
||||
* @author Soner Sayakci <shyim@posteo.de>
|
||||
*/
|
||||
public function toggleEndpoint(Request $request) : JsonResponse
|
||||
public function toggleEndpoint(Request $request): JsonResponse
|
||||
{
|
||||
$id = $request->request->get('id');
|
||||
$endpoint = $this->endpointRepository->find($id);
|
||||
@ -277,7 +296,7 @@ class Streams extends Controller
|
||||
* @throws \Doctrine\ORM\OptimisticLockException
|
||||
* @throws \Doctrine\ORM\TransactionRequiredException
|
||||
*/
|
||||
public function deleteEndpoint(Request $request) : Response
|
||||
public function deleteEndpoint(Request $request): Response
|
||||
{
|
||||
$manager = $this->get('doctrine.orm.entity_manager');
|
||||
$endpoint = $manager->find(Endpoint::class, $request->request->get('id'));
|
||||
|
Loading…
x
Reference in New Issue
Block a user