Apply .gitignore rules
This commit is contained in:
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
未实现的哈希表方法:
|
||||
MOVE、SCAN、SORT、FLUSHDB、FLUSHALL、SELECT、SWAPDB
|
||||
*/
|
||||
package redisUtil
|
||||
|
||||
import (
|
||||
"github.com/gomodule/redigo/redis"
|
||||
)
|
||||
|
||||
/*
|
||||
EXPIRE key seconds
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(1)
|
||||
为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。
|
||||
|
||||
在 Redis 中,带有生存时间的 key 被称为『易失的』(volatile)。
|
||||
|
||||
生存时间可以通过使用 DEL 命令来删除整个 key 来移除,或者被 SET 和 GETSET 命令覆写(overwrite),这意味着,如果一个命令只是修改(alter)一个带生存时间的 key 的值而不是用一个新的 key 值来代替(replace)它的话,那么生存时间不会被改变。
|
||||
|
||||
比如说,对一个 key 执行 INCR 命令,对一个列表进行 LPUSH 命令,或者对一个哈希表执行 HSET 命令,这类操作都不会修改 key 本身的生存时间。
|
||||
|
||||
另一方面,如果使用 RENAME 对一个 key 进行改名,那么改名后的 key 的生存时间和改名前一样。
|
||||
|
||||
RENAME 命令的另一种可能是,尝试将一个带生存时间的 key 改名成另一个带生存时间的 another_key ,这时旧的 another_key (以及它的生存时间)会被删除,然后旧的 key 会改名为 another_key ,因此,新的 another_key 的生存时间也和原本的 key 一样。
|
||||
|
||||
使用 PERSIST 命令可以在不删除 key 的情况下,移除 key 的生存时间,让 key 重新成为一个『持久的』(persistent) key 。
|
||||
|
||||
更新生存时间
|
||||
可以对一个已经带有生存时间的 key 执行 EXPIRE 命令,新指定的生存时间会取代旧的生存时间。
|
||||
|
||||
过期时间的精确度
|
||||
在 Redis 2.4 版本中,过期时间的延迟在 1 秒钟之内 —— 也即是,就算 key 已经过期,但它还是可能在过期之后一秒钟之内被访问到,而在新的 Redis 2.6 版本中,延迟被降低到 1 毫秒之内。
|
||||
|
||||
Redis 2.1.3 之前的不同之处
|
||||
在 Redis 2.1.3 之前的版本中,修改一个带有生存时间的 key 会导致整个 key 被删除,这一行为是受当时复制(replication)层的限制而作出的,现在这一限制已经被修复。
|
||||
|
||||
返回值
|
||||
设置成功返回 1 。 当 key 不存在或者不能为 key 设置生存时间时(比如在低于 2.1.3 版本的 Redis 中你尝试更新 key 的生存时间),返回 0 。
|
||||
*/
|
||||
func (this *RedisPool) Expire(key string, seconds int64) (successful bool, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
var result int
|
||||
if result, err = redis.Int(conn.Do("EXPIRE", key, seconds)); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if result == 1 {
|
||||
successful = true
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
EXPIREAT key timestamp
|
||||
可用版本: >= 1.2.0
|
||||
时间复杂度: O(1)
|
||||
EXPIREAT 的作用和 EXPIRE 类似,都用于为 key 设置生存时间。
|
||||
|
||||
不同在于 EXPIREAT 命令接受的时间参数是 UNIX 时间戳(unix timestamp)。
|
||||
|
||||
返回值
|
||||
如果生存时间设置成功,返回 1 ; 当 key 不存在或没办法设置生存时间,返回 0 。
|
||||
*/
|
||||
func (this *RedisPool) ExpireAt(key string, timestamp int64) (successful bool, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
var result int
|
||||
if result, err = redis.Int(conn.Do("EXPIREAT", key, timestamp)); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if result == 1 {
|
||||
successful = true
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
TTL key
|
||||
可用版本: >= 1.0.0
|
||||
时间复杂度: O(1)
|
||||
以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)。
|
||||
|
||||
返回值
|
||||
当 key 不存在时,返回 -2 。 当 key 存在但没有设置剩余生存时间时,返回 -1 。 否则,以秒为单位,返回 key 的剩余生存时间。
|
||||
|
||||
Note
|
||||
|
||||
在 Redis 2.8 以前,当 key 不存在,或者 key 没有设置剩余生存时间时,命令都返回 -1 。
|
||||
*/
|
||||
func (this *RedisPool) TTL(key string) (ttl int64, exist, persisted bool, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
ttl, err = redis.Int64(conn.Do("TTL", key))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if ttl == -2 {
|
||||
exist = false
|
||||
persisted = false
|
||||
} else if ttl == -1 {
|
||||
exist = true
|
||||
persisted = true
|
||||
} else {
|
||||
exist = true
|
||||
persisted = false
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
PERSIST key
|
||||
可用版本: >= 2.2.0
|
||||
时间复杂度: O(1)
|
||||
移除给定 key 的生存时间,将这个 key 从“易失的”(带生存时间 key )转换成“持久的”(一个不带生存时间、永不过期的 key )。
|
||||
|
||||
返回值
|
||||
当生存时间移除成功时,返回 1 . 如果 key 不存在或 key 没有设置生存时间,返回 0 。
|
||||
*/
|
||||
func (this *RedisPool) Persist(key string) (successful bool, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
var result int
|
||||
if result, err = redis.Int(conn.Do("PERSIST", key)); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if result == 1 {
|
||||
successful = true
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
PEXPIRE key milliseconds
|
||||
可用版本: >= 2.6.0
|
||||
时间复杂度: O(1)
|
||||
这个命令和 EXPIRE 命令的作用类似,但是它以毫秒为单位设置 key 的生存时间,而不像 EXPIRE 命令那样,以秒为单位。
|
||||
|
||||
返回值
|
||||
设置成功,返回 1 key 不存在或设置失败,返回 0
|
||||
*/
|
||||
func (this *RedisPool) PExpire(key string, milliseconds int64) (successful bool, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
var result int
|
||||
if result, err = redis.Int(conn.Do("PEXPIRE", key, milliseconds)); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if result == 1 {
|
||||
successful = true
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
PEXPIREAT key milliseconds-timestamp
|
||||
可用版本: >= 2.6.0
|
||||
时间复杂度: O(1)
|
||||
这个命令和 expireat 命令类似,但它以毫秒为单位设置 key 的过期 unix 时间戳,而不是像 expireat 那样,以秒为单位。
|
||||
|
||||
返回值
|
||||
如果生存时间设置成功,返回 1 。 当 key 不存在或没办法设置生存时间时,返回 0 。(查看 EXPIRE key seconds 命令获取更多信息)
|
||||
*/
|
||||
func (this *RedisPool) PExpireAt(key string, milliseconds_timestamp int64) (successful bool, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
var result int
|
||||
if result, err = redis.Int(conn.Do("PEXPIREAT", key, milliseconds_timestamp)); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if result == 1 {
|
||||
successful = true
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
PTTL key
|
||||
可用版本: >= 2.6.0
|
||||
复杂度: O(1)
|
||||
这个命令类似于 TTL 命令,但它以毫秒为单位返回 key 的剩余生存时间,而不是像 TTL 命令那样,以秒为单位。
|
||||
|
||||
返回值
|
||||
当 key 不存在时,返回 -2 。
|
||||
|
||||
当 key 存在但没有设置剩余生存时间时,返回 -1 。
|
||||
|
||||
否则,以毫秒为单位,返回 key 的剩余生存时间。
|
||||
|
||||
Note
|
||||
|
||||
在 Redis 2.8 以前,当 key 不存在,或者 key 没有设置剩余生存时间时,命令都返回 -1 。
|
||||
*/
|
||||
func (this *RedisPool) PTTL(key string) (pttl int64, exist bool, persisted bool, err error) {
|
||||
conn := this.GetConnection()
|
||||
defer conn.Close()
|
||||
|
||||
pttl, err = redis.Int64(conn.Do("PTTL", key))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if pttl == -2 {
|
||||
exist = false
|
||||
persisted = false
|
||||
} else if pttl == -1 {
|
||||
exist = true
|
||||
persisted = true
|
||||
} else {
|
||||
exist = true
|
||||
persisted = false
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 查找 adminServer 的 PID
|
||||
PID=$(pgrep adminServer)
|
||||
|
||||
if [ -z "$PID" ]; then
|
||||
echo "adminServer 进程未找到"
|
||||
else
|
||||
echo "停止中... (PID: $PID)"
|
||||
kill $PID
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "adminServer 进程已终止 (PID: $PID)"
|
||||
else
|
||||
echo "无法终止 adminServer 进程 (PID: $PID)"
|
||||
fi
|
||||
fi
|
||||
@@ -0,0 +1,52 @@
|
||||
package logUtil
|
||||
|
||||
// ILog
|
||||
// @description: 日志接口
|
||||
type ILog interface {
|
||||
// InfoLog
|
||||
// @description: 信息日志记录
|
||||
// parameter:
|
||||
// @format:日志格式
|
||||
// @args:参数列表
|
||||
// return:
|
||||
InfoLog(format string, args ...interface{})
|
||||
|
||||
// DebugLog
|
||||
// @description: 调试日志记录
|
||||
// parameter:
|
||||
// @format:日志格式
|
||||
// @args:参数列表
|
||||
// return:
|
||||
DebugLog(format string, args ...interface{})
|
||||
|
||||
// WarnLog
|
||||
// @description: 警告日志记录
|
||||
// parameter:
|
||||
// @format:日志格式
|
||||
// @args:参数列表
|
||||
// return:
|
||||
WarnLog(format string, args ...interface{})
|
||||
|
||||
// ErrorLog
|
||||
// @description: 错误日志记录
|
||||
// parameter:
|
||||
// @format:日志格式
|
||||
// @args:参数列表
|
||||
// return:
|
||||
ErrorLog(format string, args ...interface{})
|
||||
|
||||
// FatalLog
|
||||
// @description: 致命错误日志记录
|
||||
// parameter:
|
||||
// @format:日志格式
|
||||
// @args:参数列表
|
||||
// return:
|
||||
FatalLog(format string, args ...interface{})
|
||||
|
||||
// CloseLog
|
||||
// @description: 关闭日志
|
||||
// parameter:
|
||||
// @waitFinish:是否等待日志
|
||||
// return:
|
||||
CloseLog(waitFinish bool)
|
||||
}
|
||||
@@ -0,0 +1,450 @@
|
||||
// ************************************
|
||||
// @package: websocketServer
|
||||
// @description: websocket管理
|
||||
// @author:
|
||||
// @revision history:
|
||||
// @create date: 2022-02-18 15:38:17
|
||||
// ************************************
|
||||
package websocketServer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/gorilla/websocket"
|
||||
routineCtrlUtil "goutil/routineCtrlUtil"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// 默认广播并发数
|
||||
con_DEFAULT_BROADCAST_CONCURRENT = 10
|
||||
)
|
||||
|
||||
// connManager
|
||||
// @description: websocket连接管理
|
||||
type connManager struct {
|
||||
// 是否禁止新连接
|
||||
disableNewConn bool
|
||||
|
||||
// 广播并发数
|
||||
broadcastConcurrent int
|
||||
|
||||
// websocket服务端配置结构
|
||||
upgrader *websocket.Upgrader
|
||||
|
||||
// 广播锁-限制 消息广播/关闭所有连接 并发访问
|
||||
muBroadcast sync.Mutex
|
||||
|
||||
// 连接池map写锁(增加/删除)
|
||||
muAllConns sync.Mutex
|
||||
|
||||
// 连接池-所有已连接的websocket
|
||||
allConns map[*websocket.Conn]*Context
|
||||
|
||||
//-------------------
|
||||
// 心跳控制
|
||||
|
||||
// 接收到Ping消息时,是否自动回复Pong
|
||||
autuPong bool
|
||||
|
||||
// 心跳周期
|
||||
heartbeatCycle time.Duration
|
||||
|
||||
// 断连周期数(超过几个心跳周期即自动关闭连接);设置为0即关闭心跳检测功能
|
||||
heartbeatCloseCount int
|
||||
|
||||
// 是否已开启心跳检测协程
|
||||
isHeartbeatDetectStart bool
|
||||
}
|
||||
|
||||
// heartbeatDetect
|
||||
// @description: 开启心跳检测协程
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
//
|
||||
// return:
|
||||
func (connMgr *connManager) heartbeatDetect() {
|
||||
// 限制每个websocket连接管理只开启一个心跳检测协程
|
||||
if !connMgr.isHeartbeatDetectStart {
|
||||
connMgr.isHeartbeatDetectStart = true
|
||||
|
||||
// 开启心跳检测协程
|
||||
go func() {
|
||||
for {
|
||||
if connMgr.heartbeatCloseCount <= 0 {
|
||||
// 心跳检测功能已关闭;每秒检测此标志
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
// 心跳检测功能已开启
|
||||
|
||||
connMgr.muAllConns.Lock() // 连接池map锁
|
||||
ctxs_timeout := make([]*Context, 0, len(connMgr.allConns)) // 存放心跳超时,需要关闭的websocket环境
|
||||
for _, ctx := range connMgr.allConns {
|
||||
if time.Since(ctx.heartbeat) > (connMgr.heartbeatCycle*time.Duration(connMgr.heartbeatCloseCount) + 1) {
|
||||
// 心跳超时,需要关闭的websocket环境加入列表
|
||||
ctxs_timeout = append(ctxs_timeout, ctx)
|
||||
}
|
||||
}
|
||||
connMgr.muAllConns.Unlock() // 连接池map及时解锁
|
||||
|
||||
// 关闭所有心跳超时的连接
|
||||
func() {
|
||||
// 获取广播并发数
|
||||
broadcastConcurrent := connMgr.broadcastConcurrent
|
||||
if broadcastConcurrent <= 0 {
|
||||
broadcastConcurrent = con_DEFAULT_BROADCAST_CONCURRENT
|
||||
}
|
||||
|
||||
// 协程并发限制
|
||||
rtCtrl := routineCtrlUtil.New(broadcastConcurrent)
|
||||
for _, ctx := range ctxs_timeout {
|
||||
ctxTemp := ctx
|
||||
rtCtrl.Run(func(arg interface{}) {
|
||||
// 执行受限并发函数
|
||||
ctxTemp.Close()
|
||||
}, nil)
|
||||
}
|
||||
|
||||
// 等待完成
|
||||
rtCtrl.Wait()
|
||||
}()
|
||||
|
||||
// 休眠半个心跳周期
|
||||
slpTime := time.Duration(connMgr.heartbeatCycle / 2)
|
||||
if slpTime < time.Second {
|
||||
slpTime = time.Second
|
||||
}
|
||||
time.Sleep(slpTime)
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
// upgrade
|
||||
// @description: 升级为websocket
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
// @ctx: websocket环境
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @*websocket.Conn: 建立的连接对象
|
||||
// @error:
|
||||
func (connMgr *connManager) upgrade(ctx *Context) (conn *websocket.Conn, err error) {
|
||||
if connMgr.disableNewConn {
|
||||
// 禁止新连接
|
||||
return nil, errors.New("connManager(disableNewConn)")
|
||||
}
|
||||
|
||||
// 建立websocket连接
|
||||
conn, err = connMgr.upgrader.Upgrade(ctx.GetWebServerContext().GetResponseWriter(), ctx.GetWebServerContext().GetRequest(), nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// 添加到连接池
|
||||
ctx.conn = conn
|
||||
connMgr.addConn(conn, ctx)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// addConn
|
||||
// @description: 添加到连接池
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
// @conn:
|
||||
// @ctx:
|
||||
//
|
||||
// return:
|
||||
func (connMgr *connManager) addConn(conn *websocket.Conn, ctx *Context) {
|
||||
connMgr.muAllConns.Lock()
|
||||
defer connMgr.muAllConns.Unlock()
|
||||
|
||||
connMgr.allConns[conn] = ctx
|
||||
}
|
||||
|
||||
// delConn
|
||||
// @description: 将连接从连接池删除
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
// @conn:
|
||||
//
|
||||
// return:
|
||||
func (connMgr *connManager) delConn(conn *websocket.Conn) {
|
||||
connMgr.muAllConns.Lock()
|
||||
defer connMgr.muAllConns.Unlock()
|
||||
|
||||
delete(connMgr.allConns, conn)
|
||||
}
|
||||
|
||||
// renewAllConnsMap
|
||||
// @description: 重新替换一个新allConns的map结构,以免被标记删除的冗余信息造成存储和性能问题
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @map[*websocket.Conn]*Context: 返回原内部使用的连接池(现内部已不再使用)
|
||||
func (connMgr *connManager) renewAllConnsMap() map[*websocket.Conn]*Context {
|
||||
connMgr.muAllConns.Lock()
|
||||
defer connMgr.muAllConns.Unlock()
|
||||
|
||||
// map拷贝
|
||||
allConnsCopy := make(map[*websocket.Conn]*Context, len(connMgr.allConns))
|
||||
for conn, ctx := range connMgr.allConns {
|
||||
allConnsCopy[conn] = ctx
|
||||
}
|
||||
// map替换;因map删除时只是标记,并非真正删除,使用一段时间后可能会出现大量未使用信息;这里顺便更新一下map
|
||||
connMgr.allConns, allConnsCopy = allConnsCopy, connMgr.allConns
|
||||
|
||||
return allConnsCopy
|
||||
}
|
||||
|
||||
// SetBroadcastConcurrent
|
||||
// @description: 设置广播并发数
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
// @n: 广播并发数
|
||||
//
|
||||
// return:
|
||||
func (connMgr *connManager) SetBroadcastConcurrent(n int) {
|
||||
connMgr.broadcastConcurrent = n
|
||||
}
|
||||
|
||||
// EnableNewConn
|
||||
// @description: 允许新连接
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
//
|
||||
// return:
|
||||
func (connMgr *connManager) EnableNewConn() {
|
||||
connMgr.disableNewConn = false
|
||||
}
|
||||
|
||||
// DisableNewConn
|
||||
// @description: 禁用新连接
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
//
|
||||
// return:
|
||||
func (connMgr *connManager) DisableNewConn() {
|
||||
connMgr.disableNewConn = true
|
||||
}
|
||||
|
||||
// MulticastMessage
|
||||
// @description: 多播消息(给指定多用户发送消息)
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
// @ctxs: 指定多用户的*Context切片
|
||||
// @messageType: websocket类型
|
||||
// @data: 发送的数据
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @err: 若有错误,则为最后一个错误
|
||||
func (connMgr *connManager) MulticastMessage(ctxs []*Context, messageType int, data []byte) (err error) {
|
||||
// 广播锁,防重入
|
||||
connMgr.muBroadcast.Lock()
|
||||
defer connMgr.muBroadcast.Unlock()
|
||||
|
||||
// 获取广播并发数
|
||||
broadcastConcurrent := connMgr.broadcastConcurrent
|
||||
if broadcastConcurrent <= 0 {
|
||||
broadcastConcurrent = con_DEFAULT_BROADCAST_CONCURRENT
|
||||
}
|
||||
|
||||
// 协程并发限制
|
||||
rtCtrl := routineCtrlUtil.New(broadcastConcurrent)
|
||||
var mu sync.Mutex
|
||||
for _, ctx := range ctxs {
|
||||
// 执行受限并发函数
|
||||
// 注意:这里的ctx需要使用参数传入Run;否则随时变化的ctx在闭包内使用时,会出现不符合程序要求逻辑的结果
|
||||
rtCtrl.Run(func(arg interface{}) {
|
||||
ctxTemp, _ := arg.(*Context)
|
||||
e := ctxTemp.SendMessage(messageType, data)
|
||||
if e != nil {
|
||||
mu.Lock()
|
||||
err = e
|
||||
mu.Unlock()
|
||||
}
|
||||
}, ctx)
|
||||
}
|
||||
|
||||
// 等待完成
|
||||
rtCtrl.Wait()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// BroadcastMessage
|
||||
// @description: 消息广播
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
// @messageType: websocket类型
|
||||
// @data: 发送的数据
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @err: 若有错误,则为最后一个错误
|
||||
func (connMgr *connManager) BroadcastMessage(messageType int, data []byte) (err error) {
|
||||
// 广播锁,防重入
|
||||
connMgr.muBroadcast.Lock()
|
||||
defer connMgr.muBroadcast.Unlock()
|
||||
|
||||
// 重新替换一个新allConns的map结构,以免被标记删除的冗余信息造成存储和性能问题
|
||||
allConnsCopy := connMgr.renewAllConnsMap()
|
||||
|
||||
// 获取广播并发数
|
||||
broadcastConcurrent := connMgr.broadcastConcurrent
|
||||
if broadcastConcurrent <= 0 {
|
||||
broadcastConcurrent = con_DEFAULT_BROADCAST_CONCURRENT
|
||||
}
|
||||
|
||||
// 协程并发限制
|
||||
rtCtrl := routineCtrlUtil.New(broadcastConcurrent)
|
||||
var mu sync.Mutex
|
||||
for _, ctx := range allConnsCopy {
|
||||
// 执行受限并发函数
|
||||
// 注意:这里的ctx需要使用参数传入Run;否则随时变化的ctx在闭包内使用时,会出现不符合程序要求逻辑的结果
|
||||
rtCtrl.Run(func(arg interface{}) {
|
||||
ctxTemp, _ := arg.(*Context)
|
||||
e := ctxTemp.SendMessage(messageType, data)
|
||||
if e != nil {
|
||||
mu.Lock()
|
||||
err = e
|
||||
mu.Unlock()
|
||||
}
|
||||
}, ctx)
|
||||
}
|
||||
|
||||
// 等待完成
|
||||
rtCtrl.Wait()
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// CloseAll
|
||||
// @description: 关闭所有连接
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
//
|
||||
// return:
|
||||
func (connMgr *connManager) CloseAll() {
|
||||
// 广播锁,防重入
|
||||
connMgr.muBroadcast.Lock()
|
||||
defer connMgr.muBroadcast.Unlock()
|
||||
|
||||
// 重新替换一个新allConns的map结构,以免被标记删除的冗余信息造成存储和性能问题
|
||||
allConnsCopy := connMgr.renewAllConnsMap()
|
||||
|
||||
// 获取广播并发数
|
||||
broadcastConcurrent := connMgr.broadcastConcurrent
|
||||
if broadcastConcurrent <= 0 {
|
||||
broadcastConcurrent = con_DEFAULT_BROADCAST_CONCURRENT
|
||||
}
|
||||
|
||||
// 协程并发限制
|
||||
rtCtrl := routineCtrlUtil.New(broadcastConcurrent)
|
||||
for _, ctx := range allConnsCopy {
|
||||
rtCtrl.Run(func(arg interface{}) {
|
||||
ctxTemp, _ := arg.(*Context)
|
||||
// 执行受限并发函数
|
||||
ctxTemp.Close()
|
||||
}, ctx)
|
||||
}
|
||||
|
||||
// 等待完成
|
||||
rtCtrl.Wait()
|
||||
}
|
||||
|
||||
// SetUpgrader
|
||||
// @description: 设置websocket参数结构
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
// @upgrader: websocket中的websocket.Upgrader结构体指针(可以设置握手超时/读写缓存/是否允许跨域等)
|
||||
//
|
||||
// return:
|
||||
func (connMgr *connManager) SetUpgrader(upgrader *websocket.Upgrader) {
|
||||
connMgr.upgrader = upgrader
|
||||
}
|
||||
|
||||
// GetUpgrader
|
||||
// @description: 获取websocket参数结构
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @*websocket.Upgrader: websocket中的websocket.Upgrader结构体指针(可以设置握手超时/读写缓存/是否允许跨域等)
|
||||
func (connMgr *connManager) GetUpgrader() *websocket.Upgrader {
|
||||
return connMgr.upgrader
|
||||
}
|
||||
|
||||
// SetAutoPong
|
||||
// @description: 设置接收到Ping消息时,是否自动回复Pong信息
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
// @autuPong:
|
||||
//
|
||||
// return:
|
||||
func (connMgr *connManager) SetAutoPong(autuPong bool) {
|
||||
connMgr.autuPong = autuPong
|
||||
}
|
||||
|
||||
// GetAutoPong
|
||||
// @description: 获取接收到Ping消息时,是否自动回复Pong信息
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @bool:
|
||||
func (connMgr *connManager) GetAutoPong() bool {
|
||||
return connMgr.autuPong
|
||||
}
|
||||
|
||||
// SetHeartbeatDetectInfo
|
||||
// @description: 设置心跳检测信息
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
// @heartbeatCloseCount: 断连周期数(超过几个心跳周期即自动关闭连接);设置为0即关闭心跳检测功能
|
||||
// @heartbeatCycle: 心跳周期
|
||||
//
|
||||
// return:
|
||||
func (connMgr *connManager) SetHeartbeatDetectInfo(heartbeatCloseCount int, heartbeatCycle time.Duration) {
|
||||
connMgr.heartbeatCycle = heartbeatCycle
|
||||
connMgr.heartbeatCloseCount = heartbeatCloseCount
|
||||
}
|
||||
|
||||
// GetHeartbeatDetectInfo
|
||||
// @description: 获取心跳检测信息
|
||||
// parameter:
|
||||
//
|
||||
// @receiver connMgr:
|
||||
//
|
||||
// return:
|
||||
//
|
||||
// @heartbeatCloseCount: 断连周期数(超过几个心跳周期即自动关闭连接)
|
||||
// @heartbeatCycle: 心跳周期
|
||||
func (connMgr *connManager) GetHeartbeatDetectInfo() (heartbeatCloseCount int, heartbeatCycle time.Duration) {
|
||||
return connMgr.heartbeatCloseCount, connMgr.heartbeatCycle
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"common/connection"
|
||||
"goutil/logUtilPlus"
|
||||
)
|
||||
|
||||
// AddUser 添加用户
|
||||
// AddUser 添加新的用户到数据库中。
|
||||
// 参数 User: 包含用户信息的对象。
|
||||
// 返回值: 插入操作影响的行数和可能发生的错误。
|
||||
func AddUser(User *User) (int64, error) {
|
||||
|
||||
//处理一些验证
|
||||
|
||||
// 写入到数据库
|
||||
result := connection.GetUserDB().Create(&User) // 通过数据的指针来创建
|
||||
|
||||
if result.Error != nil {
|
||||
logUtilPlus.ErrorLog("添加用户失败 错误信息:", result.Error.Error())
|
||||
}
|
||||
return User.ID, nil
|
||||
}
|
||||
|
||||
// GetUserByID 根据用户ID获取用户信息
|
||||
func GetUserByID(UserID int64) (*User, error) {
|
||||
var User User
|
||||
|
||||
//缓存判断等一些设置
|
||||
|
||||
result := connection.GetUserDB().First(&User, UserID)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
return &User, nil
|
||||
}
|
||||
|
||||
// 用户登录
|
||||
func Login(account string, password string) (*User, error) {
|
||||
var User User
|
||||
result := connection.GetUserDB().Where("account = ? AND password = ?", account, password).First(&User)
|
||||
if result.Error != nil {
|
||||
return nil, result.Error
|
||||
}
|
||||
return &User, nil
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package intAndBytesUtil
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBytesToInt(t *testing.T) {
|
||||
var givenBigEndian []byte = []byte{0, 0, 1, 0}
|
||||
var givenLittleEndian []byte = []byte{0, 1, 0, 0}
|
||||
var expectedInt int32 = 256
|
||||
|
||||
result := BytesToInt32(givenBigEndian, binary.BigEndian)
|
||||
if result != expectedInt {
|
||||
t.Errorf("BytesToInt(%v) failed.Got %v, expected %v", givenBigEndian, result, expectedInt)
|
||||
}
|
||||
|
||||
result = BytesToInt32(givenLittleEndian, binary.LittleEndian)
|
||||
if result != expectedInt {
|
||||
t.Errorf("BytesToInt(%v) failed.Got %v, expected %v", givenLittleEndian, result, expectedInt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBytesToInt16(t *testing.T) {
|
||||
var givenBigEndian []byte = []byte{1, 0}
|
||||
var givenLittleEndian []byte = []byte{0, 1}
|
||||
var expectedInt int16 = 256
|
||||
|
||||
result := BytesToInt16(givenBigEndian, binary.BigEndian)
|
||||
if result != expectedInt {
|
||||
t.Errorf("BytesToInt(%v) failed.Got %v, expected %v", givenBigEndian, result, expectedInt)
|
||||
}
|
||||
|
||||
result = BytesToInt16(givenLittleEndian, binary.LittleEndian)
|
||||
if result != expectedInt {
|
||||
t.Errorf("BytesToInt(%v) failed.Got %v, expected %v", givenLittleEndian, result, expectedInt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBytesToInt32(t *testing.T) {
|
||||
var givenBigEndian []byte = []byte{0, 0, 1, 0}
|
||||
var givenLittleEndian []byte = []byte{0, 1, 0, 0}
|
||||
var expectedInt int32 = 256
|
||||
|
||||
result := BytesToInt32(givenBigEndian, binary.BigEndian)
|
||||
if result != expectedInt {
|
||||
t.Errorf("BytesToInt(%v) failed.Got %v, expected %v", givenBigEndian, result, expectedInt)
|
||||
}
|
||||
|
||||
result = BytesToInt32(givenLittleEndian, binary.LittleEndian)
|
||||
if result != expectedInt {
|
||||
t.Errorf("BytesToInt(%v) failed.Got %v, expected %v", givenLittleEndian, result, expectedInt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBytesToInt64(t *testing.T) {
|
||||
var givenBigEndian []byte = []byte{0, 0, 0, 0, 0, 0, 1, 0}
|
||||
var givenLittleEndian []byte = []byte{0, 1, 0, 0, 0, 0, 0, 0}
|
||||
var expectedInt int64 = 256
|
||||
|
||||
result := BytesToInt64(givenBigEndian, binary.BigEndian)
|
||||
if result != expectedInt {
|
||||
t.Errorf("BytesToInt(%v) failed.Got %v, expected %v", givenBigEndian, result, expectedInt)
|
||||
}
|
||||
|
||||
result = BytesToInt64(givenLittleEndian, binary.LittleEndian)
|
||||
if result != expectedInt {
|
||||
t.Errorf("BytesToInt(%v) failed.Got %v, expected %v", givenLittleEndian, result, expectedInt)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package ensureSendUtil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"goutil/debugUtil"
|
||||
"goutil/zlibUtil"
|
||||
)
|
||||
|
||||
// 保存接收的数据用于校验
|
||||
var tcp_recv_msg = make([]byte, 0)
|
||||
|
||||
func init() {
|
||||
debugUtil.SetDebug(true)
|
||||
}
|
||||
|
||||
// 创建socket服务器,保存收到的数据
|
||||
func server(addr string) net.Listener {
|
||||
listener, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
conn, err := listener.Accept()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
buff := make([]byte, 512)
|
||||
_, err := conn.Read(buff)
|
||||
if err != nil {
|
||||
break
|
||||
} else {
|
||||
decompressed, err := zlibUtil.Decompress(buff[4:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
tcp_recv_msg = append(tcp_recv_msg, decompressed...)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return listener
|
||||
}
|
||||
|
||||
func Test_tcp(t *testing.T) {
|
||||
// 开启服务器
|
||||
l := server("127.0.0.1:9559")
|
||||
|
||||
tcp, err := NewTCPSender("./test_tcp", "127.0.0.1:9559")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// 发送消息
|
||||
tcp.Write("tcp-msg-1")
|
||||
time.Sleep(time.Millisecond * 50) // 等待协程发送数据
|
||||
|
||||
// 关闭连接和服务器
|
||||
l.Close()
|
||||
(tcp.(*tcpSender)).conn.Close()
|
||||
|
||||
// 发送消息,此数据会失败
|
||||
tcp.Write("tcp-msg-2")
|
||||
// time.Sleep(time.Millisecond * 50)
|
||||
|
||||
// 保存数据
|
||||
tcp.Close()
|
||||
|
||||
// 重启,检查是否重发tcp-msg-2
|
||||
l = server("127.0.0.1:9559")
|
||||
tcp, err = NewTCPSender("./test_tcp", "127.0.0.1:9559")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
time.Sleep(time.Second * 2)
|
||||
|
||||
if string(tcp_recv_msg) != "tcp-msg-1tcp-msg-2" {
|
||||
t.Error("message error. got " + string(tcp_recv_msg))
|
||||
} else {
|
||||
fmt.Println("TCP OK")
|
||||
}
|
||||
|
||||
tcp.Close()
|
||||
l.Close()
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package esLogUtil
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestWrite(t *testing.T) {
|
||||
Start("http://10.1.0.86:9200", "dzg_gs_log_gmc2", 20008)
|
||||
for i := 0; i < 10000; i++ {
|
||||
InfoLog("ES在线日志测试")
|
||||
WarnLog("ES在线日志测试")
|
||||
DebugLog("ES在线日志测试")
|
||||
ErrorLog("ES在线日志测试")
|
||||
FatalLog("ES在线日志测试")
|
||||
}
|
||||
Stop()
|
||||
}
|
||||
|
||||
func BenchmarkWrite(b *testing.B) {
|
||||
Start("http://106.52.100.147:14001", "20008_gs_log", 20008)
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
InfoLog("ES在线日志测试%d", i)
|
||||
WarnLog("ES在线日志测试%d", i)
|
||||
DebugLog("ES在线日志测试%d", i)
|
||||
ErrorLog("ES在线日志测试%d", i)
|
||||
FatalLog("ES在线日志测试%d", i)
|
||||
}
|
||||
b.StopTimer()
|
||||
|
||||
time.Sleep(30 * time.Second)
|
||||
Stop()
|
||||
}
|
||||
Reference in New Issue
Block a user