From 2908793ce288d555167997db2a13d254def45415 Mon Sep 17 00:00:00 2001 From: James Gilliland Date: Fri, 4 Mar 2022 00:18:18 -0600 Subject: [PATCH] Start working on an all in one command --- .gitignore | 1 + bin/pfatt | 14 +++++++ composer.json | 37 +++++++++++++++++ phpstan-baseline.neon | 3 ++ phpstan.neon.dist | 6 +++ psalm.xml | 15 +++++++ src/Commands/Monitor.php | 61 +++++++++++++++++++++++++++ src/Config.php | 66 +++++++++++++++++++++++++++++ src/Logger.php | 63 ++++++++++++++++++++++++++++ src/NgController.php | 89 ++++++++++++++++++++++++++++++++++++++++ 10 files changed, 355 insertions(+) create mode 100644 .gitignore create mode 100755 bin/pfatt create mode 100644 composer.json create mode 100644 phpstan-baseline.neon create mode 100644 phpstan.neon.dist create mode 100644 psalm.xml create mode 100644 src/Commands/Monitor.php create mode 100644 src/Config.php create mode 100644 src/Logger.php create mode 100644 src/NgController.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..57872d0 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/vendor/ diff --git a/bin/pfatt b/bin/pfatt new file mode 100755 index 0000000..0aa1822 --- /dev/null +++ b/bin/pfatt @@ -0,0 +1,14 @@ +#!/usr/bin/env php +add(new Monitor()); +// ... register commands + +$application->run(); diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..01d9218 --- /dev/null +++ b/composer.json @@ -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 + } +} diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 0000000..846a8df --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,3 @@ +parameters: + ignoreErrors: [] + diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000..44e39dc --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,6 @@ +includes: + - phpstan-baseline.neon +parameters: + level: 9 + paths: + - src diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..3240886 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/src/Commands/Monitor.php b/src/Commands/Monitor.php new file mode 100644 index 0000000..473b0d1 --- /dev/null +++ b/src/Commands/Monitor.php @@ -0,0 +1,61 @@ +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; + } +} diff --git a/src/Config.php b/src/Config.php new file mode 100644 index 0000000..80b6a63 --- /dev/null +++ b/src/Config.php @@ -0,0 +1,66 @@ +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; + } +} diff --git a/src/Logger.php b/src/Logger.php new file mode 100644 index 0000000..91f6052 --- /dev/null +++ b/src/Logger.php @@ -0,0 +1,63 @@ +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); + } +} diff --git a/src/NgController.php b/src/NgController.php new file mode 100644 index 0000000..726f47b --- /dev/null +++ b/src/NgController.php @@ -0,0 +1,89 @@ +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; + } +}