Compare commits

..

14 Commits

Author SHA1 Message Date
duanhf2012
8e0ed62fca 优化smath模块 2024-09-11 15:06:33 +08:00
duanhf2012
7116b509e9 新增权重随机相关函数 2024-09-11 14:50:31 +08:00
duanhf2012
73d384361d 优化Service多协程模式 2024-08-30 16:56:48 +08:00
boyce
ce56b19fe8 优化服务筛选 2024-06-29 14:58:41 +08:00
boyce
1367d776e6 优化readme事件说明 2024-06-29 12:02:13 +08:00
boyce
987d35ff15 优化origin服务发现 2024-06-28 12:29:58 +08:00
boyce
d225bb4bd2 优化启动参数logchannelcap默认值 2024-06-25 09:20:03 +08:00
boyce
ea37fb5081 新增日志接口--SetSkip/GetSkip 2024-06-24 15:29:54 +08:00
boyce
0a92f48d0b 优化node状态 2024-06-20 09:10:18 +08:00
boyce
f5e86fee02 新增Stop接口,断开mongo连接 2024-06-19 15:51:31 +08:00
boyce
166facc959 优化mongodb驱动 2024-06-18 10:07:54 +08:00
boyce
5bb747201b 补充readme说明 2024-06-14 17:46:58 +08:00
boyce
1014bc54e4 优化网络处理器 2024-06-14 16:21:52 +08:00
boyce
9c26c742fe 优化协程池退出 2024-06-14 15:42:23 +08:00
22 changed files with 373 additions and 343 deletions

123
README.md
View File

