refact: fix lease metadatas

Kim committed Apr 1, 2026 at 18:54 UTC 9786244c6de9a0007a988a227bff01256e9fb5b3
13 files changed +189 -183
cmd/relay-server/admin.go
+1 -1
@@ -193,7 +193,7 @@ func (f *Frontend) serveAdmin(w http.ResponseWriter, r *http.Request) {
193 utils.WriteAPIData(w, http.StatusOK, types.AdminSnapshotResponse{
194 ApprovalMode: string(runtime.Approver().Mode()),
195 LandingPageEnabled: f.isLandingPageEnabled(),
196 - Leases: f.adminLeaseSnapshots(),
196 + Leases: f.server.AdminLeaseSnapshots(),
197 UDP: types.AdminUDPSettingsResponse{
198 Enabled: runtime.IsUDPEnabled(),
199 MaxLeases: runtime.UDPMaxLeases(),
cmd/relay-server/frontend.go
+1 -53
@@ -16,7 +16,6 @@ import (
16 "strings"
17 "sync"
18 "sync/atomic"
19 - "time"
19
20 "github.com/gosuda/portal/v2/cmd/portal-tunnel/installer"
21 "github.com/gosuda/portal/v2/portal"
@@ -194,7 +193,7 @@ func (f *Frontend) servePortalHTMLWithSSR(w http.ResponseWriter) {
193 func (f *Frontend) injectServerData(htmlContent string) string {
194 var snapshots []types.Lease
195 if f.server != nil {
197 - snapshots = f.publicLeaseSnapshots()
196 + snapshots = f.server.LeaseSnapshots()
197 }
198 jsonData, err := json.Marshal(snapshots)
199 if err != nil {
@@ -257,57 +256,6 @@ func (f *Frontend) setLandingPageEnabled(enabled bool) {
256 f.landingPageEnabled.Store(enabled)
257 }
258
260 -func (f *Frontend) adminLeaseSnapshots() []types.Lease {
261 - snapshots := f.server.LeaseSnapshots()
262 - if len(snapshots) == 0 {
263 - return nil
264 - }
265 - now := time.Now()
266 - filtered := make([]types.Lease, 0, len(snapshots))
267 - for _, snapshot := range snapshots {
268 - if now.After(snapshot.ExpiresAt) {
269 - continue
270 - }
271 - filtered = append(filtered, snapshot)
272 - }
273 - return filtered
274 -}
275 -
276 -func (f *Frontend) publicLeaseSnapshots() []types.Lease {
277 - snapshots := f.server.LeaseSnapshots()
278 - if len(snapshots) == 0 {
279 - return nil
280 - }
281 -
282 - now := time.Now()
283 - filtered := make([]types.Lease, 0, len(snapshots))
284 - for _, snapshot := range snapshots {
285 - if now.After(snapshot.ExpiresAt) {
286 - continue
287 - }
288 - since := time.Duration(0)
289 - if !snapshot.LastSeenAt.IsZero() {
290 - since = max(now.Sub(snapshot.LastSeenAt), 0)
291 - }
292 - if snapshot.IsBanned || snapshot.IsDenied || !snapshot.IsApproved || snapshot.Metadata.Hide {
293 - continue
294 - }
295 - if snapshot.Ready == 0 && since >= 3*time.Minute {
296 - continue
297 - }
298 -
299 - snapshot.ClientIP = ""
300 - snapshot.Address = ""
301 - snapshot.BPS = 0
302 - snapshot.IsApproved = false
303 - snapshot.IsBanned = false
304 - snapshot.IsDenied = false
305 - snapshot.IsIPBanned = false
306 - filtered = append(filtered, snapshot)
307 - }
308 - return filtered
309 -}
310 -
259 func getContentType(ext string) string {
260 ext = strings.TrimSpace(ext)
261 if ext == "" {
frontend/src/hooks/useAdmin.test.ts
+3 -3
@@ -1,13 +1,13 @@
1 import { act, renderHook, waitFor } from "@testing-library/react";
2 import { beforeEach, describe, expect, it, vi } from "vitest";
3
4 -import type { ServerData } from "@/hooks/useSSRData";
4 +import type { AdminLeaseData } from "@/hooks/useSSRData";
5 import { useAdmin } from "@/hooks/useAdmin";
6 import { API_PATHS, adminLeasePath } from "@/lib/apiPaths";
7 import { APIClientError, apiClient } from "@/lib/apiClient";
8
9 type DeferredAdminSnapshot = {
10 - leases: ServerData[];
10 + leases: AdminLeaseData[];
11 approval_mode: "auto" | "manual";
12 };
13
@@ -43,7 +43,7 @@ vi.mock("@/lib/apiClient", async () => {
43 };
44 });
45
46 -function buildLease(address: string, name: string = "relay-1"): ServerData {
46 +function buildLease(address: string, name: string = "relay-1"): AdminLeaseData {
47 return {
48 ExpiresAt: "2026-03-03T01:00:00Z",
49 FirstSeenAt: "2026-03-02T00:00:00Z",
frontend/src/hooks/useAdmin.ts
+19 -19
@@ -1,5 +1,5 @@
1 import { useEffect, useMemo, useState } from "react";
2 -import type { ServerData } from "@/hooks/useSSRData";
2 +import type { AdminLeaseData } from "@/hooks/useSSRData";
3 import { useList, type BaseServer } from "@/hooks/useList";
4 import type { BanFilter } from "@/components/ServerListView";
5 import {
@@ -25,7 +25,7 @@ type LandingPageSettingsResponse = {
25 type AdminSnapshotResponse = {
26 approval_mode?: ApprovalMode;
27 landing_page_enabled?: boolean;
28 - leases?: ServerData[];
28 + leases?: AdminLeaseData[];
29 udp?: { enabled: boolean; max_leases: number };
30 };
31
@@ -89,12 +89,12 @@ function buildIdentityKey(name: string, address: string): string {
89 }
90
91 function resolveLeaseIdentity(
92 - rows: ServerData[],
92 + rows: AdminLeaseData[],
93 identityKey: string
94 ): { name: string; address: string } {
95 const match = rows.find((row) => {
96 const name = (row.name || "").trim();
97 - const address = (row.address || "").trim();
97 + const address = row.address.trim();
98 return buildIdentityKey(name, address) === identityKey;
99 });
100 if (!match) {
@@ -103,18 +103,18 @@ function resolveLeaseIdentity(
103
104 return {
105 name: (match.name || "").trim(),
106 - address: (match.address || "").trim(),
106 + address: match.address.trim(),
107 };
108 }
109
110 function toAdminServer(
111 - row: ServerData,
111 + row: AdminLeaseData,
112 index: number
113 ): AdminServer {
114 const metadata = parseLeaseMetadata(row.Metadata);
115 const hostname = row.Hostname || "";
116 const serviceName = row.name || "";
117 - const address = (row.address || "").trim();
117 + const address = row.address.trim();
118
119 return {
120 id: index + 1,
@@ -130,13 +130,13 @@ function toAdminServer(
130 firstSeen: row.FirstSeenAt || undefined,
131 identityKey: buildIdentityKey(serviceName, address),
132 address,
133 - isBanned: row.IsBanned || false,
134 - bps: row.BPS || 0,
135 - isApproved: row.IsApproved || false,
136 - isDenied: row.IsDenied || false,
137 - ip: row.ClientIP || "",
138 - displayIP: row.ReportedIP || row.ClientIP || "",
139 - isIPBanned: row.IsIPBanned || false,
133 + isBanned: row.IsBanned,
134 + bps: row.BPS,
135 + isApproved: row.IsApproved,
136 + isDenied: row.IsDenied,
137 + ip: row.ClientIP,
138 + displayIP: row.ReportedIP || row.ClientIP,
139 + isIPBanned: row.IsIPBanned,
140 };
141 }
142
@@ -160,7 +160,7 @@ function dedupeStrings(values: string[]): string[] {
160 }
161
162 interface AdminSnapshot {
163 - serverData: ServerData[];
163 + serverData: AdminLeaseData[];
164 approvalMode: ApprovalMode;
165 landingPageEnabled: boolean;
166 udpSettings: UDPSettings;
@@ -182,7 +182,7 @@ async function loadAdminSnapshot(): Promise<AdminSnapshot> {
182 }
183
184 export function useAdmin() {
185 - const [serverData, setServerData] = useState<ServerData[]>([]);
185 + const [serverData, setServerData] = useState<AdminLeaseData[]>([]);
186 const [approvalMode, setApprovalMode] = useState<ApprovalMode>("auto");
187 const [landingPageEnabled, setLandingPageEnabled] = useState(true);
188 const [udpSettings, setUDPSettings] = useState<UDPSettings>({ enabled: false, maxLeases: 0 });
@@ -299,13 +299,13 @@ export function useAdmin() {
299 const normalizedBPS = Math.max(0, Math.trunc(bps));
300 const previousBPS =
301 serverData.find((row) =>
302 - buildIdentityKey((row.name || "").trim(), (row.address || "").trim()) ===
302 + buildIdentityKey((row.name || "").trim(), row.address.trim()) ===
303 identityKey
304 )?.BPS ?? 0;
305
306 setServerData((prev) =>
307 prev.map((row) =>
308 - buildIdentityKey((row.name || "").trim(), (row.address || "").trim()) ===
308 + buildIdentityKey((row.name || "").trim(), row.address.trim()) ===
309 identityKey
310 ? { ...row, BPS: normalizedBPS }
311 : row
@@ -328,7 +328,7 @@ export function useAdmin() {
328 } catch (err) {
329 setServerData((prev) =>
330 prev.map((row) =>
331 - buildIdentityKey((row.name || "").trim(), (row.address || "").trim()) ===
331 + buildIdentityKey((row.name || "").trim(), row.address.trim()) ===
332 identityKey
333 ? { ...row, BPS: previousBPS }
334 : row
frontend/src/hooks/useSSRData.ts
+14 -11
@@ -8,30 +8,33 @@ export interface Metadata {
8 hide: boolean;
9 }
10
11 -export interface ServerData {
11 +export interface PublicLeaseData {
12 ExpiresAt: string;
13 FirstSeenAt: string;
14 LastSeenAt: string;
15 name?: string;
16 - address?: string;
17 - BPS?: number;
18 - ClientIP: string;
19 - ReportedIP?: string;
16 Hostname: string;
17 Metadata: unknown;
18 Ready: number;
23 - IsApproved?: boolean;
24 - IsBanned?: boolean;
25 - IsDenied?: boolean;
26 - IsIPBanned?: boolean;
19 +}
20 +
21 +export interface AdminLeaseData extends PublicLeaseData {
22 + address: string;
23 + BPS: number;
24 + ClientIP: string;
25 + ReportedIP: string;
26 + IsApproved: boolean;
27 + IsBanned: boolean;
28 + IsDenied: boolean;
29 + IsIPBanned: boolean;
30 }
31
32 /**
33 * useSSRData hook reads server data injected by Go SSR
34 * The data is embedded in a <script id="__SSR_DATA__"> tag in the HTML
35 */
33 -export function useSSRData(): ServerData[] {
34 - const [data, setData] = useState<ServerData[]>([]);
36 +export function useSSRData(): PublicLeaseData[] {
37 + const [data, setData] = useState<PublicLeaseData[]>([]);
38
39 useEffect(() => {
40 const ssrScript = document.getElementById("__SSR_DATA__");
frontend/src/hooks/useServerList.ts
+2 -2
@@ -1,12 +1,12 @@
1 import { useMemo } from "react";
2 import { useSSRData } from "@/hooks/useSSRData";
3 -import type { ServerData } from "@/hooks/useSSRData";
3 +import type { PublicLeaseData } from "@/hooks/useSSRData";
4 import { useList, type BaseServer } from "@/hooks/useList";
5 import { parseLeaseMetadata } from "@/lib/metadata";
6
7 export type ClientServer = BaseServer;
8
9 -function convertSSRDataToServers(ssrData: ServerData[]): ClientServer[] {
9 +function convertSSRDataToServers(ssrData: PublicLeaseData[]): ClientServer[] {
10 return ssrData.map((row, index) => {
11 const metadata = parseLeaseMetadata(row.Metadata);
12 const hostname = row.Hostname || "";
portal/api_server.go
+11 -13
@@ -559,18 +559,16 @@ func (s *Server) registerLease(req types.RegisterChallengeRequest, clientIP, rep
559 expiresAt := claims.Expiry.Time().UTC()
560 identityKey := identity.Key()
561 record := &leaseRecord{
562 - Lease: types.Lease{
563 - Identity: identity,
564 - Hostname: hostname,
565 - Metadata: req.Metadata,
566 - ExpiresAt: expiresAt,
567 - FirstSeenAt: issuedAt,
568 - LastSeenAt: issuedAt,
569 - ClientIP: clientIP,
570 - ReportedIP: utils.SanitizeReportedIP(reportedIP),
571 - UDPEnabled: req.UDPEnabled,
572 - },
573 - stream: transport.NewRelayStream(identityKey, defaultIdleKeepalive, defaultReadyQueueLimit),
562 + Identity: identity,
563 + Hostname: hostname,
564 + Metadata: req.Metadata.Copy(),
565 + ExpiresAt: expiresAt,
566 + FirstSeenAt: issuedAt,
567 + LastSeenAt: issuedAt,
568 + ClientIP: clientIP,
569 + ReportedIP: utils.SanitizeReportedIP(reportedIP),
570 + UDPEnabled: req.UDPEnabled,
571 + stream: transport.NewRelayStream(identityKey, defaultIdleKeepalive, defaultReadyQueueLimit),
572 }
573 if req.UDPEnabled {
574 if s.ports == nil {
@@ -597,7 +595,7 @@ func (s *Server) registerLease(req types.RegisterChallengeRequest, clientIP, rep
595 resp := types.RegisterResponse{
596 Identity: record.Copy(),
597 Hostname: hostname,
600 - Metadata: record.Metadata,
598 + Metadata: record.Metadata.Copy(),
599 ExpiresAt: expiresAt,
600 AccessToken: accessToken,
601 UDPEnabled: record.UDPEnabled,
portal/lease.go
+43 -15
@@ -294,28 +294,56 @@ func (r *leaseRegistry) Snapshot(record *leaseRecord) types.Lease {
294 return types.Lease{}
295 }
296
297 - snapshot := record.Lease
298 - snapshot.Metadata = snapshot.Metadata.Copy()
299 - clientIP := record.ClientIP
300 - identityKey := record.Key()
301 - snapshot.BPS = r.policy.BPSManager().IdentityBPS(identityKey)
297 + snapshot := types.Lease{
298 + Name: record.Name,
299 + ExpiresAt: record.ExpiresAt,
300 + FirstSeenAt: record.FirstSeenAt,
301 + LastSeenAt: record.LastSeenAt,
302 + Hostname: record.Hostname,
303 + UDPEnabled: record.UDPEnabled,
304 + Metadata: record.Metadata.Copy(),
305 + }
306 if record.stream != nil {
307 snapshot.Ready = record.stream.ReadyCount()
308 }
305 - snapshot.IsApproved = r.policy.EffectiveApproval(identityKey)
306 - snapshot.IsBanned = r.policy.IsIdentityBanned(identityKey)
307 - snapshot.IsDenied = r.policy.IsIdentityDenied(identityKey)
308 - snapshot.IsIPBanned = r.policy.IPFilter().IsIPBanned(clientIP)
309 return snapshot
310 }
311
312 type leaseRecord struct {
313 - types.Lease
314 - datagram *transport.RelayDatagram
315 - ports *transport.PortAllocator
316 - stream *transport.RelayStream
317 - startErr error
318 - startOnce sync.Once
313 + types.Identity
314 + ExpiresAt time.Time
315 + FirstSeenAt time.Time
316 + LastSeenAt time.Time
317 + ClientIP string
318 + ReportedIP string
319 + Hostname string
320 + UDPEnabled bool
321 + Metadata types.LeaseMetadata
322 + datagram *transport.RelayDatagram
323 + ports *transport.PortAllocator
324 + stream *transport.RelayStream
325 + startErr error
326 + startOnce sync.Once
327 +}
328 +
329 +func (r *leaseRegistry) AdminSnapshot(record *leaseRecord) types.AdminLease {
330 + if record == nil {
331 + return types.AdminLease{}
332 + }
333 +
334 + clientIP := record.ClientIP
335 + identityKey := record.Key()
336 + return types.AdminLease{
337 + Lease: r.Snapshot(record),
338 + Address: record.Address,
339 + BPS: r.policy.BPSManager().IdentityBPS(identityKey),
340 + ClientIP: clientIP,
341 + ReportedIP: record.ReportedIP,
342 + IsApproved: r.policy.EffectiveApproval(identityKey),
343 + IsBanned: r.policy.IsIdentityBanned(identityKey),
344 + IsDenied: r.policy.IsIdentityDenied(identityKey),
345 + IsIPBanned: r.policy.IPFilter().IsIPBanned(clientIP),
346 + }
347 }
348
349 func (r *leaseRecord) Start() error {
portal/lease_test.go
+35 -45
@@ -18,15 +18,13 @@ func TestLeaseRegistryLifecycle(t *testing.T) {
18 runtime := policy.NewRuntime()
19 registry := newLeaseRegistry(runtime)
20 record := &leaseRecord{
21 - Lease: types.Lease{
22 - Identity: types.Identity{
23 - Name: "demo",
24 - Address: "addr-1",
25 - },
26 - Hostname: "demo.example.com",
27 - ExpiresAt: time.Now().Add(30 * time.Second),
21 + Identity: types.Identity{
22 + Name: "demo",
23 + Address: "addr-1",
24 },
29 - stream: transport.NewRelayStream("addr-1", time.Minute, 1),
25 + Hostname: "demo.example.com",
26 + ExpiresAt: time.Now().Add(30 * time.Second),
27 + stream: transport.NewRelayStream("addr-1", time.Minute, 1),
28 }
29
30 if err := registry.Register(record); err != nil {
@@ -70,15 +68,13 @@ func TestLeaseRegistryWildcardAndConflict(t *testing.T) {
68
69 registry := newLeaseRegistry(policy.NewRuntime())
70 wildcardLease := &leaseRecord{
73 - Lease: types.Lease{
74 - Identity: types.Identity{
75 - Name: "wildcard",
76 - Address: "addr-wildcard",
77 - },
78 - Hostname: "*.example.com",
79 - ExpiresAt: time.Now().Add(30 * time.Second),
71 + Identity: types.Identity{
72 + Name: "wildcard",
73 + Address: "addr-wildcard",
74 },
81 - stream: transport.NewRelayStream("addr-wildcard", time.Minute, 1),
75 + Hostname: "*.example.com",
76 + ExpiresAt: time.Now().Add(30 * time.Second),
77 + stream: transport.NewRelayStream("addr-wildcard", time.Minute, 1),
78 }
79 if err := registry.Register(wildcardLease); err != nil {
80 t.Fatalf("Register(wildcard) error = %v", err)
@@ -92,15 +88,13 @@ func TestLeaseRegistryWildcardAndConflict(t *testing.T) {
88 }
89
90 conflict := &leaseRecord{
95 - Lease: types.Lease{
96 - Identity: types.Identity{
97 - Name: "conflict",
98 - Address: "addr-conflict",
99 - },
100 - Hostname: "*.example.com",
101 - ExpiresAt: time.Now().Add(30 * time.Second),
91 + Identity: types.Identity{
92 + Name: "conflict",
93 + Address: "addr-conflict",
94 },
103 - stream: transport.NewRelayStream("addr-conflict", time.Minute, 1),
95 + Hostname: "*.example.com",
96 + ExpiresAt: time.Now().Add(30 * time.Second),
97 + stream: transport.NewRelayStream("addr-conflict", time.Minute, 1),
98 }
99 err := registry.Register(conflict)
100 if !errors.Is(err, errHostnameConflict) {
@@ -118,16 +112,14 @@ func TestLeaseRegistrySnapshotAndRoutableUsePolicy(t *testing.T) {
112
113 registry := newLeaseRegistry(runtime)
114 record := &leaseRecord{
121 - Lease: types.Lease{
122 - Identity: types.Identity{
123 - Name: "demo",
124 - Address: "addr-policy",
125 - },
126 - Hostname: "demo.example.com",
127 - ExpiresAt: time.Now().Add(30 * time.Second),
128 - ClientIP: "203.0.113.20",
115 + Identity: types.Identity{
116 + Name: "demo",
117 + Address: "addr-policy",
118 },
130 - stream: transport.NewRelayStream("addr-policy", time.Minute, 1),
119 + Hostname: "demo.example.com",
120 + ExpiresAt: time.Now().Add(30 * time.Second),
121 + ClientIP: "203.0.113.20",
122 + stream: transport.NewRelayStream("addr-policy", time.Minute, 1),
123 }
124 if err := registry.Register(record); err != nil {
125 t.Fatalf("Register() error = %v", err)
@@ -137,9 +129,9 @@ func TestLeaseRegistrySnapshotAndRoutableUsePolicy(t *testing.T) {
129 t.Fatal("policy.IsIdentityRoutable() = true, want false before approval")
130 }
131
140 - snapshot := registry.Snapshot(record)
132 + snapshot := registry.AdminSnapshot(record)
133 if snapshot.IsApproved {
142 - t.Fatal("Snapshot().IsApproved = true, want false before approval")
134 + t.Fatal("AdminSnapshot().IsApproved = true, want false before approval")
135 }
136 if got := runtime.IPFilter().IdentityIP(record.Key()); got != "203.0.113.20" {
137 t.Fatalf("Register() lease IP = %q, want %q", got, "203.0.113.20")
@@ -150,9 +142,9 @@ func TestLeaseRegistrySnapshotAndRoutableUsePolicy(t *testing.T) {
142 t.Fatal("policy.IsIdentityRoutable() = false, want true after approval")
143 }
144
153 - snapshot = registry.Snapshot(record)
145 + snapshot = registry.AdminSnapshot(record)
146 if !snapshot.IsApproved {
155 - t.Fatal("Snapshot().IsApproved = false, want true after approval")
147 + t.Fatal("AdminSnapshot().IsApproved = false, want true after approval")
148 }
149 }
150
@@ -161,15 +153,13 @@ func TestLeaseRegistryCleanupExpiredClosesBroker(t *testing.T) {
153
154 registry := newLeaseRegistry(policy.NewRuntime())
155 record := &leaseRecord{
164 - Lease: types.Lease{
165 - Identity: types.Identity{
166 - Name: "expired",
167 - Address: "addr-expired",
168 - },
169 - Hostname: "expired.example.com",
170 - ExpiresAt: time.Now().Add(-time.Second),
156 + Identity: types.Identity{
157 + Name: "expired",
158 + Address: "addr-expired",
159 },
172 - stream: transport.NewRelayStream("addr-expired", time.Minute, 1),
160 + Hostname: "expired.example.com",
161 + ExpiresAt: time.Now().Add(-time.Second),
162 + stream: transport.NewRelayStream("addr-expired", time.Minute, 1),
163 }
164 if err := registry.Register(record); err != nil {
165 t.Fatalf("Register() error = %v", err)
portal/server.go
+35 -1
@@ -335,13 +335,47 @@ func (s *Server) LeaseSnapshots() []types.Lease {
335 s.registry.mu.RLock()
336 defer s.registry.mu.RUnlock()
337
338 + now := time.Now()
339 records := make([]*leaseRecord, 0, len(s.registry.leasesByKey))
340 for _, record := range s.registry.leasesByKey {
341 records = append(records, record)
342 }
343 snapshots := make([]types.Lease, 0, len(records))
344 for _, record := range records {
344 - snapshots = append(snapshots, s.registry.Snapshot(record))
345 + if now.After(record.ExpiresAt) {
346 + continue
347 + }
348 + adminSnapshot := s.registry.AdminSnapshot(record)
349 + since := time.Duration(0)
350 + if !adminSnapshot.LastSeenAt.IsZero() {
351 + since = max(now.Sub(adminSnapshot.LastSeenAt), 0)
352 + }
353 + if adminSnapshot.IsBanned || adminSnapshot.IsDenied || !adminSnapshot.IsApproved || adminSnapshot.Metadata.Hide {
354 + continue
355 + }
356 + if adminSnapshot.Ready == 0 && since >= 3*time.Minute {
357 + continue
358 + }
359 + snapshots = append(snapshots, adminSnapshot.Lease)
360 + }
361 + return snapshots
362 +}
363 +
364 +func (s *Server) AdminLeaseSnapshots() []types.AdminLease {
365 + s.registry.mu.RLock()
366 + defer s.registry.mu.RUnlock()
367 +
368 + now := time.Now()
369 + records := make([]*leaseRecord, 0, len(s.registry.leasesByKey))
370 + for _, record := range s.registry.leasesByKey {
371 + records = append(records, record)
372 + }
373 + snapshots := make([]types.AdminLease, 0, len(records))
374 + for _, record := range records {
375 + if now.After(record.ExpiresAt) {
376 + continue
377 + }
378 + snapshots = append(snapshots, s.registry.AdminSnapshot(record))
379 }
380 return snapshots
381 }
sdk/sdk_test.go
+1 -1
@@ -122,7 +122,7 @@ func TestNewListenerRegistersLeaseWithMainContract(t *testing.T) {
122 }
123 })
124 waitForSDKTest(t, func() bool {
125 - return listener.Address() == challengeReq.Identity.Address
125 + return listener.Hostname() == "127.0.0.1"
126 })
127
128 if challengeReq.TTL != 42 {
types/api.go
+1 -1
@@ -147,7 +147,7 @@ type AdminAuthStatusResponse struct {
147 type AdminSnapshotResponse struct {
148 ApprovalMode string `json:"approval_mode"`
149 LandingPageEnabled bool `json:"landing_page_enabled"`
150 - Leases []Lease `json:"leases,omitempty"`
150 + Leases []AdminLease `json:"leases,omitempty"`
151 UDP AdminUDPSettingsResponse `json:"udp"`
152 }
153
types/identity.go
+23 -18
@@ -32,24 +32,6 @@ func (i Identity) Key() string {
32 return name + IdentityKeySeparator + address
33 }
34
35 -type Lease struct {
36 - Identity
37 - ExpiresAt time.Time
38 - FirstSeenAt time.Time
39 - LastSeenAt time.Time
40 - BPS int64
41 - ClientIP string
42 - ReportedIP string
43 - Hostname string
44 - UDPEnabled bool
45 - Metadata LeaseMetadata
46 - Ready int
47 - IsApproved bool
48 - IsBanned bool
49 - IsDenied bool
50 - IsIPBanned bool
51 -}
52 -
35 type LeaseMetadata struct {
36 Description string `json:"description,omitempty"`
37 Owner string `json:"owner,omitempty"`
@@ -68,6 +50,29 @@ func (m LeaseMetadata) Copy() LeaseMetadata {
50 }
51 }
52
53 +type Lease struct {
54 + Name string `json:"name,omitempty"`
55 + ExpiresAt time.Time
56 + FirstSeenAt time.Time
57 + LastSeenAt time.Time
58 + Hostname string
59 + UDPEnabled bool
60 + Metadata LeaseMetadata
61 + Ready int
62 +}
63 +
64 +type AdminLease struct {
65 + Lease
66 + Address string `json:"address,omitempty"`
67 + BPS int64
68 + ClientIP string
69 + ReportedIP string
70 + IsApproved bool
71 + IsBanned bool
72 + IsDenied bool
73 + IsIPBanned bool
74 +}
75 +
76 type RelayDescriptor struct {
77 Identity
78