183 lines
3.6 KiB
Go
183 lines
3.6 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"github.com/fox/fox/ksync"
|
|
"github.com/fox/fox/log"
|
|
"github.com/fox/fox/safeChan"
|
|
"github.com/fox/fox/timer"
|
|
"time"
|
|
)
|
|
|
|
type BaseService struct {
|
|
*timer.Timer
|
|
type_ string
|
|
name string
|
|
|
|
onFunc IOnFunc
|
|
sender ISender
|
|
|
|
msg *safeChan.SafeChan[[]byte]
|
|
job *safeChan.SafeChan[func()]
|
|
stop context.Context
|
|
stopFunc context.CancelFunc
|
|
waitStop context.Context
|
|
waitStopFunc context.CancelFunc
|
|
}
|
|
|
|
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),
|
|
}
|
|
s.stop, s.stopFunc = context.WithCancel(context.Background())
|
|
s.waitStop, s.waitStopFunc = context.WithCancel(context.Background())
|
|
|
|
//s.Run()
|
|
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)
|
|
}
|
|
|
|
func (s *BaseService) RunOnce(cb func()) {
|
|
select {
|
|
case <-s.stop.Done():
|
|
log.Error(s.Log("want stop, can not call RunOnce function"))
|
|
return
|
|
default:
|
|
_ = s.job.Write(cb)
|
|
}
|
|
}
|
|
|
|
func (s *BaseService) RunWait(cb func() (retValue any)) (retValue any, err error) {
|
|
select {
|
|
case <-s.stop.Done():
|
|
err = fmt.Errorf(s.Log("want stop, can not call RunOnce function"))
|
|
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
|
|
}
|
|
}
|
|
|
|
func (s *BaseService) Send(topic string, msg []byte) error {
|
|
if s.sender != nil {
|
|
return s.sender.Send(topic, msg)
|
|
}
|
|
return s.Err("send is nil")
|
|
}
|
|
func (s *BaseService) Call(topic string, timeout time.Duration, msg []byte) ([]byte, error) {
|
|
if s.sender != nil {
|
|
return s.sender.Call(topic, timeout, msg)
|
|
}
|
|
return nil, s.Err("call is nil")
|
|
}
|
|
|
|
func (s *BaseService) WaitStop() {
|
|
select {
|
|
case <-s.waitStop.Done():
|
|
return
|
|
}
|
|
}
|
|
|
|
func (s *BaseService) NotifyStop() {
|
|
s.stopFunc()
|
|
// log.Debug(fmt.Sprintf("notify %v service stop", s.name))
|
|
}
|
|
|
|
func (s *BaseService) allChanEmpty() bool {
|
|
if s.job.Size() == 0 && s.msg.Size() == 0 {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (s *BaseService) canStop() bool {
|
|
select {
|
|
case <-s.stop.Done():
|
|
if s.allChanEmpty() {
|
|
return true
|
|
}
|
|
return false
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
func (s *BaseService) run() {
|
|
for {
|
|
if s.canStop() {
|
|
if s.onFunc != nil {
|
|
s.onFunc.OnStop()
|
|
s.waitStopFunc()
|
|
}
|
|
break
|
|
}
|
|
select {
|
|
case msg, ok := <-s.msg.Reader():
|
|
if ok && s.onFunc != nil {
|
|
_ = s.onFunc.OnMessage(msg)
|
|
}
|
|
case cb, ok := <-s.job.Reader():
|
|
if ok && cb != nil {
|
|
cb()
|
|
}
|
|
case t, ok := <-s.Timer.Reader():
|
|
if ok && t != nil && t.Func != nil {
|
|
t.Func()
|
|
}
|
|
case _ = <-s.stop.Done():
|
|
if s.onFunc != nil {
|
|
s.msg.Close()
|
|
s.job.Close()
|
|
s.Timer.CancelAllTimer()
|
|
s.Timer.Close()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *BaseService) Run() {
|
|
ksync.GoSafe(s.run, s.Run)
|
|
}
|
|
|
|
func (s *BaseService) Log(format string, a ...any) string {
|
|
head := fmt.Sprintf("service:%v ", s.name)
|
|
return head + fmt.Sprintf(format, a...)
|
|
}
|
|
|
|
func (s *BaseService) Err(format string, a ...any) error {
|
|
head := fmt.Sprintf("service:%v ", s.name)
|
|
return fmt.Errorf(head + fmt.Sprintf(format, a...))
|
|
}
|