Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
feb3071
Add Apprise
svenvg93 Jan 1, 2025
390a013
Merge branch 'alexjustesen:main' into add-apprise
svenvg93 Jan 5, 2025
7dbb71c
Merge branch 'alexjustesen:main' into add-apprise
svenvg93 Jan 22, 2025
6466e5a
Merge branch 'alexjustesen:main' into add-apprise
svenvg93 Feb 3, 2025
ac23efc
Merge branch 'alexjustesen:main' into add-apprise
svenvg93 Apr 16, 2025
2396cff
Merge branch 'alexjustesen:main' into add-apprise
svenvg93 Apr 27, 2025
910229b
first step refactor
svenvg93 Apr 27, 2025
f64823f
Add SpeedtestBenchmarkFailed
svenvg93 Apr 28, 2025
388ea10
lint
svenvg93 Apr 28, 2025
8e72592
add failed notifications
svenvg93 Apr 28, 2025
36e0afd
remove failed tests
svenvg93 Apr 29, 2025
ebebb0f
update subscriber
svenvg93 Apr 29, 2025
b3ebdac
lint and remove data collection
svenvg93 Apr 29, 2025
22a3a7d
Merge branch 'main' into add-apprise
svenvg93 Apr 29, 2025
d441660
remove faker data
svenvg93 Apr 29, 2025
a96a531
fix benchmarkfaild
svenvg93 Apr 29, 2025
f096a11
placeholder change
svenvg93 Apr 29, 2025
0d7be50
Disbale repeaters
svenvg93 Apr 30, 2025
512c25c
Lint
svenvg93 Apr 30, 2025
cff30bc
Add test command for notifications
svenvg93 Apr 30, 2025
1fbad1f
add SpeedtestNotificationData
svenvg93 May 4, 2025
f6251f2
undo data
svenvg93 May 7, 2025
35a66be
Undo data
svenvg93 May 7, 2025
398346c
Merge branch 'main' into add-apprise
svenvg93 May 8, 2025
d27e0c3
Fix the download upload latency
svenvg93 May 8, 2025
080a442
fix style
svenvg93 May 8, 2025
eaeb0c1
Merge branch 'main' into add-apprise
svenvg93 May 9, 2025
bd2a483
Merge branch 'alexjustesen:main' into add-apprise
svenvg93 May 19, 2025
74b2432
Merge branch 'alexjustesen:main' into add-apprise
svenvg93 May 19, 2025
8b6f4c7
Merge branch 'main' into add-apprise
svenvg93 May 27, 2025
5bc2e17
chore clean up
svenvg93 May 27, 2025
229d905
Merge branch 'main' into add-apprise
svenvg93 May 28, 2025
6188c94
bring on par with main
svenvg93 May 28, 2025
0b40a08
revert mail, webhook, database
svenvg93 May 28, 2025
06e8f49
update SpeedtestEventSubscriber
svenvg93 May 28, 2025
8d64da7
Fix thresholds
svenvg93 May 28, 2025
5a35129
improve error handle
svenvg93 Jun 4, 2025
598bf0f
Merge branch 'main' into add-apprise
svenvg93 Jun 4, 2025
893ed40
Add ssl check for self signed certs
svenvg93 Jun 4, 2025
253354e
refactor sending method
svenvg93 Jun 6, 2025
eebb398
Merge branch 'alexjustesen:main' into add-apprise
svenvg93 Jun 14, 2025
afb5f51
Merge branch 'alexjustesen:main' into add-apprise
svenvg93 Jun 17, 2025
f7046b8
add tests
svenvg93 Jun 25, 2025
b4a6e38
Remove tests
svenvg93 Jun 26, 2025
eb96752
Merge branch 'main' into add-apprise
svenvg93 Jun 26, 2025
bfc7630
Merge branch 'main' into add-apprise
svenvg93 Jul 11, 2025
86a73ad
Merge branch 'main' into add-apprise
svenvg93 Jul 25, 2025
a3f3863
Merge branch 'main' into add-apprise
svenvg93 Jul 28, 2025
c2e77ae
Merge branch 'alexjustesen:main' into add-apprise
svenvg93 Jul 28, 2025
ab7824e
Merge branch 'alexjustesen:main' into add-apprise
svenvg93 Aug 1, 2025
64c3f00
Merge branch 'main' into add-apprise
svenvg93 Aug 5, 2025
55cc19f
Merge branch 'feat/apprise-notification-channel' of https://github.co…
svenvg93 Nov 3, 2025
bb81c3d
Update with branch
svenvg93 Nov 3, 2025
709f08f
Revert Jitter latency changes
svenvg93 Nov 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions app/Actions/Notifications/SendAppriseTestNotification.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace App\Actions\Notifications;

