1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
package monitor
import (
"context"
"fmt"
"net"
"time"
"github.com/Fuwn/kaze/internal/config"
)
// TCPMonitor monitors TCP endpoints
type TCPMonitor struct {
id string
name string
group string
target string
interval time.Duration
timeout time.Duration
retries int
roundResponseTime bool
roundUptime bool
}
// NewTCPMonitor creates a new TCP monitor
func NewTCPMonitor(cfg config.MonitorConfig) (*TCPMonitor, error) {
// Validate target format (should be host:port)
_, _, err := net.SplitHostPort(cfg.Target)
if err != nil {
return nil, fmt.Errorf("invalid TCP target %q: must be host:port format: %w", cfg.Target, err)
}
return &TCPMonitor{
id: cfg.ID(),
name: cfg.Name,
group: cfg.Group,
target: cfg.Target,
interval: cfg.Interval.Duration,
timeout: cfg.Timeout.Duration,
retries: cfg.Retries,
roundResponseTime: cfg.RoundResponseTime,
roundUptime: cfg.RoundUptime,
}, nil
}
// ID returns the unique identifier for this monitor
func (m *TCPMonitor) ID() string {
return m.id
}
// Name returns the monitor's name
func (m *TCPMonitor) Name() string {
return m.name
}
// Group returns the group this monitor belongs to
func (m *TCPMonitor) Group() string {
return m.group
}
// Type returns the monitor type
func (m *TCPMonitor) Type() string {
return "tcp"
}
// Target returns the monitor target
func (m *TCPMonitor) Target() string {
return m.target
}
// Interval returns the check interval
func (m *TCPMonitor) Interval() time.Duration {
return m.interval
}
// Retries returns the number of retry attempts
func (m *TCPMonitor) Retries() int {
return m.retries
}
// HideSSLDays returns whether to hide SSL days from display
func (m *TCPMonitor) HideSSLDays() bool {
return false // TCP doesn't use SSL
}
// RoundResponseTime returns whether to round response time
func (m *TCPMonitor) RoundResponseTime() bool {
return m.roundResponseTime
}
// RoundUptime returns whether to round uptime percentage
func (m *TCPMonitor) RoundUptime() bool {
return m.roundUptime
}
// Check performs the TCP connection check
func (m *TCPMonitor) Check(ctx context.Context) *Result {
result := &Result{
MonitorName: m.id,
Timestamp: time.Now(),
}
// Create a dialer with timeout
dialer := &net.Dialer{
Timeout: m.timeout,
}
// Attempt to connect
start := time.Now()
conn, err := dialer.DialContext(ctx, "tcp", m.target)
result.ResponseTime = time.Since(start)
if err != nil {
result.Status = StatusDown
result.Error = fmt.Errorf("connection failed: %w", err)
return result
}
defer conn.Close()
result.Status = StatusUp
return result
}
|