spb/internetpressure
Public
TypeScript 36.3%
Python 31.8%
Go 18%
JavaScript 9.8%
Shell 1.9%
SQL 1.4%
CSS 0.5%
1// Package protocol holds the wire types of the probe ↔ ingestion protocol (docs/PROBE-PROTOCOL.md, v1).2//3// Field names and JSON tags mirror the document exactly; optional fields use pointers with omitempty so that4// "fields not relevant to kind" are omitted (the protocol allows omitted or null).5package protocol67import "time"89// TimeFormat is the UTC RFC 3339 format with milliseconds used everywhere on the wire.10const TimeFormat = "2006-01-02T15:04:05.000Z07:00"1112// FormatTime renders t as UTC RFC 3339 with milliseconds ("2026-09-12T05:10:04.123Z").13func FormatTime(t time.Time) string { return t.UTC().Format(TimeFormat) }1415// ParseTime accepts RFC 3339 with or without fractional seconds.16func ParseTime(s string) (time.Time, error) {17 if t, err := time.Parse(time.RFC3339Nano, s); err == nil {18 return t, nil19 }20 return time.Parse(time.RFC3339, s)21}2223// ---- GET /config -------------------------------------------------------------------------------------------2425// RemoteConfig is the probe assignment returned by GET /ingest/v1/config.26type RemoteConfig struct {27 ServerTime string `json:"server_time"`28 ConfigVersion string `json:"config_version"`29 Probe ProbeInfo `json:"probe"`30 Schedule Schedule `json:"schedule"`31 Resolvers []Resolver `json:"resolvers"`32 Targets []Target `json:"targets"`33}3435// ProbeInfo describes the probe as known by the server.36type ProbeInfo struct {37 ProbeID string `json:"probe_id"`38 Name string `json:"name"`39 Region string `json:"region"`40 Country string `json:"country"`41 City string `json:"city"`42 Provider string `json:"provider"`43 ASN int `json:"asn"`44 Lat *float64 `json:"lat"`45 Lon *float64 `json:"lon"`46 Enabled bool `json:"enabled"`47}4849// Schedule carries the interval parameters. Tiers keys are strings ("1", "2", "3") as in the JSON document.50type Schedule struct {51 Tiers map[string]int `json:"tiers"`52 DNSEvery int `json:"dns_every"`53 PingEvery int `json:"ping_every"`54 TracerouteEvery int `json:"traceroute_every"`55 BatchFlushSeconds int `json:"batch_flush_seconds"`56 MaxBatch int `json:"max_batch"`57 ConfigRefreshSeconds int `json:"config_refresh_seconds"`58 Boost *Boost `json:"boost,omitempty"`59}6061// Boost multiplies the intervals of the listed targets by Factor until Until.62type Boost struct {63 Targets []string `json:"targets"`64 Factor float64 `json:"factor"`65 Until string `json:"until"`66}6768// Active reports whether the boost applies to targetID at time now.69func (b *Boost) Active(targetID string, now time.Time) bool {70 if b == nil || b.Factor <= 0 {71 return false72 }73 until, err := ParseTime(b.Until)74 if err != nil || !now.Before(until) {75 return false76 }77 for _, t := range b.Targets {78 if t == targetID {79 return true80 }81 }82 return false83}8485// Resolver is a DNS resolver to query. ID "system" (empty address) means the OS resolver.86type Resolver struct {87 ID string `json:"id"`88 Address string `json:"address"`89}9091// Target is one monitored endpoint.92type Target struct {93 TargetID string `json:"target_id"`94 Name string `json:"name"`95 Hostname string `json:"hostname"`96 URL string `json:"url"`97 IP *string `json:"ip"`98 Port int `json:"port"`99 Category string `json:"category"`100 Provider string `json:"provider"`101 ServiceID string `json:"service_id"`102 Country *string `json:"country"`103 Region string `json:"region"`104 Importance int `json:"importance"`105 Tier int `json:"tier"`106 Checks []string `json:"checks"`107 Traceroute bool `json:"traceroute"`108}109110// HasCheck reports whether kind is listed in Checks.111func (t Target) HasCheck(kind string) bool {112 for _, c := range t.Checks {113 if c == kind {114 return true115 }116 }117 return false118}119120// FixedIP returns the pinned IP ("" when none).121func (t Target) FixedIP() string {122 if t.IP == nil {123 return ""124 }125 return *t.IP126}127128// ---- POST /batch -------------------------------------------------------------------------------------------129130// Batch is the (pre-gzip) body of POST /ingest/v1/batch.131type Batch struct {132 ProbeID string `json:"probe_id"`133 AgentVersion string `json:"agent_version"`134 SentAt string `json:"sent_at"`135 Measurements []Measurement `json:"measurements"`136 Traceroutes []Traceroute `json:"traceroutes,omitempty"`137 Health *Health `json:"health,omitempty"`138}139140// Measurement is one http / dns / ping / tcp observation.141type Measurement struct {142 TS string `json:"ts"`143 TargetID string `json:"target_id"`144 Kind string `json:"kind"` // "http" | "dns" | "ping" | "tcp"145 OK bool `json:"ok"`146 Error string `json:"error"` // "" or one of the protocol error codes147148 // http149 DNSMs *float64 `json:"dns_ms,omitempty"`150 TCPMs *float64 `json:"tcp_ms,omitempty"`151 TLSMs *float64 `json:"tls_ms,omitempty"`152 TTFBMs *float64 `json:"ttfb_ms,omitempty"`153 TotalMs *float64 `json:"total_ms,omitempty"`154 HTTPStatus *int `json:"http_status,omitempty"`155 HTTPProto string `json:"http_proto,omitempty"`156 TLSVersion string `json:"tls_version,omitempty"`157 ResolvedIP string `json:"resolved_ip,omitempty"`158159 // dns160 Resolver string `json:"resolver,omitempty"`161 DNSRcode string `json:"dns_rcode,omitempty"`162 DNSAnswers []string `json:"dns_answers,omitempty"`163164 // ping / tcp165 Sent *int `json:"sent,omitempty"`166 Received *int `json:"received,omitempty"`167 PacketLoss *float64 `json:"packet_loss,omitempty"`168 RTTMinMs *float64 `json:"rtt_min_ms,omitempty"`169 RTTAvgMs *float64 `json:"rtt_avg_ms,omitempty"`170 RTTMaxMs *float64 `json:"rtt_max_ms,omitempty"`171 JitterMs *float64 `json:"jitter_ms,omitempty"`172}173174// Traceroute is one path measurement.175type Traceroute struct {176 TS string `json:"ts"`177 TargetID string `json:"target_id"`178 DestIP string `json:"dest_ip"`179 Reached bool `json:"reached"`180 HopCount int `json:"hop_count"`181 TotalMs *float64 `json:"total_ms"`182 RouteHash string `json:"route_hash"`183 Hops []Hop `json:"hops"`184}185186// Hop is one traceroute hop; IP is "*" and RTTMs nil when unanswered.187type Hop struct {188 N int `json:"n"`189 IP string `json:"ip"`190 RTTMs *float64 `json:"rtt_ms"`191}192193// Health is the agent self-report (at most once per minute).194type Health struct {195 TS string `json:"ts"`196 AgentVersion string `json:"agent_version"`197 UptimeS int64 `json:"uptime_s"`198 Buffered int `json:"buffered"`199 SpoolBytes int64 `json:"spool_bytes"`200 MeasurementsTotal uint64 `json:"measurements_total"`201 ErrorsTotal uint64 `json:"errors_total"`202 ClockOffsetMs int64 `json:"clock_offset_ms"`203 RSSMb float64 `json:"rss_mb"`204 Goroutines int `json:"goroutines"`205 Capabilities []string `json:"capabilities"`206 OS string `json:"os"`207 Arch string `json:"arch"`208 Identity *Identity `json:"identity,omitempty"`209}210211// Identity is the public, city-level network identity of the probe (never more precise than city).212type Identity struct {213 PublicIP string `json:"public_ip"`214 ASN int `json:"asn"`215 Org string `json:"org"`216 Country string `json:"country"`217 City string `json:"city"`218 Lat *float64 `json:"lat"`219 Lon *float64 `json:"lon"`220 Source string `json:"source"`221}222223// BatchResponse is the body returned by POST /batch.224type BatchResponse struct {225 Accepted int `json:"accepted"`226 Rejected int `json:"rejected"`227 ConfigVersion string `json:"config_version"`228 ServerTime string `json:"server_time"`229 Boost *Boost `json:"boost,omitempty"`230}231232// ---- GET /agent/latest -------------------------------------------------------------------------------------233234// AgentLatest describes the newest agent release.235type AgentLatest struct {236 Version string `json:"version"`237 Assets map[string]Asset `json:"assets"`238}239240// Asset is one downloadable binary.241type Asset struct {242 URL string `json:"url"`243 SHA256 string `json:"sha256"`244}245246// Error codes (docs/PROBE-PROTOCOL.md § Measurement).247const (248 ErrDNSFail = "dns_fail"249 ErrDNSTimeout = "dns_timeout"250 ErrDNSServfail = "dns_servfail"251 ErrDNSNxdomain = "dns_nxdomain"252 ErrTCPTimeout = "tcp_timeout"253 ErrTCPRefused = "tcp_refused"254 ErrTCPReset = "tcp_reset"255 ErrTLSFail = "tls_fail"256 ErrTLSCert = "tls_cert"257 ErrHTTPTimeout = "http_timeout"258 ErrHTTP5xx = "http_5xx"259 ErrHTTP4xx = "http_4xx"260 ErrReset = "reset"261 ErrUnreachable = "unreachable"262 ErrICMPUnavailable = "icmp_unavailable"263 ErrOther = "other"264)265266// F returns a pointer to v (helper for optional float fields).267func F(v float64) *float64 { return &v }268269// I returns a pointer to v (helper for optional int fields).270func I(v int) *int { return &v }271272// Ms converts a duration to milliseconds with 0.1 ms resolution.273func Ms(d time.Duration) float64 { return float64(d.Microseconds()) / 1000 }274