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 )