refact: remove unnecessary types field

Kim committed Apr 9, 2026 at 15:25 UTC 579dc856560152cc724ea36dc97008d91c294942
13 files changed +91 -115
portal/acme/acme.go
+6 -6
@@ -381,7 +381,7 @@ func (m *Manager) syncENSGasless(ctx context.Context) error {
381 return errors.New("ACME_DNS_PROVIDER is required")
382 }
383
384 - status, err := m.dns.EnsureDNSSEC(ctx, m.cfg.BaseDomain)
384 + state, dsRecord, message, err := m.dns.EnsureDNSSEC(ctx, m.cfg.BaseDomain)
385 if err != nil {
386 return fmt.Errorf("ensure dnssec: %w", err)
387 }
@@ -389,12 +389,12 @@ func (m *Manager) syncENSGasless(ctx context.Context) error {
389 event := log.Info().
390 Str("provider", m.dns.Name()).
391 Str("base_domain", m.cfg.BaseDomain).
392 - Str("state", strings.TrimSpace(status.State))
393 - if strings.TrimSpace(status.DSRecord) != "" {
394 - event = event.Str("ds_record", strings.TrimSpace(status.DSRecord))
392 + Str("state", strings.TrimSpace(state))
393 + if strings.TrimSpace(dsRecord) != "" {
394 + event = event.Str("ds_record", strings.TrimSpace(dsRecord))
395 }
396 - if strings.TrimSpace(status.Message) != "" {
397 - event = event.Str("message", strings.TrimSpace(status.Message))
396 + if strings.TrimSpace(message) != "" {
397 + event = event.Str("message", strings.TrimSpace(message))
398 }
399 event.Msg("dnssec configured")
400 })
portal/acme/cloudflare/provider.go
+13 -16
@@ -11,7 +11,6 @@ import (
11 "github.com/go-acme/lego/v4/challenge"
12 "github.com/go-acme/lego/v4/providers/dns/cloudflare"
13
14 - "github.com/gosuda/portal-tunnel/v2/types"
14 "github.com/gosuda/portal-tunnel/v2/utils"
15 )
16
@@ -244,48 +243,46 @@ func (p *Provider) DeleteTXTRecords(ctx context.Context, name, matchPrefix strin
243 return nil
244 }
245
247 -func (p *Provider) EnsureDNSSEC(ctx context.Context, baseDomain string) (types.DNSSECStatus, error) {
246 +func (p *Provider) EnsureDNSSEC(ctx context.Context, baseDomain string) (state, dsRecord, message string, err error) {
247 if p == nil {
249 - return types.DNSSECStatus{}, errors.New("cloudflare provider is nil")
248 + return "", "", "", errors.New("cloudflare provider is nil")
249 }
250 baseDomain = utils.NormalizeBaseDomain(baseDomain)
251 if baseDomain == "" {
253 - return types.DNSSECStatus{}, errors.New("base domain is required")
252 + return "", "", "", errors.New("base domain is required")
253 }
254 if p.token == "" {
256 - return types.DNSSECStatus{}, errors.New("cloudflare token is required")
255 + return "", "", "", errors.New("cloudflare token is required")
256 }
257
258 zoneID, err := findZoneID(ctx, p.token, baseDomain)
259 if err != nil {
261 - return types.DNSSECStatus{}, fmt.Errorf("find cloudflare zone: %w", err)
260 + return "", "", "", fmt.Errorf("find cloudflare zone: %w", err)
261 }
262
263 details, err := getDNSSEC(ctx, p.token, zoneID)
264 if err != nil {
266 - return types.DNSSECStatus{}, fmt.Errorf("get cloudflare dnssec status: %w", err)
265 + return "", "", "", fmt.Errorf("get cloudflare dnssec status: %w", err)
266 }
267
268 switch strings.ToLower(strings.TrimSpace(details.Status)) {
269 case "active", "pending":
270 default:
271 if err := enableDNSSEC(ctx, p.token, zoneID); err != nil {
273 - return types.DNSSECStatus{}, fmt.Errorf("enable cloudflare dnssec: %w", err)
272 + return "", "", "", fmt.Errorf("enable cloudflare dnssec: %w", err)
273 }
274 details, err = getDNSSEC(ctx, p.token, zoneID)
275 if err != nil {
277 - return types.DNSSECStatus{}, fmt.Errorf("refresh cloudflare dnssec status: %w", err)
276 + return "", "", "", fmt.Errorf("refresh cloudflare dnssec status: %w", err)
277 }
278 }
279
281 - status := types.DNSSECStatus{
282 - State: strings.TrimSpace(details.Status),
283 - DSRecord: strings.TrimSpace(details.DS),
280 + state = strings.TrimSpace(details.Status)
281 + dsRecord = strings.TrimSpace(details.DS)
282 + if dsRecord != "" {
283 + message = "publish the DS record at the registrar if Cloudflare Registrar does not manage the zone"
284 }
285 - if status.DSRecord != "" {
286 - status.Message = "publish the DS record at the registrar if Cloudflare Registrar does not manage the zone"
287 - }
288 - return status, nil
285 + return state, dsRecord, message, nil
286 }
287
288 func findZoneID(ctx context.Context, token, domain string) (string, error) {
portal/acme/gcloud/provider.go
+18 -20
@@ -17,7 +17,6 @@ import (
17 "google.golang.org/api/dns/v1"
18 "google.golang.org/api/option"
19
20 - "github.com/gosuda/portal-tunnel/v2/types"
20 "github.com/gosuda/portal-tunnel/v2/utils"
21 )
22
@@ -287,38 +286,38 @@ func (p *Provider) DeleteTXTRecords(ctx context.Context, name, matchPrefix strin
286 return nil
287 }
288
290 -func (p *Provider) EnsureDNSSEC(ctx context.Context, baseDomain string) (types.DNSSECStatus, error) {
289 +func (p *Provider) EnsureDNSSEC(ctx context.Context, baseDomain string) (state, dsRecord, message string, err error) {
290 if p == nil {
292 - return types.DNSSECStatus{}, errors.New("gcloud provider is nil")
291 + return "", "", "", errors.New("gcloud provider is nil")
292 }
293 baseDomain = utils.NormalizeBaseDomain(baseDomain)
294 if baseDomain == "" {
296 - return types.DNSSECStatus{}, errors.New("base domain is required")
295 + return "", "", "", errors.New("base domain is required")
296 }
297
298 service, runtimeCfg, zone, err := newService(ctx, p.cfg, baseDomain)
299 if err != nil {
301 - return types.DNSSECStatus{}, err
300 + return "", "", "", err
301 }
302 managedZone := zone.Name
303
305 - state := strings.ToLower(strings.TrimSpace(dnssecState(zone)))
306 - if state != "on" && state != "transfer" {
304 + currentState := strings.ToLower(strings.TrimSpace(dnssecState(zone)))
305 + if currentState != "on" && currentState != "transfer" {
306 if err := enableDNSSEC(ctx, service, runtimeCfg.ProjectID, managedZone); err != nil {
308 - return types.DNSSECStatus{}, fmt.Errorf("enable gcloud dnssec: %w", err)
307 + return "", "", "", fmt.Errorf("enable gcloud dnssec: %w", err)
308 }
309 zone, err = service.ManagedZones.Get(runtimeCfg.ProjectID, managedZone).Context(ctx).Do()
310 if err != nil {
312 - return types.DNSSECStatus{}, fmt.Errorf("refresh gcloud managed zone %s: %w", managedZone, err)
311 + return "", "", "", fmt.Errorf("refresh gcloud managed zone %s: %w", managedZone, err)
312 }
313 }
314
315 keys, err := listDNSKeys(ctx, service, runtimeCfg.ProjectID, managedZone)
316 if err != nil {
318 - return types.DNSSECStatus{}, fmt.Errorf("list gcloud dnssec keys: %w", err)
317 + return "", "", "", fmt.Errorf("list gcloud dnssec keys: %w", err)
318 }
319
321 - return dnssecStatusFromZone(zone, keys), nil
320 + return dnssecStatusFromZone(zone, keys)
321 }
322
323 func newRuntimeConfig(ctx context.Context, cfg Config) (runtimeConfig, error) {
@@ -527,16 +526,15 @@ func listDNSKeys(ctx context.Context, service *dns.Service, projectID, managedZo
526 return keys, nil
527 }
528
530 -func dnssecStatusFromZone(zone *dns.ManagedZone, keys []*dns.DnsKey) types.DNSSECStatus {
531 - status := types.DNSSECStatus{
532 - State: strings.TrimSpace(dnssecState(zone)),
529 +func dnssecStatusFromZone(zone *dns.ManagedZone, keys []*dns.DnsKey) (state, dsRecord, message string, err error) {
530 + state = strings.TrimSpace(dnssecState(zone))
531 + dsRecord = activeDSRecord(keys)
532 + if dsRecord != "" {
533 + message = "publish the DS record at the registrar after Cloud DNS zone signing is enabled"
534 + } else if strings.EqualFold(state, "on") || strings.EqualFold(state, "transfer") {
535 + message = "wait for the active Cloud DNS DS record before updating the registrar"
536 }
534 - if status.DSRecord = activeDSRecord(keys); status.DSRecord != "" {
535 - status.Message = "publish the DS record at the registrar after Cloud DNS zone signing is enabled"
536 - } else if strings.EqualFold(status.State, "on") || strings.EqualFold(status.State, "transfer") {
537 - status.Message = "wait for the active Cloud DNS DS record before updating the registrar"
538 - }
539 - return status
537 + return state, dsRecord, message, nil
538 }
539
540 func activeDSRecord(keys []*dns.DnsKey) string {
portal/acme/gcloud/provider_test.go
+8 -5
@@ -30,7 +30,7 @@ func TestDNSKeyDSRecordPrefersSHA256(t *testing.T) {
30 func TestDNSSECStatusFromZoneUsesActiveKeySigningKey(t *testing.T) {
31 t.Parallel()
32
33 - status := dnssecStatusFromZone(&gdns.ManagedZone{
33 + state, dsRecord, _, err := dnssecStatusFromZone(&gdns.ManagedZone{
34 DnssecConfig: &gdns.ManagedZoneDnsSecConfig{State: "on"},
35 }, []*gdns.DnsKey{
36 {
@@ -52,11 +52,14 @@ func TestDNSSECStatusFromZoneUsesActiveKeySigningKey(t *testing.T) {
52 },
53 },
54 })
55 + if err != nil {
56 + t.Fatalf("dnssecStatusFromZone() error = %v, want nil", err)
57 + }
58
56 - if status.State != "on" {
57 - t.Fatalf("dnssecStatusFromZone().State = %q, want %q", status.State, "on")
59 + if state != "on" {
60 + t.Fatalf("dnssecStatusFromZone().state = %q, want %q", state, "on")
61 }
59 - if status.DSRecord != "200 8 2 USEME" {
60 - t.Fatalf("dnssecStatusFromZone().DSRecord = %q, want %q", status.DSRecord, "200 8 2 USEME")
62 + if dsRecord != "200 8 2 USEME" {
63 + t.Fatalf("dnssecStatusFromZone().dsRecord = %q, want %q", dsRecord, "200 8 2 USEME")
64 }
65 }
portal/acme/provider.go
+1 -2
@@ -10,7 +10,6 @@ import (
10 "github.com/gosuda/portal-tunnel/v2/portal/acme/cloudflare"
11 "github.com/gosuda/portal-tunnel/v2/portal/acme/gcloud"
12 "github.com/gosuda/portal-tunnel/v2/portal/acme/route53"
13 - "github.com/gosuda/portal-tunnel/v2/types"
13 )
14
15 const (
@@ -27,7 +26,7 @@ type DNSProvider interface {
26 DeleteARecord(ctx context.Context, name string) error
27 EnsureTXTRecord(ctx context.Context, name, value string) error
28 DeleteTXTRecords(ctx context.Context, name, matchPrefix string) error
30 - EnsureDNSSEC(ctx context.Context, baseDomain string) (types.DNSSECStatus, error)
29 + EnsureDNSSEC(ctx context.Context, baseDomain string) (state, dsRecord, message string, err error)
30 }
31
32 func NewDNSProvider(providerType string, cfg Config) (DNSProvider, error) {
portal/acme/route53/provider.go
+25 -26
@@ -16,7 +16,6 @@ import (
16 "github.com/go-acme/lego/v4/challenge"
17 "github.com/go-acme/lego/v4/providers/dns/route53"
18
19 - "github.com/gosuda/portal-tunnel/v2/types"
19 "github.com/gosuda/portal-tunnel/v2/utils"
20 )
21
@@ -221,58 +220,59 @@ func (p *Provider) DeleteTXTRecords(ctx context.Context, name, matchPrefix strin
220 return nil
221 }
222
224 -func (p *Provider) EnsureDNSSEC(ctx context.Context, baseDomain string) (types.DNSSECStatus, error) {
223 +func (p *Provider) EnsureDNSSEC(ctx context.Context, baseDomain string) (state, dsRecord, message string, err error) {
224 if p == nil {
226 - return types.DNSSECStatus{}, errors.New("route53 provider is nil")
225 + return "", "", "", errors.New("route53 provider is nil")
226 }
227 baseDomain = utils.NormalizeBaseDomain(baseDomain)
228 if baseDomain == "" {
230 - return types.DNSSECStatus{}, errors.New("base domain is required")
229 + return "", "", "", errors.New("base domain is required")
230 }
231
232 client, err := newClient(ctx, p.cfg)
233 if err != nil {
235 - return types.DNSSECStatus{}, err
234 + return "", "", "", err
235 }
236
237 hostedZoneID, err := findHostedZoneID(ctx, client, baseDomain, p.cfg.HostedZoneID)
238 if err != nil {
240 - return types.DNSSECStatus{}, err
239 + return "", "", "", err
240 }
241
242 out, err := getDNSSECStatus(ctx, client, hostedZoneID)
243 if err != nil {
245 - return types.DNSSECStatus{}, fmt.Errorf("get route53 dnssec status: %w", err)
244 + return "", "", "", fmt.Errorf("get route53 dnssec status: %w", err)
245 }
247 - status := dnssecStatusFromOutput(out)
248 - if strings.EqualFold(status.State, "SIGNING") {
249 - return status, nil
246 + state, dsRecord, message = dnssecStatusFromOutput(out)
247 + if strings.EqualFold(state, "SIGNING") {
248 + return state, dsRecord, message, nil
249 }
250
251 if _, ok := activeKeySigningKey(out.KeySigningKeys); !ok {
252 if err := ensureActiveKeySigningKey(ctx, client, hostedZoneID, p.cfg, out.KeySigningKeys); err != nil {
254 - return types.DNSSECStatus{}, err
253 + return "", "", "", err
254 }
255 out, err = getDNSSECStatus(ctx, client, hostedZoneID)
256 if err != nil {
258 - return types.DNSSECStatus{}, fmt.Errorf("refresh route53 dnssec status: %w", err)
257 + return "", "", "", fmt.Errorf("refresh route53 dnssec status: %w", err)
258 }
259 if _, ok := activeKeySigningKey(out.KeySigningKeys); !ok {
261 - return types.DNSSECStatus{}, errors.New("route53 dnssec requires an ACTIVE key-signing key")
260 + return "", "", "", errors.New("route53 dnssec requires an ACTIVE key-signing key")
261 }
262 }
263
264 if _, err := client.EnableHostedZoneDNSSEC(ctx, &awsroute53.EnableHostedZoneDNSSECInput{
265 HostedZoneId: aws.String(hostedZoneID),
266 }); err != nil {
268 - return types.DNSSECStatus{}, fmt.Errorf("enable route53 dnssec: %w", err)
267 + return "", "", "", fmt.Errorf("enable route53 dnssec: %w", err)
268 }
269
270 out, err = getDNSSECStatus(ctx, client, hostedZoneID)
271 if err != nil {
273 - return types.DNSSECStatus{}, fmt.Errorf("refresh route53 dnssec status: %w", err)
272 + return "", "", "", fmt.Errorf("refresh route53 dnssec status: %w", err)
273 }
275 - return dnssecStatusFromOutput(out), nil
274 + state, dsRecord, message = dnssecStatusFromOutput(out)
275 + return state, dsRecord, message, nil
276 }
277
278 func newClient(ctx context.Context, cfg Config) (*awsroute53.Client, error) {
@@ -587,30 +587,29 @@ func ensureActiveKeySigningKey(ctx context.Context, client *awsroute53.Client, h
587 return nil
588 }
589
590 -func dnssecStatusFromOutput(out *awsroute53.GetDNSSECOutput) types.DNSSECStatus {
590 +func dnssecStatusFromOutput(out *awsroute53.GetDNSSECOutput) (state, dsRecord, message string) {
591 if out == nil {
592 - return types.DNSSECStatus{}
592 + return "", "", ""
593 }
594
595 - status := types.DNSSECStatus{}
595 if out.Status != nil {
597 - status.State = strings.TrimSpace(aws.ToString(out.Status.ServeSignature))
598 - status.Message = strings.TrimSpace(aws.ToString(out.Status.StatusMessage))
596 + state = strings.TrimSpace(aws.ToString(out.Status.ServeSignature))
597 + message = strings.TrimSpace(aws.ToString(out.Status.StatusMessage))
598 }
599 if active, ok := activeKeySigningKey(out.KeySigningKeys); ok {
601 - status.DSRecord = strings.TrimSpace(aws.ToString(active.DSRecord))
600 + dsRecord = strings.TrimSpace(aws.ToString(active.DSRecord))
601 } else {
602 for _, key := range out.KeySigningKeys {
603 if strings.TrimSpace(aws.ToString(key.DSRecord)) != "" {
605 - status.DSRecord = strings.TrimSpace(aws.ToString(key.DSRecord))
604 + dsRecord = strings.TrimSpace(aws.ToString(key.DSRecord))
605 break
606 }
607 }
608 }
610 - if status.Message == "" && status.DSRecord != "" {
611 - status.Message = "publish the DS record at the registrar after Route53 zone signing is enabled"
609 + if message == "" && dsRecord != "" {
610 + message = "publish the DS record at the registrar after Route53 zone signing is enabled"
611 }
613 - return status
612 + return state, dsRecord, message
613 }
614
615 func activeKeySigningKey(keys []route53types.KeySigningKey) (route53types.KeySigningKey, bool) {
portal/api_server.go
+1 -1
@@ -198,7 +198,7 @@ func (s *Server) handleRelayDiscovery(w http.ResponseWriter, r *http.Request) {
198 Sequence: uint64(now.UnixMilli()),
199 Version: 1,
200 IssuedAt: now,
201 - ExpiresAt: now.Add(2 * types.DiscoveryPollInterval),
201 + ExpiresAt: now.Add(2 * discovery.DiscoveryPollInterval),
202 APIHTTPSAddr: s.cfg.PortalURL,
203 IngressTLSAddr: ingressAddr,
204 WireGuardPublicKey: wireGuardField(s.wireGuardOverlayEnabled(), s.cfg.WireGuardPublicKey),
portal/discovery/discovery.go
+4 -13
@@ -16,7 +16,10 @@ import (
16 "github.com/gosuda/portal-tunnel/v2/utils"
17 )
18
19 -const defaultRequestTimeout = 15 * time.Second
19 +const (
20 + defaultRequestTimeout = 15 * time.Second
21 + DiscoveryPollInterval = 1 * time.Minute
22 +)
23
24 func NormalizeDescriptor(desc types.RelayDescriptor) (types.RelayDescriptor, error) {
25 desc.Name = utils.NormalizeHostname(desc.Name)
@@ -212,18 +215,6 @@ func DiscoverRelayDiscovery(ctx context.Context, baseURL string, rootCAPEM []byt
215 return resp, nil
216 }
217
215 -func DiscoveryUnavailableStatus(err error) (statusCode int, code string, unavailable bool) {
216 - var apiErr *types.APIRequestError
217 - if !errors.As(err, &apiErr) || apiErr == nil {
218 - return 0, "", false
219 - }
220 - code = strings.TrimSpace(apiErr.Code)
221 - if apiErr.StatusCode == http.StatusNotFound || code == types.APIErrorCodeFeatureUnavailable {
222 - return apiErr.StatusCode, code, true
223 - }
224 - return 0, "", false
225 -}
226 -
218 func RequireOverlayRelayDescriptor(desc types.RelayDescriptor) error {
219 if !desc.SupportsOverlayPeer {
220 return errors.New("descriptor does not support overlay peer")
portal/discovery/refresher.go
-3
@@ -63,9 +63,6 @@ func (r *Refresher) refreshHTTPS(ctx context.Context) error {
63 if ctx.Err() != nil {
64 return ctx.Err()
65 }
66 - if _, _, unavailable := DiscoveryUnavailableStatus(err); unavailable {
67 - continue
68 - }
66 continue
67 }
68
portal/server.go
+1 -1
@@ -699,7 +699,7 @@ func (s *Server) runRelayDiscoveryLoop(ctx context.Context) error {
699 if err != nil {
700 return err
701 }
702 - ticker := time.NewTicker(types.DiscoveryPollInterval)
702 + ticker := time.NewTicker(discovery.DiscoveryPollInterval)
703 defer ticker.Stop()
704
705 for {
portal/wireguard/overlay.go
+13 -13
@@ -85,15 +85,15 @@ func NormalizeConfig(rootHost string, cfg Config) (Config, error) {
85 }
86
87 type Overlay struct {
88 - selfWireGuardPublicKey string
89 - stack *stack
90 - listener net.Listener
91 - server *http.Server
88 + publicKey string
89 + stack *stack
90 + listener net.Listener
91 + server *http.Server
92 }
93
94 func NewOverlay(cfg Config, handler http.Handler) (*Overlay, error) {
95 - selfWireGuardPublicKey := strings.TrimSpace(cfg.PublicKey)
96 - if selfWireGuardPublicKey == "" {
95 + publicKey := strings.TrimSpace(cfg.PublicKey)
96 + if publicKey == "" {
97 return nil, errors.New("wireguard public key is required")
98 }
99
@@ -114,10 +114,10 @@ func NewOverlay(cfg Config, handler http.Handler) (*Overlay, error) {
114 }
115
116 return &Overlay{
117 - selfWireGuardPublicKey: selfWireGuardPublicKey,
118 - stack: stack,
119 - listener: listener,
120 - server: server,
117 + publicKey: publicKey,
118 + stack: stack,
119 + listener: listener,
120 + server: server,
121 }, nil
122 }
123
@@ -192,17 +192,17 @@ func (o *Overlay) Sync(view map[string]discovery.RelayState) error {
192 if o == nil || o.stack == nil {
193 return nil
194 }
195 - return o.stack.ApplyPeers(peersForView(o.selfWireGuardPublicKey, view))
195 + return o.stack.ApplyPeers(peersForView(o.publicKey, view))
196 }
197
198 -func peersForView(selfWireGuardPublicKey string, view map[string]discovery.RelayState) []desiredPeer {
198 +func peersForView(publicKey string, view map[string]discovery.RelayState) []desiredPeer {
199 peers := make([]desiredPeer, 0, len(view))
200 for _, relay := range view {
201 if relay.Expired || relay.Banned {
202 continue
203 }
204 desc := relay.Descriptor
205 - if desc.WireGuardPublicKey == selfWireGuardPublicKey || !desc.SupportsOverlayPeer {
205 + if desc.WireGuardPublicKey == publicKey || !desc.SupportsOverlayPeer {
206 continue
207 }
208 if desc.WireGuardPublicKey == "" || desc.WireGuardEndpoint == "" || desc.OverlayIPv4 == "" {
sdk/expose.go
+1 -1
@@ -139,7 +139,7 @@ func (e *Exposure) runDiscoveryLoop(ctx context.Context) {
139 if err != nil {
140 return
141 }
142 - ticker := time.NewTicker(types.DiscoveryPollInterval)
142 + ticker := time.NewTicker(discovery.DiscoveryPollInterval)
143 defer ticker.Stop()
144
145 for {
types/identity.go
-8
@@ -99,11 +99,3 @@ type RelayDescriptor struct {
99 LoadScore float64 `json:"load_score,omitempty"`
100 LastUpdated int64 `json:"last_updated,omitempty"`
101 }
102 -
103 -const DiscoveryPollInterval = 1 * time.Minute
104 -
105 -type DNSSECStatus struct {
106 - State string `json:"state,omitempty"`
107 - DSRecord string `json:"ds_record,omitempty"`
108 - Message string `json:"message,omitempty"`
109 -}