2021-10-08 12:39:31 +00:00
|
|
|
// SPDX-FileCopyrightText: 2021 The NGI Pointer Secure-Scuttlebutt Team of 2020/2021
|
|
|
|
//
|
2021-04-09 11:25:40 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
|
|
|
package admin
|
|
|
|
|
|
|
|
import (
|
2021-06-01 12:23:42 +00:00
|
|
|
"errors"
|
2021-04-09 11:25:40 +00:00
|
|
|
"fmt"
|
|
|
|
"net/http"
|
2021-05-31 05:38:52 +00:00
|
|
|
"time"
|
2021-04-09 11:25:40 +00:00
|
|
|
|
2022-11-07 09:18:13 +00:00
|
|
|
refs "github.com/ssbc/go-ssb-refs"
|
2021-04-09 11:25:40 +00:00
|
|
|
"go.mindeco.de/http/render"
|
2021-05-31 05:38:52 +00:00
|
|
|
"go.mindeco.de/log/level"
|
|
|
|
"go.mindeco.de/logging"
|
2021-04-09 11:25:40 +00:00
|
|
|
|
2022-11-07 09:18:13 +00:00
|
|
|
"github.com/ssbc/go-ssb-room/v2/internal/network"
|
|
|
|
"github.com/ssbc/go-ssb-room/v2/roomdb"
|
|
|
|
"github.com/ssbc/go-ssb-room/v2/roomstate"
|
|
|
|
weberrors "github.com/ssbc/go-ssb-room/v2/web/errors"
|
2021-04-09 11:25:40 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type dashboardHandler struct {
|
2021-04-12 09:23:11 +00:00
|
|
|
r *render.Renderer
|
|
|
|
flashes *weberrors.FlashHelper
|
|
|
|
|
2021-04-09 11:25:40 +00:00
|
|
|
roomState *roomstate.Manager
|
2021-04-15 13:24:57 +00:00
|
|
|
netInfo network.ServerEndpointDetails
|
2021-04-09 11:25:40 +00:00
|
|
|
dbs Databases
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h dashboardHandler) overview(w http.ResponseWriter, req *http.Request) (interface{}, error) {
|
2021-05-31 05:38:52 +00:00
|
|
|
var (
|
2021-06-01 12:23:42 +00:00
|
|
|
err error
|
2021-05-31 05:38:52 +00:00
|
|
|
ctx = req.Context()
|
2022-11-07 09:18:13 +00:00
|
|
|
roomRef = h.netInfo.RoomID.String()
|
2021-05-31 05:38:52 +00:00
|
|
|
|
|
|
|
onlineRefs []refs.FeedRef
|
|
|
|
refsUpdateCh = make(chan []refs.FeedRef)
|
|
|
|
onlineCount = -1
|
|
|
|
)
|
|
|
|
|
|
|
|
// this is an attempt to sidestep the _dashboard doesn't render_ bug (issue #210)
|
|
|
|
// first we retreive the member state via a goroutine in the background
|
|
|
|
go func() {
|
|
|
|
refsUpdateCh <- h.roomState.ListAsRefs()
|
|
|
|
}()
|
|
|
|
|
|
|
|
// if it doesn't complete in 10 seconds the slice stays empty and onlineCount remains -1 (to indicate a problem)
|
|
|
|
select {
|
|
|
|
case <-time.After(10 * time.Second):
|
|
|
|
logger := logging.FromContext(ctx)
|
|
|
|
level.Warn(logger).Log("event", "didnt retreive room state in time")
|
|
|
|
|
|
|
|
case onlineRefs = <-refsUpdateCh:
|
|
|
|
onlineCount = len(onlineRefs)
|
|
|
|
}
|
2021-04-15 13:24:57 +00:00
|
|
|
|
2021-05-31 05:38:52 +00:00
|
|
|
// in the timeout case, nothing will happen here since the onlineRefs slice is empty
|
2021-06-01 12:23:42 +00:00
|
|
|
onlineUsers := make([]connectedUser, len(onlineRefs))
|
2021-05-31 05:38:52 +00:00
|
|
|
for i, ref := range onlineRefs {
|
2021-06-01 12:23:42 +00:00
|
|
|
// try to get the member
|
|
|
|
onlineUsers[i].Member, err = h.dbs.Members.GetByFeed(ctx, ref)
|
2021-04-15 13:24:57 +00:00
|
|
|
if err != nil {
|
2021-06-01 12:23:42 +00:00
|
|
|
if !errors.Is(err, roomdb.ErrNotFound) { // any other error can't be handled here
|
|
|
|
return nil, fmt.Errorf("failed to lookup online member: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// if there is no member for this ref present it as role unknown
|
|
|
|
onlineUsers[i].ID = -1
|
|
|
|
onlineUsers[i].PubKey = ref
|
|
|
|
onlineUsers[i].Role = roomdb.RoleUnknown
|
2021-04-15 13:24:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-31 05:38:52 +00:00
|
|
|
memberCount, err := h.dbs.Members.Count(ctx)
|
2021-04-09 11:25:40 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to count members: %w", err)
|
|
|
|
}
|
2021-04-15 13:24:57 +00:00
|
|
|
|
2021-06-12 21:43:04 +00:00
|
|
|
inviteCount, err := h.dbs.Invites.Count(ctx, true)
|
2021-04-09 11:25:40 +00:00
|
|
|
if err != nil {
|
2021-06-10 15:02:16 +00:00
|
|
|
return nil, fmt.Errorf("failed to count active invites: %w", err)
|
2021-04-09 11:25:40 +00:00
|
|
|
}
|
2021-04-15 13:24:57 +00:00
|
|
|
|
2021-05-31 05:38:52 +00:00
|
|
|
deniedCount, err := h.dbs.DeniedKeys.Count(ctx)
|
2021-04-09 11:25:40 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to count denied keys: %w", err)
|
|
|
|
}
|
|
|
|
|
2021-04-12 09:23:11 +00:00
|
|
|
pageData := map[string]interface{}{
|
2021-06-01 12:23:42 +00:00
|
|
|
"RoomRef": roomRef,
|
|
|
|
"OnlineUsers": onlineUsers,
|
|
|
|
"OnlineCount": onlineCount,
|
|
|
|
"MemberCount": memberCount,
|
|
|
|
"InviteCount": inviteCount,
|
|
|
|
"DeniedCount": deniedCount,
|
2021-04-12 09:23:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pageData["Flashes"], err = h.flashes.GetAll(w, req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return pageData, nil
|
2021-04-09 11:25:40 +00:00
|
|
|
}
|
2021-06-01 12:23:42 +00:00
|
|
|
|
|
|
|
// connectedUser defines how we want to present a connected user
|
|
|
|
type connectedUser struct {
|
|
|
|
roomdb.Member
|
|
|
|
}
|
|
|
|
|
|
|
|
// if the member has an alias, use the first one. Otherwise use the public key
|
|
|
|
func (dm connectedUser) String() string {
|
|
|
|
if len(dm.Aliases) > 0 {
|
|
|
|
return dm.Aliases[0].Name
|
|
|
|
}
|
2022-11-07 09:18:13 +00:00
|
|
|
return dm.PubKey.String()
|
2021-06-01 12:23:42 +00:00
|
|
|
}
|