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

     1  package core
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/15mga/kiwi"
     6  	"net"
     7  	"strings"
     8  	"sync"
     9  	"sync/atomic"
    10  
    11  	"github.com/15mga/kiwi/ds"
    12  	"github.com/15mga/kiwi/network"
    13  	"github.com/15mga/kiwi/util"
    14  	"github.com/15mga/kiwi/worker"
    15  	"github.com/fasthttp/websocket"
    16  )
    17  
    18  const (
    19  	DefConnCap = 1 << 12
    20  )
    21  
    22  type (
    23  	GateOption func(option *gateOption)
    24  	gateOption struct {
    25  		ip           string
    26  		tcp          int
    27  		web          int
    28  		udp          int
    29  		connCap      int32
    30  		connected    kiwi.FnAgent
    31  		disconnected kiwi.FnAgentErr
    32  		checkIp      util.StrToBool
    33  		deadline     int
    34  		headLen      int
    35  		roles        map[kiwi.TSvcCode][]int64
    36  	}
    37  )
    38  
    39  func GateIp(ip string) GateOption {
    40  	return func(option *gateOption) {
    41  		option.ip = ip
    42  	}
    43  }
    44  
    45  func GateTcpPort(port int) GateOption {
    46  	return func(option *gateOption) {
    47  		option.tcp = port
    48  	}
    49  }
    50  
    51  func GateWebsocketPort(port int) GateOption {
    52  	return func(option *gateOption) {
    53  		option.web = port
    54  	}
    55  }
    56  
    57  func GateUdpPort(port int) GateOption {
    58  	return func(option *gateOption) {
    59  		option.udp = port
    60  	}
    61  }
    62  
    63  func GateConnCap(cap int32) GateOption {
    64  	return func(option *gateOption) {
    65  		option.connCap = cap
    66  	}
    67  }
    68  
    69  func GateConnected(connected kiwi.FnAgent) GateOption {
    70  	return func(option *gateOption) {
    71  		option.connected = connected
    72  	}
    73  }
    74  
    75  func GateDisconnected(disconnected kiwi.FnAgentErr) GateOption {
    76  	return func(option *gateOption) {
    77  		option.disconnected = disconnected
    78  	}
    79  }
    80  
    81  func GateCheckIp(fn util.StrToBool) GateOption {
    82  	return func(option *gateOption) {
    83  		option.checkIp = fn
    84  	}
    85  }
    86  
    87  func GateDeadlineSecs(deadline int) GateOption {
    88  	return func(option *gateOption) {
    89  		option.deadline = deadline
    90  	}
    91  }
    92  
    93  func GateHeadLen(headLen int) GateOption {
    94  	return func(option *gateOption) {
    95  		option.headLen = headLen
    96  	}
    97  }
    98  
    99  func GateRoles(roles map[kiwi.TSvcCode][]int64) GateOption {
   100  	return func(option *gateOption) {
   101  		option.roles = roles
   102  	}
   103  }
   104  
   105  func InitGate(receiver kiwi.FnAgentBytes, opts ...GateOption) {
   106  	o := &gateOption{
   107  		connCap: DefConnCap,
   108  		checkIp: func(s string) bool {
   109  			return true
   110  		},
   111  		headLen: 4,
   112  		connected: func(agent kiwi.IAgent) {
   113  
   114  		},
   115  		disconnected: func(agent kiwi.IAgent, err *util.Err) {
   116  
   117  		},
   118  	}
   119  	for _, opt := range opts {
   120  		opt(o)
   121  	}
   122  	g := &gate{
   123  		option:   o,
   124  		receiver: receiver,
   125  		idToAgent: ds.NewKSet[string, kiwi.IAgent](1024, func(agent kiwi.IAgent) string {
   126  			return agent.Id()
   127  		}),
   128  		addrToAgent: ds.NewKSet[string, kiwi.IAgent](1024, func(agent kiwi.IAgent) string {
   129  			return agent.Addr()
   130  		}),
   131  		msgToRoles: sync.Map{},
   132  	}
   133  	g.SetRoles(o.roles)
   134  	g.worker = worker.NewJobWorker(g.process)
   135  	g.worker.Start()
   136  	if o.ip == "" {
   137  		ip, err := util.GetLocalIp()
   138  		if err != nil {
   139  			kiwi.Fatal(err)
   140  		}
   141  		kiwi.Info("use local ip", util.M{
   142  			"ip": ip,
   143  		})
   144  		o.ip = ip
   145  	}
   146  	if g.option.udp > 0 {
   147  		addr := fmt.Sprintf("%s:%d", g.option.ip, g.option.udp)
   148  		listener := network.NewUdpListener(addr, g.onAddUdpConn)
   149  		g.listeners = append(g.listeners, listener)
   150  		err := listener.Start()
   151  		if err != nil {
   152  			kiwi.Fatal(err)
   153  		}
   154  		_ = kiwi.GetNodeMeta().Data.Set2(g.option.udp, "gate", "udp")
   155  	}
   156  	if g.option.tcp > 0 {
   157  		addr := fmt.Sprintf("%s:%d", g.option.ip, g.option.tcp)
   158  		listener := network.NewTcpListener(addr, g.onAddTcpConn)
   159  		err := listener.Start()
   160  		if err != nil {
   161  			kiwi.Fatal(err)
   162  		}
   163  		g.listeners = append(g.listeners, listener)
   164  		_ = kiwi.GetNodeMeta().Data.Set2(g.option.tcp, "gate", "tcp")
   165  	}
   166  	if g.option.web > 0 {
   167  		addr := fmt.Sprintf("%s:%d", g.option.ip, g.option.web)
   168  		listener := network.NewWebListener(g.onAddWebConn, network.WebAddr(addr))
   169  		err := listener.Start()
   170  		if err != nil {
   171  			kiwi.Fatal(err)
   172  		}
   173  		g.listeners = append(g.listeners, listener)
   174  		_ = kiwi.GetNodeMeta().Data.Set2(g.option.web, "gate", "web")
   175  	}
   176  	kiwi.SetGate(g)
   177  }
   178  
   179  type gate struct {
   180  	option      *gateOption
   181  	receiver    kiwi.FnAgentBytes
   182  	worker      *worker.JobWorker
   183  	listeners   []kiwi.IListener
   184  	idToAgent   *ds.KSet[string, kiwi.IAgent]
   185  	addrToAgent *ds.KSet[string, kiwi.IAgent]
   186  	agentCount  int32
   187  	msgToRoles  sync.Map
   188  }
   189  
   190  func (g *gate) Dispose() *util.Err {
   191  	for _, listener := range g.listeners {
   192  		listener.Close()
   193  	}
   194  	return nil
   195  }
   196  
   197  func (g *gate) onAddTcpConn(conn net.Conn) {
   198  	addr := conn.RemoteAddr().String()
   199  	c := atomic.LoadInt32(&g.agentCount)
   200  	if c == g.option.connCap {
   201  		_ = conn.Close()
   202  		kiwi.Warn(util.NewErr(util.EcTooManyConn, util.M{
   203  			"addr": addr,
   204  		}))
   205  		return
   206  	}
   207  
   208  	if !g.option.checkIp(strings.Split(addr, ":")[0]) {
   209  		_ = conn.Close()
   210  		kiwi.Warn(util.NewErr(util.EcIllegalConn, util.M{
   211  			"addr": addr,
   212  		}))
   213  		return
   214  	}
   215  
   216  	agent := network.NewTcpAgent(addr, g.receiver,
   217  		kiwi.AgentErr(func(err *util.Err) {
   218  			err.AddParam("addr", addr)
   219  			kiwi.Error(err)
   220  		}),
   221  		kiwi.AgentDeadline(g.option.deadline),
   222  		kiwi.AgentHeadLen(g.option.headLen),
   223  	)
   224  	agent.BindConnected(g.onAgentConnected)
   225  	agent.BindDisconnected(g.onAgentClosed)
   226  	agent.Start(util.Ctx(), conn)
   227  }
   228  
   229  func (g *gate) onAddUdpConn(conn net.Conn) {
   230  	addr := conn.RemoteAddr().String()
   231  	c := atomic.LoadInt32(&g.agentCount)
   232  	if c == g.option.connCap {
   233  		_ = conn.Close()
   234  		kiwi.Warn(util.NewErr(util.EcTooManyConn, util.M{
   235  			"addr": addr,
   236  		}))
   237  		return
   238  	}
   239  
   240  	if !g.option.checkIp(strings.Split(addr, ":")[0]) {
   241  		_ = conn.Close()
   242  		kiwi.Warn(util.NewErr(util.EcIllegalConn, util.M{
   243  			"addr": addr,
   244  		}))
   245  		return
   246  	}
   247  
   248  	agent := network.NewUdpAgent(addr, g.receiver,
   249  		kiwi.AgentErr(func(err *util.Err) {
   250  			err.AddParam("addr", addr)
   251  			kiwi.Error(err)
   252  		}),
   253  		kiwi.AgentDeadline(g.option.deadline),
   254  		kiwi.AgentHeadLen(g.option.headLen),
   255  	)
   256  	agent.BindConnected(g.onAgentConnected)
   257  	agent.BindDisconnected(g.onAgentClosed)
   258  	agent.Start(util.Ctx(), conn)
   259  }
   260  
   261  func (g *gate) onAddWebConn(conn *websocket.Conn) {
   262  	addr := conn.RemoteAddr().String()
   263  	c := atomic.LoadInt32(&g.agentCount)
   264  	if c == g.option.connCap {
   265  		_ = conn.Close()
   266  		kiwi.Warn(util.NewErr(util.EcTooManyConn, util.M{
   267  			"addr": addr,
   268  		}))
   269  		return
   270  	}
   271  
   272  	if !g.option.checkIp(strings.Split(addr, ":")[0]) {
   273  		_ = conn.Close()
   274  		kiwi.Warn(util.NewErr(util.EcIllegalConn, util.M{
   275  			"addr": addr,
   276  		}))
   277  		return
   278  	}
   279  
   280  	agent := network.NewWebAgent(addr, 2, g.receiver,
   281  		kiwi.AgentErr(func(err *util.Err) {
   282  			err.AddParam("addr", addr)
   283  			kiwi.Error(err)
   284  		}),
   285  		kiwi.AgentDeadline(g.option.deadline),
   286  		kiwi.AgentHeadLen(g.option.headLen),
   287  	)
   288  	agent.BindConnected(g.onAgentConnected)
   289  	agent.BindDisconnected(g.onAgentClosed)
   290  	agent.Start(util.Ctx(), conn)
   291  }
   292  
   293  func (g *gate) onAgentConnected(agent kiwi.IAgent) {
   294  	g.worker.Push(gateConnected, agent)
   295  }
   296  
   297  func (g *gate) onAgentClosed(agent kiwi.IAgent, err *util.Err) {
   298  	g.worker.Push(gateDisconnected, agent, err)
   299  }
   300  
   301  func (g *gate) Send(tid int64, id string, bytes []byte, handler util.FnBool) {
   302  	g.worker.Push(gateSend, tid, id, bytes, handler)
   303  }
   304  
   305  func (g *gate) AddrSend(tid int64, addr string, bytes []byte, handler util.FnBool) {
   306  	g.worker.Push(gateAddrSend, tid, addr, bytes, handler)
   307  }
   308  
   309  func (g *gate) MultiSend(tid int64, idToPayload map[string][]byte, handler util.FnMapBool) {
   310  	g.worker.Push(gateMultiSend, tid, idToPayload, handler)
   311  }
   312  
   313  func (g *gate) MultiAddrSend(tid int64, addrToPayload map[string][]byte, handler util.FnMapBool) {
   314  	g.worker.Push(gateMultiAddrSend, tid, addrToPayload, handler)
   315  }
   316  
   317  func (g *gate) AllSend(tid int64, bytes []byte) {
   318  	g.worker.Push(gateAllSend, tid, bytes)
   319  }
   320  
   321  func (g *gate) UpdateHeadCache(tid int64, id string, head, cache util.M, handler util.FnBool) {
   322  	g.worker.Push(gateUpdate, tid, id, head, cache, handler)
   323  }
   324  
   325  func (g *gate) UpdateAddrHeadCache(tid int64, addr string, head, cache util.M, handler util.FnBool) {
   326  	g.worker.Push(gateUpdateAddr, tid, addr, head, cache, handler)
   327  }
   328  
   329  func (g *gate) RemoveHeadCache(tid int64, addr string, head, cache []string, handler util.FnBool) {
   330  	g.worker.Push(gateRemove, tid, addr, head, cache, handler)
   331  }
   332  
   333  func (g *gate) RemoveAddrHeadCache(tid int64, addr string, head, cache []string, handler util.FnBool) {
   334  	g.worker.Push(gateRemoveAddr, tid, addr, head, cache, handler)
   335  }
   336  
   337  func (g *gate) GetHeadCache(tid int64, id string, fn util.FnM2Bool) {
   338  	g.worker.Push(gateGet, tid, id, fn)
   339  }
   340  
   341  func (g *gate) GetAddrHeadCache(tid int64, id string, fn util.FnM2Bool) {
   342  	g.worker.Push(gateGetAddr, tid, id, fn)
   343  }
   344  
   345  func (g *gate) CloseWithId(tid int64, id string, removeHeadKeys, removeCacheKeys []string) {
   346  	g.worker.Push(gateClose, tid, id, removeHeadKeys, removeCacheKeys)
   347  }
   348  
   349  func (g *gate) CloseWithAddr(tid int64, addr string, removeHeadKeys, removeCacheKeys []string) {
   350  	g.worker.Push(gateAddrClose, tid, addr, removeHeadKeys, removeCacheKeys)
   351  }
   352  
   353  func (g *gate) SetRoles(m map[kiwi.TSvcCode][]int64) {
   354  	for code, roles := range m {
   355  		g.msgToRoles.Store(code, roles)
   356  	}
   357  }
   358  
   359  func (g *gate) Authenticate(mask int64, svc kiwi.TSvc, code kiwi.TCode) bool {
   360  	slc, o := g.msgToRoles.Load(kiwi.MergeSvcCode(svc, code))
   361  	if !o {
   362  		return false
   363  	}
   364  	for _, role := range slc.([]int64) {
   365  		if util.TestMask(role, mask) {
   366  			return true
   367  		}
   368  	}
   369  	return false
   370  }
   371  
   372  func (g *gate) process(job *worker.Job) {
   373  	switch job.Name {
   374  	case gateConnected:
   375  		agent := util.SplitSlc1[kiwi.IAgent](job.Data)
   376  		ok := g.idToAgent.AddNX(agent)
   377  		if !ok {
   378  			return
   379  		}
   380  		_ = g.addrToAgent.AddNX(agent)
   381  		kiwi.Info("agent connected", util.M{
   382  			"id":   agent.Id(),
   383  			"addr": agent.Addr(),
   384  		})
   385  		atomic.AddInt32(&g.agentCount, 1)
   386  		g.option.connected(agent)
   387  	case gateDisconnected:
   388  		agent, err := util.SplitSlc2[kiwi.IAgent, *util.Err](job.Data)
   389  		agentAddr := agent.Addr()
   390  		agent, ok := g.addrToAgent.Del(agentAddr)
   391  		if !ok {
   392  			return
   393  		}
   394  		agentId := agent.Id()
   395  		kiwi.Info("agent disconnected", util.M{
   396  			"id":   agentId,
   397  			"addr": agentAddr,
   398  		})
   399  		atomic.AddInt32(&g.agentCount, -1)
   400  		g.option.disconnected(agent, err)
   401  		agent2, ok := g.idToAgent.Get(agentId)
   402  		if !ok || agent2.Addr() != agentAddr { //id被新agent替换
   403  			return
   404  		}
   405  		_, _ = g.idToAgent.Del(agentId)
   406  	case gateSend:
   407  		tid, id, bytes, fn := util.SplitSlc4[int64, string, []byte, util.FnBool](job.Data)
   408  		agent, ok := g.idToAgent.Get(id)
   409  		if !ok {
   410  			fn(false)
   411  			return
   412  		}
   413  		err := agent.Send(bytes)
   414  		if err != nil {
   415  			err.AddParam("id", id)
   416  			kiwi.TE(tid, err)
   417  			fn(false)
   418  			return
   419  		}
   420  		fn(true)
   421  	case gateAddrSend:
   422  		tid, addr, bytes, fn := util.SplitSlc4[int64, string, []byte, util.FnBool](job.Data)
   423  		agent, ok := g.addrToAgent.Get(addr)
   424  		if !ok {
   425  			fn(false)
   426  			return
   427  		}
   428  		err := agent.Send(bytes)
   429  		if err != nil {
   430  			err.AddParam("addr", addr)
   431  			kiwi.TE(tid, err)
   432  			fn(false)
   433  			return
   434  		}
   435  		fn(true)
   436  	case gateMultiSend:
   437  		tid, idToPayload, fn := util.SplitSlc3[int64, map[string][]byte, util.FnMapBool](job.Data)
   438  		m := make(map[string]bool, len(idToPayload))
   439  		for id, payload := range idToPayload {
   440  			agent, ok := g.idToAgent.Get(id)
   441  			if !ok {
   442  				m[id] = false
   443  				continue
   444  			}
   445  			err := agent.Send(payload)
   446  			if err != nil {
   447  				kiwi.TE(tid, err)
   448  				m[id] = false
   449  				continue
   450  			}
   451  			m[id] = true
   452  		}
   453  		fn(m)
   454  	case gateMultiAddrSend:
   455  		tid, addrToPayload, fn := util.SplitSlc3[int64, map[string][]byte, util.FnMapBool](job.Data)
   456  		m := make(map[string]bool, len(addrToPayload))
   457  		for addr, payload := range addrToPayload {
   458  			agent, ok := g.addrToAgent.Get(addr)
   459  			if !ok {
   460  				m[addr] = false
   461  				continue
   462  			}
   463  			err := agent.Send(payload)
   464  			if err != nil {
   465  				kiwi.TE(tid, err)
   466  				m[addr] = false
   467  				continue
   468  			}
   469  			m[addr] = true
   470  		}
   471  		fn(m)
   472  	case gateAllSend:
   473  		tid, bytes := util.SplitSlc2[int64, []byte](job.Data)
   474  		g.idToAgent.Iter(func(item kiwi.IAgent) {
   475  			err := item.Send(util.CopyBytes(bytes))
   476  			if err != nil {
   477  				kiwi.TE(tid, err)
   478  			}
   479  		})
   480  		util.RecycleBytes(bytes)
   481  	case gateUpdate:
   482  		tid, id, head, cache, fn := util.SplitSlc5[int64, string, util.M, util.M, util.FnBool](job.Data)
   483  		agent, ok := g.idToAgent.Get(id)
   484  		if !ok {
   485  			fn(false)
   486  			return
   487  		}
   488  		if head != nil {
   489  			_, ok := head["addr"]
   490  			if ok {
   491  				delete(head, "addr") //这个不能覆盖
   492  			}
   493  			newId, ok := util.MGet[string](head, "id")
   494  			if ok {
   495  				oldId := agent.Id()
   496  				agent.SetId(newId)
   497  				g.idToAgent.ReplaceOrNew(oldId, agent)
   498  			}
   499  			agent.SetHeads(head)
   500  		}
   501  		if cache != nil {
   502  			agent.SetCaches(cache)
   503  		}
   504  		kiwi.TD(tid, "gate id update", util.M{
   505  			"head":  head,
   506  			"cache": cache,
   507  		})
   508  		fn(true)
   509  	case gateUpdateAddr:
   510  		tid, addr, head, cache, fn := util.SplitSlc5[int64, string, util.M, util.M, util.FnBool](job.Data)
   511  		agent, ok := g.addrToAgent.Get(addr)
   512  		if !ok {
   513  			fn(false)
   514  			return
   515  		}
   516  		if head != nil {
   517  			_, ok := head["addr"]
   518  			if ok {
   519  				delete(head, "addr") //这个不能覆盖
   520  			}
   521  			newId, ok := util.MGet[string](head, "id")
   522  			if ok {
   523  				oldId := agent.Id()
   524  				agent.SetId(newId)
   525  				g.idToAgent.ReplaceOrNew(oldId, agent)
   526  			}
   527  			agent.SetHeads(head)
   528  		}
   529  		if cache != nil {
   530  			agent.SetCaches(cache)
   531  		}
   532  		kiwi.TD(tid, "gate addr update", util.M{
   533  			"head":  head,
   534  			"cache": cache,
   535  		})
   536  		fn(true)
   537  	case gateRemove:
   538  		tid, id, head, cache, fn := util.SplitSlc5[int64, string, []string, []string, util.FnBool](job.Data)
   539  		agent, ok := g.idToAgent.Get(id)
   540  		if !ok {
   541  			fn(false)
   542  			return
   543  		}
   544  		agent.DelHead(head...)
   545  		agent.DelCache(cache...)
   546  		kiwi.TD(tid, "gate id remove", util.M{
   547  			"head":  head,
   548  			"cache": cache,
   549  		})
   550  		fn(true)
   551  	case gateRemoveAddr:
   552  		tid, addr, head, cache, fn := util.SplitSlc5[int64, string, []string, []string, util.FnBool](job.Data)
   553  		agent, ok := g.addrToAgent.Get(addr)
   554  		if !ok {
   555  			fn(false)
   556  			return
   557  		}
   558  		agent.DelHead(head...)
   559  		agent.DelCache(cache...)
   560  		kiwi.TD(tid, "gate addr remove", util.M{
   561  			"head":  head,
   562  			"cache": cache,
   563  		})
   564  		fn(true)
   565  	case gateGet:
   566  		_, id, fn := util.SplitSlc3[int64, string, util.FnM2Bool](job.Data)
   567  		agent, ok := g.idToAgent.Get(id)
   568  		if !ok {
   569  			fn(nil, nil, false)
   570  			return
   571  		}
   572  		head := util.M{}
   573  		cache := util.M{}
   574  		agent.CopyHead(head)
   575  		agent.CopyCache(cache)
   576  		fn(head, cache, true)
   577  	case gateGetAddr:
   578  		_, addr, fn := util.SplitSlc3[int64, string, util.FnM2Bool](job.Data)
   579  		agent, ok := g.addrToAgent.Get(addr)
   580  		if !ok {
   581  			fn(nil, nil, false)
   582  			return
   583  		}
   584  		head := util.M{}
   585  		cache := util.M{}
   586  		agent.CopyHead(head)
   587  		agent.CopyCache(cache)
   588  		fn(head, cache, true)
   589  	case gateClose:
   590  		_, id, head, cache := util.SplitSlc4[int64, string, []string, []string](job.Data)
   591  		agent, ok := g.idToAgent.Get(id)
   592  		if !ok {
   593  			return
   594  		}
   595  		agent.DelHead(head...)
   596  		agent.DelCache(cache...)
   597  		agent.Dispose()
   598  	case gateAddrClose:
   599  		_, addr, head, cache := util.SplitSlc4[int64, string, []string, []string](job.Data)
   600  		agent, ok := g.addrToAgent.Get(addr)
   601  		if !ok {
   602  			return
   603  		}
   604  		agent.DelHead(head...)
   605  		agent.DelCache(cache...)
   606  		agent.Dispose()
   607  	}
   608  }
   609  
   610  const (
   611  	gateConnected     = "connected"
   612  	gateDisconnected  = "disconnected"
   613  	gateSend          = "send"
   614  	gateAddrSend      = "send_addr"
   615  	gateMultiSend     = "multi_send"
   616  	gateMultiAddrSend = "multi_send_addr"
   617  	gateAllSend       = "all_send"
   618  	gateUpdate        = "update_head_cache"
   619  	gateUpdateAddr    = "update_addr_head_cache"
   620  	gateRemove        = "remove_head_cache"
   621  	gateRemoveAddr    = "remove_addr_head_cache"
   622  	gateGet           = "get_head_cache"
   623  	gateGetAddr       = "get_addr_head_cache"
   624  	gateAddrClose     = "addr_close"
   625  	gateClose         = "close"
   626  )