Go Agent barebone notification tests

This commit is contained in:
headlesdev 2025-05-25 15:42:08 +02:00
parent 1b4a716c3d
commit 67909493a2
12 changed files with 296 additions and 31 deletions

5
agent/go.mod Normal file
View File

@ -0,0 +1,5 @@
module github.com/crocofied/CoreControl
go 1.24.3
require github.com/lib/pq v1.10.9

2
agent/go.sum Normal file
View File

@ -0,0 +1,2 @@
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=

183
agent/main.go Normal file
View File

@ -0,0 +1,183 @@
package main
import (
"database/sql"
"encoding/json"
"fmt"
"log"
"os"
"time"
_ "github.com/lib/pq"
)
var db *sql.DB
type NotificationType string
const (
Telegram NotificationType = "TELEGRAM"
Ntfy NotificationType = "NTFY"
SMTP NotificationType = "SMTP"
)
type NotificationTest struct {
ID int
NotificationProviderID int
Sent bool
Success sql.NullBool
ProviderType string
ProviderConfig json.RawMessage
}
func main() {
var err error
db, err = sql.Open("postgres", os.Getenv("DATABASE_URL"))
if err != nil {
log.Fatal("Failed to connect to database:", err)
}
defer db.Close()
if err = db.Ping(); err != nil {
log.Fatal("Failed to ping database:", err)
}
ticker := time.NewTicker(10 * time.Second)
defer ticker.Stop()
for range ticker.C {
processPendingTests()
}
}
func processPendingTests() {
log.Println("Checking for pending notification tests...")
tests, err := getPendingTests()
if err != nil {
log.Println("Error fetching tests:", err)
return
}
for _, test := range tests {
providerType := NotificationType(test.ProviderType)
err := SendNotification(providerType, test.ProviderConfig, test)
if updateErr := updateTestStatus(test.ID, err == nil); updateErr != nil {
log.Printf("Error updating test status: %v", updateErr)
}
if err != nil {
log.Printf("Failed to send test %d: %v", test.ID, err)
continue
}
log.Printf("Successfully sent test %d", test.ID)
}
}
func SendNotification(providerType NotificationType, config json.RawMessage, test NotificationTest) error {
switch providerType {
case Telegram:
return sendTelegramNotification(config, test)
case Ntfy:
return sendNtfyNotification(config, test)
case SMTP:
return sendSMTPNotification(config, test)
default:
return fmt.Errorf("unknown provider type: %s", providerType)
}
}
func sendTelegramNotification(config json.RawMessage, test NotificationTest) error {
var cfg struct {
BotToken string `json:"botToken"`
ChatID string `json:"chatID"`
}
if err := json.Unmarshal(config, &cfg); err != nil {
return fmt.Errorf("invalid Telegram config: %w", err)
}
log.Printf("Sending Telegram test to chat %s", cfg.ChatID)
return nil
}
func sendNtfyNotification(config json.RawMessage, test NotificationTest) error {
var cfg struct {
Topic string `json:"topic"`
Server string `json:"server"`
}
if err := json.Unmarshal(config, &cfg); err != nil {
return fmt.Errorf("invalid NTFY config: %w", err)
}
log.Printf("Sending NTFY test to topic %s on %s", cfg.Topic, cfg.Server)
return nil
}
func sendSMTPNotification(config json.RawMessage, test NotificationTest) error {
var cfg struct {
Server string `json:"server"`
Port int `json:"port"`
Username string `json:"username"`
To string `json:"to"`
}
if err := json.Unmarshal(config, &cfg); err != nil {
return fmt.Errorf("invalid SMTP config: %w", err)
}
log.Printf("Sending SMTP test to %s via %s:%d", cfg.To, cfg.Server, cfg.Port)
return nil
}
func getPendingTests() ([]NotificationTest, error) {
query := `
SELECT t.id,
"t"."notificationProviderId",
t.sent,
t.success,
p.type,
p.config
FROM notification_tests t
JOIN notification_providers p
ON "t"."notificationProviderId" = p.id
WHERE t.success IS NOT TRUE`
rows, err := db.Query(query)
if err != nil {
return nil, err
}
defer rows.Close()
var tests []NotificationTest
for rows.Next() {
var t NotificationTest
var pt string
if err := rows.Scan(
&t.ID,
&t.NotificationProviderID,
&t.Sent,
&t.Success,
&pt,
&t.ProviderConfig,
); err != nil {
return nil, err
}
t.ProviderType = pt
tests = append(tests, t)
}
return tests, nil
}
func updateTestStatus(testID int, success bool) error {
_, err := db.Exec(
"UPDATE notification_tests SET sent = true, success = $1 WHERE id = $2",
success, testID,
)
return err
}

