Server side sorting for the websessions page. No longer using LinkedMap as a result.

This commit is contained in:
Erik Brakkee 2024-08-16 00:25:17 +02:00
parent 1de3c90146
commit 3574b64842
8 changed files with 55 additions and 34 deletions

View File

@ -21,7 +21,7 @@ func pageHandler(w http.ResponseWriter, r *http.Request) {
case "downloads.html":
templates2.DownloadsTab().Render(r.Context(), w)
case "sessions.html":
templates2.SessionsTab(nil, access.Location).Render(r.Context(), w)
templates2.SessionsTab(nil, nil, access.Location).Render(r.Context(), w)
default:
http.NotFound(w, r)
}

View File

@ -24,10 +24,10 @@ func NewPrometheusState(state *models.State) *PrometheusState {
agents: collections.NewLinkedMap[models.AgentGuid, *models.Agent](),
clients: collections.NewLinkedMap[models.ClientGuid, *models.Client](),
}
for agent := range state.Agents.RangeValues() {
for _, agent := range state.Agents {
res.agents.Put(agent.Guid, agent)
}
for client := range state.Clients.RangeValues() {
for _, client := range state.Clients {
res.clients.Put(client.Guid, client)
}
return &res

View File

@ -70,7 +70,7 @@ func main() {
render(dir, "downloads.html", templates2.Downloads)
render(dir, "sessions-none.html", func() templ.Component {
return templates2.SessionsTab(nil, netherlands)
return templates2.SessionsTab(nil, nil, netherlands)
})
render(dir, "sessions.html", func() templ.Component {
@ -94,7 +94,7 @@ func main() {
},
}
agent.SetExpiryTime(time.Now().In(japan).Add(10 * time.Minute))
state.Agents.Put(agent.Guid, &agent)
state.Agents[agent.Guid] = &agent
client := models.Client{
Guid: models.ClientGuid(strconv.Itoa(rand.Int())),
RemoteAddr: models.RemoteAddr("10.1.3.3"),
@ -104,7 +104,9 @@ func main() {
StartTime: time.Now().In(japan),
SessionType: models.SessionType("sftp"),
}
state.Clients.Put(client.Guid, &client)
return templates2.SessionsTab(state, netherlands)
state.Clients[client.Guid] = &client
agents, clients := state.Slices()
return templates2.SessionsTab(agents, clients, netherlands)
})
}

View File

@ -2,7 +2,7 @@ package models
import (
"git.wamblee.org/converge/pkg/comms"
"git.wamblee.org/converge/pkg/support/collections"
"sort"
"sync/atomic"
"time"
)
@ -56,25 +56,43 @@ type Client struct {
// Created by the server and used for updating the web client
// and prometheus metrics.
type State struct {
Agents *collections.LinkedMap[AgentGuid, *Agent]
Clients *collections.LinkedMap[ClientGuid, *Client]
Agents map[AgentGuid]*Agent
Clients map[ClientGuid]*Client
}
func NewState() *State {
return &State{
Agents: collections.NewLinkedMap[AgentGuid, *Agent](),
Clients: collections.NewLinkedMap[ClientGuid, *Client](),
Agents: make(map[AgentGuid]*Agent),
Clients: make(map[ClientGuid]*Client),
}
}
// for copy on write
func (state *State) Copy() *State {
res := NewState()
for entry := range state.Agents.RangeEntries() {
res.Agents.Put(entry.Key, entry.Value)
for k, v := range state.Agents {
res.Agents[k] = v
}
for entry := range state.Clients.RangeEntries() {
res.Clients.Put(entry.Key, entry.Value)
for k, v := range state.Clients {
res.Clients[k] = v
}
return res
}
func (state *State) Slices() ([]*Agent, []*Client) {
agents := make([]*Agent, 0, len(state.Agents))
clients := make([]*Client, 0, len(state.Clients))
for _, agent := range state.Agents {
agents = append(agents, agent)
}
for _, client := range state.Clients {
clients = append(clients, client)
}
sort.Slice(agents, func(i int, j int) bool {
return agents[i].StartTime.Before(agents[j].StartTime)
})
sort.Slice(clients, func(i int, j int) bool {
return clients[i].StartTime.Before(clients[j].StartTime)
})
return agents, clients
}

View File

@ -140,7 +140,7 @@ func (admin *Admin) AddAgent(publicId models.RendezVousId, agentInfo comms.Envir
agent := newAgent(commChannel, publicId, agentInfo)
admin.state = admin.state.Copy()
admin.state.Agents.Put(agent.Info.Guid, agent.Info)
admin.state.Agents[agent.Info.Guid] = agent.Info
admin.agents[publicId] = agent
return agent, nil
}
@ -175,7 +175,7 @@ func (admin *Admin) AddClient(publicId models.RendezVousId, clientConn iowrapper
}
admin.state = admin.state.Copy()
admin.state.Clients.Put(client.Info.Guid, client.Info)
admin.state.Clients[client.Info.Guid] = client.Info
admin.clients[client.Info.ClientId] = client
return client, nil
}
@ -206,7 +206,7 @@ func (admin *Admin) RemoveAgent(publicId models.RendezVousId) error {
log.Printf("Could not close yamux client session for '%s'\n", publicId)
}
admin.state = admin.state.Copy()
admin.state.Agents.Delete(agent.Info.Guid)
delete(admin.state.Agents, agent.Info.Guid)
delete(admin.agents, publicId)
return nil
}
@ -222,7 +222,7 @@ func (admin *Admin) RemoveClient(client *clientConnection) error {
_ = client.clientConnection.Close()
admin.state = admin.state.Copy()
admin.state.Clients.Delete(client.Info.Guid)
delete(admin.state.Clients, client.Info.Guid)
delete(admin.clients, client.Info.ClientId)
return nil
}
@ -230,7 +230,7 @@ func (admin *Admin) RemoveClient(client *clientConnection) error {
func (admin *Admin) SetSessionType(clientId models.ClientId, sessionType models.SessionType) {
admin.mutex.Lock()
defer admin.mutex.Unlock()
for client := range admin.state.Clients.RangeValues() {
for _, client := range admin.state.Clients {
if client.ClientId == clientId {
client.SessionType = sessionType
break

View File

@ -134,7 +134,7 @@ func logStatusImpl(admin *models.State, notifier Notifier) {
lines = append(lines, fmt.Sprintf(format, "AGENT", "ACTIVE_SINCE", "EXPIRY_TIME",
"USER", "HOST", "OS"))
for agent := range admin.Agents.RangeValues() {
for _, agent := range admin.Agents {
lines = append(lines, fmt.Sprintf(format, agent.PublicId,
agent.StartTime.Format(time.DateTime),
agent.GetExpiryTime().Format(time.DateTime),
@ -145,7 +145,7 @@ func logStatusImpl(admin *models.State, notifier Notifier) {
lines = append(lines, "")
format = "%-10s %-20s %-20s %-20s %-20s"
lines = append(lines, fmt.Sprintf(format, "CLIENT", "AGENT", "ACTIVE_SINCE", "REMOTE_ADDRESS", "SESSION_TYPE"))
for client := range admin.Clients.RangeValues() {
for _, client := range admin.Clients {
lines = append(lines, fmt.Sprintf(format,
client.ClientId,
client.PublicId,

View File

@ -137,7 +137,8 @@ func (session *WebSession) WriteNotifications(location *time.Location, ctx conte
}
func (session *WebSession) writeNotificationToClient(location *time.Location, notification *models.State) bool {
err := templates.State(notification, location).Render(context.Background(), session.conn)
agents, clients := notification.Slices()
err := templates.State(agents, clients, location).Render(context.Background(), session.conn)
if err != nil {
log.Printf("WS connection closed: %v", err)
return false

View File

@ -7,7 +7,7 @@ import (
)
templ Sessions(state *models.State, loc *time.Location) {
templ Sessions(agents []*models.Agent, clients []*models.Client, loc *time.Location) {
<div>
<div ws-send
hx-trigger="load"
@ -16,8 +16,8 @@ templ Sessions(state *models.State, loc *time.Location) {
<h1>sessions</h1>
<div id="status">
if state != nil {
@State(state, loc)
if len(agents) > 0 {
@State(agents, clients, loc)
} else {
Loading...
}
@ -26,12 +26,12 @@ templ Sessions(state *models.State, loc *time.Location) {
}
templ State(state *models.State, location *time.Location) {
templ State(agents []*models.Agent, clients []*models.Client, location *time.Location) {
<div id="status">
<h3>agents</h3>
if state.Agents.Len() == 0 {
if len(agents) == 0 {
<p>-</p>
} else {
<table class="table">
@ -46,7 +46,7 @@ templ State(state *models.State, location *time.Location) {
<th>shell</th>
</tr>
</thead>
for agent := range state.Agents.RangeValues() {
for _, agent := range agents {
<tr>
<td>{string(agent.PublicId)}</td>
<td>{agent.StartTime.In(location).Format(time.DateTime)}</td>
@ -64,7 +64,7 @@ templ State(state *models.State, location *time.Location) {
<h3>clients</h3>
if state.Clients.Len() == 0 {
if len(clients) == 0 {
<p>-</p>
} else {
<table class="table">
@ -80,7 +80,7 @@ templ State(state *models.State, location *time.Location) {
<th>shell</th>
</tr>
</thead>
for client := range state.Clients.RangeValues() {
for _, client := range clients {
<tr>
<td>{string(client.ClientId)}</td>
<td>{client.StartTime.In(location).Format(time.DateTime)}</td>
@ -98,8 +98,8 @@ templ State(state *models.State, location *time.Location) {
}
templ SessionsTab(state *models.State, loc *time.Location) {
templ SessionsTab(agents []*models.Agent, clients []*models.Client, loc *time.Location) {
@BasePage(4) {
@Sessions(state, loc)
@Sessions(agents, clients, loc)
}
}