show past sessions in UI

This commit is contained in:
1e99 2025-04-12 11:31:16 +02:00
parent 4e73711018
commit 653fc133ce
7 changed files with 112 additions and 35 deletions

12
a
View file

@ -1,12 +0,0 @@
2025/04/12 11:09:47 No "WOLBODGE_ADDRESS" provided, defaulting to ":3000"
2025/04/12 11:09:47 No "WOLBODGE_DEVICE_TYPE" provided, defaulting to "test"
2025/04/12 11:09:47 No "WOLBODGE_STORAGE_TYPE" provided, defaulting to "mem"
2025/04/12 11:09:47 Using device: test
2025/04/12 11:09:47 Using session storage: mem
2025/04/12 11:09:47 Listening on :3000
2025/04/12 11:09:51 No "WOLBODGE_ADDRESS" provided, defaulting to ":3000"
2025/04/12 11:09:51 No "WOLBODGE_DEVICE_TYPE" provided, defaulting to "test"
2025/04/12 11:09:51 No "WOLBODGE_STORAGE_TYPE" provided, defaulting to "mem"
2025/04/12 11:09:51 Using device: test
2025/04/12 11:09:51 Using session storage: mem
2025/04/12 11:09:51 Listening on :3000

View file

@ -63,7 +63,7 @@
</thead> </thead>
<tbody> <tbody>
{{ range $session := .Sessions }} {{ range $session := .ActiveSessions }}
<tr> <tr>
<td>{{ $session.Id }}</td> <td>{{ $session.Id }}</td>
<td>{{ $session.Description }}</td> <td>{{ $session.Description }}</td>
@ -79,6 +79,29 @@
{{ end }} {{ end }}
</tbody> </tbody>
</table> </table>
<h2>Past sessions</h2>
<table>
<thead>
<tr>
<th style="width: 10%">ID</th>
<th style="width: 50%">Description</th>
<th style="width: 20%">Created at</th>
<th style="width: 20%">Ended at</th>
</tr>
</thead>
<tbody>
{{ range $session := .PastSessions }}
<tr>
<td>{{ $session.Id }}</td>
<td>{{ $session.Description }}</td>
<td>{{ $session.CreatedAt.Format "02.01.2006 15:04:05" }}</td>
<td>{{ $session.EndedAt.Format "02.01.2006 15:04:05" }}</td>
</tr>
{{ end }}
</tbody>
</table>
</div> </div>
</main> </main>
</body> </body>

14
main.go
View file