use App\Notifications\Apprise\TestNotification;
use Filament\Notifications\Notification;
use Illuminate\Support\Facades\Notification as FacadesNotification;
use Lorisleiva\Actions\Concerns\AsAction;

class SendAppriseTestNotification
{
use AsAction;

public function handle(array $channel_urls)
{
if (! count($channel_urls)) {
Notification::make()
->title('You need to add Apprise channel URLs!')
->warning()
->send();

return;
}

foreach ($channel_urls as $row) {
$channelUrl = $row['channel_url'] ?? null;
if (! $channelUrl) {
Notification::make()
->title('Skipping missing channel URL!')
->warning()
->send();

continue;
}

FacadesNotification::route('apprise_urls', $channelUrl)
->notify(new TestNotification);
}

Notification::make()
->title('Test Apprise notification sent.')
->success()
->send();
}
}
40 changes: 40 additions & 0 deletions app/Console/Commands/TestNotification.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace App\Console\Commands;

use App\Jobs\Notifications\Apprise\SendSpeedtestCompletedNotification as AppriseCompleted;
use App\Jobs\Notifications\Apprise\SendSpeedtestThresholdNotification as AppriseThreshold;
use App\Models\Result;
use Illuminate\Console\Command;

class TestNotification extends Command
{
protected $signature = 'notification:test
{type=completed : Notification type (completed or threshold)}
{--channel=apprise : Notification channel (apprise)}';

protected $description = 'Send a test notification using a fake result';

public function handle(): int
{
$type = $this->argument('type');
$channel = $this->option('channel');

$this->info("Creating fake result for type: {$type}");

$result = Result::factory()->create([
'status' => 'completed',
]);

$this->info("Dispatching {$channel} notification...");

match ("{$channel}-{$type}") {
'apprise-completed' => AppriseCompleted::dispatch($result),
'apprise-threshold' => AppriseThreshold::dispatch($result),
};

$this->info('✅ Notification dispatched!');

return self::SUCCESS;
}
}
926 changes: 503 additions & 423 deletions app/Filament/Pages/Settings/NotificationPage.php

Large diffs are not rendered by default.

54 changes: 54 additions & 0 deletions app/Listeners/Apprise/SendSpeedtestCompletedNotification.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace App\Listeners\Apprise;

use App\Events\SpeedtestCompleted;
use App\Notifications\Apprise\SpeedtestNotification;
use App\Services\Notifications\SpeedtestNotificationData;
use App\Settings\NotificationSettings;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;

class SendSpeedtestCompletedNotification
{
/**
* Handle the event.
*/
public function handle(SpeedtestCompleted $event): void
{
$notificationSettings = new NotificationSettings;

if (! $notificationSettings->apprise_enabled) {
return;
}

if (! $notificationSettings->apprise_on_speedtest_run) {
return;
}

if (empty($notificationSettings->apprise_channel_urls) || ! is_array($notificationSettings->apprise_channel_urls)) {
Log::warning('Apprise service URLs not found; check Apprise notification settings.');

return;
}

// Build the speedtest data
$data = SpeedtestNotificationData::make($event->result);

$body = view('apprise.speedtest-completed', $data)->render();
$title = 'Speedtest Completed – #'.$event->result->id;

// Send notification to each configured channel URL
foreach ($notificationSettings->apprise_channel_urls as $row) {
$channelUrl = $row['channel_url'] ?? null;
if (! $channelUrl) {
Log::warning('Skipping entry with missing channel_url.');

continue;
}

Notification::route('apprise_urls', $channelUrl)
->notify(new SpeedtestNotification($title, $body, 'info'));
}
}
}
139 changes: 139 additions & 0 deletions app/Listeners/Apprise/SendSpeedtestThresholdNotification.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<?php

namespace App\Listeners\Apprise;

use App\Events\SpeedtestCompleted;
use App\Helpers\Number;
use App\Notifications\Apprise\SpeedtestNotification;
use App\Settings\NotificationSettings;
use App\Settings\ThresholdSettings;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Str;

