Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions assets/frps/static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
15 changes: 5 additions & 10 deletions server/client_registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package server

import (
"fmt"
"maps"
"sync"
"time"
)
Expand All @@ -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
Expand All @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand All @@ -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 {
Expand Down
22 changes: 11 additions & 11 deletions server/dashboard_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,16 +94,16 @@ type serverInfoResp struct {
}

type clientInfoResp struct {
Key string `json:"key"`
User string `json:"user"`
ClientID string `json:"clientId"`
RunID string `json:"runId"`
Hostname string `json:"hostname"`
Metas map[string]string `json:"metas,omitempty"`
FirstConnectedAt int64 `json:"firstConnectedAt"`
LastConnectedAt int64 `json:"lastConnectedAt"`
DisconnectedAt int64 `json:"disconnectedAt,omitempty"`
Online bool `json:"online"`
Key string `json:"key"`
User string `json:"user"`
ClientID string `json:"clientID"`
RunID string `json:"runID"`
Hostname string `json:"hostname"`
ClientIP string `json:"clientIP,omitempty"`
FirstConnectedAt int64 `json:"firstConnectedAt"`
LastConnectedAt int64 `json:"lastConnectedAt"`
DisconnectedAt int64 `json:"disconnectedAt,omitempty"`
Online bool `json:"online"`
}

// /healthz
Expand Down Expand Up @@ -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,
Expand Down
6 changes: 5 additions & 1 deletion server/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
55 changes: 8 additions & 47 deletions web/frps/src/components/ClientCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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">
Expand All @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down
5 changes: 3 additions & 2 deletions web/frps/src/types/client.ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down
22 changes: 12 additions & 10 deletions web/frps/src/utils/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)) {
Expand All @@ -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 {
Expand Down Expand Up @@ -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)
)
}
Expand Down