This commit is contained in:
RPRX 2020-11-25 19:01:53 +08:00
parent 47d23e9972
commit c7f7c08ead
711 changed files with 82154 additions and 2 deletions

29
common/serial/serial.go Normal file
View file

@ -0,0 +1,29 @@
package serial
import (
"encoding/binary"
"io"
)
// ReadUint16 reads first two bytes from the reader, and then coverts them to an uint16 value.
func ReadUint16(reader io.Reader) (uint16, error) {
var b [2]byte
if _, err := io.ReadFull(reader, b[:]); err != nil {
return 0, err
}
return binary.BigEndian.Uint16(b[:]), nil
}
// WriteUint16 writes an uint16 value into writer.
func WriteUint16(writer io.Writer, value uint16) (int, error) {
var b [2]byte
binary.BigEndian.PutUint16(b[:], value)
return writer.Write(b[:])
}
// WriteUint64 writes an uint64 value into writer.
func WriteUint64(writer io.Writer, value uint64) (int, error) {
var b [8]byte
binary.BigEndian.PutUint64(b[:], value)
return writer.Write(b[:])
}

View file

@ -0,0 +1,88 @@
package serial_test
import (
"bytes"
"testing"
"github.com/google/go-cmp/cmp"
"github.com/xtls/xray-core/v1/common"
"github.com/xtls/xray-core/v1/common/buf"
"github.com/xtls/xray-core/v1/common/serial"
)
func TestUint16Serial(t *testing.T) {
b := buf.New()
defer b.Release()
n, err := serial.WriteUint16(b, 10)
common.Must(err)
if n != 2 {
t.Error("expect 2 bytes writtng, but actually ", n)
}
if diff := cmp.Diff(b.Bytes(), []byte{0, 10}); diff != "" {
t.Error(diff)
}
}
func TestUint64Serial(t *testing.T) {
b := buf.New()
defer b.Release()
n, err := serial.WriteUint64(b, 10)
common.Must(err)
if n != 8 {
t.Error("expect 8 bytes writtng, but actually ", n)
}
if diff := cmp.Diff(b.Bytes(), []byte{0, 0, 0, 0, 0, 0, 0, 10}); diff != "" {
t.Error(diff)
}
}
func TestReadUint16(t *testing.T) {
testCases := []struct {
Input []byte
Output uint16
}{
{
Input: []byte{0, 1},
Output: 1,
},
}
for _, testCase := range testCases {
v, err := serial.ReadUint16(bytes.NewReader(testCase.Input))
common.Must(err)
if v != testCase.Output {
t.Error("for input ", testCase.Input, " expect output ", testCase.Output, " but got ", v)
}
}
}
func BenchmarkReadUint16(b *testing.B) {
reader := buf.New()
defer reader.Release()
common.Must2(reader.Write([]byte{0, 1}))
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := serial.ReadUint16(reader)
common.Must(err)
reader.Clear()
reader.Extend(2)
}
}
func BenchmarkWriteUint64(b *testing.B) {
writer := buf.New()
defer writer.Release()
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := serial.WriteUint64(writer, 8)
common.Must(err)
writer.Clear()
}
}

35
common/serial/string.go Normal file
View file

@ -0,0 +1,35 @@
package serial
import (
"fmt"
"strings"
)
// ToString serialize an arbitrary value into string.
func ToString(v interface{}) string {
if v == nil {
return " "
}
switch value := v.(type) {
case string:
return value
case *string:
return *value
case fmt.Stringer:
return value.String()
case error:
return value.Error()
default:
return fmt.Sprintf("%+v", value)
}
}
// Concat concatenates all input into a single string.
func Concat(v ...interface{}) string {
builder := strings.Builder{}
for _, value := range v {
builder.WriteString(ToString(value))
}
return builder.String()
}

View file

