feat: Optimize SSH session performance on Ubuntu 25. (#13152)

* feat: Optimize SSH session performance on Ubuntu 25.

* feat: Optimize SSH session performance on Ubuntu 25.

* feat: Optimize SSH session performance on Ubuntu 25.

* feat: Optimize SSH session performance on Ubuntu 25.
This commit is contained in:
CityFun
2026-06-30 18:36:28 +08:00
committed by GitHub
parent f31f0a89ff
commit d97aa9c2a0
2 changed files with 108 additions and 3 deletions

View File

@@ -5,6 +5,8 @@ import (
"encoding/json"
"fmt"
"os"
"os/exec"
"strconv"
"strings"
"time"
@@ -250,8 +252,13 @@ func getSSHSessions(config SSHSessionConfig) (res []byte, err error) {
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)
defer cancel()
if sessions, ok := loadLoginctlSSHSessions(ctx); ok && len(sessions) > 0 {
res, err = json.Marshal(filterSSHSessions(sessions, config))
return
}
users, err = host.UsersWithContext(ctx)
if err != nil {
if err != nil || len(users) == 0 {
res, err = json.Marshal(result)
return
}
@@ -275,6 +282,22 @@ func getSSHSessions(config SSHSessionConfig) (res []byte, err error) {
return
}
connections, err := net.ConnectionsMaxWithContext(ctx, "all", 32768)
if err != nil {
res, err = json.Marshal(result)
return
}
pidConnections := make(map[int32][]net.ConnectionStat, 256)
for _, conn := range connections {
if conn.Pid == 0 || conn.Raddr.IP == "" {
continue
}
if _, ok := usersByHost[conn.Raddr.IP]; !ok {
continue
}
pidConnections[conn.Pid] = append(pidConnections[conn.Pid], conn)
}
processes, err = process.ProcessesWithContext(ctx)
if err != nil {
res, err = json.Marshal(result)
@@ -286,12 +309,12 @@ func getSSHSessions(config SSHSessionConfig) (res []byte, err error) {
if name != "sshd" || proc.Pid == 0 {
continue
}
connections, _ := proc.Connections()
connections := pidConnections[proc.Pid]
if len(connections) == 0 {
continue
}
cmdline, cmdErr := proc.Cmdline()
cmdline, cmdErr := proc.CmdlineWithContext(ctx)
if cmdErr != nil {
continue
}
@@ -320,6 +343,86 @@ func getSSHSessions(config SSHSessionConfig) (res []byte, err error) {
return
}
func loadLoginctlSSHSessions(ctx context.Context) ([]sshSession, bool) {
if _, err := exec.LookPath("loginctl"); err != nil {
return nil, false
}
output, err := exec.CommandContext(ctx, "loginctl", "list-sessions", "--no-legend", "--no-pager").Output()
if err != nil {
return nil, false
}
var result []sshSession
for _, line := range strings.Split(string(output), "\n") {
fields := strings.Fields(line)
if len(fields) == 0 {
continue
}
sessionOutput, err := exec.CommandContext(ctx, "loginctl", "show-session", fields[0], "--no-pager",
"-p", "Name", "-p", "Remote", "-p", "RemoteHost", "-p", "TTY", "-p", "Timestamp", "-p", "Leader", "-p", "Service", "-p", "State").Output()
if err != nil {
continue
}
session, ok := parseLoginctlSSHSession(string(sessionOutput))
if !ok {
continue
}
result = append(result, session)
}
return result, true
}
func filterSSHSessions(sessions []sshSession, config SSHSessionConfig) []sshSession {
result := make([]sshSession, 0, len(sessions))
for _, session := range sessions {
if config.LoginUser != "" && !strings.Contains(session.Username, config.LoginUser) {
continue
}
if config.LoginIP != "" && !strings.Contains(session.Host, config.LoginIP) {
continue
}
result = append(result, session)
}
return result
}
func parseLoginctlSSHSession(output string) (sshSession, bool) {
props := map[string]string{}
for _, line := range strings.Split(output, "\n") {
key, value, ok := strings.Cut(line, "=")
if ok {
props[key] = strings.TrimSpace(value)
}
}
service := props["Service"]
if props["Remote"] != "yes" || props["Name"] == "" || props["RemoteHost"] == "" || props["State"] != "active" || (service != "sshd" && service != "ssh") {
return sshSession{}, false
}
pid, _ := strconv.ParseInt(props["Leader"], 10, 32)
return sshSession{
Username: props["Name"],
Host: props["RemoteHost"],
Terminal: props["TTY"],
PID: int32(pid),
LoginTime: parseLoginctlTimestamp(props["Timestamp"]),
}, true
}
func parseLoginctlTimestamp(value string) string {
fields := strings.Fields(value)
for i := 0; i < len(fields)-1; i++ {
if strings.Count(fields[i], "-") != 2 || strings.Count(fields[i+1], ":") != 2 {
continue
}
candidate := fields[i] + " " + fields[i+1]
t, err := time.ParseInLocation("2006-01-02 15:04:05", candidate, time.Local)
if err != nil {
return candidate
}
return t.Format("2006-1-2 15:04:05")
}
return value
}
func getNetConnections(config NetConfig) (res []byte, err error) {
result := make([]ProcessConnect, 0, 1024)
ctx, cancel := context.WithTimeout(context.Background(), defaultTimeout)

View File

@@ -134,6 +134,8 @@ const stop = async (PID: number) => {
.then(async () => {
try {
await stopProcess({ PID: PID });
data.value = data.value.filter((item: any) => item.PID !== PID);
search();
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
} catch (error) {
MsgError(error);