server initial commit
This commit is contained in:
421
core/AEGS_methods.go
Normal file
421
core/AEGS_methods.go
Normal file
@ -0,0 +1,421 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"anvil/shared"
|
||||
"errors"
|
||||
"net"
|
||||
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
/*
|
||||
func (gs *AeGameServer) LobbyCheckIn(ip net.IP, inSocketPort int32) {
|
||||
gs.lock.Lock()
|
||||
defer gs.lock.Unlock()
|
||||
|
||||
gs.LobbyIp = ip
|
||||
gs.LobbyPort = inSocketPort
|
||||
}
|
||||
|
||||
func (gs *AeGameServer) GetUrlLobbyChekedIn() string {
|
||||
gs.lock.Lock()
|
||||
defer gs.lock.Unlock()
|
||||
|
||||
if len(gs.LobbyIp) != 0 {
|
||||
return fmt.Sprintf("%s:%d", gs.LobbyIp.String(), gs.LobbyPort)
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func (gs *AeGameServer) WorldCheckIn(ip net.IP, inSocketPort int32) {
|
||||
gs.lock.Lock()
|
||||
defer gs.lock.Unlock()
|
||||
|
||||
gs.WorldIp = ip
|
||||
gs.WorldPort = inSocketPort
|
||||
}
|
||||
|
||||
func (gs *AeGameServer) GetUrlWorldChekedIn() string {
|
||||
gs.lock.Lock()
|
||||
defer gs.lock.Unlock()
|
||||
|
||||
if len(gs.WorldIp) != 0 {
|
||||
return fmt.Sprintf("%s:%d", gs.WorldIp.String(), gs.LobbyPort)
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
func (gs *AeGameServer) FindDsCheckedIn(Type int32, Version string) string {
|
||||
gs.lock.Lock()
|
||||
defer gs.lock.Unlock()
|
||||
|
||||
var priority float32 = 0
|
||||
url := ""
|
||||
|
||||
for _, s := range gs.sockets {
|
||||
|
||||
if s.IsCompatible(Type, Version) {
|
||||
if tmpUrl := s.GetUrlChekedIn(); tmpUrl != "" {
|
||||
tmpPriority := s.GetPriority()
|
||||
if tmpPriority >= priority {
|
||||
url = tmpUrl
|
||||
priority = tmpPriority
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return url
|
||||
}
|
||||
|
||||
func (tx *transaction) Hello() shared.RPCReturnType {
|
||||
tx.gs.Logger.Println("hello, too")
|
||||
return shared.MakeRPCReturn("hello, too.", nil)
|
||||
}
|
||||
|
||||
func externalIP() (net.IP, error) {
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, iface := range ifaces {
|
||||
if iface.Flags&net.FlagUp == 0 {
|
||||
continue // interface down
|
||||
}
|
||||
if iface.Flags&net.FlagLoopback != 0 {
|
||||
continue // loopback interface
|
||||
}
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
var ip net.IP
|
||||
switch v := addr.(type) {
|
||||
case *net.IPNet:
|
||||
ip = v.IP
|
||||
case *net.IPAddr:
|
||||
ip = v.IP
|
||||
}
|
||||
if ip == nil || ip.IsLoopback() {
|
||||
continue
|
||||
}
|
||||
ip = ip.To4()
|
||||
if ip == nil {
|
||||
continue // not an ipv4 address
|
||||
}
|
||||
return ip, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("are you connected to the network?")
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
func (tx *transaction) LobbyCheckIn(inSocketPort int32) shared.RPCReturnType {
|
||||
// list.Append(test)
|
||||
tx.gs.Logger.Printf("remoteaddr %s : %d", tx.r.RemoteAddr, inSocketPort)
|
||||
|
||||
ip, _, err := net.SplitHostPort(tx.r.RemoteAddr)
|
||||
if err != nil {
|
||||
tx.gs.Logger.Printf("userip: %q is not IP:port", tx.r.RemoteAddr)
|
||||
return shared.MakeRPCReturn(nil, errors.New("IP invalid"))
|
||||
}
|
||||
|
||||
userIP := net.ParseIP(ip)
|
||||
if userIP == nil {
|
||||
tx.gs.Logger.Printf("userip: %q is not IP:port", tx.r.RemoteAddr)
|
||||
return shared.MakeRPCReturn(nil, errors.New("IP invalid"))
|
||||
}
|
||||
|
||||
if userIP.IsLoopback() {
|
||||
if tmpIp, err := externalIP(); err == nil {
|
||||
userIP = tmpIp
|
||||
} else {
|
||||
return shared.MakeRPCReturn(nil, errors.New("IP invalid"))
|
||||
}
|
||||
}
|
||||
|
||||
tx.gs.LobbyCheckIn(userIP, inSocketPort)
|
||||
|
||||
return shared.MakeRPCReturn("lobby checked in.", nil)
|
||||
}
|
||||
|
||||
func (tx *transaction) WorldCheckIn(inSocketPort int32) shared.RPCReturnType {
|
||||
// list.Append(test)
|
||||
tx.gs.Logger.Printf("remoteaddr %s : %d", tx.r.RemoteAddr, inSocketPort)
|
||||
|
||||
ip, _, err := net.SplitHostPort(tx.r.RemoteAddr)
|
||||
if err != nil {
|
||||
tx.gs.Logger.Printf("userip: %q is not IP:port", tx.r.RemoteAddr)
|
||||
return shared.MakeRPCReturn(nil, errors.New("IP invalid"))
|
||||
}
|
||||
|
||||
userIP := net.ParseIP(ip)
|
||||
if userIP == nil {
|
||||
tx.gs.Logger.Printf("userip: %q is not IP:port", tx.r.RemoteAddr)
|
||||
return shared.MakeRPCReturn(nil, errors.New("IP invalid"))
|
||||
}
|
||||
|
||||
if userIP.IsLoopback() {
|
||||
if tmpIp, err := externalIP(); err == nil {
|
||||
userIP = tmpIp
|
||||
} else {
|
||||
return shared.MakeRPCReturn(nil, errors.New("IP invalid"))
|
||||
}
|
||||
}
|
||||
|
||||
tx.gs.WorldCheckIn(userIP, inSocketPort)
|
||||
|
||||
return shared.MakeRPCReturn("world checked in.", nil)
|
||||
}
|
||||
*/
|
||||
|
||||
func (tx *transaction) GetCheckedIn(Type int32, Version string) shared.RPCReturnType {
|
||||
|
||||
// url := tx.gs.GetUrlLobbyChekedIn()
|
||||
url := tx.gs.FindDsCheckedIn(Type, Version)
|
||||
tx.gs.Logger.Println("lobby url checked in : ", url)
|
||||
if url == "" {
|
||||
return shared.MakeRPCReturn(nil, errors.New("no url"))
|
||||
} else {
|
||||
return shared.MakeRPCReturn(url, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// func (tx *transaction) GetLobbyCheckedIn() shared.RPCReturnType {
|
||||
|
||||
// // url := tx.gs.GetUrlLobbyChekedIn()
|
||||
// url := tx.gs.FindDsCheckedIn(2)
|
||||
// tx.gs.Logger.Println("lobby url checked in : ", url)
|
||||
// if url == "" {
|
||||
// return shared.MakeRPCReturn(nil, errors.New("no url"))
|
||||
// } else {
|
||||
// return shared.MakeRPCReturn(url, nil)
|
||||
// }
|
||||
// }
|
||||
|
||||
// func (tx *transaction) GetWorldCheckedIn() shared.RPCReturnType {
|
||||
|
||||
// // url := tx.gs.GetUrlWorldChekedIn()
|
||||
// url := tx.gs.FindDsCheckedIn(1)
|
||||
// tx.gs.Logger.Println("world url checked in : ", url)
|
||||
// if url == "" {
|
||||
// return shared.MakeRPCReturn(nil, errors.New("no url"))
|
||||
// } else {
|
||||
// return shared.MakeRPCReturn(url, nil)
|
||||
// }
|
||||
// }
|
||||
|
||||
func (tx *transaction) ReadDB(collection string, _id interface{}) shared.RPCReturnType {
|
||||
|
||||
raw, err := tx.gs.mongoClient.FindOneAndUpdate(shared.CollectionName(collection),
|
||||
bson.M{"_id": _id},
|
||||
bson.M{
|
||||
"$setOnInsert": bson.M{"_id": _id},
|
||||
},
|
||||
options.FindOneAndUpdate().SetProjection(bson.M{"_id": 0, "_ts": 0}),
|
||||
options.FindOneAndUpdate().SetReturnDocument(options.After),
|
||||
options.FindOneAndUpdate().SetUpsert(true))
|
||||
|
||||
tx.gs.Logger.Println("db read : ", _id, raw)
|
||||
|
||||
return shared.MakeRPCReturn(raw, err)
|
||||
}
|
||||
|
||||
func (tx *transaction) ReadMany(collection string, in []interface{}) shared.RPCReturnType {
|
||||
|
||||
raw, err := tx.gs.mongoClient.FindAll(shared.CollectionName(collection), bson.M{"_id": bson.M{"$in": in}},
|
||||
options.Find().SetProjection(bson.M{"_ts": 0}))
|
||||
|
||||
tx.gs.Logger.Println("db read : ", raw)
|
||||
|
||||
return shared.MakeRPCReturn(raw, err)
|
||||
}
|
||||
|
||||
func (tx *transaction) WriteDB(collection string, raw map[string]interface{}) shared.RPCReturnType {
|
||||
|
||||
tx.gs.Logger.Println("db access in collection : ", collection, raw)
|
||||
|
||||
_, _, err := tx.gs.mongoClient.Update(shared.CollectionName(collection),
|
||||
bson.M{"_id": raw["_id"]},
|
||||
bson.M{
|
||||
"$currentDate": bson.M{"_ts": true},
|
||||
"$set": raw,
|
||||
}, options.Update().SetUpsert(true))
|
||||
|
||||
return shared.MakeRPCReturn(nil, err)
|
||||
}
|
||||
|
||||
func (tx *transaction) RemoveDB(collection string, keys []interface{}) shared.RPCReturnType {
|
||||
|
||||
count, err := tx.gs.mongoClient.DeleteMany(shared.CollectionName(collection), bson.M{"_id": bson.M{"$in": keys}})
|
||||
|
||||
return shared.MakeRPCReturn(count, err)
|
||||
}
|
||||
|
||||
func (tx *transaction) UpdatePlayerInfo(raw map[string]interface{}) shared.RPCReturnType {
|
||||
|
||||
var playerid string
|
||||
if v, ok := tx.r.Header["Player-Id"]; ok && len(v) > 0 {
|
||||
playerid = v[0]
|
||||
} else {
|
||||
return shared.MakeRPCReturn(nil, errors.New("no player id"))
|
||||
}
|
||||
|
||||
tx.gs.Logger.Println("db write : ", playerid, raw)
|
||||
|
||||
_, _, err := tx.gs.mongoClient.Update("PlayerInfo",
|
||||
bson.M{"_id": playerid},
|
||||
bson.M{
|
||||
"$currentDate": bson.M{"_ts": true},
|
||||
"$set": raw,
|
||||
}, options.Update().SetUpsert(true))
|
||||
|
||||
if err == nil {
|
||||
return shared.MakeRPCReturn("update success", err)
|
||||
} else {
|
||||
return shared.MakeRPCReturn(nil, errors.New("invalid body"))
|
||||
}
|
||||
}
|
||||
|
||||
func (tx *transaction) GetPlayerInfo() shared.RPCReturnType {
|
||||
|
||||
var playerid string
|
||||
if v, ok := tx.r.Header["Player-Id"]; ok && len(v) > 0 {
|
||||
playerid = v[0]
|
||||
} else {
|
||||
return shared.MakeRPCReturn(nil, errors.New("no player id"))
|
||||
}
|
||||
|
||||
raw, err := tx.gs.mongoClient.FindOneAndUpdate("PlayerInfo",
|
||||
bson.M{"_id": playerid},
|
||||
bson.M{
|
||||
"$setOnInsert": bson.M{"_id": playerid, "charId": 101},
|
||||
},
|
||||
options.FindOneAndUpdate().SetProjection(bson.M{"_id": 0, "_ts": 0}),
|
||||
options.FindOneAndUpdate().SetReturnDocument(options.After),
|
||||
options.FindOneAndUpdate().SetUpsert(true))
|
||||
|
||||
tx.gs.Logger.Println("db read : ", playerid, raw)
|
||||
|
||||
if err == nil {
|
||||
return shared.MakeRPCReturn(raw, err)
|
||||
} else {
|
||||
return shared.MakeRPCReturn(nil, errors.New("not matched"))
|
||||
}
|
||||
}
|
||||
|
||||
func (tx *transaction) UpdateInventory(charId int32, raw map[string]interface{}) shared.RPCReturnType {
|
||||
|
||||
var playerid string
|
||||
if v, ok := tx.r.Header["Player-Id"]; ok && len(v) > 0 {
|
||||
playerid = v[0]
|
||||
} else {
|
||||
return shared.MakeRPCReturn(nil, errors.New("no player id"))
|
||||
}
|
||||
|
||||
tx.gs.Logger.Println("inventory write : ", playerid, raw)
|
||||
|
||||
var err error
|
||||
|
||||
q, _ := tx.gs.mongoClient.FindOne("Inventory", bson.M{"_id": playerid, "inven.charId": charId},
|
||||
options.FindOne().SetProjection(bson.M{"inven.$": 1}))
|
||||
|
||||
if q == nil {
|
||||
_, _, err = tx.gs.mongoClient.Update("Inventory",
|
||||
bson.M{"_id": playerid},
|
||||
bson.M{
|
||||
"$currentDate": bson.M{"_ts": true},
|
||||
"$addToSet": bson.M{"inven": bson.M{"charId": charId, "slots": raw}},
|
||||
},
|
||||
options.Update().SetUpsert(true))
|
||||
} else {
|
||||
// _, _, err = tx.gs.mongoClient.Update("Inventory",
|
||||
// bson.M{"_id": playerid},
|
||||
// bson.M{
|
||||
// "$currentDate": bson.M{"_ts": true},
|
||||
// "$set": bson.M{"inven.$[x].slots": raw},
|
||||
// },
|
||||
// options.Update().SetArrayFilters(options.ArrayFilters{Filters: bson.A{bson.M{"x.charId": charId}}}),
|
||||
// options.Update().SetUpsert(true))
|
||||
|
||||
slots := q["inven"].(bson.A)[0].(map[string]interface{})["slots"].(map[string]interface{})
|
||||
tx.gs.Logger.Println("current inventory", slots)
|
||||
|
||||
for k, v := range raw {
|
||||
slots[k] = v
|
||||
}
|
||||
|
||||
tx.gs.Logger.Println("new inventory", slots)
|
||||
|
||||
_, _, err = tx.gs.mongoClient.Update("Inventory",
|
||||
bson.M{"_id": playerid, "inven.charId": charId},
|
||||
bson.M{
|
||||
"$currentDate": bson.M{"_ts": true},
|
||||
"$set": bson.M{"inven.$.slots": slots},
|
||||
})
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
tx.gs.Logger.Println("inventory write success")
|
||||
|
||||
return shared.MakeRPCReturn(raw, err)
|
||||
} else {
|
||||
return shared.MakeRPCReturn(nil, errors.New("invalid body"))
|
||||
}
|
||||
}
|
||||
|
||||
func (tx *transaction) GetInventory(charId int32) shared.RPCReturnType {
|
||||
|
||||
var playerid string
|
||||
if v, ok := tx.r.Header["Player-Id"]; ok && len(v) > 0 {
|
||||
playerid = v[0]
|
||||
} else {
|
||||
return shared.MakeRPCReturn(nil, errors.New("no player id"))
|
||||
}
|
||||
|
||||
raw, err := tx.gs.mongoClient.FindOne("Inventory",
|
||||
bson.M{"_id": playerid, "inven.charId": charId},
|
||||
options.FindOne().SetProjection(bson.M{"inven.$": 1}))
|
||||
|
||||
if raw == nil {
|
||||
_, err = tx.gs.mongoClient.FindOneAndUpdate("Inventory",
|
||||
bson.M{"_id": playerid},
|
||||
bson.M{
|
||||
"$setOnInsert": bson.M{"_id": playerid, "inven": bson.A{}},
|
||||
},
|
||||
options.FindOneAndUpdate().SetUpsert(true))
|
||||
|
||||
raw, err = tx.gs.mongoClient.FindOneAndUpdate("Inventory",
|
||||
bson.M{"_id": playerid},
|
||||
bson.M{
|
||||
"$currentDate": bson.M{"_ts": true},
|
||||
"$addToSet": bson.M{"inven": bson.M{"charId": charId, "slots": bson.M{}}},
|
||||
},
|
||||
options.FindOneAndUpdate().SetProjection(bson.M{"inven": bson.M{"$elemMatch": bson.M{"charId": charId}}}),
|
||||
options.FindOneAndUpdate().SetReturnDocument(options.After),
|
||||
options.FindOneAndUpdate().SetUpsert(true))
|
||||
}
|
||||
|
||||
// raw, err := tx.gs.mongoClient.FindOneAndUpdate("Inventory",
|
||||
// bson.M{"_id": playerid, "inven.charId": charId},
|
||||
// bson.M{
|
||||
// "$setOnInsert": bson.M{"_id": playerid, "inven": bson.A{bson.M{"charId": charId, "slots": bson.M{}}}},
|
||||
// },
|
||||
// options.FindOneAndUpdate().SetProjection(bson.M{"inven.$": 1}),
|
||||
// options.FindOneAndUpdate().SetReturnDocument(options.After),
|
||||
// options.FindOneAndUpdate().SetUpsert(true))
|
||||
|
||||
if err == nil {
|
||||
slots := raw["inven"].(bson.A)[0].(map[string]interface{})["slots"]
|
||||
tx.gs.Logger.Println("inventory read : ", playerid, slots)
|
||||
return shared.MakeRPCReturn(slots, err)
|
||||
} else {
|
||||
return shared.MakeRPCReturn(nil, errors.New("not matched"))
|
||||
}
|
||||
}
|
||||
91
core/AEGS_test.go
Normal file
91
core/AEGS_test.go
Normal file
@ -0,0 +1,91 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestDSRegister(t *testing.T) {
|
||||
// if tt, err := New(); err != nil {
|
||||
// panic(err)
|
||||
// } else {
|
||||
// err := tt.Start(nil)
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
|
||||
// time.Sleep(5)
|
||||
|
||||
// tt.Shutdown(shared.ShutdownFlagTerminating)
|
||||
// }
|
||||
|
||||
assert := assert.New(t)
|
||||
|
||||
tt, _ := New()
|
||||
mux := http.NewServeMux()
|
||||
tt.registerHandlers(mux, "")
|
||||
|
||||
// hello call
|
||||
{
|
||||
helloCall := struct {
|
||||
Method string
|
||||
}{Method: "Hello"}
|
||||
|
||||
res := httptest.NewRecorder()
|
||||
content, _ := json.Marshal(helloCall)
|
||||
req := httptest.NewRequest("POST", "/", bytes.NewBuffer(content))
|
||||
|
||||
mux.ServeHTTP(res, req)
|
||||
|
||||
assert.Equal(http.StatusOK, res.Code)
|
||||
}
|
||||
|
||||
// url := "127.0.0.2"
|
||||
|
||||
// checkin call
|
||||
{
|
||||
// helloCall := struct {
|
||||
// Method string
|
||||
// Args []interface{}
|
||||
// }{Method: "CheckIn", Args: []interface{}{url /*"fuck", struct{ test string }{test: "numb"}*/}}
|
||||
checkInCall := struct {
|
||||
Method string
|
||||
}{Method: "CheckIn"}
|
||||
|
||||
res := httptest.NewRecorder()
|
||||
content, _ := json.Marshal(checkInCall)
|
||||
req := httptest.NewRequest("POST", "/", bytes.NewBuffer(content))
|
||||
|
||||
mux.ServeHTTP(res, req)
|
||||
|
||||
assert.Equal(http.StatusOK, res.Code)
|
||||
}
|
||||
|
||||
// is checked in
|
||||
{
|
||||
helloCall := struct {
|
||||
Method string
|
||||
Args []interface{}
|
||||
}{Method: "GetCheckedIn"}
|
||||
|
||||
res := httptest.NewRecorder()
|
||||
content, _ := json.Marshal(helloCall)
|
||||
req := httptest.NewRequest("POST", "/", bytes.NewBuffer(content))
|
||||
|
||||
mux.ServeHTTP(res, req)
|
||||
|
||||
assert.Equal(http.StatusOK, res.Code)
|
||||
data, _ := io.ReadAll(res.Body)
|
||||
assert.Equal(req.RemoteAddr, string(data))
|
||||
|
||||
fmt.Println("return : ", string(data))
|
||||
}
|
||||
|
||||
}
|
||||
366
core/AeGameServer.go
Normal file
366
core/AeGameServer.go
Normal file
@ -0,0 +1,366 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"anvil/shared"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
// Warehouse :
|
||||
type AeGameServer struct {
|
||||
version string
|
||||
fullversion string
|
||||
Logger *log.Logger
|
||||
|
||||
server *shared.Server
|
||||
|
||||
mongoClient shared.MongoClient
|
||||
|
||||
WorldIp net.IP
|
||||
WorldPort int32
|
||||
|
||||
LobbyIp net.IP
|
||||
LobbyPort int32
|
||||
|
||||
sockets []*SocketContext
|
||||
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
type transaction struct {
|
||||
gs *AeGameServer
|
||||
|
||||
w http.ResponseWriter
|
||||
r *http.Request
|
||||
}
|
||||
|
||||
type SocketContext struct {
|
||||
connection *websocket.Conn
|
||||
|
||||
gs *AeGameServer
|
||||
|
||||
Type int32
|
||||
Port int32
|
||||
Ip net.IP
|
||||
Version string
|
||||
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
// type category struct {
|
||||
// gs *TestTest
|
||||
// name string
|
||||
// }
|
||||
|
||||
// type constCategory struct {
|
||||
// category
|
||||
// w http.ResponseWriter
|
||||
// r *http.Request
|
||||
// }
|
||||
|
||||
// Version :
|
||||
func (gs *AeGameServer) Version() string {
|
||||
return gs.version
|
||||
}
|
||||
|
||||
// New :
|
||||
func New() (*AeGameServer, error) {
|
||||
|
||||
logfilename := fmt.Sprintf("AEGS_%s.log", time.Now().Format("2006-01-02T15-04-05"))
|
||||
logFile, err := os.OpenFile(logfilename, os.O_CREATE|os.O_WRONLY|os.O_CREATE, 0666)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
w := &AeGameServer{
|
||||
version: "0.0.1",
|
||||
fullversion: "0.0.1.0",
|
||||
Logger: log.New(io.MultiWriter(logFile, os.Stdout), "[AEGS]", log.LstdFlags),
|
||||
}
|
||||
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// IsRunning :
|
||||
func (gs *AeGameServer) IsRunning() bool {
|
||||
return gs.server.ShutdownFlag() == shared.ShutdownFlagRunning
|
||||
}
|
||||
|
||||
// Start :
|
||||
func (gs *AeGameServer) Start(serveMux *http.ServeMux) error {
|
||||
http.DefaultClient.Timeout = time.Minute * 1
|
||||
gs.sockets = make([]*SocketContext, 0, 10)
|
||||
|
||||
if serveMux != nil {
|
||||
// 외부 serveMux가 있을 때는 registerHandler를 한번만 해야한다.
|
||||
gs.registerHandlers(serveMux, "AeGameServer")
|
||||
gs.server = shared.NewDependentServer(nil)
|
||||
}
|
||||
|
||||
printStartErr := false
|
||||
for {
|
||||
if serveMux == nil {
|
||||
serveMux = http.NewServeMux()
|
||||
gs.registerHandlers(serveMux, "")
|
||||
gs.server = shared.NewHTTPServer(serveMux, nil)
|
||||
}
|
||||
|
||||
err := gs.startimpl()
|
||||
if err != nil {
|
||||
if !printStartErr {
|
||||
printStartErr = true
|
||||
fmt.Println(err)
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
|
||||
printStartErr = false
|
||||
for {
|
||||
sf := gs.server.ShutdownFlag()
|
||||
if sf == shared.ShutdownFlagTerminating {
|
||||
return err
|
||||
} else if sf == shared.ShutdownFlagIdle {
|
||||
time.Sleep(time.Second)
|
||||
} else if sf == shared.ShutdownFlagRestarting {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (gs *AeGameServer) startimpl() (err error) {
|
||||
|
||||
gs.Logger.Println("creating MongoClient...")
|
||||
gs.mongoClient, err = shared.NewMongoClient(&shared.ConnectionInfo{
|
||||
Url: "mongodb://192.168.8.94:27017/?replicaSet=repl01",
|
||||
Database: "AEtest",
|
||||
})
|
||||
if err != nil {
|
||||
gs.Logger.Println("failed to create MongoClient. shutting down.")
|
||||
gs.server.Shutdown(shared.ShutdownFlagTerminating)
|
||||
return err
|
||||
}
|
||||
defer gs.mongoClient.Close()
|
||||
|
||||
gs.server.Start()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (gs *AeGameServer) Shutdown(flag shared.ShutdownFlag) {
|
||||
gs.server.Shutdown(flag)
|
||||
}
|
||||
|
||||
func (gs *AeGameServer) registerHandlers(serveMux *http.ServeMux, prefix string) error {
|
||||
|
||||
if len(prefix) > 0 && prefix[0] != '/' {
|
||||
prefix = "/" + prefix
|
||||
}
|
||||
|
||||
if len(prefix) > 0 && prefix[len(prefix)-1] == '/' {
|
||||
prefix = prefix[0 : len(prefix)-1]
|
||||
}
|
||||
|
||||
if len(prefix) == 0 {
|
||||
prefix = "/"
|
||||
}
|
||||
|
||||
var upgrader = websocket.Upgrader{} // use default options
|
||||
|
||||
serveMux.HandleFunc(prefix, func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
defer func() {
|
||||
s := recover()
|
||||
if s != nil {
|
||||
debug.PrintStack()
|
||||
gs.Logger.Println(s)
|
||||
}
|
||||
|
||||
io.Copy(ioutil.Discard, r.Body)
|
||||
r.Body.Close()
|
||||
}()
|
||||
|
||||
if r.ContentLength == 0 {
|
||||
w.Write([]byte("no content"))
|
||||
return
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
tx := &transaction{
|
||||
gs: gs,
|
||||
w: w,
|
||||
r: r,
|
||||
}
|
||||
|
||||
if retval, err := shared.CallMethod(tx, body); err != nil {
|
||||
gs.Logger.Println("CallMethod failed : ", r.RemoteAddr, string(body), r.Header, err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
} else {
|
||||
retval.Serialize(w)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
serveMux.HandleFunc(path.Join(prefix, "ws"), func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
gs.lock.Lock()
|
||||
defer gs.lock.Unlock()
|
||||
|
||||
defer func() {
|
||||
s := recover()
|
||||
if s != nil {
|
||||
debug.PrintStack()
|
||||
gs.Logger.Println(s)
|
||||
}
|
||||
|
||||
io.Copy(ioutil.Discard, r.Body)
|
||||
r.Body.Close()
|
||||
}()
|
||||
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
|
||||
st := &SocketContext{
|
||||
gs: gs,
|
||||
connection: conn,
|
||||
}
|
||||
|
||||
gs.sockets = append(gs.sockets, st)
|
||||
|
||||
if err != nil {
|
||||
gs.Logger.Printf("upgrader.Upgrade: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
for {
|
||||
_, body, err := st.connection.ReadMessage()
|
||||
|
||||
if err != nil {
|
||||
gs.Logger.Printf("conn.ReadMessage: %v", err)
|
||||
|
||||
func() {
|
||||
gs.lock.Lock()
|
||||
defer gs.lock.Unlock()
|
||||
|
||||
for i, s := range gs.sockets {
|
||||
if st == s {
|
||||
gs.sockets[i] = gs.sockets[len(gs.sockets)-1]
|
||||
gs.sockets = gs.sockets[:len(gs.sockets)-1]
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
st.connection.Close()
|
||||
|
||||
return
|
||||
} else {
|
||||
|
||||
gs.Logger.Printf("msg from socket %s %s %s", st.connection.LocalAddr(), st.connection.RemoteAddr(), body)
|
||||
|
||||
if retval, err := shared.CallMethod(st, body); err != nil {
|
||||
gs.Logger.Println("CallMethod failed : ", r.RemoteAddr, string(body), r.Header, err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
} else {
|
||||
var b bytes.Buffer
|
||||
retval.Serialize(&b)
|
||||
st.connection.WriteMessage(websocket.TextMessage, b.Bytes())
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
})
|
||||
|
||||
// categoryHandler := func(name string, receiver interface{}, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// defer func() {
|
||||
// s := recover()
|
||||
// if s != nil {
|
||||
// debug.PrintStack()
|
||||
// gs.Logger.Println(s)
|
||||
// }
|
||||
|
||||
// io.Copy(ioutil.Discard, r.Body)
|
||||
// r.Body.Close()
|
||||
// }()
|
||||
|
||||
// // ip, port, err := net.SplitHostPort(r.RemoteAddr)
|
||||
// // if err != nil {
|
||||
// // //return nil, fmt.Errorf("userip: %q is not IP:port", req.RemoteAddr)
|
||||
|
||||
// // gs.Logger.Printf("userip: %q is not IP:port", r.RemoteAddr)
|
||||
// // }
|
||||
|
||||
// // userIP := net.ParseIP(ip)
|
||||
// // if userIP == nil {
|
||||
// // //return nil, fmt.Errorf("userip: %q is not IP:port", req.RemoteAddr)
|
||||
// // gs.Logger.Printf("userip: %q is not IP:port", r.RemoteAddr)
|
||||
// // return
|
||||
// // }
|
||||
|
||||
// // // This will only be defined when site is accessed via non-anonymous proxy
|
||||
// // // and takes precedence over RemoteAddr
|
||||
// // // Header.Get is case-insensitive
|
||||
// // forward := r.Header.Get("X-Forwarded-For")
|
||||
|
||||
// // gs.Logger.Printf("<p>IP: %s</p>", ip)
|
||||
// // gs.Logger.Printf("<p>Port: %s</p>", port)
|
||||
// // gs.Logger.Printf("<p>Forwarded for: %s</p>", forward)
|
||||
|
||||
// if r.ContentLength == 0 {
|
||||
// w.Write([]byte("no content"))
|
||||
// return
|
||||
// }
|
||||
|
||||
// body, err := ioutil.ReadAll(r.Body)
|
||||
// if err != nil {
|
||||
// w.WriteHeader(http.StatusInternalServerError)
|
||||
// }
|
||||
|
||||
// if len(body) == 0 {
|
||||
// w.Write([]byte("no body"))
|
||||
// gs.Logger.Println("no body")
|
||||
// return
|
||||
// }
|
||||
|
||||
// if retval, err := shared.CallMethod(receiver, body); err != nil {
|
||||
// gs.Logger.Println("CallMethod failed : ", r.RemoteAddr, string(body), r.Header, err)
|
||||
// } else {
|
||||
// retval.Serialize(w)
|
||||
// }
|
||||
// }
|
||||
|
||||
// serveMux.HandleFunc(prefix+"/const", func(w http.ResponseWriter, r *http.Request) {
|
||||
// // 읽기 전용
|
||||
// constcat := constCategory{
|
||||
// category: category{
|
||||
// gs: gs,
|
||||
// name: "const",
|
||||
// },
|
||||
// w: w,
|
||||
// r: r,
|
||||
// }
|
||||
|
||||
// categoryHandler(constcat.name, &constcat, w, r)
|
||||
// })
|
||||
|
||||
return nil
|
||||
}
|
||||
75
core/SocketContext.go
Normal file
75
core/SocketContext.go
Normal file
@ -0,0 +1,75 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"anvil/shared"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
)
|
||||
|
||||
func (st *SocketContext) Hello() shared.RPCReturnType {
|
||||
st.gs.Logger.Println("hello from socket client.")
|
||||
return shared.MakeRPCReturn("hello from socket server, too.", nil)
|
||||
}
|
||||
|
||||
func (st *SocketContext) IsCompatible(Type int32, Version string) bool {
|
||||
st.lock.Lock()
|
||||
defer st.lock.Unlock()
|
||||
|
||||
return st.Type == Type && st.Version == Version
|
||||
}
|
||||
|
||||
func (st *SocketContext) GetUrlChekedIn() string {
|
||||
st.lock.Lock()
|
||||
defer st.lock.Unlock()
|
||||
|
||||
if len(st.Ip) != 0 {
|
||||
return fmt.Sprintf("%s:%d", st.Ip.String(), st.Port)
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func (st *SocketContext) GetPriority() float32 {
|
||||
return rand.Float32()
|
||||
}
|
||||
|
||||
func (st *SocketContext) DSCheckIn(DsType int32, inSocketPort int32, Version string) shared.RPCReturnType {
|
||||
st.lock.Lock()
|
||||
defer st.lock.Unlock()
|
||||
|
||||
addr := st.connection.RemoteAddr().String()
|
||||
|
||||
st.gs.Logger.Printf("remoteaddr %s : %d", addr, inSocketPort)
|
||||
|
||||
ip, _, err := net.SplitHostPort(addr)
|
||||
if err != nil {
|
||||
st.gs.Logger.Printf("userip: %q is not IP:port", addr)
|
||||
return shared.MakeRPCReturn(nil, errors.New("IP invalid"))
|
||||
}
|
||||
|
||||
userIP := net.ParseIP(ip)
|
||||
if userIP == nil {
|
||||
st.gs.Logger.Printf("userip: %q is not IP:port", addr)
|
||||
return shared.MakeRPCReturn(nil, errors.New("IP invalid"))
|
||||
}
|
||||
|
||||
if userIP.IsLoopback() {
|
||||
if tmpIp, err := externalIP(); err == nil {
|
||||
userIP = tmpIp
|
||||
} else {
|
||||
return shared.MakeRPCReturn(nil, errors.New("IP invalid"))
|
||||
}
|
||||
}
|
||||
|
||||
// st.gs.LobbyCheckIn(userIP, inSocketPort)
|
||||
st.Ip = userIP
|
||||
st.Port = inSocketPort
|
||||
st.Type = DsType
|
||||
st.Version = Version
|
||||
|
||||
st.gs.Logger.Printf("type : %d, id : %s, port : %d, version : %s", DsType, userIP, inSocketPort, st.Version)
|
||||
|
||||
return shared.MakeRPCReturn("ds checked in.", nil)
|
||||
}
|
||||
Reference in New Issue
Block a user