server: replace client metadata with IP address in registry (#5118)

This commit is contained in:
fatedier
2026-01-09 11:07:19 +08:00
committed by GitHub
parent 479e9f50c2
commit 1245f8804e
9 changed files with 48 additions and 85 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -4,8 +4,8 @@
<head>
<meta charset="utf-8">
<title>frp server</title>
<script type="module" crossorigin src="./index-BUrDiw1t.js"></script>
<link rel="stylesheet" crossorigin href="./index-D4KRVvIu.css">
<script type="module" crossorigin src="./index-r9B2t7lx.js"></script>
<link rel="stylesheet" crossorigin href="./index-Cl4R6mJh.css">
</head>
<body>

View File

@@ -2,7 +2,6 @@ package server
import (
"fmt"
"maps"
"sync"
"time"
)
@@ -14,7 +13,7 @@ type ClientInfo struct {
ClientID string
RunID string
Hostname string
Metas map[string]string
IP string
FirstConnectedAt time.Time
LastConnectedAt time.Time
DisconnectedAt time.Time
@@ -37,7 +36,7 @@ func NewClientRegistry() *ClientRegistry {
}
// Register stores/updates metadata for a client and returns the registry key plus whether it conflicts with an online client.
func (cr *ClientRegistry) Register(user, clientID, runID, hostname string, metas map[string]string) (key string, conflict bool) {
func (cr *ClientRegistry) Register(user, clientID, runID, hostname, remoteAddr string) (key string, conflict bool) {
if runID == "" {
return "", false
}
@@ -72,7 +71,7 @@ func (cr *ClientRegistry) Register(user, clientID, runID, hostname string, metas
info.RunID = runID
info.Hostname = hostname
info.Metas = metas
info.IP = remoteAddr
if info.FirstConnectedAt.IsZero() {
info.FirstConnectedAt = now
}
@@ -113,9 +112,7 @@ func (cr *ClientRegistry) List() []ClientInfo {
result := make([]ClientInfo, 0, len(cr.clients))
for _, info := range cr.clients {
cp := *info
cp.Metas = maps.Clone(info.Metas)
result = append(result, cp)
result = append(result, *info)
}
return result
}
@@ -129,9 +126,7 @@ func (cr *ClientRegistry) GetByKey(key string) (ClientInfo, bool) {
if !ok {
return ClientInfo{}, false
}
cp := *info
cp.Metas = maps.Clone(info.Metas)
return cp, true
return *info, true
}
func (cr *ClientRegistry) composeClientKey(user, id string) string {

View File

@@ -96,10 +96,10 @@ type serverInfoResp struct {
type clientInfoResp struct {
Key string `json:"key"`
User string `json:"user"`
ClientID string `json:"clientId"`
RunID string `json:"runId"`
ClientID string `json:"clientID"`
RunID string `json:"runID"`
Hostname string `json:"hostname"`
Metas map[string]string `json:"metas,omitempty"`
ClientIP string `json:"clientIP,omitempty"`
FirstConnectedAt int64 `json:"firstConnectedAt"`
LastConnectedAt int64 `json:"lastConnectedAt"`
DisconnectedAt int64 `json:"disconnectedAt,omitempty"`
@@ -531,7 +531,7 @@ func buildClientInfoResp(info ClientInfo) clientInfoResp {
ClientID: info.ClientID,
RunID: info.RunID,
Hostname: info.Hostname,
Metas: info.Metas,
ClientIP: info.IP,
FirstConnectedAt: toUnix(info.FirstConnectedAt),
LastConnectedAt: toUnix(info.LastConnectedAt),
Online: info.Online,

View File

@@ -615,7 +615,11 @@ func (svr *Service) RegisterControl(ctlConn net.Conn, loginMsg *msg.Login, inter
oldCtl.WaitClosed()
}
_, conflict := svr.clientRegistry.Register(loginMsg.User, loginMsg.ClientID, loginMsg.RunID, loginMsg.Hostname, loginMsg.Metas)
remoteAddr := ctlConn.RemoteAddr().String()
if host, _, err := net.SplitHostPort(remoteAddr); err == nil {
remoteAddr = host
}
_, conflict := svr.clientRegistry.Register(loginMsg.User, loginMsg.ClientID, loginMsg.RunID, loginMsg.Hostname, remoteAddr)
if conflict {
svr.ctlManager.Del(loginMsg.RunID, ctl)
ctl.Close()

View File

@@ -17,6 +17,12 @@
<span class="info-value">{{ client.hostname || 'N/A' }}</span>
</div>
<div class="info-row" v-if="client.ip">
<el-icon class="info-icon"><Connection /></el-icon>
<span class="info-label">IP:</span>
<span class="info-value monospace">{{ client.ip }}</span>
</div>
<div class="info-row" v-if="client.user">
<el-icon class="info-icon"><User /></el-icon>
<span class="info-label">User:</span>
@@ -26,7 +32,7 @@
<div class="info-row">
<el-icon class="info-icon"><Key /></el-icon>
<span class="info-label">Run ID:</span>
<span class="info-value monospace">{{ client.runId }}</span>
<span class="info-value monospace">{{ client.runID }}</span>
</div>
<div class="info-row" v-if="client.firstConnectedAt">
@@ -48,26 +54,12 @@
</div>
</div>
<div class="client-metas" v-if="client.metasArray.length > 0">
<div class="metas-label">Metadata:</div>
<div class="metas-tags">
<el-tag
v-for="meta in client.metasArray"
:key="meta.key"
size="small"
type="info"
class="meta-tag"
>
{{ meta.key }}: {{ meta.value }}
</el-tag>
</div>
</div>
</el-card>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import { Monitor, User, Key, Clock, CircleClose } from '@element-plus/icons-vue'
import { Monitor, User, Key, Clock, CircleClose, Connection } from '@element-plus/icons-vue'
import type { Client } from '../utils/client'
interface Props {
@@ -190,37 +182,6 @@ html.dark .info-value {
color: #d1d5db;
}
.client-metas {
margin-bottom: 16px;
padding-top: 12px;
border-top: 1px solid #e4e7ed;
}
html.dark .client-metas {
border-top-color: #3a3d5c;
}
.metas-label {
font-size: 13px;
color: #909399;
font-weight: 500;
margin-bottom: 8px;
}
html.dark .metas-label {
color: #9ca3af;
}
.metas-tags {
display: flex;
flex-wrap: wrap;
gap: 6px;
}
.meta-tag {
font-size: 12px;
}
.monospace {
font-family: 'Courier New', Courier, monospace;
font-size: 12px;

View File

@@ -1,9 +1,10 @@
export interface ClientInfoData {
key: string
user: string
clientId: string
runId: string
clientID: string
runID: string
hostname: string
clientIP?: string
metas?: Record<string, string>
firstConnectedAt: number
lastConnectedAt: number

View File

@@ -4,9 +4,10 @@ import type { ClientInfoData } from '../types/client'
export class Client {
key: string
user: string
clientId: string
runId: string
clientID: string
runID: string
hostname: string
ip: string
metas: Map<string, string>
firstConnectedAt: Date
lastConnectedAt: Date
@@ -16,9 +17,10 @@ export class Client {
constructor(data: ClientInfoData) {
this.key = data.key
this.user = data.user
this.clientId = data.clientId
this.runId = data.runId
this.clientID = data.clientID
this.runID = data.runID
this.hostname = data.hostname
this.ip = data.clientIP || ''
this.metas = new Map<string, string>()
if (data.metas) {
for (const [key, value] of Object.entries(data.metas)) {
@@ -34,14 +36,14 @@ export class Client {
}
get displayName(): string {
if (this.clientId) {
return this.user ? `${this.user}.${this.clientId}` : this.clientId
if (this.clientID) {
return this.user ? `${this.user}.${this.clientID}` : this.clientID
}
return this.runId
return this.runID
}
get shortRunId(): string {
return this.runId.substring(0, 8)
return this.runID.substring(0, 8)
}
get firstConnectedAgo(): string {
@@ -74,8 +76,8 @@ export class Client {
return (
this.key.toLowerCase().includes(search) ||
this.user.toLowerCase().includes(search) ||
this.clientId.toLowerCase().includes(search) ||
this.runId.toLowerCase().includes(search) ||
this.clientID.toLowerCase().includes(search) ||
this.runID.toLowerCase().includes(search) ||
this.hostname.toLowerCase().includes(search)
)
}