@@ -661,51 +661,7 @@ Module1 Release.
第四章:事件使用
----------------
事件是origin中一个重要的组成部分可以在同一个node中的service与service或者与module之间进行事件通知。系统内置的几个服务TcpService/HttpService等都是通过事件功能实现。他也是一个典型的观察者设计模型。在event中有两个类型的interface一个是event.IEventProcessor它提供注册与卸载功能另一个是event.IEventHandler提供消息广播等功能。
在目录simple_event/TestService4.go中
```
package simple_event
import (
"github.com/duanhf2012/origin/v2/event"
"github.com/duanhf2012/origin/v2/node"
"github.com/duanhf2012/origin/v2/service"
"time"
)
const (
//自定义事件类型必需从event.Sys_Event_User_Define开始
//event.Sys_Event_User_Define以内给系统预留
EVENT1 event.EventType =event.Sys_Event_User_Define+1
)
func init(){
node.Setup(&TestService4{})
}
type TestService4 struct {
service.Service
}
func (slf *TestService4) OnInit() error {
//10秒后触发广播事件
slf.AfterFunc(time.Second*10,slf.TriggerEvent)
return nil
}
func (slf *TestService4) TriggerEvent(){
//广播事件传入event.Event对象类型为EVENT1,Data可以自定义任何数据
//这样,所有监听者都可以收到该事件
slf.GetEventHandler().NotifyEvent(&event.Event{
Type: EVENT1,
Data: "event data.",
})
}
```
事件是origin中一个重要的组成部分可以在服务与各module之间进行事件通知。它也是一个典型的观察者设计模型。在event中有两个类型的interface一个是event.IEventProcessor它提供注册与卸载功能另一个是event.IEventHandler提供消息广播等功能。
在目录simple_event/TestService5.go中
@@ -713,53 +669,68 @@ func (slf *TestService4) TriggerEvent(){
package simple_event
import (
"fmt"
"github.com/duanhf2012/origin/v2/event"
"github.com/duanhf2012/origin/v2/node"
"github.com/duanhf2012/origin/v2/service"
"fmt"
"github.com/duanhf2012/origin/v2/event"
"github.com/duanhf2012/origin/v2/node"
"github.com/duanhf2012/origin/v2/service"
"github.com/duanhf2012/origin/v2/util/timer"
"time"
)
func init(){
node.Setup(&TestService5{})
func init() {
node.Setup(&TestService5{})
}
const (
//自定义事件类型必需从event.Sys_Event_User_Define开始
//event.Sys_Event_User_Define以内给系统预留
EVENT1 event.EventType = event.Sys_Event_User_Define + 1
)
type TestService5 struct {
service.Service
service.Service
}
type TestModule struct {
service.Module
service.Module
}
func (slf *TestModule) OnInit() error{
//在当前node中查找TestService4
pService := node.GetService("TestService4")
func (slf *TestModule) OnInit() error {
//在TestModule中注册监听EVENT1事件
slf.GetEventProcessor().RegEventReceiverFunc(EVENT1, slf.GetEventHandler(), slf.OnModuleEvent)
//在TestModule中往TestService4中注册EVENT1类型事件监听
pService.(*TestService4).GetEventProcessor().RegEventReciverFunc(EVENT1,slf.GetEventHandler(),slf.OnModuleEvent)
return nil
return nil
}
func (slf *TestModule) OnModuleEvent(ev event.IEvent){
event := ev.(*event.Event)
fmt.Printf("OnModuleEvent type :%d data:%+v\n",event.GetEventType(),event.Data)
// OnModuleEvent 模块监听事件回调
func (slf *TestModule) OnModuleEvent(ev event.IEvent) {
event := ev.(*event.Event)
fmt.Printf("OnModuleEvent type :%d data:%+v\n", event.GetEventType(), event.Data)
}
//服务初始化函数在安装服务时服务将自动调用OnInit函数
// OnInit 服务初始化函数在安装服务时服务将自动调用OnInit函数
func (slf *TestService5) OnInit() error {
//通过服务名获取服务对象
pService := node.GetService("TestService4")
//在服务中注册监听EVENT1类型事件
slf.RegEventReceiverFunc(EVENT1, slf.GetEventHandler(), slf.OnServiceEvent)
slf.AddModule(&TestModule{})
////在TestModule中往TestService4中注册EVENT1类型事件监听
pService.(*TestService4).GetEventProcessor().RegEventReciverFunc(EVENT1,slf.GetEventHandler(),slf.OnServiceEvent)
slf.AddModule(&TestModule{})
return nil
slf.AfterFunc(time.Second*10, slf.TriggerEvent)
return nil
}
func (slf *TestService5) OnServiceEvent(ev event.IEvent){
event := ev.(*event.Event)
fmt.Printf("OnServiceEvent type :%d data:%+v\n",event.Type,event.Data)
// OnServiceEvent 服务监听事件回调
func (slf *TestService5) OnServiceEvent(ev event.IEvent) {
event := ev.(*event.Event)
fmt.Printf("OnServiceEvent type :%d data:%+v\n", event.Type, event.Data)
}
func (slf *TestService5) TriggerEvent(t *timer.Timer) {
//广播事件传入event.Event对象类型为EVENT1,Data可以自定义任何数据
//这样,所有监听者都可以收到该事件
slf.GetEventHandler().NotifyEvent(&event.Event{
Type: EVENT1,
Data: "event data.",
})
}
@@ -768,8 +739,8 @@ func (slf *TestService5) OnServiceEvent(ev event.IEvent){
程序运行10秒后调用slf.TriggerEvent函数广播事件于是在TestService5中会收到
```
OnServiceEvent type :1001 data:event data.
OnModuleEvent type :1001 data:event data.
OnServiceEvent type :2 data:event data.
OnModuleEvent type :2 data:event data.
```
在上面的TestModule中监听的事情当这个Module被Release时监听会自动卸载。
@@ -1181,6 +1152,8 @@ func (slf *TestTcpService) OnRequest (clientid string,msg proto.Message){
* log/log.go:日志的封装,可以使用它构建对象记录业务文件日志
* util:在该目录下有常用的uuid,hash,md5,协程封装等工具库
* https://github.com/duanhf2012/originservice: 其他扩展支持的服务可以在该工程上看到目前支持firebase推送的封装。
* https://github.com/duanhf2012/origingame: 基础游戏服务器的框架
* etcd与nats开发环境搭建可以从https://github.com/duanhf2012/originserver_v2下的docker-compose获取
备注:
-----

View File

@@ -469,6 +469,11 @@ func (cls *Cluster) GetNodeInfo(nodeId string) (NodeInfo,bool) {
func (dc *Cluster) CanDiscoveryService(fromMasterNodeId string,serviceName string) bool{
canDiscovery := true
splitServiceName := strings.Split(serviceName,":")
if len(splitServiceName) == 2 {
serviceName = splitServiceName[0]
}
for i:=0;i<len(dc.GetLocalNodeInfo().DiscoveryService);i++{
masterNodeId := dc.GetLocalNodeInfo().DiscoveryService[i].MasterNodeId
//无效的配置,则跳过

View File

@@ -160,6 +160,12 @@ func (dc *OriginDiscoveryMaster) OnNatsDisconnect(){
}
func (ds *OriginDiscoveryMaster) OnNodeConnected(nodeId string) {
var notifyDiscover rpc.SubscribeDiscoverNotify
notifyDiscover.IsFull = true
notifyDiscover.NodeInfo = ds.nodeInfo
notifyDiscover.MasterNodeId = cluster.GetLocalNodeInfo().NodeId
ds.GoNode(nodeId, SubServiceDiscover, &notifyDiscover)
}
func (ds *OriginDiscoveryMaster) OnNodeDisconnect(nodeId string) {

View File

@@ -10,6 +10,7 @@ import (
"github.com/duanhf2012/origin/v2/log"
"github.com/duanhf2012/origin/v2/util/queue"
"context"
)
var idleTimeout = int64(2 * time.Second)
@@ -30,6 +31,9 @@ type dispatch struct {
waitWorker sync.WaitGroup
waitDispatch sync.WaitGroup
cancelContext context.Context
cancel context.CancelFunc
}
func (d *dispatch) open(minGoroutineNum int32, maxGoroutineNum int32, tasks chan task, cbChannel chan func(error)) {
@@ -40,7 +44,7 @@ func (d *dispatch) open(minGoroutineNum int32, maxGoroutineNum int32, tasks chan
d.workerQueue = make(chan task)
d.cbChannel = cbChannel
d.queueIdChannel = make(chan int64, cap(tasks))
d.cancelContext,d.cancel = context.WithCancel(context.Background())
d.waitDispatch.Add(1)
go d.run()
}
@@ -64,10 +68,12 @@ func (d *dispatch) run() {
d.processqueueEvent(queueId)
case <-timeout.C:
d.processTimer()
if atomic.LoadInt32(&d.minConcurrentNum) == -1 && len(d.tasks) == 0 {
atomic.StoreInt64(&idleTimeout,int64(time.Millisecond * 10))
}
case <- d.cancelContext.Done():
atomic.StoreInt64(&idleTimeout,int64(time.Millisecond * 5))
timeout.Reset(time.Duration(atomic.LoadInt64(&idleTimeout)))
for i:=int32(0);i<d.workerNum;i++{
d.processIdle()
}
}
}
@@ -166,6 +172,8 @@ func (c *dispatch) pushAsyncDoCallbackEvent(cb func(err error)) {
func (d *dispatch) close() {
atomic.StoreInt32(&d.minConcurrentNum, -1)
d.cancel()
breakFor:
for {

View File

@@ -10,16 +10,20 @@ import (
"sync"
)
const defaultSkip = 7
type IOriginHandler interface {
slog.Handler
Lock()
UnLock()
SetSkip(skip int)
GetSkip() int
}
type BaseHandler struct {
addSource bool
w io.Writer
locker sync.Mutex
skip int
}
type OriginTextHandler struct {
@@ -32,6 +36,14 @@ type OriginJsonHandler struct {
*slog.JSONHandler
}
func (bh *BaseHandler) SetSkip(skip int){
bh.skip = skip
}
func (bh *BaseHandler) GetSkip() int{
return bh.skip
}
func getStrLevel(level slog.Level) string{
switch level {
case LevelTrace:
@@ -78,6 +90,7 @@ func NewOriginTextHandler(level slog.Level,w io.Writer,addSource bool,replaceAtt
ReplaceAttr: replaceAttr,
})
textHandler.skip = defaultSkip
return &textHandler
}
@@ -124,6 +137,7 @@ func NewOriginJsonHandler(level slog.Level,w io.Writer,addSource bool,replaceAtt
ReplaceAttr: replaceAttr,
})
jsonHandler.skip = defaultSkip
return &jsonHandler
}
@@ -141,7 +155,7 @@ func (oh *OriginJsonHandler) Handle(context context.Context, record slog.Record)
func (b *BaseHandler) Fill(context context.Context, record *slog.Record) {
if b.addSource {
var pcs [1]uintptr
runtime.Callers(7, pcs[:])
runtime.Callers(b.skip, pcs[:])
record.PC = pcs[0]
}
}

View File

@@ -239,6 +239,10 @@ func (iw *IoWriter) swichFile() error{
return nil
}
func GetDefaultHandler() IOriginHandler{
return gLogger.(*Logger).Slogger.Handler().(IOriginHandler)
}
func NewTextLogger(level slog.Level,pathName string,filePrefix string,addSource bool,logChannelCap int) (ILogger,error){
var logger Logger
logger.ioWriter.filePath = pathName

View File

@@ -45,8 +45,10 @@ func (jsonProcessor *JsonProcessor) SetByteOrder(littleEndian bool) {
}
// must goroutine safe
func (jsonProcessor *JsonProcessor ) MsgRoute(clientId string,msg interface{}) error{
func (jsonProcessor *JsonProcessor ) MsgRoute(clientId string,msg interface{},recyclerReaderBytes func(data []byte)) error{
pPackInfo := msg.(*JsonPackInfo)
defer recyclerReaderBytes(pPackInfo.rawMsg)
v,ok := jsonProcessor.mapMsg[pPackInfo.typ]
if ok == false {
return fmt.Errorf("cannot find msgtype %d is register!",pPackInfo.typ)
@@ -58,7 +60,6 @@ func (jsonProcessor *JsonProcessor ) MsgRoute(clientId string,msg interface{}) e
func (jsonProcessor *JsonProcessor) Unmarshal(clientId string,data []byte) (interface{}, error) {
typeStruct := struct {Type int `json:"typ"`}{}
defer jsonProcessor.ReleaseBytes(data)
err := json.Unmarshal(data, &typeStruct)
if err != nil {
return nil, err
@@ -76,7 +77,7 @@ func (jsonProcessor *JsonProcessor) Unmarshal(clientId string,data []byte) (inte
return nil,err
}
return &JsonPackInfo{typ:msgType,msg:msgData},nil
return &JsonPackInfo{typ:msgType,msg:msgData,rawMsg: data},nil
}
func (jsonProcessor *JsonProcessor) Marshal(clientId string,msg interface{}) ([]byte, error) {
@@ -104,7 +105,8 @@ func (jsonProcessor *JsonProcessor) MakeRawMsg(msgType uint16,msg []byte) *JsonP
return &JsonPackInfo{typ:msgType,rawMsg:msg}
}
func (jsonProcessor *JsonProcessor) UnknownMsgRoute(clientId string,msg interface{}){
func (jsonProcessor *JsonProcessor) UnknownMsgRoute(clientId string,msg interface{},recyclerReaderBytes func(data []byte)){
defer recyclerReaderBytes(msg.([]byte))
if jsonProcessor.unknownMessageHandler==nil {
log.Debug("Unknown message",log.String("clientId",clientId))
return

View File

@@ -54,8 +54,10 @@ func (slf *PBPackInfo) GetMsg() proto.Message {
}
// must goroutine safe
func (pbProcessor *PBProcessor) MsgRoute(clientId string, msg interface{}) error {
func (pbProcessor *PBProcessor) MsgRoute(clientId string, msg interface{},recyclerReaderBytes func(data []byte)) error {
pPackInfo := msg.(*PBPackInfo)
defer recyclerReaderBytes(pPackInfo.rawMsg)
v, ok := pbProcessor.mapMsg[pPackInfo.typ]
if ok == false {
return fmt.Errorf("Cannot find msgtype %d is register!", pPackInfo.typ)
@@ -67,7 +69,6 @@ func (pbProcessor *PBProcessor) MsgRoute(clientId string, msg interface{}) error
// must goroutine safe
func (pbProcessor *PBProcessor) Unmarshal(clientId string, data []byte) (interface{}, error) {
defer pbProcessor.ReleaseBytes(data)
return pbProcessor.UnmarshalWithOutRelease(clientId, data)
}
@@ -91,7 +92,7 @@ func (pbProcessor *PBProcessor) UnmarshalWithOutRelease(clientId string, data []
return nil, err
}
return &PBPackInfo{typ: msgType, msg: protoMsg}, nil
return &PBPackInfo{typ: msgType, msg: protoMsg,rawMsg:data}, nil
}
// must goroutine safe
@@ -133,8 +134,9 @@ func (pbProcessor *PBProcessor) MakeRawMsg(msgType uint16, msg []byte) *PBPackIn
return &PBPackInfo{typ: msgType, rawMsg: msg}
}
func (pbProcessor *PBProcessor) UnknownMsgRoute(clientId string, msg interface{}) {
func (pbProcessor *PBProcessor) UnknownMsgRoute(clientId string, msg interface{},recyclerReaderBytes func(data []byte)) {
pbProcessor.unknownMessageHandler(clientId, msg.([]byte))
recyclerReaderBytes(msg.([]byte))
}
// connect event

View File

@@ -38,9 +38,11 @@ func (pbRawProcessor *PBRawProcessor) SetByteOrder(littleEndian bool) {
}
// must goroutine safe
func (pbRawProcessor *PBRawProcessor ) MsgRoute(clientId string, msg interface{}) error{
func (pbRawProcessor *PBRawProcessor ) MsgRoute(clientId string, msg interface{},recyclerReaderBytes func(data []byte)) error{
pPackInfo := msg.(*PBRawPackInfo)
pbRawProcessor.msgHandler(clientId,pPackInfo.typ,pPackInfo.rawMsg)
recyclerReaderBytes(pPackInfo.rawMsg)
return nil
}
@@ -80,7 +82,8 @@ func (pbRawProcessor *PBRawProcessor) MakeRawMsg(msgType uint16,msg []byte,pbRaw
pbRawPackInfo.rawMsg = msg
}
func (pbRawProcessor *PBRawProcessor) UnknownMsgRoute(clientId string,msg interface{}){
func (pbRawProcessor *PBRawProcessor) UnknownMsgRoute(clientId string,msg interface{},recyclerReaderBytes func(data []byte)){
defer recyclerReaderBytes(msg.([]byte))
if pbRawProcessor.unknownMessageHandler == nil {
return
}

View File

@@ -3,9 +3,9 @@ package processor
type IProcessor interface {
// must goroutine safe
MsgRoute(clientId string,msg interface{}) error
MsgRoute(clientId string,msg interface{},recyclerReaderBytes func(data []byte)) error
//must goroutine safe
UnknownMsgRoute(clientId string,msg interface{})
UnknownMsgRoute(clientId string,msg interface{},recyclerReaderBytes func(data []byte))
// connect event
ConnectedRoute(clientId string)
DisConnectedRoute(clientId string)

View File

@@ -129,6 +129,13 @@ func (tcpConn *TCPConn) ReadMsg() ([]byte, error) {
return tcpConn.msgParser.Read(tcpConn)
}
func (tcpConn *TCPConn) GetRecyclerReaderBytes() func (data []byte) {
bytePool := tcpConn.msgParser.IBytesMempool
return func(data []byte) {
bytePool.ReleaseBytes(data)
}
}
func (tcpConn *TCPConn) ReleaseReadMsg(byteBuff []byte){
tcpConn.msgParser.ReleaseBytes(byteBuff)
}

View File

@@ -29,6 +29,7 @@ var preSetupTemplateService []func()service.IService
var profilerInterval time.Duration
var bValid bool
var configDir = "./config/"
var NodeIsRun = false
const(
SingleStop syscall.Signal = 10
@@ -57,7 +58,7 @@ func init() {
console.RegisterCommandString("loglevel", "debug", "<-loglevel debug|release|warning|error|fatal> Set loglevel.", setLevel)
console.RegisterCommandString("logpath", "", "<-logpath path> Set log file path.", setLogPath)
console.RegisterCommandInt("logsize", 0, "<-logsize size> Set log size(MB).", setLogSize)
console.RegisterCommandInt("logchannelcap", 0, "<-logchannelcap num> Set log channel cap.", setLogChannelCapNum)
console.RegisterCommandInt("logchannelcap", -1, "<-logchannelcap num> Set log channel cap.", setLogChannelCapNum)
console.RegisterCommandString("pprof", "", "<-pprof ip:port> Open performance analysis.", setPprof)
}
@@ -354,13 +355,14 @@ func startNode(args interface{}) error {
cluster.GetCluster().Start()
//6.监听程序退出信号&性能报告
bRun := true
var pProfilerTicker *time.Ticker = &time.Ticker{}
if profilerInterval > 0 {
pProfilerTicker = time.NewTicker(profilerInterval)
}
for bRun {
NodeIsRun = true
for NodeIsRun {
select {
case s := <-sig:
signal := s.(syscall.Signal)
@@ -368,7 +370,7 @@ func startNode(args interface{}) error {
log.Info("receipt retire signal.")
notifyAllServiceRetire()
}else {
bRun = false
NodeIsRun = false
log.Info("receipt stop signal.")
}
case <-pProfilerTicker.C:
@@ -504,6 +506,10 @@ func setLogChannelCapNum(args interface{}) error {
return errors.New("param logsize is error")
}
if logChannelCap == -1 {
return nil
}
log.LogChannelCap = logChannelCap
return nil
}

View File

@@ -110,7 +110,6 @@ type IRpcHandler interface {
GoNode(nodeId string, serviceMethod string, args interface{}) error
RawGoNode(rpcProcessorType RpcProcessorType, nodeId string, rpcMethodId uint32, serviceName string, rawArgs []byte) error
CastGo(serviceMethod string, args interface{}) error
IsSingleCoroutine() bool
UnmarshalInParam(rpcProcessor IRpcProcessor, serviceMethod string, rawRpcMethodId uint32, inParam []byte) (interface{}, error)
GetRpcServer() FuncRpcServer
}
@@ -539,10 +538,6 @@ func (handler *RpcHandler) GetName() string {
return handler.rpcHandler.GetName()
}
func (handler *RpcHandler) IsSingleCoroutine() bool {
return handler.rpcHandler.IsSingleCoroutine()
}
func (handler *RpcHandler) CallWithTimeout(timeout time.Duration,serviceMethod string, args interface{}, reply interface{}) error {
return handler.callRpc(timeout,NodeIdNull, serviceMethod, args, reply)
}

View File

@@ -58,6 +58,7 @@ type Service struct {
serviceCfg interface{}
goroutineNum int32
startStatus bool
isRelease int32
retire int32
eventProcessor event.IEventProcessor
profiler *profiler.Profiler //性能分析器
@@ -148,34 +149,36 @@ func (s *Service) Init(iService IService,getClientFun rpc.FuncRpcClient,getServe
func (s *Service) Start() {
s.startStatus = true
atomic.StoreInt32(&s.isRelease,0)
var waitRun sync.WaitGroup
log.Info(s.GetName()+" service is running",)
s.self.(IService).OnStart()
for i:=int32(0);i< s.goroutineNum;i++{
s.wg.Add(1)
waitRun.Add(1)
go func(){
log.Info(s.GetName()+" service is running",)
waitRun.Done()
s.Run()
s.run()
}()
}
waitRun.Wait()
}
func (s *Service) Run() {
func (s *Service) run() {
defer s.wg.Done()
var bStop = false
concurrent := s.IConcurrent.(*concurrent.Concurrent)
concurrentCBChannel := concurrent.GetCallBackChannel()
s.self.(IService).OnStart()
for{
var analyzer *profiler.Analyzer
select {
case <- s.closeSig:
bStop = true
s.Release()
concurrent.Close()
case cb:=<-concurrentCBChannel:
concurrent.DoCallback(cb)
@@ -248,10 +251,6 @@ func (s *Service) Run() {
}
if bStop == true {
if atomic.AddInt32(&s.goroutineNum,-1)<=0 {
s.startStatus = false
s.Release()
}
break
}
}
@@ -274,8 +273,11 @@ func (s *Service) Release(){
log.Dump(string(buf[:l]),log.String("error",errString))
}
}()
s.self.OnRelease()
if atomic.AddInt32(&s.isRelease,-1) == -1{
s.self.OnRelease()
}
}
func (s *Service) OnRelease(){
@@ -326,10 +328,6 @@ func (s *Service) UnRegEventReceiverFunc(eventType event.EventType, receiver eve
s.eventProcessor.UnRegEventReceiverFun(eventType, receiver)
}
func (s *Service) IsSingleCoroutine() bool {
return s.goroutineNum == 1
}
func (s *Service) RegRawRpc(rpcMethodId uint32,rawRpcCB rpc.RawRpcCallBack){
s.rpcHandler.RegRawRpc(rpcMethodId,rawRpcCB)
}

View File

@@ -5,7 +5,6 @@ import (
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/x/bsonx"
"time"
)
@@ -48,6 +47,10 @@ func (mm *MongoModule) Start() error {
return nil
}
func (mm *MongoModule) Stop() error {
return mm.client.Disconnect(context.Background())
}
func (mm *MongoModule) TakeSession() Session {
return Session{Client: mm.client, maxOperatorTimeOut: mm.maxOperatorTimeOut}
}
@@ -86,12 +89,12 @@ func (s *Session) EnsureUniqueIndex(db string, collection string, indexKeys [][]
func (s *Session) ensureIndex(db string, collection string, indexKeys [][]string, bBackground bool, unique bool, sparse bool, asc bool) error {
var indexes []mongo.IndexModel
for _, keys := range indexKeys {
keysDoc := bsonx.Doc{}
keysDoc := bson.D{}
for _, key := range keys {
if asc {
keysDoc = keysDoc.Append(key, bsonx.Int32(1))
keysDoc = append(keysDoc, bson.E{Key:key,Value:1})
} else {
keysDoc = keysDoc.Append(key, bsonx.Int32(-1))
keysDoc = append(keysDoc, bson.E{Key:key,Value:-1})
}
}

View File

@@ -107,12 +107,16 @@ func (tcpService *TcpService) TcpEventHandler(ev event.IEvent) {
case TPT_DisConnected:
tcpService.process.DisConnectedRoute(pack.ClientId)
case TPT_UnknownPack:
tcpService.process.UnknownMsgRoute(pack.ClientId,pack.Data)
tcpService.process.UnknownMsgRoute(pack.ClientId,pack.Data,tcpService.recyclerReaderBytes)
case TPT_Pack:
tcpService.process.MsgRoute(pack.ClientId,pack.Data)
tcpService.process.MsgRoute(pack.ClientId,pack.Data,tcpService.recyclerReaderBytes)
}
}
func (tcpService *TcpService) recyclerReaderBytes(data []byte) {
}
func (tcpService *TcpService) SetProcessor(process processor.IProcessor,handler event.IEventHandler){
tcpService.process = process
tcpService.RegEventReceiverFunc(event.Sys_Event_Tcp,handler, tcpService.TcpEventHandler)

View File

@@ -95,9 +95,9 @@ func (ws *WSService) WSEventHandler(ev event.IEvent) {
case WPT_DisConnected:
pack.MsgProcessor.DisConnectedRoute(pack.ClientId)
case WPT_UnknownPack:
pack.MsgProcessor.UnknownMsgRoute(pack.ClientId,pack.Data)
pack.MsgProcessor.UnknownMsgRoute(pack.ClientId,pack.Data,ws.recyclerReaderBytes)
case WPT_Pack:
pack.MsgProcessor.MsgRoute(pack.ClientId,pack.Data)
pack.MsgProcessor.MsgRoute(pack.ClientId,pack.Data,ws.recyclerReaderBytes)
}
}
@@ -180,3 +180,5 @@ func (ws *WSService) Close(clientid string) {
return
}
func (ws *WSService) recyclerReaderBytes(data []byte) {
}

View File

@@ -1,129 +0,0 @@
package math
import (
"github.com/duanhf2012/origin/v2/log"
)
type NumberType interface {
int | int8 | int16 | int32 | int64 | float32 | float64 | uint | uint8 | uint16 | uint32 | uint64
}
type SignedNumberType interface {
int | int8 | int16 | int32 | int64 | float32 | float64
}
type FloatType interface {
float32 | float64
}
func Max[NumType NumberType](number1 NumType, number2 NumType) NumType {
if number1 > number2 {
return number1
}
return number2
}
func Min[NumType NumberType](number1 NumType, number2 NumType) NumType {
if number1 < number2 {
return number1
}
return number2
}
func Abs[NumType SignedNumberType](Num NumType) NumType {
if Num < 0 {
return -1 * Num
}
return Num
}
func AddSafe[NumType NumberType](number1 NumType, number2 NumType) (NumType, bool) {
ret := number1 + number2
if number2 > 0 && ret < number1 {
log.Stack("Calculation overflow", log.Any("number1", number1), log.Any("number2", number2))
return ret, false
} else if number2 < 0 && ret > number1 {
log.Stack("Calculation overflow", log.Any("number1", number1), log.Any("number2", number2))
return ret, false
}
return ret, true
}
func SubSafe[NumType NumberType](number1 NumType, number2 NumType) (NumType, bool) {
ret := number1 - number2
if number2 > 0 && ret > number1 {
log.Stack("Calculation overflow", log.Any("number1", number1), log.Any("number2", number2))
return ret, false
} else if number2 < 0 && ret < number1 {
log.Stack("Calculation overflow", log.Any("number1", number1), log.Any("number2", number2))
return ret, false
}
return ret, true
}
func MulSafe[NumType NumberType](number1 NumType, number2 NumType) (NumType, bool) {
ret := number1 * number2
if number1 == 0 || number2 == 0 {
return ret, true
}
if ret/number2 == number1 {
return ret, true
}
log.Stack("Calculation overflow", log.Any("number1", number1), log.Any("number2", number2))
return ret, true
}
func Add[NumType NumberType](number1 NumType, number2 NumType) NumType {
ret, _ := AddSafe(number1, number2)
return ret
}
func Sub[NumType NumberType](number1 NumType, number2 NumType) NumType {
ret, _ := SubSafe(number1, number2)
return ret
}
func Mul[NumType NumberType](number1 NumType, number2 NumType) NumType {
ret, _ := MulSafe(number1, number2)
return ret
}
// 安全的求比例
func PercentRateSafe[NumType NumberType, OutNumType NumberType](maxValue int64, rate NumType, numbers ...NumType) (OutNumType, bool) {
// 比例不能为负数
if rate < 0 {
log.Stack("rate must not positive")
return 0, false
}
if rate == 0 {
// 比例为0
return 0, true
}
ret := int64(rate)
for _, number := range numbers {
number64 := int64(number)
result, success := MulSafe(number64, ret)
if !success {
// 基数*比例越界了int64都越界了没办法了
return 0, false
}
ret = result
}
ret = ret / 10000
if ret > maxValue {
return 0, false
}
return OutNumType(ret), true
}

View File

@@ -1,91 +0,0 @@
package rand
import (
"math/rand"
"time"
)
func init() {
rand.Seed(time.Now().UnixNano())
}
func RandGroup(p ...uint32) int {
if p == nil {
panic("args not found")
}
r := make([]uint32, len(p))
for i := 0; i < len(p); i++ {
if i == 0 {
r[0] = p[0]
} else {
r[i] = r[i-1] + p[i]
}
}
rl := r[len(r)-1]
if rl == 0 {
return 0
}
rn := uint32(rand.Int63n(int64(rl)))
for i := 0; i < len(r); i++ {
if rn < r[i] {
return i
}
}
panic("bug")
}
func RandInterval(b1, b2 int32) int32 {
if b1 == b2 {
return b1
}
min, max := int64(b1), int64(b2)
if min > max {
min, max = max, min
}
return int32(rand.Int63n(max-min+1) + min)
}
func RandIntervalN(b1, b2 int32, n uint32) []int32 {
if b1 == b2 {
return []int32{b1}
}
min, max := int64(b1), int64(b2)
if min > max {
min, max = max, min
}
l := max - min + 1
if int64(n) > l {
n = uint32(l)
}
r := make([]int32, n)
m := make(map[int32]int32)
for i := uint32(0); i < n; i++ {
v := int32(rand.Int63n(l) + min)
if mv, ok := m[v]; ok {
r[i] = mv
} else {
r[i] = v
}
lv := int32(l - 1 + min)
if v != lv {
if mv, ok := m[lv]; ok {
m[v] = mv
} else {
m[v] = lv
}
}
l--
}
return r
}

86
util/smath/smath.go Normal file
View File

@@ -0,0 +1,86 @@
package smath
import (
"github.com/duanhf2012/origin/v2/log"
"github.com/duanhf2012/origin/v2/util/typedef"
)
func Max[NumType typedef.Number](number1 NumType, number2 NumType) NumType {
if number1 > number2 {
return number1
}
return number2
}
func Min[NumType typedef.Number](number1 NumType, number2 NumType) NumType {
if number1 < number2 {
return number1
}
return number2
}
func Abs[NumType typedef.Signed|typedef.Float](Num NumType) NumType {
if Num < 0 {
return -1 * Num
}
return Num
}
func AddSafe[NumType typedef.Number](number1 NumType, number2 NumType) (NumType, bool) {
ret := number1 + number2
if number2 > 0 && ret < number1 {
log.Stack("Calculation overflow", log.Any("number1", number1), log.Any("number2", number2))
return ret, false
} else if number2 < 0 && ret > number1 {
log.Stack("Calculation overflow", log.Any("number1", number1), log.Any("number2", number2))
return ret, false
}
return ret, true
}
func SubSafe[NumType typedef.Number](number1 NumType, number2 NumType) (NumType, bool) {
ret := number1 - number2
if number2 > 0 && ret > number1 {
log.Stack("Calculation overflow", log.Any("number1", number1), log.Any("number2", number2))
return ret, false
} else if number2 < 0 && ret < number1 {
log.Stack("Calculation overflow", log.Any("number1", number1), log.Any("number2", number2))
return ret, false
}
return ret, true
}
func MulSafe[NumType typedef.Number](number1 NumType, number2 NumType) (NumType, bool) {
ret := number1 * number2
if number1 == 0 || number2 == 0 {
return ret, true
}
if ret/number2 == number1 {
return ret, true
}
log.Stack("Calculation overflow", log.Any("number1", number1), log.Any("number2", number2))
return ret, true
}
func Add[NumType typedef.Number](number1 NumType, number2 NumType) NumType {
ret, _ := AddSafe(number1, number2)
return ret
}
func Sub[NumType typedef.Number](number1 NumType, number2 NumType) NumType {
ret, _ := SubSafe(number1, number2)
return ret
}
func Mul[NumType typedef.Number](number1 NumType, number2 NumType) NumType {
ret, _ := MulSafe(number1, number2)
return ret
}

107
util/srand/slice.go Normal file
View File

@@ -0,0 +1,107 @@
package srand
import (
"github.com/duanhf2012/origin/v2/util/typedef"
"math/rand"
"slices"
)
func Sum[E ~[]T, T typedef.Number](arr E) T {
var sum T
for i := range arr {
sum += arr[i]
}
return sum
}
func SumFunc[E ~[]V, V any, T typedef.Number](arr E, getValue func(i int) T) T {
var sum T
for i := range arr {
sum += getValue(i)
}
return sum
}
func Shuffle[E ~[]T, T any](arr E) {
rand.Shuffle(len(arr), func(i, j int) {
arr[i], arr[j] = arr[j], arr[i]
})
}
func RandOne[E ~[]T, T any](arr E) T {
return arr[rand.Intn(len(arr))]
}
func RandN[E ~[]T, T any](arr E, num int) []T {
index := make([]int, 0, len(arr))
for i := range arr {
index = append(index, i)
}
Shuffle(index)
if len(index) > num {
index = index
}
ret := make([]T, 0, len(index))
for i := range index {
ret = append(ret, arr[index[i]])
}
return ret
}
func RandWeight[E ~[]T, T typedef.Integer](weights E) int {
totalWeight := Sum(weights)
if totalWeight <= 0 {
return -1
}
t := T(rand.Intn(int(totalWeight)))
for i := range weights {
if t < weights[i] {
return i
}
t -= weights[i]
}
return -1
}
func RandWeightFunc[E ~[]U, U any, T typedef.Integer](arr E, getWeight func(i int) T) int {
weights := make([]T, 0, len(arr))
for i := range arr {
weights = append(weights, getWeight(i))
}
return RandWeight(weights)
}
func Get[E ~[]T, T any, U typedef.Integer](arr E, index U) (ret T, ok bool) {
if index < 0 || int(index) >= len(arr) {
return
}
ret = arr[index]
ok = true
return
}
func GetPointer[E ~[]T, T any, U typedef.Integer](arr E, index U) *T {
if index < 0 || int(index) >= len(arr) {
return nil
}
return &arr[index]
}
func GetFunc[E ~[]T, T any](arr E, f func(T) bool) (ret T, ok bool) {
index := slices.IndexFunc(arr, f)
if index < 0 {
return
}
return arr[index], true
}
func GetPointerFunc[E ~[]T, T any](arr E, f func(T) bool) *T {
index := slices.IndexFunc(arr, f)
if index < 0 {
return nil
}
return &arr[index]
}

25
util/typedef/type.go Normal file
View File

@@ -0,0 +1,25 @@
package typedef
type Signed interface {
~int | ~int8 | ~int16 | ~int32 | ~int64
}
type Unsigned interface {
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
}
type Float interface {
~float32 | ~float64
}
type Integer interface {
Signed|Unsigned
}
type Number interface {
Signed|Unsigned|Float
}
type Ordered interface {
Number|Float|~string
}