github.com/glide-im/glide@v1.6.0/pkg/messaging/default_impl.go (about)

     1  package messaging
     2  
     3  import (
     4  	"github.com/glide-im/glide/pkg/gate"
     5  	"github.com/glide-im/glide/pkg/logger"
     6  	"github.com/glide-im/glide/pkg/messages"
     7  	"github.com/glide-im/glide/pkg/subscription"
     8  	"github.com/panjf2000/ants/v2"
     9  )
    10  
    11  type Options struct {
    12  	NotifyServerError     bool
    13  	MaxMessageConcurrency int
    14  }
    15  
    16  func onMessageHandlerPanic(i interface{}) {
    17  	logger.E("MessageInterfaceImpl panic: %v", i)
    18  }
    19  
    20  // MessageInterfaceImpl default implementation of the messaging interface.
    21  type MessageInterfaceImpl struct {
    22  
    23  	// execPool 100 capacity goroutine pool, 假设每个消息处理需要10ms, 一个协程则每秒能处理100条消息
    24  	execPool *ants.Pool
    25  
    26  	// hc message handler chain
    27  	hc *handlerChain
    28  
    29  	subscription subscription.Interface
    30  	gate         gate.Gateway
    31  
    32  	// notifyOnSrvErr notify client on server error
    33  	notifyOnSrvErr bool
    34  }
    35  
    36  func NewDefaultImpl(options *Options) (*MessageInterfaceImpl, error) {
    37  
    38  	ret := MessageInterfaceImpl{
    39  		notifyOnSrvErr: options.NotifyServerError,
    40  		hc:             &handlerChain{},
    41  	}
    42  
    43  	var err error
    44  	ret.execPool, err = ants.NewPool(
    45  		options.MaxMessageConcurrency,
    46  		ants.WithNonblocking(true),
    47  		ants.WithPanicHandler(onMessageHandlerPanic),
    48  		ants.WithPreAlloc(false),
    49  	)
    50  	if err != nil {
    51  		return nil, err
    52  	}
    53  	return &ret, nil
    54  }
    55  
    56  func (d *MessageInterfaceImpl) Handle(cInfo *gate.Info, msg *messages.GlideMessage) error {
    57  
    58  	if !msg.GetAction().IsInternal() {
    59  		msg.From = cInfo.ID.UID()
    60  	}
    61  	logger.D("handle message: %s", msg)
    62  	err := d.execPool.Submit(func() {
    63  		handled := d.hc.handle(d, cInfo, msg)
    64  		if !handled {
    65  			if !msg.GetAction().IsInternal() {
    66  				r := messages.NewMessage(msg.GetSeq(), messages.ActionNotifyUnknownAction, msg.GetAction())
    67  				_ = d.gate.EnqueueMessage(cInfo.ID, r)
    68  			}
    69  			logger.W("action is not handled: %s", msg.GetAction())
    70  		}
    71  	})
    72  	if err != nil {
    73  		d.OnHandleMessageError(cInfo, msg, err)
    74  		return err
    75  	}
    76  	return nil
    77  }
    78  
    79  func (d *MessageInterfaceImpl) AddHandler(i MessageHandler) {
    80  	d.hc.add(i)
    81  }
    82  
    83  func (d *MessageInterfaceImpl) SetGate(g gate.Gateway) {
    84  	d.gate = g
    85  }
    86  
    87  func (d *MessageInterfaceImpl) SetSubscription(g subscription.Interface) {
    88  	d.subscription = g
    89  }
    90  
    91  func (d *MessageInterfaceImpl) SetNotifyErrorOnServer(enable bool) {
    92  	d.notifyOnSrvErr = enable
    93  }
    94  
    95  func (d *MessageInterfaceImpl) GetClientInterface() gate.Gateway {
    96  	return d.gate
    97  }
    98  
    99  func (d *MessageInterfaceImpl) GetGroupInterface() subscription.Interface {
   100  	return d.subscription
   101  }
   102  
   103  func (d *MessageInterfaceImpl) OnHandleMessageError(cInfo *gate.Info, msg *messages.GlideMessage, err error) {
   104  	if d.notifyOnSrvErr {
   105  		_ = d.gate.EnqueueMessage(cInfo.ID, messages.NewMessage(-1, messages.ActionNotifyError, err.Error()))
   106  	}
   107  }
   108  
   109  // handlerChain is a chain of MessageHandlers.
   110  type handlerChain struct {
   111  	h    MessageHandler
   112  	next *handlerChain
   113  }
   114  
   115  func (hc *handlerChain) add(i MessageHandler) {
   116  	if hc.next == nil {
   117  		hc.next = &handlerChain{
   118  			h: i,
   119  		}
   120  	} else {
   121  		hc.next.add(i)
   122  	}
   123  }
   124  
   125  func (hc handlerChain) handle(h2 *MessageInterfaceImpl, cliInfo *gate.Info, message *messages.GlideMessage) bool {
   126  	if hc.h != nil && hc.h.Handle(h2, cliInfo, message) {
   127  		return true
   128  	}
   129  	if hc.next != nil {
   130  		return hc.next.handle(h2, cliInfo, message)
   131  	}
   132  	return false
   133  }