2025-05-25 20:02:15 +08:00
|
|
|
|
package service
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"fmt"
|
2025-05-29 11:49:24 +08:00
|
|
|
|
"github.com/fox/fox/ipb"
|
2025-05-25 20:02:15 +08:00
|
|
|
|
"github.com/fox/fox/ksync"
|
|
|
|
|
"github.com/fox/fox/log"
|
|
|
|
|
"github.com/fox/fox/safeChan"
|
|
|
|
|
"github.com/fox/fox/timer"
|
2025-06-07 23:51:40 +08:00
|
|
|
|
"sync"
|
2025-05-25 20:02:15 +08:00
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type BaseService struct {
|
|
|
|
|
*timer.Timer
|
|
|
|
|
type_ string
|
|
|
|
|
name string
|
2025-06-07 23:51:40 +08:00
|
|
|
|
once sync.Once
|
2025-05-25 20:02:15 +08:00
|
|
|
|
|
|
|
|
|
onFunc IOnFunc
|
|
|
|
|
sender ISender
|
|
|
|
|
|
2025-05-28 17:52:28 +08:00
|
|
|
|
msg *safeChan.SafeChan[[]byte]
|
|
|
|
|
job *safeChan.SafeChan[func()]
|
|
|
|
|
readyStop context.Context // 通知关闭的chan
|
|
|
|
|
readyStopFunc context.CancelFunc // NotifyStop会调用该方法,触发服务进入关闭流程
|
|
|
|
|
waitStop context.Context
|
|
|
|
|
waitStopFunc context.CancelFunc
|
2025-05-25 20:02:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NewBaseService(type_, name string, onFunc IOnFunc, sender ISender) *BaseService {
|
|
|
|
|
s := &BaseService{
|
|
|
|
|
type_: type_,
|
|
|
|
|
name: name,
|
|
|
|
|
Timer: timer.NewTimer(),
|
|
|
|
|
onFunc: onFunc,
|
|
|
|
|
sender: sender,
|
|
|
|
|
|
|
|
|
|
msg: safeChan.NewSafeChan[[]byte](128),
|
|
|
|
|
job: safeChan.NewSafeChan[func()](128),
|
|
|
|
|
}
|
2025-05-28 17:52:28 +08:00
|
|
|
|
s.readyStop, s.readyStopFunc = context.WithCancel(context.Background())
|
2025-05-25 20:02:15 +08:00
|
|
|
|
s.waitStop, s.waitStopFunc = context.WithCancel(context.Background())
|
|
|
|
|
|
2025-05-28 14:54:19 +08:00
|
|
|
|
//s.Run()
|
2025-05-25 20:02:15 +08:00
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *BaseService) Name() string {
|
|
|
|
|
return s.name
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *BaseService) Type() string {
|
|
|
|
|
return s.type_
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *BaseService) Write(msg []byte) error {
|
|
|
|
|
return s.msg.Write(msg)
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-31 09:35:55 +08:00
|
|
|
|
// 执行一次回调
|
2025-05-25 20:02:15 +08:00
|
|
|
|
func (s *BaseService) RunOnce(cb func()) {
|
|
|
|
|
select {
|
2025-05-28 17:52:28 +08:00
|
|
|
|
case <-s.readyStop.Done():
|
|
|
|
|
log.Error(s.Log("want readyStop, can not call RunOnce function"))
|
2025-05-25 20:02:15 +08:00
|
|
|
|
return
|
|
|
|
|
default:
|
|
|
|
|
_ = s.job.Write(cb)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-31 09:35:55 +08:00
|
|
|
|
// 执行一次回调并等待返回值
|
2025-05-25 20:02:15 +08:00
|
|
|
|
func (s *BaseService) RunWait(cb func() (retValue any)) (retValue any, err error) {
|
|
|
|
|
select {
|
2025-05-28 17:52:28 +08:00
|
|
|
|
case <-s.readyStop.Done():
|
|
|
|
|
err = fmt.Errorf(s.Log("want readyStop, can not call RunOnce function"))
|
2025-05-25 20:02:15 +08:00
|
|
|
|
log.Error(err.Error())
|
|
|
|
|
return nil, err
|
|
|
|
|
default:
|
|
|
|
|
wait := make(chan any, 2)
|
|
|
|
|
err = s.job.Write(func() {
|
|
|
|
|
retValue = cb()
|
|
|
|
|
wait <- retValue
|
|
|
|
|
})
|
|
|
|
|
if err == nil {
|
|
|
|
|
select {
|
|
|
|
|
case retValue = <-wait:
|
|
|
|
|
return retValue, nil
|
|
|
|
|
case <-time.After(time.Second * time.Duration(30)):
|
|
|
|
|
return nil, fmt.Errorf("timeout fail")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-29 11:49:24 +08:00
|
|
|
|
func (s *BaseService) Send(topic string, msg *ipb.InternalMsg) error {
|
2025-05-25 20:02:15 +08:00
|
|
|
|
if s.sender != nil {
|
|
|
|
|
return s.sender.Send(topic, msg)
|
|
|
|
|
}
|
|
|
|
|
return s.Err("send is nil")
|
|
|
|
|
}
|
2025-06-01 09:57:01 +08:00
|
|
|
|
func (s *BaseService) Call(rpcTopic string, timeout time.Duration, msg *ipb.InternalMsg) (*ipb.InternalMsg, error) {
|
2025-05-25 20:02:15 +08:00
|
|
|
|
if s.sender != nil {
|
2025-06-01 09:57:01 +08:00
|
|
|
|
return s.sender.Call(rpcTopic, timeout, msg)
|
2025-05-25 20:02:15 +08:00
|
|
|
|
}
|
2025-06-01 09:57:01 +08:00
|
|
|
|
return nil, s.Err("call is nil")
|
2025-05-25 20:02:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *BaseService) WaitStop() {
|
|
|
|
|
select {
|
|
|
|
|
case <-s.waitStop.Done():
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *BaseService) NotifyStop() {
|
2025-05-28 17:52:28 +08:00
|
|
|
|
s.readyStopFunc()
|
2025-05-31 09:35:55 +08:00
|
|
|
|
//log.Debug(s.Log("notify %v service readyStop", s.name))
|
2025-05-25 20:02:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
2025-05-28 17:52:28 +08:00
|
|
|
|
//func (s *BaseService) allChanEmpty() bool {
|
|
|
|
|
// if s.job.Size() == 0 && s.msg.Size() == 0 {
|
|
|
|
|
// return true
|
|
|
|
|
// }
|
|
|
|
|
// return false
|
|
|
|
|
//}
|
2025-05-25 20:02:15 +08:00
|
|
|
|
|
|
|
|
|
func (s *BaseService) canStop() bool {
|
|
|
|
|
select {
|
2025-05-28 17:52:28 +08:00
|
|
|
|
case <-s.readyStop.Done():
|
2025-05-31 09:35:55 +08:00
|
|
|
|
//log.Error(s.Log("want readyStop"))
|
2025-05-28 17:52:28 +08:00
|
|
|
|
return true
|
2025-05-25 20:02:15 +08:00
|
|
|
|
default:
|
2025-05-31 09:35:55 +08:00
|
|
|
|
//log.Error(s.Log("can not Stop"))
|
2025-05-25 20:02:15 +08:00
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *BaseService) run() {
|
|
|
|
|
for {
|
2025-05-28 17:52:28 +08:00
|
|
|
|
if s.onFunc.CanStop() && s.canStop() {
|
2025-05-31 09:35:55 +08:00
|
|
|
|
//log.Error(s.Log("stop service"))
|
2025-05-28 17:52:28 +08:00
|
|
|
|
s.msg.Close()
|
|
|
|
|
s.job.Close()
|
|
|
|
|
s.Timer.CancelAllTimer()
|
|
|
|
|
s.Timer.Close()
|
|
|
|
|
|
|
|
|
|
s.onFunc.OnStop()
|
|
|
|
|
s.waitStopFunc()
|
2025-05-25 20:02:15 +08:00
|
|
|
|
break
|
|
|
|
|
}
|
2025-05-31 09:35:55 +08:00
|
|
|
|
// select无default会阻塞在case的chan中直到有可读chan
|
2025-05-25 20:02:15 +08:00
|
|
|
|
select {
|
|
|
|
|
case msg, ok := <-s.msg.Reader():
|
2025-05-31 09:35:55 +08:00
|
|
|
|
//log.Debug(s.Log("msg reader"))
|
2025-05-28 17:52:28 +08:00
|
|
|
|
if ok {
|
2025-05-25 20:02:15 +08:00
|
|
|
|
_ = s.onFunc.OnMessage(msg)
|
|
|
|
|
}
|
|
|
|
|
case cb, ok := <-s.job.Reader():
|
2025-05-31 09:35:55 +08:00
|
|
|
|
//log.Debug(s.Log("job reader"))
|
2025-05-25 20:02:15 +08:00
|
|
|
|
if ok && cb != nil {
|
|
|
|
|
cb()
|
|
|
|
|
}
|
|
|
|
|
case t, ok := <-s.Timer.Reader():
|
2025-05-31 09:35:55 +08:00
|
|
|
|
//log.Debug(s.Log("timer reader"))
|
2025-05-25 20:02:15 +08:00
|
|
|
|
if ok && t != nil && t.Func != nil {
|
|
|
|
|
t.Func()
|
|
|
|
|
}
|
2025-05-31 09:35:55 +08:00
|
|
|
|
default:
|
|
|
|
|
// 休眠50微秒,避免cpu占用过高
|
|
|
|
|
time.Sleep(50 * time.Microsecond)
|
2025-05-25 20:02:15 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-07 23:52:13 +08:00
|
|
|
|
// 核心函数,让服务跑起来
|
2025-05-25 20:02:15 +08:00
|
|
|
|
func (s *BaseService) Run() {
|
2025-06-07 23:51:40 +08:00
|
|
|
|
s.once.Do(func() {
|
|
|
|
|
ksync.GoSafe(s.run, s.run)
|
|
|
|
|
})
|
2025-05-25 20:02:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *BaseService) Log(format string, a ...any) string {
|
2025-05-26 16:02:54 +08:00
|
|
|
|
head := fmt.Sprintf("service:%v ", s.name)
|
2025-05-25 20:02:15 +08:00
|
|
|
|
return head + fmt.Sprintf(format, a...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *BaseService) Err(format string, a ...any) error {
|
2025-05-26 16:02:54 +08:00
|
|
|
|
head := fmt.Sprintf("service:%v ", s.name)
|
2025-05-25 20:02:15 +08:00
|
|
|
|
return fmt.Errorf(head + fmt.Sprintf(format, a...))
|
|
|
|
|
}
|