1
0
Fork 0
mirror of https://codeberg.org/june64/mrvc.git synced 2026-01-10 16:06:33 +01:00
mrvc/roominfotree/roominfotree.go
June 9441eef002
move building of homeservers array into separate function
Move building of homeservers array into separate function to make Get
function easier to follow.
2025-08-17 23:05:42 +02:00

181 lines
5.2 KiB
Go

package roominfotree
import (
"context"
"log"
"sync"
"github.com/matrix-org/gomatrixserverlib/fclient"
"github.com/matrix-org/gomatrixserverlib/spec"
"maunium.net/go/mautrix"
"maunium.net/go/mautrix/id"
)
type homeserverServerVersionInfo struct {
homeserver string
serverVersionInfo fclient.Version
}
type RoomInfoTree map[id.RoomID](*RoomInfo)
type RoomInfo struct {
MemberCount uint
MaxRoomVersions map[string](*MaxRoomVersionInfo)
}
type MaxRoomVersionInfo struct {
MemberCount uint
Servers map[string](*ServerInfo)
}
type ServerInfo struct {
MemberCount uint
Versions map[string](*VersionInfo)
}
type VersionInfo struct {
MemberCount uint
Homeservers map[string](*HomeserverInfo)
}
type HomeserverInfo struct {
MemberCount uint
}
var unknownServerVersionInfo = fclient.Version{
Server: struct {
Name string `json:"name"`
Version string `json:"version"`
}{
Name: "unknown",
Version: "unknown",
},
}
func getMembersByHomeserverByRoomID(roomIDs []id.RoomID, client *mautrix.Client) map[id.RoomID](map[string]uint) {
joinedMembersByRoomID := make(map[id.RoomID]*mautrix.RespJoinedMembers)
for _, roomID := range roomIDs {
joinedMembers, err := client.JoinedMembers(context.Background(), roomID)
if err != nil {
log.Fatal(err)
}
joinedMembersByRoomID[roomID] = joinedMembers
}
membersByHomeserverByRoomID := make(map[id.RoomID](map[string]uint))
for roomID, joinedMembers := range joinedMembersByRoomID {
membersByHomeserver := make(map[string]uint)
for userID := range joinedMembers.Joined {
membersByHomeserver[userID.Homeserver()]++
}
membersByHomeserverByRoomID[roomID] = membersByHomeserver
}
return membersByHomeserverByRoomID
}
// Gets the homeservers appearing in the given membersByHomeserverByRoomID map tree.
func getHomeservers(membersByHomeserverByRoomID map[id.RoomID]map[string]uint) []string {
homeserverSet := make(map[string]bool)
for _, membersByHomeserver := range membersByHomeserverByRoomID {
for hs := range membersByHomeserver {
homeserverSet[hs] = true
}
}
homeservers := make([]string, 0, len(homeserverSet))
for hs := range homeserverSet {
homeservers = append(homeservers, hs)
}
return homeservers
}
func getServerVersionInfoByHomeserver(homeservers []string, federationClient *fclient.Client) map[string](fclient.Version) {
homeserverChannel := make(chan string)
go func() {
for _, hs := range homeservers {
homeserverChannel <- hs
}
close(homeserverChannel)
}()
homeserverSVInfoChannel := make(chan homeserverServerVersionInfo)
var wg sync.WaitGroup
const numHomeserverSVInfoReceivers = 100
wg.Add(numHomeserverSVInfoReceivers)
for i := 0; i < numHomeserverSVInfoReceivers; i++ {
go func() {
for hs := range homeserverChannel {
serverVersionInfo, err := federationClient.GetVersion(context.Background(), spec.ServerName(hs))
if err != nil {
serverVersionInfo = unknownServerVersionInfo
}
homeserverSVInfoChannel <- homeserverServerVersionInfo{hs, serverVersionInfo}
}
wg.Done()
}()
}
go func() {
wg.Wait()
close(homeserverSVInfoChannel)
}()
serverVersionInfoByHomeserver := make(map[string](fclient.Version))
for homeserverSVInfo := range homeserverSVInfoChannel {
serverVersionInfoByHomeserver[homeserverSVInfo.homeserver] = homeserverSVInfo.serverVersionInfo
}
return serverVersionInfoByHomeserver
}
func Get(roomIDs []id.RoomID, client *mautrix.Client, federationClient *fclient.Client) RoomInfoTree {
membersByHomeserverByRoomID := getMembersByHomeserverByRoomID(roomIDs, client)
homeservers := getHomeservers(membersByHomeserverByRoomID)
serverVersionInfoByHomeserver := getServerVersionInfoByHomeserver(homeservers, federationClient)
roomInfoTree := make(RoomInfoTree)
for roomID, membersByHomeserver := range membersByHomeserverByRoomID {
for hs, members := range membersByHomeserver {
serverVersionInfo := serverVersionInfoByHomeserver[hs]
maxRoomVersion := getMaxRoomVersion(serverVersionInfo)
// Sort into roomInfoTree and add to counters.
roomInfo, ok := roomInfoTree[roomID]
if !ok {
roomInfo = &RoomInfo{MaxRoomVersions: make(map[string]*MaxRoomVersionInfo)}
roomInfoTree[roomID] = roomInfo
}
maxRoomVersionInfo, ok := roomInfo.MaxRoomVersions[maxRoomVersion]
if !ok {
maxRoomVersionInfo = &MaxRoomVersionInfo{Servers: make(map[string]*ServerInfo)}
roomInfo.MaxRoomVersions[maxRoomVersion] = maxRoomVersionInfo
}
serverInfo, ok := maxRoomVersionInfo.Servers[serverVersionInfo.Server.Name]
if !ok {
serverInfo = &ServerInfo{Versions: make(map[string]*VersionInfo)}
maxRoomVersionInfo.Servers[serverVersionInfo.Server.Name] = serverInfo
}
versionInfo, ok := serverInfo.Versions[serverVersionInfo.Server.Version]
if !ok {
versionInfo = &VersionInfo{Homeservers: make(map[string]*HomeserverInfo)}
serverInfo.Versions[serverVersionInfo.Server.Version] = versionInfo
}
homeserverInfo, ok := versionInfo.Homeservers[hs]
if !ok {
homeserverInfo = &HomeserverInfo{}
versionInfo.Homeservers[hs] = homeserverInfo
}
homeserverInfo.MemberCount = members
versionInfo.MemberCount += members
serverInfo.MemberCount += members
maxRoomVersionInfo.MemberCount += members
roomInfo.MemberCount += members
}
}
return roomInfoTree
}