online cache

pull/2393/head
withchao 1 year ago
parent 28c8b78b31
commit 6e2659c64a

@ -60,7 +60,7 @@ type WsServer struct {
registerChan chan *Client registerChan chan *Client
unregisterChan chan *Client unregisterChan chan *Client
kickHandlerChan chan *kickHandler kickHandlerChan chan *kickHandler
clients UMap clients UserMap
clientPool sync.Pool clientPool sync.Pool
onlineUserNum atomic.Int64 onlineUserNum atomic.Int64
onlineUserConnNum atomic.Int64 onlineUserConnNum atomic.Int64

@ -1,40 +1,32 @@
// Copyright © 2023 OpenIM. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package msggateway package msggateway
import ( import (
"context" "github.com/openimsdk/tools/utils/datautil"
"sync" "sync"
"time" "time"
"github.com/openimsdk/tools/log"
"github.com/openimsdk/tools/utils/datautil"
) )
func newUserMap1() UMap { type UserMap interface {
return &UserMap{ GetAll(userID string) ([]*Client, bool)
ch: make(chan UserState, 1024), Get(userID string, platformID int) ([]*Client, bool, bool)
} Set(userID string, v *Client)
DeleteClients(userID string, clients []*Client) (isDeleteUser bool)
UserState() <-chan UserState
GetAllUserStatus(deadline time.Time, nowtime time.Time) []UserState
} }
type UserPlatform1 struct { type UserState struct {
UserID string
Online []int32
Offline []int32
}
type UserPlatform struct {
Time time.Time Time time.Time
Clients []*Client Clients []*Client
} }
func (u *UserPlatform1) PlatformIDs() []int32 { func (u *UserPlatform) PlatformIDs() []int32 {
if len(u.Clients) == 0 { if len(u.Clients) == 0 {
return nil return nil
} }
@ -45,36 +37,20 @@ func (u *UserPlatform1) PlatformIDs() []int32 {
return platformIDs return platformIDs
} }
type UserMap struct { func newUserMap() UserMap {
m sync.Map return &userMap{
ch chan UserState data: make(map[string]*UserPlatform),
} ch: make(chan UserState, 10000),
}
func (u *UserMap) UserState() <-chan UserState {
return u.ch
} }
func (u *UserMap) GetAllUserStatus(deadline time.Time, nowtime time.Time) []UserState { type userMap struct {
var result []UserState lock sync.RWMutex
u.m.Range(func(key, value any) bool { data map[string]*UserPlatform
client := value.(*UserPlatform1) ch chan UserState
if client.Time.Before(deadline) {
return true
}
client.Time = nowtime
us := UserState{
UserID: key.(string),
Online: make([]int32, 0, len(client.Clients)),
}
for _, c := range client.Clients {
us.Online = append(us.Online, int32(c.PlatformID))
}
return true
})
return result
} }
func (u *UserMap) push(userID string, userPlatform *UserPlatform1, offline []int32) bool { func (u *userMap) push(userID string, userPlatform *UserPlatform, offline []int32) bool {
select { select {
case u.ch <- UserState{UserID: userID, Online: userPlatform.PlatformIDs(), Offline: offline}: case u.ch <- UserState{UserID: userID, Online: userPlatform.PlatformIDs(), Offline: offline}:
userPlatform.Time = time.Now() userPlatform.Time = time.Now()
@ -84,83 +60,95 @@ func (u *UserMap) push(userID string, userPlatform *UserPlatform1, offline []int
} }
} }
func (u *UserMap) GetAll(key string) ([]*Client, bool) { func (u *userMap) GetAll(userID string) ([]*Client, bool) {
allClients, ok := u.m.Load(key) u.lock.RLock()
if ok { defer u.lock.RUnlock()
return allClients.(*UserPlatform1).Clients, ok result, ok := u.data[userID]
if !ok {
return nil, false
} }
return nil, ok return result.Clients, true
} }
func (u *UserMap) Get(key string, platformID int) ([]*Client, bool, bool) { func (u *userMap) Get(userID string, platformID int) ([]*Client, bool, bool) {
allClients, userExisted := u.m.Load(key) u.lock.RLock()
if userExisted { defer u.lock.RUnlock()
var clients []*Client result, ok := u.data[userID]
for _, client := range allClients.(*UserPlatform1).Clients { if !ok {
if client.PlatformID == platformID { return nil, false, false
clients = append(clients, client) }
} var clients []*Client
} for _, client := range result.Clients {
if len(clients) > 0 { if client.PlatformID == platformID {
return clients, true, true clients = append(clients, client)
} }
return clients, true, false
} }
return nil, false, false return clients, true, len(clients) > 0
} }
// Set adds a client to the map. func (u *userMap) Set(userID string, client *Client) {
func (u *UserMap) Set(key string, v *Client) { u.lock.Lock()
allClients, existed := u.m.Load(key) defer u.lock.Unlock()
if existed { result, ok := u.data[userID]
log.ZDebug(context.Background(), "Set existed", "user_id", key, "client_user_id", v.UserID) if ok {
oldClients := allClients.(*UserPlatform1) result.Clients = append(result.Clients, client)
oldClients.Time = time.Now()
oldClients.Clients = append(oldClients.Clients, v)
u.push(key, oldClients, nil)
} else { } else {
log.ZDebug(context.Background(), "Set not existed", "user_id", key, "client_user_id", v.UserID) result = &UserPlatform{
cli := &UserPlatform1{ Clients: []*Client{client},
Time: time.Now(),
Clients: []*Client{v},
} }
u.m.Store(key, cli) u.data[userID] = result
u.push(key, cli, nil)
} }
u.push(client.UserID, result, nil)
} }
func (u *UserMap) DeleteClients(key string, clients []*Client) (isDeleteUser bool) { func (u *userMap) DeleteClients(userID string, clients []*Client) (isDeleteUser bool) {
m := datautil.SliceToMapAny(clients, func(c *Client) (string, struct{}) { if len(clients) == 0 {
return c.ctx.GetRemoteAddr(), struct{}{}
})
allClients, existed := u.m.Load(key)
if !existed {
// If the key doesn't exist, return false.
return false return false
} }
u.lock.Lock()
// Filter out clients that are in the deleteMap. defer u.lock.Unlock()
oldClients := allClients.(*UserPlatform1) result, ok := u.data[userID]
var ( if !ok {
remainingClients []*Client return false
offline []int32 }
) offline := make([]int32, 0, len(clients))
for _, client := range oldClients.Clients { deleteAddr := datautil.SliceSetAny(clients, func(client *Client) string {
if _, shouldBeDeleted := m[client.ctx.GetRemoteAddr()]; !shouldBeDeleted { return client.ctx.GetRemoteAddr()
remainingClients = append(remainingClients, client) })
} else { tmp := result.Clients
offline = append(offline, int32(client.PlatformID)) result.Clients = result.Clients[:0]
for _, client := range tmp {
if _, ok := deleteAddr[client.ctx.GetRemoteAddr()]; ok {
continue
} }
result.Clients = append(result.Clients, client)
} }
defer u.push(userID, result, offline)
if len(result.Clients) > 0 {
return false
}
delete(u.data, userID)
return true
}
oldClients.Clients = remainingClients func (u *userMap) GetAllUserStatus(deadline time.Time, nowtime time.Time) []UserState {
defer u.push(key, oldClients, offline) u.lock.RLock()
// Update or delete the key based on the remaining clients. defer u.lock.RUnlock()
if len(remainingClients) == 0 { result := make([]UserState, 0, len(u.data))
u.m.Delete(key) for userID, userPlatform := range u.data {
return true if userPlatform.Time.Before(deadline) {
continue
}
userPlatform.Time = nowtime
online := make([]int32, 0, len(userPlatform.Clients))
for _, client := range userPlatform.Clients {
online = append(online, int32(client.PlatformID))
}
result = append(result, UserState{UserID: userID, Online: online})
} }
return result
}
return false func (u *userMap) UserState() <-chan UserState {
return u.ch
} }

@ -1,161 +0,0 @@
package msggateway
import (
"context"
"github.com/openimsdk/tools/log"
"github.com/openimsdk/tools/utils/datautil"
"sync"
"time"
)
type UMap interface {
GetAll(userID string) ([]*Client, bool)
Get(userID string, platformID int) ([]*Client, bool, bool)
Set(userID string, v *Client)
DeleteClients(userID string, clients []*Client) (isDeleteUser bool)
UserState() <-chan UserState
GetAllUserStatus(deadline time.Time, nowtime time.Time) []UserState
}
var _ UMap = (*userMap)(nil)
type UserPlatform struct {
Time time.Time
Clients []*Client
}
func (u *UserPlatform) PlatformIDs() []int32 {
if len(u.Clients) == 0 {
return nil
}
platformIDs := make([]int32, 0, len(u.Clients))
for _, client := range u.Clients {
platformIDs = append(platformIDs, int32(client.PlatformID))
}
return platformIDs
}
func newUserMap() UMap {
return &userMap{
data: make(map[string]*UserPlatform),
ch: make(chan UserState, 10000),
}
}
type userMap struct {
lock sync.RWMutex
data map[string]*UserPlatform
ch chan UserState
}
func (u *userMap) push(userID string, userPlatform *UserPlatform, offline []int32) bool {
select {
case u.ch <- UserState{UserID: userID, Online: userPlatform.PlatformIDs(), Offline: offline}:
userPlatform.Time = time.Now()
return true
default:
return false
}
}
func (u *userMap) GetAll(userID string) ([]*Client, bool) {
log.ZInfo(context.Background(), "UserMap GetAll", "userID", userID)
u.lock.RLock()
defer u.lock.RUnlock()
result, ok := u.data[userID]
if !ok {
return nil, false
}
return result.Clients, true
}
func (u *userMap) Get(userID string, platformID int) ([]*Client, bool, bool) {
log.ZInfo(context.Background(), "UserMap Get", "userID", userID, "platformID", platformID)
u.lock.RLock()
defer u.lock.RUnlock()
result, ok := u.data[userID]
if !ok {
return nil, false, false
}
var clients []*Client
for _, client := range result.Clients {
if client.PlatformID == platformID {
clients = append(clients, client)
}
}
return clients, true, len(clients) > 0
}
func (u *userMap) Set(userID string, client *Client) {
log.ZInfo(context.Background(), "UserMap Set", "userID", userID, "client", client.ctx.GetRemoteAddr())
u.lock.Lock()
defer u.lock.Unlock()
result, ok := u.data[userID]
if ok {
result.Clients = append(result.Clients, client)
} else {
result = &UserPlatform{
Clients: []*Client{client},
}
}
u.push(client.UserID, result, nil)
}
func (u *userMap) DeleteClients(userID string, clients []*Client) (isDeleteUser bool) {
log.ZInfo(context.Background(), "UserMap DeleteClients", "userID", userID, "client", len(clients))
if len(clients) == 0 {
return false
}
u.lock.Lock()
defer u.lock.Unlock()
result, ok := u.data[userID]
if !ok {
return false
}
offline := make([]int32, 0, len(clients))
deleteAddr := datautil.SliceSetAny(clients, func(client *Client) string {
return client.ctx.GetRemoteAddr()
})
tmp := result.Clients
result.Clients = result.Clients[:0]
for _, client := range tmp {
if _, ok := deleteAddr[client.ctx.GetRemoteAddr()]; ok {
continue
}
result.Clients = append(result.Clients, client)
}
defer u.push(userID, result, offline)
if len(result.Clients) > 0 {
return false
}
delete(u.data, userID)
return true
}
func (u *userMap) GetAllUserStatus(deadline time.Time, nowtime time.Time) []UserState {
u.lock.RLock()
defer u.lock.RUnlock()
result := make([]UserState, 0, len(u.data))
for userID, userPlatform := range u.data {
if userPlatform.Time.Before(deadline) {
continue
}
userPlatform.Time = nowtime
online := make([]int32, 0, len(userPlatform.Clients))
for _, client := range userPlatform.Clients {
online = append(online, int32(client.PlatformID))
}
result = append(result, UserState{UserID: userID, Online: online})
}
return result
}
func (u *userMap) UserState() <-chan UserState {
return u.ch
}
type UserState struct {
UserID string
Online []int32
Offline []int32
}
Loading…
Cancel
Save