class SendSpeedtestThresholdNotification
{
/**
* Handle the event.
*/
public function handle(SpeedtestCompleted $event): void
{
$notificationSettings = new NotificationSettings;

if (! $notificationSettings->apprise_enabled) {
return;
}

if (! $notificationSettings->apprise_on_threshold_failure) {
return;
}

if (empty($notificationSettings->apprise_channel_urls) || ! is_array($notificationSettings->apprise_channel_urls)) {
Log::warning('Apprise service URLs not found; check Apprise notification settings.');

return;
}

$thresholdSettings = new ThresholdSettings;

if (! $thresholdSettings->absolute_enabled) {
return;
}

$failed = [];

if ($thresholdSettings->absolute_download > 0) {
array_push($failed, $this->absoluteDownloadThreshold(event: $event, thresholdSettings: $thresholdSettings));
}

if ($thresholdSettings->absolute_upload > 0) {
array_push($failed, $this->absoluteUploadThreshold(event: $event, thresholdSettings: $thresholdSettings));
}

if ($thresholdSettings->absolute_ping > 0) {
array_push($failed, $this->absolutePingThreshold(event: $event, thresholdSettings: $thresholdSettings));
}

$failed = array_filter($failed);

if (! count($failed)) {
Log::warning('Failed Apprise thresholds not found, won\'t send notification.');

return;
}

$body = view('apprise.speedtest-threshold', [
'id' => $event->result->id,
'service' => Str::title($event->result->service->getLabel()),
'serverName' => $event->result->server_name,
'serverId' => $event->result->server_id,
'isp' => $event->result->isp,
'metrics' => $failed,
'speedtest_url' => $event->result->result_url,
'url' => url('/admin/results'),
])->render();

$title = 'Speedtest Threshold Breach – #'.$event->result->id;

// Send notification to each configured channel URL
foreach ($notificationSettings->apprise_channel_urls as $row) {
$channelUrl = $row['channel_url'] ?? null;
if (! $channelUrl) {
Log::warning('Skipping entry with missing channel_url.');

continue;
}

Notification::route('apprise_urls', $channelUrl)
->notify(new SpeedtestNotification($title, $body, 'warning'));
}
}

/**
* Build Apprise notification if absolute download threshold is breached.
*/
protected function absoluteDownloadThreshold(SpeedtestCompleted $event, ThresholdSettings $thresholdSettings): bool|array
{
if (! absoluteDownloadThresholdFailed($thresholdSettings->absolute_download, $event->result->download)) {
return false;
}

return [
'name' => 'Download',
'threshold' => $thresholdSettings->absolute_download.' Mbps',
'value' => Number::toBitRate(bits: $event->result->download_bits, precision: 2),
];
}

/**
* Build Apprise notification if absolute upload threshold is breached.
*/
protected function absoluteUploadThreshold(SpeedtestCompleted $event, ThresholdSettings $thresholdSettings): bool|array
{
if (! absoluteUploadThresholdFailed($thresholdSettings->absolute_upload, $event->result->upload)) {
return false;
}

return [
'name' => 'Upload',
'threshold' => $thresholdSettings->absolute_upload.' Mbps',
'value' => Number::toBitRate(bits: $event->result->upload_bits, precision: 2),
];
}

/**
* Build Apprise notification if absolute ping threshold is breached.
*/
protected function absolutePingThreshold(SpeedtestCompleted $event, ThresholdSettings $thresholdSettings): bool|array
{
if (! absolutePingThresholdFailed($thresholdSettings->absolute_ping, $event->result->ping)) {
return false;
}

return [
'name' => 'Ping',
'threshold' => $thresholdSettings->absolute_ping.' ms',
'value' => round($event->result->ping, 2).' ms',
];
}
}
2 changes: 2 additions & 0 deletions app/Listeners/Database/SendSpeedtestCompletedNotification.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use App\Models\User;
use App\Settings\NotificationSettings;
use Filament\Notifications\Notification;
use Illuminate\Support\Facades\Log;

class SendSpeedtestCompletedNotification
{
Expand All @@ -25,6 +26,7 @@ public function handle(SpeedtestCompleted $event): void
}

foreach (User::all() as $user) {
Log::info('Notifying user', ['id' => $user->id, 'email' => $user->email]);
Notification::make()
->title('Speedtest completed')
->success()
Expand Down
1 change: 1 addition & 0 deletions app/Listeners/SpeedtestEventSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public function handleSpeedtestCompleted(SpeedtestCompleted $event): void
{
$settings = app(DataIntegrationSettings::class);

// Write to InfluxDB if enabled
if ($settings->influxdb_v2_enabled) {
WriteResult::dispatch($event->result);
}
Expand Down
66 changes: 66 additions & 0 deletions app/Notifications/Apprise/AppriseMessage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

namespace App\Notifications\Apprise;

class AppriseMessage
{
public function __construct(
public string|array $urls,
public string $title,
public string $body,
public string $type = 'info',
public string $format = 'text',
public ?string $tag = null,
) {}

public static function create(): self
{
return new self(
urls: '',
title: '',
body: '',
);
}

public function urls(string|array $urls): self
{
$this->urls = $urls;

return $this;
}

public function title(string $title): self
{
$this->title = $title;

return $this;
}

public function body(string $body): self
{
$this->body = $body;

return $this;
}

public function type(string $type): self
{
$this->type = $type;

return $this;
}

public function format(string $format): self
{
$this->format = $format;

return $this;
}

public function tag(string $tag): self
{
$this->tag = $tag;

return $this;
}
}
Loading