server initial commit

This commit is contained in:
김도한 [dominick]
2022-10-18 11:50:10 +09:00
commit 8fe1f31bf2
10 changed files with 1899 additions and 0 deletions

421
core/AEGS_methods.go Normal file
View 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
View 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
View 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
View 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)
}