Commit ba3d18d1 authored by Patrycja Rosa's avatar Patrycja Rosa
Browse files

feat: Initial commit

parents
package proto
import (
"fmt"
"git.ddd.rip/ddd-im/server/proto/packets"
)
func (w Wrapper) ReadPacket() (packets.Packet, error) {
id, err := w.ReadUint8()
if err != nil {
return nil, err
}
pktMap := packets.ClientPacketIDMap
if w.IsClient {
pktMap = packets.ServerPacketIDMap
}
if _, ok := pktMap[id]; !ok {
return nil, fmt.Errorf("invalid packet id: %d", id)
}
packet := pktMap[id]()
err = w.ReadStruct(packet)
return packet, err
}
func (w Wrapper) WritePacket(packet packets.Packet) error {
err := w.WriteUint8(packet.ID())
if err != nil {
return err
}
return w.WriteStruct(packet)
}
package proto
import (
"net"
)
type Wrapper struct {
Conn net.Conn
IsClient bool
}
func (w Wrapper) ReadBytes(count uint64) ([]byte, error) {
buf := make([]byte, count)
_, err := w.Conn.Read(buf)
return buf, err
}
package proto
import "reflect"
func getFields(v reflect.Value) []reflect.StructField {
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
t := v.Type()
var fields []reflect.StructField
for i := 0; i < t.NumField(); i++ {
fields = append(fields, t.Field(i))
}
return fields
}
package proto
import (
"reflect"
)
func (w Wrapper) ReadSlice(typ reflect.Type) (reflect.Value, error) {
length, err := w.ReadUint16()
if err != nil {
return reflect.Value{}, err
}
res := reflect.MakeSlice(reflect.SliceOf(typ), int(length), int(length))
for i := 0; i < int(length); i++ {
obj := reflect.New(typ.Elem()).Interface()
err := w.ReadStruct(obj)
if err != nil {
return reflect.Value{}, err
}
res.Index(i).Set(reflect.ValueOf(obj))
}
return res, nil
}
func (w Wrapper) WriteSlice(slice []interface{}) error {
err := w.WriteUint16(uint16(len(slice)))
if err != nil {
return err
}
for _, obj := range slice {
err := w.WriteStruct(obj)
if err != nil {
return err
}
}
return nil
}
package proto
import (
"fmt"
"log"
"reflect"
)
func (w Wrapper) ReadStruct(obj interface{}) error {
reflection := reflect.ValueOf(obj)
for _, field := range getFields(reflection) {
f := reflection.Elem().FieldByName(field.Name)
switch field.Type.Kind() {
case reflect.Uint8:
val, err := w.ReadUint8()
if err != nil {
return fmt.Errorf("uint8 read error: %s", err.Error())
}
f.SetUint(uint64(val))
case reflect.Uint16:
val, err := w.ReadUint16()
if err != nil {
return fmt.Errorf("uint16 read error: %s", err.Error())
}
f.SetUint(uint64(val))
case reflect.Uint32:
val, err := w.ReadUint32()
if err != nil {
return fmt.Errorf("uint32 read error: %s", err.Error())
}
f.SetUint(uint64(val))
case reflect.Uint64:
val, err := w.ReadUint64()
if err != nil {
return fmt.Errorf("uint64 read error: %s", err.Error())
}
f.SetUint(val)
case reflect.String:
val, err := w.ReadVarString()
if err != nil {
return fmt.Errorf("string read error: %s", err.Error())
}
f.SetString(val)
case reflect.Slice:
cv := reflect.New(f.Type().Elem()).Elem()
val, err := w.ReadSlice(cv.Type())
if err != nil {
return fmt.Errorf("slice read error: %s", err.Error())
}
f.Set(val)
default:
return fmt.Errorf("invalid struct field type: %s", field.Type.Kind())
}
}
return nil
}
func (w Wrapper) WriteStruct(obj interface{}) error {
reflection := reflect.ValueOf(obj)
for _, field := range getFields(reflection) {
f := reflection.Elem().FieldByName(field.Name)
switch field.Type.Kind() {
case reflect.Uint8:
err := w.WriteUint8(uint8(f.Uint()))
if err != nil {
return fmt.Errorf("uint8 write error: %s", err.Error())
}
case reflect.Uint16:
err := w.WriteUint16(uint16(f.Uint()))
if err != nil {
return fmt.Errorf("uint16 write error: %s", err.Error())
}
case reflect.Uint32:
err := w.WriteUint32(uint32(f.Uint()))
if err != nil {
return fmt.Errorf("uint32 write error: %s", err.Error())
}
case reflect.Uint64:
err := w.WriteUint64(f.Uint())
if err != nil {
return fmt.Errorf("uint64 write error: %s", err.Error())
}
case reflect.String:
err := w.WriteVarString(f.String())
if err != nil {
return fmt.Errorf("string write error: %s", err.Error())
}
case reflect.Slice:
var tmp []interface{}
for i := 0; i < f.Len(); i++ {
tmp = append(tmp, f.Index(i).Interface())
}
err := w.WriteSlice(tmp)
if err != nil {
return fmt.Errorf("slice write error: %s", err.Error())
}
default:
log.Println(field.Type.Kind())
return fmt.Errorf("invalid struct field type: %s", field.Type.Name())
}
}
return nil
}
package proto
import "encoding/binary"
func (w Wrapper) ReadUint64() (uint64, error) {
buf, err := w.ReadBytes(8)
if err != nil {
return 0, err
}
return binary.BigEndian.Uint64(buf), nil
}
func (w Wrapper) ReadUint32() (uint32, error) {
buf, err := w.ReadBytes(4)
if err != nil {
return 0, err
}
return binary.BigEndian.Uint32(buf), nil
}
func (w Wrapper) ReadUint16() (uint16, error) {
buf, err := w.ReadBytes(2)
if err != nil {
return 0, err
}
return binary.BigEndian.Uint16(buf), nil
}
func (w Wrapper) ReadUint8() (uint8, error) {
buf, err := w.ReadBytes(1)
if err != nil {
return 0, err
}
return buf[0], nil
}
func (w Wrapper) WriteUint64(val uint64) error {
buf := make([]byte, 8)
binary.BigEndian.PutUint64(buf, val)
_, err := w.Conn.Write(buf)
return err
}
func (w Wrapper) WriteUint32(val uint32) error {
buf := make([]byte, 4)
binary.BigEndian.PutUint32(buf, val)
_, err := w.Conn.Write(buf)
return err
}
func (w Wrapper) WriteUint16(val uint16) error {
buf := make([]byte, 2)
binary.BigEndian.PutUint16(buf, val)
_, err := w.Conn.Write(buf)
return err
}
func (w Wrapper) WriteUint8(val uint8) error {
_, err := w.Conn.Write([]byte{val})
return err
}
package proto
func (w Wrapper) ReadVarString() (string, error) {
length, err := w.ReadUint16()
if err != nil {
return "", err
}
buf, err := w.ReadBytes(uint64(length))
if err != nil {
return "", err
}
return string(buf), nil
}
func (w Wrapper) WriteVarString(val string) error {
err := w.WriteUint16(uint16(len(val)))
if err != nil {
return err
}
_, err = w.Conn.Write([]byte(val))
return err
}
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