@ -0,0 +1,59 @@
package serial_test
import (
"errors"
"testing"
"github.com/google/go-cmp/cmp"
. "github.com/xtls/xray-core/v1/common/serial"
)
func TestToString(t *testing.T) {
s := "a"
data := []struct {
Value interface{}
String string
}{
{Value: s, String: s},
{Value: &s, String: s},
{Value: errors.New("t"), String: "t"},
{Value: []byte{'b', 'c'}, String: "[98 99]"},
}
for _, c := range data {
if r := cmp.Diff(ToString(c.Value), c.String); r != "" {
t.Error(r)
}
}
}
func TestConcat(t *testing.T) {
testCases := []struct {
Input []interface{}
Output string
}{
{
Input: []interface{}{
"a", "b",
},
Output: "ab",
},
}
for _, testCase := range testCases {
actual := Concat(testCase.Input...)
if actual != testCase.Output {
t.Error("Unexpected output: ", actual, " but want: ", testCase.Output)
}
}
}
func BenchmarkConcat(b *testing.B) {
input := []interface{}{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"}
b.ReportAllocs()
for i := 0; i < b.N; i++ {
_ = Concat(input...)
}
}

View file

@ -0,0 +1,47 @@
package serial
import (
"errors"
"reflect"
"github.com/golang/protobuf/proto"
)
// ToTypedMessage converts a proto Message into TypedMessage.
func ToTypedMessage(message proto.Message) *TypedMessage {
if message == nil {
return nil
}
settings, _ := proto.Marshal(message)
return &TypedMessage{
Type: GetMessageType(message),
Value: settings,
}
}
// GetMessageType returns the name of this proto Message.
func GetMessageType(message proto.Message) string {
return proto.MessageName(message)
}
// GetInstance creates a new instance of the message with messageType.
func GetInstance(messageType string) (interface{}, error) {
mType := proto.MessageType(messageType)
if mType == nil || mType.Elem() == nil {
return nil, errors.New("Serial: Unknown type: " + messageType)
}
return reflect.New(mType.Elem()).Interface(), nil
}
// GetInstance converts current TypedMessage into a proto Message.
func (v *TypedMessage) GetInstance() (proto.Message, error) {
instance, err := GetInstance(v.Type)
if err != nil {
return nil, err
}
protoMessage := instance.(proto.Message)
if err := proto.Unmarshal(v.Value, protoMessage); err != nil {
return nil, err
}
return protoMessage, nil
}

View file

@ -0,0 +1,166 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.14.0
// source: common/serial/typed_message.proto
package serial
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
// TypedMessage is a serialized proto message along with its type name.
type TypedMessage struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// The name of the message type, retrieved from protobuf API.
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
// Serialized proto message.
Value []byte `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"`
}
func (x *TypedMessage) Reset() {
*x = TypedMessage{}
if protoimpl.UnsafeEnabled {
mi := &file_common_serial_typed_message_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *TypedMessage) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*TypedMessage) ProtoMessage() {}
func (x *TypedMessage) ProtoReflect() protoreflect.Message {
mi := &file_common_serial_typed_message_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use TypedMessage.ProtoReflect.Descriptor instead.
func (*TypedMessage) Descriptor() ([]byte, []int) {
return file_common_serial_typed_message_proto_rawDescGZIP(), []int{0}
}
func (x *TypedMessage) GetType() string {
if x != nil {
return x.Type
}
return ""
}
func (x *TypedMessage) GetValue() []byte {
if x != nil {
return x.Value
}
return nil
}
var File_common_serial_typed_message_proto protoreflect.FileDescriptor
var file_common_serial_typed_message_proto_rawDesc = []byte{
0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2f,
0x74, 0x79, 0x70, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x12, 0x12, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e,
0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x22, 0x38, 0x0a, 0x0c, 0x54, 0x79, 0x70, 0x65, 0x64,
0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x42, 0x5b, 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x2e, 0x78, 0x72, 0x61, 0x79, 0x2e, 0x63, 0x6f,
0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x50, 0x01, 0x5a, 0x2a, 0x67,
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x78, 0x74, 0x6c, 0x73, 0x2f, 0x78,
0x72, 0x61, 0x79, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d,
0x6f, 0x6e, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0xaa, 0x02, 0x12, 0x58, 0x72, 0x61, 0x79,
0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_common_serial_typed_message_proto_rawDescOnce sync.Once
file_common_serial_typed_message_proto_rawDescData = file_common_serial_typed_message_proto_rawDesc
)
func file_common_serial_typed_message_proto_rawDescGZIP() []byte {
file_common_serial_typed_message_proto_rawDescOnce.Do(func() {
file_common_serial_typed_message_proto_rawDescData = protoimpl.X.CompressGZIP(file_common_serial_typed_message_proto_rawDescData)
})
return file_common_serial_typed_message_proto_rawDescData
}
var file_common_serial_typed_message_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_common_serial_typed_message_proto_goTypes = []interface{}{
(*TypedMessage)(nil), // 0: xray.common.serial.TypedMessage
}
var file_common_serial_typed_message_proto_depIdxs = []int32{
0, // [0:0] is the sub-list for method output_type
0, // [0:0] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
}
func init() { file_common_serial_typed_message_proto_init() }
func file_common_serial_typed_message_proto_init() {
if File_common_serial_typed_message_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_common_serial_typed_message_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*TypedMessage); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_common_serial_typed_message_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_common_serial_typed_message_proto_goTypes,
DependencyIndexes: file_common_serial_typed_message_proto_depIdxs,
MessageInfos: file_common_serial_typed_message_proto_msgTypes,
}.Build()
File_common_serial_typed_message_proto = out.File
file_common_serial_typed_message_proto_rawDesc = nil
file_common_serial_typed_message_proto_goTypes = nil
file_common_serial_typed_message_proto_depIdxs = nil
}

View file

@ -0,0 +1,15 @@
syntax = "proto3";
package xray.common.serial;
option csharp_namespace = "Xray.Common.Serial";
option go_package = "github.com/xtls/xray-core/v1/common/serial";
option java_package = "com.xray.common.serial";
option java_multiple_files = true;
// TypedMessage is a serialized proto message along with its type name.
message TypedMessage {
// The name of the message type, retrieved from protobuf API.
string type = 1;
// Serialized proto message.
bytes value = 2;
}

View file

@ -0,0 +1,24 @@
package serial_test
import (
"testing"
. "github.com/xtls/xray-core/v1/common/serial"
)
func TestGetInstance(t *testing.T) {
p, err := GetInstance("")
if p != nil {
t.Error("expected nil instance, but got ", p)
}
if err == nil {
t.Error("expect non-nil error, but got nil")
}
}
func TestConvertingNilMessage(t *testing.T) {
x := ToTypedMessage(nil)
if x != nil {
t.Error("expect nil, but actually not")
}
}