Commit 6f2ba85e authored by Chunchi Che's avatar Chunchi Che Committed by GitHub

Merge pull request #3 from DarkNeos/dev

Dev
parents e4d56fc9 6368e27a
package darkneos
import (
"encoding/binary"
"errors"
"fmt"
"unicode/utf16"
"github.com/sktt1ryze/ygopro-proxy/DarkNeos/ygopropb"
"google.golang.org/protobuf/proto"
)
const FILLING_TOKEN uint16 = 0xcccc
const UTF16_BUFFER_MAX_LEN int = 20
const PACKET_MIN_LEN int = 3
const (
ProtobufToRawBuf = 1
RawBufToProtobuf = 2
)
const (
CtosProtoPlayerInfo = 16
CtosProtoJoinGame = 18
StocChat = 25
)
type YgoPacket struct {
PacketLen uint16
Proto uint8
Exdata []byte
}
func packetToBuffer(pkt YgoPacket) []byte {
buf := make([]byte, 0)
// packet len
buf = append(buf, byte(pkt.PacketLen), byte(pkt.PacketLen>>8))
// proto
buf = append(buf, byte(pkt.Proto))
// exdata
for _, v := range pkt.Exdata {
buf = append(buf, v)
}
return buf
}
func bufferToPacket(p []byte) (YgoPacket, error) {
if len(p) < PACKET_MIN_LEN {
return YgoPacket{}, errors.New(fmt.Sprintf("Packet len too short, len=%d", len(p)))
}
// todo: impl Reader/Writer for buffer
packet_len := binary.LittleEndian.Uint16(p)
proto := p[2]
exdata := p[3 : packet_len+2]
return YgoPacket{
PacketLen: packet_len,
Proto: proto,
Exdata: exdata,
}, nil
}
func Transform(src []byte, tranformType int) ([]byte, error) {
if tranformType == ProtobufToRawBuf {
message := &ygopropb.YgoCtosMsg{}
err := proto.Unmarshal(src, message)
if err != nil {
return nil, err
}
var packet YgoPacket
switch message.Msg.(type) {
case *(ygopropb.YgoCtosMsg_CtosPlayerInfo):
packet = transformPlayerInfo(message.GetCtosPlayerInfo())
case *(ygopropb.YgoCtosMsg_CtosJoinGame):
packet = transformJoinGame(message.GetCtosJoinGame())
default:
return nil, errors.New("Unhandled YgoCtosMsg type")
}
return packetToBuffer(packet), nil
} else if tranformType == RawBufToProtobuf {
packet, err := bufferToPacket(src)
if err != nil {
return nil, err
}
var pb ygopropb.YgoStocMsg
switch packet.Proto {
case StocChat:
msg := transformChat(packet)
pb = ygopropb.YgoStocMsg{
Msg: &msg,
}
default:
return nil, errors.New("Unhandled YgoStocMsg type")
}
return proto.Marshal(&pb)
} else {
return nil, errors.New("Unknown tranformType")
}
}
// todo: use interface
// +++++ Client To Server +++++
// @Name: [20]uint16
func transformPlayerInfo(pb *ygopropb.CtosPlayerInfo) YgoPacket {
buf := strToUtf16Buffer(pb.Name)
exdata := uint16BufToByteBuf(buf)
return YgoPacket{
PacketLen: uint16(len(exdata)) + 1,
Proto: CtosProtoPlayerInfo,
Exdata: exdata,
}
}
// @Version: uint16
// @Gameid: uint32
// @Passwd: [20]uint16
func transformJoinGame(pb *ygopropb.CtosJoinGame) YgoPacket {
exdata := make([]byte, 0)
version := uint16(pb.Version)
exdata = append(exdata, byte(version), byte(version>>8), 0, 0)
exdata = append(exdata, byte(pb.Gameid), byte(pb.Gameid>>8), byte(pb.Gameid>>16), byte(pb.Gameid>>24))
for _, v := range uint16BufToByteBuf(strToUtf16Buffer(pb.Passwd)) {
exdata = append(exdata, v)
}
return YgoPacket{
PacketLen: uint16(len(exdata)) + 1,
Proto: CtosProtoJoinGame,
Exdata: exdata,
}
}
// +++++ Server To Client +++++
// @player: uint16
// @message: []uint16
func transformChat(pkt YgoPacket) ygopropb.YgoStocMsg_StocChat {
player := int32(binary.LittleEndian.Uint16(pkt.Exdata))
message := utf16BufferToStr(pkt.Exdata[2:])
return ygopropb.YgoStocMsg_StocChat{
StocChat: &ygopropb.StocChat{
Player: player,
Msg: message,
},
}
}
// +++++ Util Functions +++++
func strToUtf16Buffer(s string) []uint16 {
b := make([]uint16, UTF16_BUFFER_MAX_LEN, UTF16_BUFFER_MAX_LEN)
for i := range b {
b[i] = FILLING_TOKEN
}
s_utf16 := utf16.Encode([]rune(s))
// todo: optimize
for i, v := range s_utf16 {
if i < UTF16_BUFFER_MAX_LEN {
b[i] = v
if i == len(s_utf16)-1 && i < len(b)-1 {
b[i+1] = 0
}
} else {
break
}
}
return b
}
func utf16BufferToStr(p []byte) string {
v := chunkBytesToUint16s(p)
return string(utf16.Decode(v))
}
func uint16BufToByteBuf(u16_b []uint16) []byte {
b := make([]byte, 0, len(u16_b)*2)
for _, v := range u16_b {
// little endian
b = append(b, byte(v), byte(v>>8))
}
return b
}
func chunkBytesToUint16s(items []byte) []uint16 {
const chunkSize = 2
var chunks []uint16
for chunkSize < len(items) {
items, chunks = items[chunkSize:], append(chunks, binary.LittleEndian.Uint16(items))
}
return chunks
}
package ygoprobuffer
const PLAYER_NAME_MAX_LEN int = 20
type CtosPlayerInfo struct {
Name [PLAYER_NAME_MAX_LEN]uint16
}
This diff is collapsed.
......@@ -2,4 +2,8 @@ module github.com/sktt1ryze/ygopro-proxy
go 1.17
require github.com/gorilla/websocket v1.5.0 // indirect
require (
github.com/golang/protobuf v1.5.2 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect
)
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
......@@ -9,6 +9,7 @@ import (
"sync"
"github.com/gorilla/websocket"
darkneos "github.com/sktt1ryze/ygopro-proxy/DarkNeos"
)
const TARGET_PORT = ":8000"
......@@ -50,10 +51,12 @@ func ygoEndpoint(w http.ResponseWriter, r *http.Request) {
}
func wsProxy(ws *websocket.Conn, tcp *net.Conn, wg *sync.WaitGroup) {
writer := bufio.NewWriter(*tcp)
for {
messageType, buf, err := ws.ReadMessage()
messageType, buffer, err := ws.ReadMessage()
if err != nil {
log.Fatal("websocket read message error: ", err)
log.Println("websocket read message error: ", err)
break
}
......@@ -62,10 +65,11 @@ func wsProxy(ws *websocket.Conn, tcp *net.Conn, wg *sync.WaitGroup) {
break
}
log.Println("websocket to tcp: " + string(buf))
writer := bufio.NewWriter(*tcp)
buffer := make([]byte, BUFFER_SIZE)
buffer, err = darkneos.Transform(buffer, darkneos.ProtobufToRawBuf)
if err != nil {
log.Fatal(err)
break
}
_, err = writer.Write(buffer)
if err != nil {
......@@ -78,23 +82,27 @@ func wsProxy(ws *websocket.Conn, tcp *net.Conn, wg *sync.WaitGroup) {
}
func tcpProxy(tcp *net.Conn, ws *websocket.Conn, wg *sync.WaitGroup) {
for {
reader := bufio.NewReader(*tcp)
buffer := make([]byte, BUFFER_SIZE)
for {
_, err := reader.Read(buffer)
if err != nil {
if err == io.EOF {
continue
}
log.Fatal("tcp read message error: ", err)
log.Println("tcp read message error: ", err)
break
}
log.Println("tcp to websocket: " + string(buffer))
buffer, err = darkneos.Transform(buffer, darkneos.RawBufToProtobuf)
if err != nil {
log.Fatal(err)
break
}
err = ws.WriteMessage(websocket.TextMessage, buffer) // temporary TextMessage, should be BinaryMessage in ygopro
err = ws.WriteMessage(websocket.BinaryMessage, buffer)
if err != nil {
log.Fatal("tcp send message error: ", err)
break
......
......@@ -4,16 +4,19 @@ package ygopro;
option go_package = "DarkNeos/ygopropb";
message YgoCtosMsg {
int32 proto = 1;
oneof msg {
CtosPlayerInfo ctos_player_info = 2;
CtosJoinGame ctos_join_game = 3;
CtosUpdateDeck ctos_update_deck = 4;
CtosPlayerInfo ctos_player_info = 1;
CtosJoinGame ctos_join_game = 2;
CtosUpdateDeck ctos_update_deck = 3;
}
}
StocJoinGame stoc_join_game = 101;
StocChat stoc_chat = 102;
StocHsPlayerEnter stoc_hs_player_enter = 103;
StocTypeChange stoc_type_change = 104;
message YgoStocMsg {
oneof msg {
StocJoinGame stoc_join_game = 1;
StocChat stoc_chat = 2;
StocHsPlayerEnter stoc_hs_player_enter = 3;
StocTypeChange stoc_type_change = 4;
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment