aboutsummaryrefslogtreecommitdiff
path: root/internal/monitor/tcp.go
blob: 50a8a4bd2f1353151f574bdff7245e8d78409ded (plain) (blame)
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
}