Switched to redis/postgres, major refactoring

- loginMetadata is passed to shards through redis now
- shards announce they're alive via redis.AnnounceShard() which just
  populates a hashset keyed 'shards'
- login servers grab the 'shards' hashset and randomly picks a shard to
  pass the player to (for now)
- ./service shard && ./service login
- Many new environment variables, check config/config.go for more info.
  or for a tl;dr just read the Dockerfile for the required ones
- Shard and login services now run in different processes ! (and
  containers?? wooaaah)
This commit is contained in:
2023-06-22 01:53:38 -05:00
parent 983588b6c9
commit d7445e0f0f
20 changed files with 489 additions and 192 deletions

View File

@@ -3,12 +3,14 @@ package login
import (
"encoding/binary"
"fmt"
"log"
"math/rand"
"time"
"github.com/CPunch/gopenfusion/config"
"github.com/CPunch/gopenfusion/core/db"
"github.com/CPunch/gopenfusion/core/protocol"
"github.com/CPunch/gopenfusion/shard"
"github.com/CPunch/gopenfusion/core/redis"
)
const (
@@ -104,6 +106,7 @@ func (server *LoginServer) Login(peer *protocol.CNPeer, pkt protocol.Packet) err
SendError(LOGIN_DATABASE_ERROR)
return err
}
log.Printf("Account (%d) %s has logged in", account.AccountID, account.Login)
// truncate plrs
if len(plrs) > 3 {
@@ -218,11 +221,13 @@ func (server *LoginServer) CharacterCreate(peer *protocol.CNPeer, pkt protocol.P
}
if err := server.dbHndlr.FinishPlayer(&charPkt, peer.AccountID); err != nil {
log.Printf("Error finishing player: %v", err)
return SendFail(peer)
}
plr, err := server.dbHndlr.GetPlayer(int(charPkt.PCStyle.IPC_UID))
if err != nil {
log.Printf("Error getting player: %v", err)
return SendFail(peer)
}
@@ -252,8 +257,10 @@ func (server *LoginServer) ShardSelect(peer *protocol.CNPeer, pkt protocol.Packe
var selection protocol.SP_CL2LS_REQ_CHAR_SELECT
pkt.Decode(&selection)
if server.shard == nil {
return fmt.Errorf("LoginServer currently has no linked shard")
shards := server.redisHndlr.GetShards()
if len(shards) == 0 {
SendFail(peer)
return fmt.Errorf("LoginServer has found no linked shards!")
}
key, err := protocol.GenSerialKey()
@@ -261,21 +268,36 @@ func (server *LoginServer) ShardSelect(peer *protocol.CNPeer, pkt protocol.Packe
return err
}
// TODO: verify peer->AccountID and selection->IPC_UID are valid!!!!
// TODO: better shard selection logic pls
// for now, pick random shard
shard := shards[rand.Intn(len(shards))]
// make sure the player is owned by the account
plr, err := server.dbHndlr.GetPlayer(int(selection.IPC_UID))
if err != nil {
log.Printf("Error getting player: %v", err)
return SendFail(peer)
}
if plr.AccountID != peer.AccountID {
log.Printf("HACK: player %d tried to join shard as player %d", peer.AccountID, plr.AccountID)
return SendFail(peer)
}
// share the login attempt
server.redisHndlr.QueueLogin(key, redis.LoginMetadata{
FEKey: peer.FE_key,
PlayerID: int32(selection.IPC_UID),
})
// craft response
resp := protocol.SP_LS2CL_REP_SHARD_SELECT_SUCC{
G_FE_ServerPort: int32(server.shard.GetPort()),
G_FE_ServerPort: int32(shard.Port),
IEnterSerialKey: key,
}
// the rest of the bytes in G_FE_ServerIP will be zero'd, so there's no need to write the NULL byte
copy(resp.G_FE_ServerIP[:], []byte(config.SHARD_IP))
server.shard.QueueLogin(key, &shard.LoginMetadata{
FEKey: peer.FE_key,
Timestamp: time.Now(),
PlayerID: int32(selection.IPC_UID),
})
copy(resp.G_FE_ServerIP[:], []byte(shard.IP))
return peer.Send(protocol.P_LS2CL_REP_SHARD_SELECT_SUCC, resp)
}

View File

@@ -6,9 +6,10 @@ import (
"net"
"sync"
"github.com/CPunch/gopenfusion/config"
"github.com/CPunch/gopenfusion/core/db"
"github.com/CPunch/gopenfusion/core/protocol"
"github.com/CPunch/gopenfusion/shard"
"github.com/CPunch/gopenfusion/core/redis"
)
type PacketHandler func(peer *protocol.CNPeer, pkt protocol.Packet) error
@@ -19,23 +20,24 @@ type LoginServer struct {
listener net.Listener
port int
dbHndlr *db.DBHandler
redisHndlr *redis.RedisHandler
packetHandlers map[uint32]PacketHandler
peers map[*protocol.CNPeer]bool
peersLock sync.Mutex
shard *shard.ShardServer
}
func NewLoginServer(dbHndlr *db.DBHandler, port int) (*LoginServer, error) {
func NewLoginServer(dbHndlr *db.DBHandler, redisHndlr *redis.RedisHandler, port int) (*LoginServer, error) {
listener, err := net.Listen("tcp", fmt.Sprintf(":%d", port))
if err != nil {
return nil, err
}
server := &LoginServer{
listener: listener,
port: port,
dbHndlr: dbHndlr,
peers: make(map[*protocol.CNPeer]bool),
listener: listener,
port: port,
dbHndlr: dbHndlr,
redisHndlr: redisHndlr,
peers: make(map[*protocol.CNPeer]bool),
}
server.packetHandlers = map[uint32]PacketHandler{
@@ -59,7 +61,7 @@ func NewLoginServer(dbHndlr *db.DBHandler, port int) (*LoginServer, error) {
}
func (server *LoginServer) Start() {
log.Printf("Server hosted on 127.0.0.1:%d\n", server.port)
log.Printf("Login service hosted on %s:%d\n", config.GetAnnounceIP(), server.port)
for {
conn, err := server.listener.Accept()
@@ -99,7 +101,3 @@ func (server *LoginServer) Connect(peer *protocol.CNPeer) {
server.peers[peer] = true
server.peersLock.Unlock()
}
func (server *LoginServer) AddShard(shard *shard.ShardServer) {
server.shard = shard
}