github.com/15mga/kiwi@v0.0.2-0.20240324021231-b95d5c3ac751/network/agent.go (about)

     1  package network
     2  
     3  import (
     4  	"context"
     5  	"github.com/15mga/kiwi"
     6  	"math"
     7  	"net"
     8  	"sync"
     9  
    10  	"github.com/15mga/kiwi/ds"
    11  
    12  	"github.com/15mga/kiwi/util"
    13  )
    14  
    15  const (
    16  	_PacketMaxCap int = math.MaxUint32
    17  	_PacketMinCap int = 1 << 11
    18  )
    19  
    20  func newAgent(addr string, receiver kiwi.FnAgentBytes, opts ...kiwi.AgentOption) agent {
    21  	opt := &kiwi.AgentOpt{
    22  		PacketMaxCap: _PacketMaxCap,
    23  		PacketMinCap: _PacketMinCap,
    24  		HeadLen:      4,
    25  	}
    26  	for _, action := range opts {
    27  		action(opt)
    28  	}
    29  	a := agent{
    30  		id:             addr,
    31  		addr:           addr,
    32  		option:         opt,
    33  		enable:         util.NewEnable(),
    34  		receiver:       receiver,
    35  		bytesLink:      ds.NewLink[[]byte](),
    36  		onConnected:    ds.NewFnLink1[kiwi.IAgent](),
    37  		onDisconnected: ds.NewFnLink2[kiwi.IAgent, *util.Err](),
    38  		head:           util.M{},
    39  		cache:          util.M{},
    40  		mtx:            &sync.RWMutex{},
    41  	}
    42  	a.head.Set("addr", addr)
    43  	return a
    44  }
    45  
    46  type agent struct {
    47  	option         *kiwi.AgentOpt
    48  	onClose        func() error
    49  	id             string
    50  	addr           string
    51  	ctx            context.Context
    52  	cancel         context.CancelFunc
    53  	writeSignCh    chan struct{}
    54  	enable         *util.Enable
    55  	receiver       kiwi.FnAgentBytes
    56  	bytesLink      *ds.Link[[]byte]
    57  	onConnected    *ds.FnLink1[kiwi.IAgent]
    58  	onDisconnected *ds.FnLink2[kiwi.IAgent, *util.Err]
    59  	head           util.M
    60  	cache          util.M
    61  	mtx            *sync.RWMutex
    62  }
    63  
    64  func (a *agent) onStart(_ []any) {
    65  	a.writeSignCh = make(chan struct{}, 1)
    66  	go a.onConnected.Invoke(a)
    67  }
    68  
    69  func (a *agent) start(ctx context.Context) {
    70  	a.ctx, a.cancel = context.WithCancel(ctx)
    71  	_ = a.enable.Enable(a.onStart)
    72  }
    73  
    74  func (a *agent) SetHead(key string, val any) {
    75  	a.mtx.Lock()
    76  	a.head[key] = val
    77  	a.mtx.Unlock()
    78  }
    79  
    80  func (a *agent) SetHeads(m util.M) {
    81  	a.mtx.Lock()
    82  	for key, val := range m {
    83  		a.head[key] = val
    84  	}
    85  	a.mtx.Unlock()
    86  }
    87  
    88  func (a *agent) GetHead(key string) (val any, exist bool) {
    89  	a.mtx.RLock()
    90  	val, exist = a.head[key]
    91  	a.mtx.RUnlock()
    92  	return
    93  }
    94  
    95  func (a *agent) DelHead(keys ...string) {
    96  	a.mtx.Lock()
    97  	for _, key := range keys {
    98  		delete(a.head, key)
    99  	}
   100  	a.mtx.Unlock()
   101  }
   102  
   103  func (a *agent) CopyHead(m util.M) {
   104  	if m == nil {
   105  		return
   106  	}
   107  	a.mtx.Lock()
   108  	for key, val := range a.head {
   109  		m[key] = val
   110  	}
   111  	a.mtx.Unlock()
   112  }
   113  
   114  func (a *agent) SetCache(key string, val any) {
   115  	a.mtx.Lock()
   116  	a.cache[key] = val
   117  	a.mtx.Unlock()
   118  }
   119  
   120  func (a *agent) SetCaches(m util.M) {
   121  	a.mtx.Lock()
   122  	for key, val := range m {
   123  		a.cache[key] = val
   124  	}
   125  	a.mtx.Unlock()
   126  }
   127  
   128  func (a *agent) GetCache(key string) (val any, exist bool) {
   129  	a.mtx.RLock()
   130  	val, exist = a.cache[key]
   131  	a.mtx.RUnlock()
   132  	return
   133  }
   134  
   135  func (a *agent) DelCache(keys ...string) {
   136  	a.mtx.Lock()
   137  	for _, key := range keys {
   138  		delete(a.cache, key)
   139  	}
   140  	a.mtx.Unlock()
   141  }
   142  
   143  func (a *agent) CopyCache(m util.M) {
   144  	a.mtx.Lock()
   145  	for key, val := range a.cache {
   146  		m[key] = val
   147  	}
   148  	a.mtx.Unlock()
   149  }
   150  
   151  func (a *agent) Id() (id string) {
   152  	a.mtx.RLock()
   153  	id = a.id
   154  	a.mtx.RUnlock()
   155  	return id
   156  }
   157  
   158  func (a *agent) SetId(id string) {
   159  	a.mtx.Lock()
   160  	a.id = id
   161  	a.mtx.Unlock()
   162  }
   163  
   164  func (a *agent) Addr() string {
   165  	return a.addr
   166  }
   167  
   168  func (a *agent) Host() string {
   169  	host, _, _ := net.SplitHostPort(a.addr)
   170  	return host
   171  }
   172  
   173  func (a *agent) Enable() *util.Enable {
   174  	return a.enable
   175  }
   176  
   177  func (a *agent) Dispose() {
   178  	a.cancel()
   179  }
   180  
   181  func (a *agent) Send(bytes []byte) *util.Err {
   182  	if bytes == nil {
   183  		return util.NewErr(util.EcEmpty, nil)
   184  	}
   185  	l := len(bytes)
   186  	if l == 0 {
   187  		return util.NewErr(util.EcEmpty, nil)
   188  	}
   189  	if l > a.option.PacketMaxCap {
   190  		return util.NewErr(util.EcTooLong, util.M{
   191  			"length": l,
   192  		})
   193  	}
   194  	return a.enable.WAction(agentPushByte, a, bytes)
   195  }
   196  
   197  func agentPushByte(params []any) {
   198  	a, bytes := util.SplitSlc2[*agent, []byte](params)
   199  	a.bytesLink.Push(bytes)
   200  	select {
   201  	case a.writeSignCh <- struct{}{}:
   202  	default:
   203  	}
   204  }
   205  
   206  func (a *agent) BindConnected(fn kiwi.FnAgent) {
   207  	a.onConnected.Push(fn)
   208  }
   209  
   210  func (a *agent) BindDisconnected(fn kiwi.FnAgentErr) {
   211  	a.onDisconnected.Push(fn)
   212  }
   213  
   214  func (a *agent) close(err *util.Err) {
   215  	a.enable.Disable(agentClose, a, err)
   216  }
   217  
   218  func agentClose(params []any) {
   219  	a, err := util.SplitSlc2[*agent, *util.Err](params)
   220  	close(a.writeSignCh)
   221  	_ = a.onClose()
   222  	go a.onDisconnected.Invoke(a, err)
   223  }