File diff suppressed because one or more lines are too long

View File

@ -222,6 +222,7 @@ exports.Prisma.NotificationProviderScalarFieldEnum = {
exports.Prisma.NotificationTestScalarFieldEnum = {
id: 'id',
notificationProviderId: 'notificationProviderId',
sent: 'sent',
success: 'success'
};

View File

@ -13147,18 +13147,21 @@ export namespace Prisma {
export type NotificationTestMinAggregateOutputType = {
id: number | null
notificationProviderId: number | null
sent: boolean | null
success: boolean | null
}
export type NotificationTestMaxAggregateOutputType = {
id: number | null
notificationProviderId: number | null
sent: boolean | null
success: boolean | null
}
export type NotificationTestCountAggregateOutputType = {
id: number
notificationProviderId: number
sent: number
success: number
_all: number
}
@ -13177,18 +13180,21 @@ export namespace Prisma {
export type NotificationTestMinAggregateInputType = {
id?: true
notificationProviderId?: true
sent?: true
success?: true
}
export type NotificationTestMaxAggregateInputType = {
id?: true
notificationProviderId?: true
sent?: true
success?: true
}
export type NotificationTestCountAggregateInputType = {
id?: true
notificationProviderId?: true
sent?: true
success?: true
_all?: true
}
@ -13282,7 +13288,8 @@ export namespace Prisma {
export type NotificationTestGroupByOutputType = {
id: number
notificationProviderId: number
success: boolean
sent: boolean
success: boolean | null
_count: NotificationTestCountAggregateOutputType | null
_avg: NotificationTestAvgAggregateOutputType | null
_sum: NotificationTestSumAggregateOutputType | null
@ -13307,6 +13314,7 @@ export namespace Prisma {
export type NotificationTestSelect<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = $Extensions.GetSelect<{
id?: boolean
notificationProviderId?: boolean
sent?: boolean
success?: boolean
notificationProvider?: boolean | NotificationProviderDefaultArgs<ExtArgs>
}, ExtArgs["result"]["notificationTest"]>
@ -13314,6 +13322,7 @@ export namespace Prisma {
export type NotificationTestSelectCreateManyAndReturn<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = $Extensions.GetSelect<{
id?: boolean
notificationProviderId?: boolean
sent?: boolean
success?: boolean
notificationProvider?: boolean | NotificationProviderDefaultArgs<ExtArgs>
}, ExtArgs["result"]["notificationTest"]>
@ -13321,6 +13330,7 @@ export namespace Prisma {
export type NotificationTestSelectUpdateManyAndReturn<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = $Extensions.GetSelect<{
id?: boolean
notificationProviderId?: boolean
sent?: boolean
success?: boolean
notificationProvider?: boolean | NotificationProviderDefaultArgs<ExtArgs>
}, ExtArgs["result"]["notificationTest"]>
@ -13328,10 +13338,11 @@ export namespace Prisma {
export type NotificationTestSelectScalar = {
id?: boolean
notificationProviderId?: boolean
sent?: boolean
success?: boolean
}
export type NotificationTestOmit<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = $Extensions.GetOmit<"id" | "notificationProviderId" | "success", ExtArgs["result"]["notificationTest"]>
export type NotificationTestOmit<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = $Extensions.GetOmit<"id" | "notificationProviderId" | "sent" | "success", ExtArgs["result"]["notificationTest"]>
export type NotificationTestInclude<ExtArgs extends $Extensions.InternalArgs = $Extensions.DefaultArgs> = {
notificationProvider?: boolean | NotificationProviderDefaultArgs<ExtArgs>
}
@ -13350,7 +13361,8 @@ export namespace Prisma {
scalars: $Extensions.GetPayloadResult<{
id: number
notificationProviderId: number
success: boolean
sent: boolean
success: boolean | null
}, ExtArgs["result"]["notificationTest"]>
composites: {}
}
@ -13777,6 +13789,7 @@ export namespace Prisma {
interface NotificationTestFieldRefs {
readonly id: FieldRef<"NotificationTest", 'Int'>
readonly notificationProviderId: FieldRef<"NotificationTest", 'Int'>
readonly sent: FieldRef<"NotificationTest", 'Boolean'>
readonly success: FieldRef<"NotificationTest", 'Boolean'>
}
@ -14338,6 +14351,7 @@ export namespace Prisma {
export const NotificationTestScalarFieldEnum: {
id: 'id',
notificationProviderId: 'notificationProviderId',
sent: 'sent',
success: 'success'
};
@ -15155,14 +15169,16 @@ export namespace Prisma {
NOT?: NotificationTestWhereInput | NotificationTestWhereInput[]
id?: IntFilter<"NotificationTest"> | number
notificationProviderId?: IntFilter<"NotificationTest"> | number
success?: BoolFilter<"NotificationTest"> | boolean
sent?: BoolFilter<"NotificationTest"> | boolean
success?: BoolNullableFilter<"NotificationTest"> | boolean | null
notificationProvider?: XOR<NotificationProviderScalarRelationFilter, NotificationProviderWhereInput>
}
export type NotificationTestOrderByWithRelationInput = {
id?: SortOrder
notificationProviderId?: SortOrder
success?: SortOrder
sent?: SortOrder
success?: SortOrderInput | SortOrder
notificationProvider?: NotificationProviderOrderByWithRelationInput
}
@ -15172,14 +15188,16 @@ export namespace Prisma {
OR?: NotificationTestWhereInput[]
NOT?: NotificationTestWhereInput | NotificationTestWhereInput[]
notificationProviderId?: IntFilter<"NotificationTest"> | number
success?: BoolFilter<"NotificationTest"> | boolean
sent?: BoolFilter<"NotificationTest"> | boolean
success?: BoolNullableFilter<"NotificationTest"> | boolean | null
notificationProvider?: XOR<NotificationProviderScalarRelationFilter, NotificationProviderWhereInput>
}, "id">
export type NotificationTestOrderByWithAggregationInput = {
id?: SortOrder
notificationProviderId?: SortOrder
success?: SortOrder
sent?: SortOrder
success?: SortOrderInput | SortOrder
_count?: NotificationTestCountOrderByAggregateInput
_avg?: NotificationTestAvgOrderByAggregateInput
_max?: NotificationTestMaxOrderByAggregateInput
@ -15193,7 +15211,8 @@ export namespace Prisma {
NOT?: NotificationTestScalarWhereWithAggregatesInput | NotificationTestScalarWhereWithAggregatesInput[]
id?: IntWithAggregatesFilter<"NotificationTest"> | number
notificationProviderId?: IntWithAggregatesFilter<"NotificationTest"> | number
success?: BoolWithAggregatesFilter<"NotificationTest"> | boolean
sent?: BoolWithAggregatesFilter<"NotificationTest"> | boolean
success?: BoolNullableWithAggregatesFilter<"NotificationTest"> | boolean | null
}
export type UserCreateInput = {
@ -15882,41 +15901,48 @@ export namespace Prisma {
}
export type NotificationTestCreateInput = {
success: boolean
sent?: boolean
success?: boolean | null
notificationProvider: NotificationProviderCreateNestedOneWithoutTestsInput
}
export type NotificationTestUncheckedCreateInput = {
id?: number
notificationProviderId: number
success: boolean
sent?: boolean
success?: boolean | null
}
export type NotificationTestUpdateInput = {
success?: BoolFieldUpdateOperationsInput | boolean
sent?: BoolFieldUpdateOperationsInput | boolean
success?: NullableBoolFieldUpdateOperationsInput | boolean | null
notificationProvider?: NotificationProviderUpdateOneRequiredWithoutTestsNestedInput
}
export type NotificationTestUncheckedUpdateInput = {
id?: IntFieldUpdateOperationsInput | number
notificationProviderId?: IntFieldUpdateOperationsInput | number
success?: BoolFieldUpdateOperationsInput | boolean
sent?: BoolFieldUpdateOperationsInput | boolean
success?: NullableBoolFieldUpdateOperationsInput | boolean | null
}
export type NotificationTestCreateManyInput = {
id?: number
notificationProviderId: number
success: boolean
sent?: boolean
success?: boolean | null
}
export type NotificationTestUpdateManyMutationInput = {
success?: BoolFieldUpdateOperationsInput | boolean
sent?: BoolFieldUpdateOperationsInput | boolean
success?: NullableBoolFieldUpdateOperationsInput | boolean | null
}
export type NotificationTestUncheckedUpdateManyInput = {
id?: IntFieldUpdateOperationsInput | number
notificationProviderId?: IntFieldUpdateOperationsInput | number
success?: BoolFieldUpdateOperationsInput | boolean
sent?: BoolFieldUpdateOperationsInput | boolean
success?: NullableBoolFieldUpdateOperationsInput | boolean | null
}
export type StringFilter<$PrismaModel = never> = {
@ -16660,6 +16686,11 @@ export namespace Prisma {
_max?: NestedJsonFilter<$PrismaModel>
}
export type BoolNullableFilter<$PrismaModel = never> = {
equals?: boolean | BooleanFieldRefInput<$PrismaModel> | null
not?: NestedBoolNullableFilter<$PrismaModel> | boolean | null
}
export type NotificationProviderScalarRelationFilter = {
is?: NotificationProviderWhereInput
isNot?: NotificationProviderWhereInput
@ -16668,6 +16699,7 @@ export namespace Prisma {
export type NotificationTestCountOrderByAggregateInput = {
id?: SortOrder
notificationProviderId?: SortOrder
sent?: SortOrder
success?: SortOrder
}
@ -16679,12 +16711,14 @@ export namespace Prisma {
export type NotificationTestMaxOrderByAggregateInput = {
id?: SortOrder
notificationProviderId?: SortOrder
sent?: SortOrder
success?: SortOrder
}
export type NotificationTestMinOrderByAggregateInput = {
id?: SortOrder
notificationProviderId?: SortOrder
sent?: SortOrder
success?: SortOrder
}
@ -16693,6 +16727,14 @@ export namespace Prisma {
notificationProviderId?: SortOrder
}
export type BoolNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: boolean | BooleanFieldRefInput<$PrismaModel> | null
not?: NestedBoolNullableWithAggregatesFilter<$PrismaModel> | boolean | null
_count?: NestedIntNullableFilter<$PrismaModel>
_min?: NestedBoolNullableFilter<$PrismaModel>
_max?: NestedBoolNullableFilter<$PrismaModel>
}
export type StringFieldUpdateOperationsInput = {
set?: string
}
@ -17061,6 +17103,10 @@ export namespace Prisma {
connect?: NotificationProviderWhereUniqueInput
}
export type NullableBoolFieldUpdateOperationsInput = {
set?: boolean | null
}
export type NotificationProviderUpdateOneRequiredWithoutTestsNestedInput = {
create?: XOR<NotificationProviderCreateWithoutTestsInput, NotificationProviderUncheckedCreateWithoutTestsInput>
connectOrCreate?: NotificationProviderCreateOrConnectWithoutTestsInput
@ -17299,6 +17345,19 @@ export namespace Prisma {
not?: InputJsonValue | JsonFieldRefInput<$PrismaModel> | JsonNullValueFilter
}
export type NestedBoolNullableFilter<$PrismaModel = never> = {
equals?: boolean | BooleanFieldRefInput<$PrismaModel> | null
not?: NestedBoolNullableFilter<$PrismaModel> | boolean | null
}
export type NestedBoolNullableWithAggregatesFilter<$PrismaModel = never> = {
equals?: boolean | BooleanFieldRefInput<$PrismaModel> | null
not?: NestedBoolNullableWithAggregatesFilter<$PrismaModel> | boolean | null
_count?: NestedIntNullableFilter<$PrismaModel>
_min?: NestedBoolNullableFilter<$PrismaModel>
_max?: NestedBoolNullableFilter<$PrismaModel>
}
export type NetworkCreateWithoutSiteInput = {
name: string
ipv4Subnet?: string | null
@ -17929,12 +17988,14 @@ export namespace Prisma {
}
export type NotificationTestCreateWithoutNotificationProviderInput = {
success: boolean
sent?: boolean
success?: boolean | null
}
export type NotificationTestUncheckedCreateWithoutNotificationProviderInput = {
id?: number
success: boolean
sent?: boolean
success?: boolean | null
}
export type NotificationTestCreateOrConnectWithoutNotificationProviderInput = {
@ -17969,7 +18030,8 @@ export namespace Prisma {
NOT?: NotificationTestScalarWhereInput | NotificationTestScalarWhereInput[]
id?: IntFilter<"NotificationTest"> | number
notificationProviderId?: IntFilter<"NotificationTest"> | number
success?: BoolFilter<"NotificationTest"> | boolean
sent?: BoolFilter<"NotificationTest"> | boolean
success?: BoolNullableFilter<"NotificationTest"> | boolean | null
}
export type NotificationProviderCreateWithoutTestsInput = {
@ -18235,21 +18297,25 @@ export namespace Prisma {
export type NotificationTestCreateManyNotificationProviderInput = {
id?: number
success: boolean
sent?: boolean
success?: boolean | null
}
export type NotificationTestUpdateWithoutNotificationProviderInput = {
success?: BoolFieldUpdateOperationsInput | boolean
sent?: BoolFieldUpdateOperationsInput | boolean
success?: NullableBoolFieldUpdateOperationsInput | boolean | null
}
export type NotificationTestUncheckedUpdateWithoutNotificationProviderInput = {
id?: IntFieldUpdateOperationsInput | number
success?: BoolFieldUpdateOperationsInput | boolean
sent?: BoolFieldUpdateOperationsInput | boolean
success?: NullableBoolFieldUpdateOperationsInput | boolean | null
}
export type NotificationTestUncheckedUpdateManyWithoutNotificationProviderInput = {
id?: IntFieldUpdateOperationsInput | number
success?: BoolFieldUpdateOperationsInput | boolean
sent?: BoolFieldUpdateOperationsInput | boolean
success?: NullableBoolFieldUpdateOperationsInput | boolean | null
}

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
{
"name": "prisma-client-cb978539556cba5867755c200de1b26bf1cb4d18f6f210053bc454d49ff1f37d",
"name": "prisma-client-b823c94fe5f895d95db8009db18bc50e6809c8320115146287940edb857ae7b6",
"main": "index.js",
"types": "index.d.ts",
"browser": "index-browser.js",

View File

@ -152,7 +152,8 @@ model NotificationTest {
id Int @id @default(autoincrement())
notificationProvider NotificationProvider @relation(fields: [notificationProviderId], references: [id], onDelete: Cascade)
notificationProviderId Int
success Boolean
sent Boolean @default(false)
success Boolean?
@@map("notification_tests")
}

View File

@ -222,6 +222,7 @@ exports.Prisma.NotificationProviderScalarFieldEnum = {
exports.Prisma.NotificationTestScalarFieldEnum = {
id: 'id',
notificationProviderId: 'notificationProviderId',
sent: 'sent',
success: 'success'
};

View File

@ -0,0 +1,3 @@
-- AlterTable
ALTER TABLE "notification_tests" ADD COLUMN "sent" BOOLEAN NOT NULL DEFAULT false,
ALTER COLUMN "success" DROP NOT NULL;

View File

@ -154,7 +154,8 @@ model NotificationTest {
id Int @id @default(autoincrement())
notificationProvider NotificationProvider @relation(fields: [notificationProviderId], references: [id], onDelete: Cascade)
notificationProviderId Int
success Boolean
sent Boolean @default(false)
success Boolean?
@@map("notification_tests")
}