Start working on an all in one command
This commit is contained in:
parent
5aa5d85f40
commit
2908793ce2
10 changed files with 355 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/vendor/
|
14
bin/pfatt
Executable file
14
bin/pfatt
Executable file
|
@ -0,0 +1,14 @@
|
||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
// application.php
|
||||||
|
|
||||||
|
require __DIR__ . '/../vendor/autoload.php';
|
||||||
|
|
||||||
|
use Pfatt\Commands\Monitor;
|
||||||
|
use Symfony\Component\Console\Application;
|
||||||
|
|
||||||
|
$application = new Application();
|
||||||
|
$application->add(new Monitor());
|
||||||
|
// ... register commands
|
||||||
|
|
||||||
|
$application->run();
|
37
composer.json
Normal file
37
composer.json
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
{
|
||||||
|
"name": "neclimdul/pfatt",
|
||||||
|
"description": "Bridge tool for PHP stuff.",
|
||||||
|
"type": "project",
|
||||||
|
"license": "MIT",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Pfatt\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "James Gilliland",
|
||||||
|
"email": "neclimdul@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"require": {
|
||||||
|
"php": "~7.4",
|
||||||
|
"psr/log": "^1.1",
|
||||||
|
"symfony/console": "^5.4"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpstan/phpstan": "^1.4",
|
||||||
|
"vimeo/psalm": "^4.22"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"psalm": "psalm",
|
||||||
|
"phpstan": "phpstan",
|
||||||
|
"static": [
|
||||||
|
"@phpstan",
|
||||||
|
"@psalm"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"sort-packages": true
|
||||||
|
}
|
||||||
|
}
|
3
phpstan-baseline.neon
Normal file
3
phpstan-baseline.neon
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
parameters:
|
||||||
|
ignoreErrors: []
|
||||||
|
|
6
phpstan.neon.dist
Normal file
6
phpstan.neon.dist
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
includes:
|
||||||
|
- phpstan-baseline.neon
|
||||||
|
parameters:
|
||||||
|
level: 9
|
||||||
|
paths:
|
||||||
|
- src
|
15
psalm.xml
Normal file
15
psalm.xml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<psalm
|
||||||
|
errorLevel="1"
|
||||||
|
resolveFromConfigFile="true"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xmlns="https://getpsalm.org/schema/config"
|
||||||
|
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
|
||||||
|
>
|
||||||
|
<projectFiles>
|
||||||
|
<directory name="src" />
|
||||||
|
<ignoreFiles>
|
||||||
|
<directory name="vendor" />
|
||||||
|
</ignoreFiles>
|
||||||
|
</projectFiles>
|
||||||
|
</psalm>
|
61
src/Commands/Monitor.php
Normal file
61
src/Commands/Monitor.php
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Pfatt\Commands;
|
||||||
|
|
||||||
|
use Pfatt\Config;
|
||||||
|
use Pfatt\Logger;
|
||||||
|
use Pfatt\NgController;
|
||||||
|
use Symfony\Component\Console\Command\Command;
|
||||||
|
use Symfony\Component\Console\Input\InputInterface;
|
||||||
|
use Symfony\Component\Console\Logger\ConsoleLogger;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
final class Monitor extends Command
|
||||||
|
{
|
||||||
|
protected static $defaultName = 'monitor';
|
||||||
|
protected static $defaultDescription = 'Monitor connection to trigger 5268AC updates';
|
||||||
|
protected Config $config;
|
||||||
|
protected Logger $logger;
|
||||||
|
protected NgController $ngControl;
|
||||||
|
|
||||||
|
protected function configure(): void
|
||||||
|
{
|
||||||
|
// @todo Inject these. Maybe with a factory or container.
|
||||||
|
$this->config = new Config('', '', '');
|
||||||
|
$this->logger = new Logger('pfatt-5268AC');
|
||||||
|
$this->ngControl = new NgController($this->logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||||
|
{
|
||||||
|
$this->logger->setOutput($output);
|
||||||
|
|
||||||
|
$this->logger->info('Starting 5268AC ping monitor ...');
|
||||||
|
register_shutdown_function(function () { $this->logger->info('Stopping 5268AC ping monitor ...'); });
|
||||||
|
|
||||||
|
while ($input->isInteractive()) {
|
||||||
|
if ($this->ping()) {
|
||||||
|
$this->ngControl->ngRmHook();
|
||||||
|
}
|
||||||
|
elseif (!$this->ngControl->ngIsConnected()) {
|
||||||
|
$this->ngControl->ngConnect();
|
||||||
|
}
|
||||||
|
sleep(5);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function ping(): int
|
||||||
|
{
|
||||||
|
$process = proc_open('/sbin/ping -t2 -q -c1 ' . $this->config->getPingHost(), [], $pipes);
|
||||||
|
if ($process) {
|
||||||
|
return proc_close($process);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
66
src/Config.php
Normal file
66
src/Config.php
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Pfatt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Config wrapper.
|
||||||
|
*/
|
||||||
|
class Config
|
||||||
|
{
|
||||||
|
private string $pingHost = '8.8.8.8';
|
||||||
|
private string $ontInterface;
|
||||||
|
private string $rgInterface;
|
||||||
|
private string $rgEthernetMac;
|
||||||
|
|
||||||
|
public function __construct(string $ontInterface, string $rgInterface, string $rgEthernetMac, ?string $pingHost = null)
|
||||||
|
{
|
||||||
|
$this->ontInterface = $ontInterface;
|
||||||
|
$this->rgInterface = $rgInterface;
|
||||||
|
$this->rgEthernetMac = $rgEthernetMac;
|
||||||
|
if (isset($pingHost)) {
|
||||||
|
$this->pingHost = $pingHost;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Host to ping to check connection.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getPingHost(): string
|
||||||
|
{
|
||||||
|
return $this->pingHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Network interface connected to the ONT.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getOntInterface(): string
|
||||||
|
{
|
||||||
|
return $this->ontInterface;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Network interface connected to the Residential Gateway.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRgInterface(): string
|
||||||
|
{
|
||||||
|
return $this->rgInterface;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Residential Gateway MAC address.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getRgEthernetMac(): string
|
||||||
|
{
|
||||||
|
return $this->rgEthernetMac;
|
||||||
|
}
|
||||||
|
}
|
63
src/Logger.php
Normal file
63
src/Logger.php
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Pfatt;
|
||||||
|
|
||||||
|
use Psr\Log\AbstractLogger;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
use Symfony\Component\Console\Logger\ConsoleLogger;
|
||||||
|
use Symfony\Component\Console\Output\OutputInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PSR-3 style logger.
|
||||||
|
*/
|
||||||
|
class Logger extends AbstractLogger
|
||||||
|
{
|
||||||
|
private string $channel;
|
||||||
|
/**
|
||||||
|
* @var \Psr\Log\LoggerInterface|null
|
||||||
|
*/
|
||||||
|
private ?LoggerInterface $logger;
|
||||||
|
|
||||||
|
public function __construct(string $channel, LoggerInterface $logger = null)
|
||||||
|
{
|
||||||
|
$this->channel = $channel;
|
||||||
|
$this->logger = $logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function log($level, $message, array $context = array())
|
||||||
|
{
|
||||||
|
$full_message = $this->getTimestamp() . ' :: [' . $this->channel . '] :: ' . $message;
|
||||||
|
if (isset($this->logger)) {
|
||||||
|
$this->logger->log($level, $full_message, $context);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
echo $full_message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current timestamp formatted for logs.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
* ISO8601 formatted timestamp.
|
||||||
|
*/
|
||||||
|
private function getTimestamp(): string
|
||||||
|
{
|
||||||
|
return (new \DateTime())->format(\DateTimeInterface::ISO8601);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add output to use for writing.
|
||||||
|
*
|
||||||
|
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||||
|
* Output service.
|
||||||
|
*/
|
||||||
|
public function setOutput(OutputInterface $output): void {
|
||||||
|
$this->logger = new ConsoleLogger($output);
|
||||||
|
}
|
||||||
|
}
|
89
src/NgController.php
Normal file
89
src/NgController.php
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Pfatt;
|
||||||
|
|
||||||
|
use Psr\Log\LoggerAwareInterface;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
class NgController implements LoggerAwareInterface
|
||||||
|
{
|
||||||
|
private LoggerInterface $logger;
|
||||||
|
|
||||||
|
public function __construct(LoggerInterface $logger)
|
||||||
|
{
|
||||||
|
$this->logger = $logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use ngctl to check connection.
|
||||||
|
*/
|
||||||
|
public function ngIsConnected(): int
|
||||||
|
{
|
||||||
|
return $this->ngCtlRun('show laneapfilter:eapout');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use ngctl remove connection.
|
||||||
|
*/
|
||||||
|
public function ngRmHook(): void
|
||||||
|
{
|
||||||
|
$this->logger->info('Disconnecting netgraph node ...');
|
||||||
|
$this->ngCtlRun('rmhook laneapfilter: eapout') ?
|
||||||
|
$this->logger->info('OK!') :
|
||||||
|
$this->logger->error('ERROR!');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use ngctl to establish connection.
|
||||||
|
*/
|
||||||
|
public function ngConnect(): void
|
||||||
|
{
|
||||||
|
$this->logger->info('Connecting netgraph node ...');
|
||||||
|
$this->ngCtlRun('connect waneapfilter: laneapfilter: eapout eapout') ?
|
||||||
|
$this->logger->info('OK!') :
|
||||||
|
$this->logger->error('ERROR!');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check filter status.
|
||||||
|
*
|
||||||
|
* @param string $arg
|
||||||
|
* Additional arguments to pass to ngctl.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
* Process return code.
|
||||||
|
*/
|
||||||
|
private function ngCtlRun(string $arg): int
|
||||||
|
{
|
||||||
|
$descriptorspec = [
|
||||||
|
// 0 => ['pipe', 'r'],
|
||||||
|
// 1 => ['pipe', 'w'],
|
||||||
|
// 2 => ['pipe', 'r'],
|
||||||
|
];
|
||||||
|
|
||||||
|
$cwd = '/tmp';
|
||||||
|
$env = [];
|
||||||
|
|
||||||
|
$process = proc_open(
|
||||||
|
'/usr/sbin/ngctl ' . $arg,
|
||||||
|
$descriptorspec,
|
||||||
|
$pipes,
|
||||||
|
$cwd,
|
||||||
|
$env
|
||||||
|
);
|
||||||
|
if ($process) {
|
||||||
|
return proc_close($process);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public function setLogger(LoggerInterface $logger): void
|
||||||
|
{
|
||||||
|
$this->logger = $logger;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue