From 4e44e2e266254a0d2ef5d8daeebb22cef82cd330 Mon Sep 17 00:00:00 2001 From: Deon George Date: Wed, 26 Jul 2023 19:44:07 +1000 Subject: [PATCH] Added system polling --- app/Classes/Protocol.php | 3 + app/Classes/Protocol/Zmodem.php | 2 - app/Console/Commands/CommBinkpSend.php | 10 +- app/Console/Commands/CommEMSISend.php | 10 +- app/Console/Commands/JobList.php | 50 +++++ app/Console/Commands/MailSend.php | 52 +++++ app/Console/Kernel.php | 5 +- app/Http/Controllers/SystemController.php | 12 +- app/Http/Requests/SystemRegister.php | 9 + app/Jobs/AddressPoll.php | 133 +++++++++++-- app/Jobs/MailSend.php | 179 ++++++++++++++++++ app/Models/Address.php | 3 +- app/Models/Job.php | 69 +++++++ app/Models/System.php | 11 ++ app/Notifications/Channels/NetmailChannel.php | 2 - app/Notifications/Netmails/PollingFailed.php | 58 ++++++ .../2023_07_25_223929_system_poll.php | 36 ++++ resources/views/system/addedit.blade.php | 10 +- .../views/system/widget/form-system.blade.php | 167 +++++++++++----- 19 files changed, 733 insertions(+), 88 deletions(-) create mode 100644 app/Console/Commands/JobList.php create mode 100644 app/Console/Commands/MailSend.php create mode 100644 app/Jobs/MailSend.php create mode 100644 app/Models/Job.php create mode 100644 app/Notifications/Netmails/PollingFailed.php create mode 100644 database/migrations/2023_07_25_223929_system_poll.php diff --git a/app/Classes/Protocol.php b/app/Classes/Protocol.php index bdd953e..7c5ff01 100644 --- a/app/Classes/Protocol.php +++ b/app/Classes/Protocol.php @@ -28,7 +28,9 @@ abstract class Protocol // Our sessions Types public const SESSION_AUTO = 0; + /** @deprecate Use mailers:class */ public const SESSION_EMSI = 1; + /** @deprecate Use mailers:class */ public const SESSION_BINKP = 2; public const SESSION_ZMODEM = 3; @@ -447,6 +449,7 @@ abstract class Protocol $slo->sessiontype = $type; $slo->sessiontime = $this->node->session_time; $slo->result = ($rc & self::S_MASK); + $slo->originate = $this->originate; $so->logs()->save($slo); } diff --git a/app/Classes/Protocol/Zmodem.php b/app/Classes/Protocol/Zmodem.php index efc2964..d48b418 100644 --- a/app/Classes/Protocol/Zmodem.php +++ b/app/Classes/Protocol/Zmodem.php @@ -1420,8 +1420,6 @@ final class Zmodem extends Protocol implements CRCInterface,ZmodemInterface $trys++; } - dump(['ls_rxHdr'=>hex_dump(join('',$this->ls_rxHdr))]); - switch (($rc=$this->ls_zrecvhdr($this->ls_rxHdr,$this->ls_HeaderTimeout))) { /* Send ZRINIT again */ case self::ZRQINIT: diff --git a/app/Console/Commands/CommBinkpSend.php b/app/Console/Commands/CommBinkpSend.php index de1b038..0fb7b1a 100644 --- a/app/Console/Commands/CommBinkpSend.php +++ b/app/Console/Commands/CommBinkpSend.php @@ -34,14 +34,14 @@ class CommBinkpSend extends Command */ public function handle(): void { - Log::info('CBS:- Call BINKP send'); - - $mo = Mailer::where('name',self::ID)->singleOrFail(); - $ao = Address::findFTN($this->argument('ftn')); if (! $ao) throw new ModelNotFoundException('Unknown node: '.$this->argument('ftn')); - Job::dispatchSync($ao,$mo); + Log::info(sprintf('CBS:- Call BINKP send for %s',$ao->ftn)); + + $mo = Mailer::where('name',self::ID)->singleOrFail(); + + Job::dispatch($ao,$mo); } } diff --git a/app/Console/Commands/CommEMSISend.php b/app/Console/Commands/CommEMSISend.php index 38f5522..1afe676 100644 --- a/app/Console/Commands/CommEMSISend.php +++ b/app/Console/Commands/CommEMSISend.php @@ -34,14 +34,14 @@ class CommEMSISend extends Command */ public function handle(): void { - Log::info('CES:- Call EMSI send'); - - $mo = Mailer::where('name',self::ID)->singleOrFail(); - $ao = Address::findFTN($this->argument('ftn')); if (! $ao) throw new ModelNotFoundException('Unknown node: '.$this->argument('ftn')); - Job::dispatchSync($ao,$mo); + Log::info(sprintf('CES:- Call EMSI send for %s',$ao->ftn)); + + $mo = Mailer::where('name',self::ID)->singleOrFail(); + + Job::dispatch($ao,$mo); } } diff --git a/app/Console/Commands/JobList.php b/app/Console/Commands/JobList.php new file mode 100644 index 0000000..2955e16 --- /dev/null +++ b/app/Console/Commands/JobList.php @@ -0,0 +1,50 @@ +orderBy('created_at')->cursor() as $o) { + if ($o->queue !== $lastq) { + $this->alert(sprintf('Queue: %s',$o->queue)); + $lastq = $o->queue; + } + + $this->info(sprintf('%s-%d: %s[%s] - %d tries (Created: %s,Timeout: %s,Next: %s)', + $o->uuid, + $o->id, + $o->display_name, + $o->command->subject, + $o->attempts, + $o->created_at, + $o->retry_until ?: '-', + $o->reserved_at ?: '-', + )); + } + } +} \ No newline at end of file diff --git a/app/Console/Commands/MailSend.php b/app/Console/Commands/MailSend.php new file mode 100644 index 0000000..2e49cef --- /dev/null +++ b/app/Console/Commands/MailSend.php @@ -0,0 +1,52 @@ +option('type')) { + case 'crash': + Log::info('CML:- Triggering polls to send CRASH mail'); + Job::dispatchSync(TRUE); + break; + + case 'normal': + Log::info('CML:- Triggering polls to send NORMAL mail'); + Job::dispatchSync(FALSE); + break; + + case 'all': + Log::info('CML:- Triggering polls to send ALL mail'); + Job::dispatchSync(NULL); + break; + + default: + $this->error('Specify -T crash, normal or all'); + } + } +} \ No newline at end of file diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index a8c5158..7040484 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -2,6 +2,7 @@ namespace App\Console; +use App\Jobs\MailSend; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; @@ -24,8 +25,8 @@ class Kernel extends ConsoleKernel */ protected function schedule(Schedule $schedule) { - // $schedule->command('inspire') - // ->hourly(); + $schedule->job(new MailSend(TRUE))->everyFiveMinutes()->withoutOverlapping(); + $schedule->job(new MailSend(FALSE))->twiceDaily(1,13); } /** diff --git a/app/Http/Controllers/SystemController.php b/app/Http/Controllers/SystemController.php index efc4ee9..a1ac308 100644 --- a/app/Http/Controllers/SystemController.php +++ b/app/Http/Controllers/SystemController.php @@ -12,6 +12,7 @@ use Illuminate\Support\Facades\Notification; use Illuminate\Support\ViewErrorBag; use App\Http\Requests\SystemRegister; +use App\Jobs\AddressPoll; use App\Models\{Address,Echoarea,Filearea,Setup,System,SystemZone,Zone}; use App\Notifications\Netmails\AddressLink; use App\Rules\{FidoInteger,TwoByteInteger}; @@ -279,6 +280,13 @@ class SystemController extends Controller foreach (['name','location','sysop','hold','phone','address','port','active','method','notes','zt_id','pkt_type'] as $key) $o->{$key} = $request->post($key); + switch ($request->post('pollmode')) { + case 1: $o->pollmode = FALSE; break; + case 2: $o->pollmode = TRUE; break; + default: $o->pollmode = NULL; + } + + $o->autohold = FALSE; $o->save(); $mailers = collect($request->post('mailer_details')) @@ -653,8 +661,10 @@ class SystemController extends Controller break; } - if ($ca->count() && $la=$ca->pop()) + if ($ca->count() && $la=$ca->pop()) { Notification::route('netmail',$la)->notify(new AddressLink(Auth::user())); + AddressPoll::dispatch($la)->delay(15); + } return view('user.system.register_send') ->with('la',$la) diff --git a/app/Http/Requests/SystemRegister.php b/app/Http/Requests/SystemRegister.php index 622f7bf..61b38e8 100644 --- a/app/Http/Requests/SystemRegister.php +++ b/app/Http/Requests/SystemRegister.php @@ -27,6 +27,14 @@ class SystemRegister extends FormRequest return Gate::allows($this->so->users->count() ? 'update' : 'register',$this->so); } + public function messages(): array + { + return [ + 'hold' => 'Must be Yes or No', + 'pollmode' => 'Must be Hold, Normal or Crash', + ]; + } + /** * Get the validation rules that apply to the request. * @@ -64,6 +72,7 @@ class SystemRegister extends FormRequest $this->so->exists ? [ 'active' => 'required|boolean', 'hold' => 'required|boolean', + 'pollmode' => 'required|integer|min:0|max:2', ] : [], )); } diff --git a/app/Jobs/AddressPoll.php b/app/Jobs/AddressPoll.php index 4a99ae4..c6f0b27 100644 --- a/app/Jobs/AddressPoll.php +++ b/app/Jobs/AddressPoll.php @@ -3,24 +3,37 @@ namespace App\Jobs; use Illuminate\Bus\Queueable; +use Illuminate\Contracts\Queue\ShouldBeUnique; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; +use Illuminate\Queue\ManuallyFailedException; +use Illuminate\Queue\MaxAttemptsExceededException; use Illuminate\Queue\SerializesModels; use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Notification; use App\Classes\Protocol; use App\Classes\Protocol\{Binkp,EMSI}; use App\Classes\Sock\SocketClient; use App\Classes\Sock\SocketException; use App\Models\{Address,Mailer,Setup}; +use App\Notifications\Netmails\PollingFailed; -class AddressPoll implements ShouldQueue +class AddressPoll implements ShouldQueue, ShouldBeUnique { private const LOGKEY = 'JAP'; use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + public $tries = 5; + + public $maxExceptions = 1; + + public $failOnTimeout = TRUE; + + public const QUEUE = 'poll'; + private Address $ao; private ?Mailer $mo; @@ -28,6 +41,50 @@ class AddressPoll implements ShouldQueue { $this->ao = $ao; $this->mo = $mo; + + $this->onQueue(self::QUEUE); + } + + public function __get($key): mixed + { + switch ($key) { + case 'address': + return $this->ao; + + case 'subject': + return $this->ao->ftn; + + default: + return NULL; + } + } + + /** + * Because pluck doesnt return __get() defined vars + * + * @param $key + * @return bool + */ + public function __isset($key): bool + { + $keys = ['address']; + + return in_array($key,$keys); + } + + /** + * Time to wait between tries + * + * @return int[] in seconds + */ + public function backoff(): array + { + return [ + 60*5, // 5 mins + 60*60, // 1 hr + 60*60*6, // 6 hrs + 60*60*12 // 12 hrs + ]; } /** @@ -35,24 +92,19 @@ class AddressPoll implements ShouldQueue */ public function handle() { - if (! $this->ao->system->mailer_preferred->count() || ($this->mo && (! $this->ao->system->mailer_preferred->find($this->mo)))) - throw new \Exception(sprintf('Unable to poll [%s] missing mailer details',$this->ao->ftn)); + if (! $this->ao->system->mailer_preferred->count() || ($this->mo && (! $this->ao->system->mailer_preferred->find($this->mo)))) { + $this->fail('Missing mailer details'); + + return; + } + + Log::info(sprintf('%s:- Polling [%s] - attempt [%d]',self::LOGKEY,$this->ao->ftn,$this->attempts())); foreach ($this->ao->system->mailer_preferred as $o) { // If we chose a protocol, skip to find the mailer details for it if ($this->mo && ($o->id !== $this->mo->id)) continue; - Log::info(sprintf('%s:- Starting a [%s] session to [%s:%d]',self::LOGKEY,$o->name,$this->ao->system->address,$o->pivot->port)); - - try { - $client = SocketClient::create($this->ao->system->address,$o->pivot->port); - - } catch (SocketException $e) { - Log::error(sprintf('%s:! Unable to connect to [%s]: %s',self::LOGKEY,$this->ao->ftn,$e->getMessage())); - exit(1); - } - switch ($o->name) { case 'BINKP': $s = new Binkp(Setup::findOrFail(config('app.id'))); @@ -67,16 +119,59 @@ class AddressPoll implements ShouldQueue break; default: - throw new \Exception(sprintf('Node [%s] has a mailer type that is unhandled',$this->ao->ftn)); + $this->fail('Mailer type unhandled'); + + return; } - if (($s->session($session,$client,$this->ao) & Protocol::S_MASK) === Protocol::S_OK) { - Log::info(sprintf('%s:= Connection ended successfully with [%s]',self::LOGKEY,$client->address_remote)); - break; + Log::info(sprintf('%s:- Trying a [%s] session to [%s:%d] (%s)', + self::LOGKEY,$o->name,$this->ao->system->address,$o->pivot->port,$this->ao->ftn)); - } else { - Log::alert(sprintf('%s:! Connection failed to [%s]',self::LOGKEY,$client->address_remote)); + try { + $client = SocketClient::create($this->ao->system->address,$o->pivot->port); + + if (($s->session($session,$client,$this->ao) & Protocol::S_MASK) === Protocol::S_OK) { + Log::info(sprintf('%s:= Connection ended successfully with [%s] (%s)',self::LOGKEY,$client->address_remote,$this->ao->ftn)); + return; + + } else { + Log::alert(sprintf('%s:! Connection failed to [%s] (%s)',self::LOGKEY,$client->address_remote,$this->ao->ftn)); + } + + } catch (SocketException $e) { + Log::error(sprintf('%s:! Unable to connect to [%s]: %s',self::LOGKEY,$this->ao->ftn,$e->getMessage())); + break; } } + + $delay = (int)($this->backoff()[$this->attempts()-1] ?? last($this->backoff())); + Log::info(sprintf('%s:= Retrying poll in %d seconds',self::LOGKEY,$delay)); + $this->release($delay); + } + + public function failed(\Throwable $exception): void + { + switch (get_class($exception)) { + case ManuallyFailedException::class: + Log::error(sprintf('%s:! Address Poll failed for [%s] (%s)',self::LOGKEY,$this->ao->ftn,$exception->getMessage())); + break; + + case MaxAttemptsExceededException::class: + Log::error(sprintf('%s:! Address Poll was tried too many times for [%s]',self::LOGKEY,$this->ao->ftn)); + Notification::route('netmail',$this->ao)->notify(new PollingFailed); + + $this->ao->system->autohold = TRUE; + $this->ao->system->save(); + + exit(0); + + default: + Log::error(sprintf('%s:! Address Poll to [%s] with an unknown exception [%s]',self::LOGKEY,$this->ao->ftn,$exception->getMessage())); + } + } + + public function uniqueId(): string + { + return $this->ao->id; } } \ No newline at end of file diff --git a/app/Jobs/MailSend.php b/app/Jobs/MailSend.php new file mode 100644 index 0000000..058aebb --- /dev/null +++ b/app/Jobs/MailSend.php @@ -0,0 +1,179 @@ +crash = $crash; + } + + /** + * Execute the job. + */ + public function handle(): void + { + // Netmail waiting by node (only netmail is routed) + $netmails = Address::select(['addresses.id','addresses.zone_id','region_id','host_id','node_id','point_id','role','addresses.system_id',DB::raw('count(netmails.id) AS nm')]) + ->join('zones',['zones.id'=>'addresses.zone_id']) + ->join('domains',['domains.id'=>'zones.domain_id']) + ->join('netmails',['netmails.tftn_id'=>'addresses.id']) + ->join('systems',['systems.id'=>'addresses.system_id']) + ->where('addresses.active',TRUE) + ->where('zones.active',TRUE) + ->where('domains.active',TRUE) + ->where(function($query) { + return $query->whereNull('autohold') + ->orWhere('autohold',FALSE); + }) + ->where(function($query) { + return $query->whereRaw(sprintf('(flags & %d) > 0',Message::FLAG_INTRANSIT)) + ->orWhereRaw(sprintf('(flags & %d) > 0',Message::FLAG_LOCAL)); + }) + ->whereRaw(sprintf('(flags & %d) = 0',Message::FLAG_SENT)) + ->when(! is_null($this->crash),function($query) { + return $query->when( + $this->crash, + function($query) { + return $query->where('pollmode',$this->crash); + }, + function($query) { + return $query->whereNotNull('pollmode'); + } + ); + }) + ->groupBy('addresses.id') + ->havingRaw('count(*) > 0') + ->get(); + + // Echomail waiting by node + $echomails = Address::select(['addresses.id','addresses.zone_id','region_id','host_id','node_id','point_id','role','addresses.system_id',DB::raw('count(*) AS em')]) + ->distinct() + ->join('zones',['zones.id'=>'addresses.zone_id']) + ->join('domains',['domains.id'=>'zones.domain_id']) + ->join('echomail_seenby',['echomail_seenby.address_id'=>'addresses.id']) + ->join('systems',['systems.id'=>'addresses.system_id']) + ->where('addresses.active',TRUE) + ->where('zones.active',TRUE) + ->where('domains.active',TRUE) + ->where(function($query) { + return $query->whereNull('autohold') + ->orWhere('autohold',FALSE); + }) + ->whereNotNull('export_at') + ->whereNull('sent_at') + ->when(! is_null($this->crash),function($query) { + return $query->when( + $this->crash, + function($query) { + return $query->where('pollmode',$this->crash); + }, + function($query) { + return $query->whereNotNull('pollmode'); + } + ); + }) + ->groupBy(['addresses.id']) + ->havingRaw('count(*) > 0') + ->FTNOrder() + ->get(); + + // Files waiting by node + $files = Address::select(['addresses.id','addresses.zone_id','region_id','host_id','node_id','point_id','role','addresses.system_id',DB::raw('count(*) AS fs')]) + ->distinct() + ->join('zones',['zones.id'=>'addresses.zone_id']) + ->join('domains',['domains.id'=>'zones.domain_id']) + ->join('file_seenby',['file_seenby.address_id'=>'addresses.id']) + ->join('systems',['systems.id'=>'addresses.system_id']) + ->where('addresses.active',TRUE) + ->where('zones.active',TRUE) + ->where('domains.active',TRUE) + ->where(function($query) { + return $query->whereNull('autohold') + ->orWhere('autohold',FALSE); + }) + ->whereNotNull('export_at') + ->whereNull('sent_at') + ->when(! is_null($this->crash),function($query) { + return $query->when( + $this->crash, + function($query) { + return $query->where('pollmode',$this->crash); + }, + function($query) { + return $query->whereNotNull('pollmode'); + } + ); + }) + ->groupBy(['addresses.id']) + ->havingRaw('count(*) > 0') + ->FTNOrder() + ->get(); + + // Merge our netmails + foreach ($echomails as $ao) { + if (($x=$netmails->search(function($item) use ($ao) { return $item->id === $ao->id; })) !== FALSE) { + $netmails->get($x)->em = $ao->em; + } else { + $netmails->push($ao); + } + } + + // Merge our files + foreach ($files as $ao) { + if (($x=$netmails->search(function($item) use ($ao) { return $item->id === $ao->id; })) !== FALSE) { + $netmails->get($x)->fs = $ao->fs; + } else { + $netmails->push($ao); + } + } + + // Remove direct links + $netmails = $netmails->filter(function($item) { return $item->parent(); }); + + foreach ($netmails->groupBy(function($item) { return $item->parent()->ftn; }) as $oo) { + $ao = $oo->first(); + + Log::info(sprintf('%s:- Polling [%s] - we have mail for [%d] links. (%d Netmail,%d Echomail,%d Files)', + self::LOGKEY, + $ao->ftn, + $oo->count(), + $oo->sum('nm'), + $oo->sum('em'), + $oo->sum('fs'), + )); + + // @todo Only send crash mail - send normal mail with a schedule or hold mail + + if (Job::where('queue',$this->queue)->get()->pluck('command.address.id')->search($ao->id) !== FALSE) { + Log::alert(sprintf('%s:= Not scheduling poll to [%s], there is already one in the queue',self::LOGKEY,$ao->ftn)); + continue; + } + + AddressPoll::dispatch($ao); + } + } +} \ No newline at end of file diff --git a/app/Models/Address.php b/app/Models/Address.php index 8cc695c..3fe281e 100644 --- a/app/Models/Address.php +++ b/app/Models/Address.php @@ -2,7 +2,6 @@ namespace App\Models; -use Carbon\Carbon; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; @@ -283,7 +282,7 @@ class Address extends Model return NULL; default: - throw new \Exception('Unknown role: '.serialize($this->role)); + throw new \Exception(sprintf('Unknown role: %s (%d)',serialize($this->role),$this->id)); } return $parent?->parent(); diff --git a/app/Models/Job.php b/app/Models/Job.php new file mode 100644 index 0000000..5ad67fa --- /dev/null +++ b/app/Models/Job.php @@ -0,0 +1,69 @@ + 'array', + 'reserved_at' => 'datetime', + 'available_at' => 'datetime', + 'created_at' => 'datetime', + ]; + + public function __construct(array $attributes = []) + { + parent::__construct($attributes); + $this->table = Config::get('queue.connections.' . (Config::get('queue.default', 'database')) . '.table', 'jobs'); + } + + public function getDisplayNameAttribute() + { + return $this->payload['displayName']; + } + + public function getMaxTriesAttribute() + { + return $this->payload['maxTries']; + } + + public function getDelayAttribute() + { + return $this->payload['delay']; + } + + public function getUUIDAttribute() + { + return $this->payload['uuid']; + } + + public function getTimeoutAttribute() + { + return $this->payload['timeout']; + } + + public function getRetryUntilAttribute() + { + return !is_null($this->payload['retryUntil']) ? new \Carbon\Carbon($this->payload['retryUntil']) : null; + } + + public function getTimeoutAtAttribute() + { + return !is_null($this->payload['timeout_at']) ? new \Carbon\Carbon($this->payload['timeout_at']) : null; + } + + public function getCommandNameAttribute() + { + return $this->payload['data']['commandName']; + } + + public function getCommandAttribute() + { + return unserialize($this->payload['data']['command']); + } +} diff --git a/app/Models/System.php b/app/Models/System.php index 4c0439f..bd18d7d 100644 --- a/app/Models/System.php +++ b/app/Models/System.php @@ -7,6 +7,8 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Auth; +use App\Jobs\AddressPoll; + class System extends Model { use HasFactory; @@ -214,4 +216,13 @@ class System extends Model return ($item->role & $type) && ($myzones->search($item->zone_id) !== FALSE); }); } + + public function poll(): ?Job + { + return Job::where('queue',AddressPoll::QUEUE) + ->get() + ->where(function($item) { + return $this->akas->pluck('id')->search($item->command->address->id) !== FALSE; }) + ->last(); + } } \ No newline at end of file diff --git a/app/Notifications/Channels/NetmailChannel.php b/app/Notifications/Channels/NetmailChannel.php index 3294452..cfb5d7a 100644 --- a/app/Notifications/Channels/NetmailChannel.php +++ b/app/Notifications/Channels/NetmailChannel.php @@ -5,7 +5,6 @@ namespace App\Notifications\Channels; use Illuminate\Notifications\Notification; use Illuminate\Support\Facades\Log; -use App\Jobs\AddressPoll as Job; use App\Models\Netmail; use App\Models\Setup; @@ -43,7 +42,6 @@ class NetmailChannel $so = Setup::findOrFail(config('app.id'))->system; $o = $notification->toNetmail($so,$notifiable); - Job::dispatch($ao); Log::info(sprintf('%s:= Sent netmail [%s] to [%s]',self::LOGKEY,$o->msgid,$ao->ftn)); } } \ No newline at end of file diff --git a/app/Notifications/Netmails/PollingFailed.php b/app/Notifications/Netmails/PollingFailed.php new file mode 100644 index 0000000..2aaf040 --- /dev/null +++ b/app/Notifications/Netmails/PollingFailed.php @@ -0,0 +1,58 @@ +setupNetmail($so,$notifiable); + $ao = $notifiable->routeNotificationFor(static::via); + + Log::info(sprintf('%s:+ Creating auto hold netmail to [%s]',self::LOGKEY,$ao->ftn)); + + $o->subject = 'Failed polling - your system is on AUTO HOLD'; + + // Message + $msg = $this->page(FALSE,'hold'); + + $msg->addText("Hi, I've been trying to poll your system without success.\r\r"); + + $msg->addText("Your system was automatically placed on hold, which means I no longer attempted to poll you.\r\r"); + + $msg->addText( + 'Since you collected this message, I automatically removed the auto hold status, but if future attempts to poll you fail '. + "you'll be automatically placed back on auto hold until you poll me. You'll also get this annoying message each time :(\r\r"); + + $msg->addText("To fix this, update your details that I use in the web interface, or change your system to HOLD while you are there.\r\r"); + + $o->msg = $msg->render(); + $o->tagline = 'Painful? We can make that painless :)'; + + $o->save(); + + return $o; + } +} \ No newline at end of file diff --git a/database/migrations/2023_07_25_223929_system_poll.php b/database/migrations/2023_07_25_223929_system_poll.php new file mode 100644 index 0000000..22816b7 --- /dev/null +++ b/database/migrations/2023_07_25_223929_system_poll.php @@ -0,0 +1,36 @@ +boolean('originate')->nullable(); + }); + + Schema::table('systems',function (Blueprint $table) { + $table->boolean('pollmode')->nullable(); + $table->boolean('autohold')->nullable(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('systems',function (Blueprint $table) { + $table->dropColumn(['pollmode','autohold']); + }); + Schema::table('system_logs',function (Blueprint $table) { + $table->dropColumn(['originate']); + }); + } +}; diff --git a/resources/views/system/addedit.blade.php b/resources/views/system/addedit.blade.php index 4a29aea..7d8902d 100644 --- a/resources/views/system/addedit.blade.php +++ b/resources/views/system/addedit.blade.php @@ -272,8 +272,8 @@ - - + + @@ -286,7 +286,7 @@ @if ($x=$oo->parent()) {{ $x->ftn4d }} @else - No destination for mail. + None @endif @@ -305,8 +305,8 @@
ZoneSystemAKAUplink
- - + + diff --git a/resources/views/system/widget/form-system.blade.php b/resources/views/system/widget/form-system.blade.php index 8f24c3c..7863114 100644 --- a/resources/views/system/widget/form-system.blade.php +++ b/resources/views/system/widget/form-system.blade.php @@ -1,3 +1,4 @@ + @php use App\Models\Setup; @endphp @@ -21,8 +22,22 @@ + +
+ +
+ + + + @error('zt_id') + {{ $message }} + @enderror + +
+
+ -
+
@can('update',$o)
@@ -36,36 +51,6 @@
@endcan
- - -
- @can('update',$o) - -
-
- hold))checked @endif> - - - hold))checked @endif> - -
-
- @endcan -
- - -
- -
- - - - @error('zt_id') - {{ $message }} - @enderror - -
-
@@ -86,7 +71,7 @@
-
+
@@ -100,10 +85,41 @@
+ + +
+ @can('update',$o) + +
+
+ hold))checked @endif> + + + hold))checked @endif> + +
+
+ @endcan +
-
+ +
+ +
+ + + + @error('address') + {{ $message }} + @enderror + +
+
+ + +
@@ -116,18 +132,28 @@
- -
- -
- - - - @error('address') - {{ $message }} - @enderror - -
+ +
+ @can('update',$o) + +
+
+ pollmode === TRUE) ? 2 : 0) === 2)checked @endif> + + + pollmode === FALSE) ? 1 : 0) === 1)checked @endif> + + + pollmode) ? 0 : 1) === 0)checked @endif> + +
+ + @error('pollmode') + {{ $message }} + @enderror + +
+ @endcan
@@ -136,6 +162,7 @@

Mailer Details

+
@foreach (\App\Models\Mailer::all() as $mo) @@ -160,6 +187,7 @@ @endforeach
+
@@ -177,6 +205,55 @@
+ @if (! is_null($o->pollmode)) +
+
ZoneSystemAKADownlink
+ + @if($job = $o->poll()) + + + + + + + + + @if ($job->attempts) + + + + + @endif + + @else + + + + + + + + + @endif + + + + + + +
@if($job->attempts)Last Attempt @else Scheduled @endif:{{ $job->created_at }}
Attempts :{{ $job->attempts ?: 0 }}
Next Attempt :{{ $job->available_at->diffForHumans(now(),$job->available_at->isFuture() ? \Carbon\CarbonInterface::DIFF_ABSOLUTE : \Carbon\CarbonInterface::DIFF_RELATIVE_TO_NOW) }}
Last Poll :{{ ($x=$o->logs->where('originate',TRUE)->last())?->created_at ?: 'Never' }}
Method :{{ $x?->sessiontype ?: '-' }}
Status : + @if ($job) Queued + @elseif ($o->autohold)Auto Hold + @else + @switch($o->pollmode) + @case(TRUE) Crash @break; + @case(FALSE) Normal @break; + @default Hold + @endswitch + @endif +
+ + @endif