@ -53,7 +53,19 @@ func Run() error {
mux.Handle("DELETE /api/session/{session_id}", routes.APIEndSession(logger, storage)) mux.Handle("DELETE /api/session/{session_id}", routes.APIEndSession(logger, storage))
exit := make(chan bool) exit := make(chan bool)
go devices.KeepDeviceInSync(logger, device, storage.HasSessions, exit) go devices.KeepDeviceInSync(
logger,
device,
func() (bool, error) {
sessions, err := storage.GetActiveSessions()
if err != nil {
return false, err
}
return len(sessions) != 0, nil
},
exit,
)
var handler http.Handler = mux var handler http.Handler = mux
if logRequests { if logRequests {

View file

@ -38,7 +38,7 @@ func APIEndSession(logger *log.Logger, storage sessions.Storage) http.HandlerFun
return func(res http.ResponseWriter, req *http.Request) { return func(res http.ResponseWriter, req *http.Request) {
sessionId := req.PathValue("session_id") sessionId := req.PathValue("session_id")
err := storage.EndSession(sessionId) err := storage.EndSession(sessionId, time.Now())
switch { switch {
case err == sessions.ErrUnknownSession: case err == sessions.ErrUnknownSession:
http.Error(res, "", http.StatusNotFound) http.Error(res, "", http.StatusNotFound)

View file

@ -18,14 +18,20 @@ func GetIndex(device devices.Device, storage sessions.Storage, tmpl *template.Te
return return
} }
sessions, err := storage.GetSessions() activeSessions, err := storage.GetActiveSessions()
if err != nil {
return
}
pastSessions, err := storage.GetPastSessions()
if err != nil { if err != nil {
return return
} }
tmpl.Execute(res, map[string]any{ tmpl.Execute(res, map[string]any{
"DeviceStatus": status, "DeviceStatus": status,
"Sessions": sessions, "ActiveSessions": activeSessions,
"PastSessions": pastSessions,
}) })
} }
} }
@ -63,7 +69,7 @@ func EndSession(logger *log.Logger, storage sessions.Storage) http.HandlerFunc {
} }
sessionId := req.FormValue("session_id") sessionId := req.FormValue("session_id")
err = storage.EndSession(sessionId) err = storage.EndSession(sessionId, time.Now())
switch { switch {
case err == sessions.ErrUnknownSession: case err == sessions.ErrUnknownSession:
http.Error(res, "", http.StatusNotFound) http.Error(res, "", http.StatusNotFound)

View file

@ -21,22 +21,44 @@ type memStorage struct {
lock sync.Mutex lock sync.Mutex
} }
func (s *memStorage) HasSessions() (bool, error) { func (s *memStorage) GetAllSessions() ([]Session, error) {
s.lock.Lock()
defer s.lock.Unlock()
return len(s.sessions) > 0, nil
}
func (s *memStorage) GetSessions() ([]Session, error) {
s.lock.Lock() s.lock.Lock()
defer s.lock.Unlock() defer s.lock.Unlock()
sessions := make([]Session, len(s.sessions)) sessions := make([]Session, len(s.sessions))
id := 0 i := 0
for _, session := range s.sessions { for _, session := range s.sessions {
sessions[id] = session sessions[i] = session
id += 1 i += 1
}
return sessions, nil
}
func (s *memStorage) GetActiveSessions() ([]Session, error) {
s.lock.Lock()
defer s.lock.Unlock()
sessions := make([]Session, 0)
for _, session := range s.sessions {
if session.EndedAt.IsZero() {
sessions = append(sessions, session)
}
}
return sessions, nil
}
func (s *memStorage) GetPastSessions() ([]Session, error) {
s.lock.Lock()
defer s.lock.Unlock()
sessions := make([]Session, 0)
for _, session := range s.sessions {
if !session.EndedAt.IsZero() {
sessions = append(sessions, session)
}
} }
return sessions, nil return sessions, nil
@ -54,13 +76,28 @@ func (s *memStorage) StartSession(description string, createdAt time.Time) (Sess
Id: id, Id: id,
Description: description, Description: description,
CreatedAt: createdAt, CreatedAt: createdAt,
EndedAt: time.Time{}, // This is the zero time
} }
s.sessions[id] = session s.sessions[id] = session
return session, nil return session, nil
} }
func (s *memStorage) EndSession(id string) error { func (s *memStorage) EndSession(id string, endedAt time.Time) error {
s.lock.Lock()
defer s.lock.Unlock()
session, found := s.sessions[id]
if !found {
return ErrUnknownSession
}
session.EndedAt = endedAt
s.sessions[id] = session
return nil
}
func (s *memStorage) DeleteSession(id string) error {
s.lock.Lock() s.lock.Lock()
defer s.lock.Unlock() defer s.lock.Unlock()

View file

@ -10,6 +10,9 @@ type Session struct {
Id string Id string
Description string Description string
CreatedAt time.Time CreatedAt time.Time
// Should be set to a zero time if the session is still active
EndedAt time.Time
} }
func (s *Session) ExistsFor() time.Duration { func (s *Session) ExistsFor() time.Duration {
@ -21,18 +24,26 @@ var (
) )
type Storage interface { type Storage interface {
// Check if the storage contains any sessions.
HasSessions() (bool, error)
// List all sessions. // List all sessions.
GetSessions() ([]Session, error) GetAllSessions() ([]Session, error)
// List all active sessions.
GetActiveSessions() ([]Session, error)
// List all past sessions.
GetPastSessions() ([]Session, error)
// Start a new session. // Start a new session.
StartSession(description string, createdAt time.Time) (Session, error) StartSession(description string, createdAt time.Time) (Session, error)
// End an old session. // End an old session.
// Should update a session's [EndedAt] property.
// Should return [ErrUnknownSession] if the session couldn't be found. // Should return [ErrUnknownSession] if the session couldn't be found.
EndSession(id string) error EndSession(id string, endedAt time.Time) error
// Delete a session.
// Should return [ErrUnknownSession] if the session couldn't be found.
DeleteSession(id string) error
fmt.Stringer fmt.Stringer
} }