阶段性提交

This commit is contained in:
刘祥超
2020-07-22 22:18:47 +08:00
parent 219732c1df
commit fa7edac94b
19 changed files with 716 additions and 14 deletions

View File

@@ -0,0 +1,28 @@
package configs
import (
"github.com/go-yaml/yaml"
"github.com/iwind/TeaGo/Tea"
"io/ioutil"
)
type APIConfig struct {
RPC struct {
Endpoints []string `yaml:"endpoints"`
} `yaml:"rpc"`
}
func LoadAPIConfig() (*APIConfig, error) {
data, err := ioutil.ReadFile(Tea.ConfigFile("api.yaml"))
if err != nil {
return nil, err
}
config := &APIConfig{}
err = yaml.Unmarshal(data, config)
if err != nil {
return nil, err
}
return config, nil
}

View File

@@ -0,0 +1,11 @@
package configs
import "testing"
func TestLoadAPIConfig(t *testing.T) {
config, err := LoadAPIConfig()
if err != nil {
t.Fatal(err)
}
t.Log(config)
}

View File

@@ -0,0 +1,4 @@
package configs
type FilterConfig struct {
}

View File

@@ -4,6 +4,7 @@ type ServerConfig struct {
Id string `yaml:"id"` // ID
IsOn bool `yaml:"isOn"` // 是否开启
Components []*ComponentConfig `yaml:"components"` // 组件
Filters []*FilterConfig `yaml:"filters"` // 过滤器
Name string `yaml:"name"` // 名称
Description string `yaml:"description"` // 描述
ServerNames []string `yaml:"serverNames"` // 域名

View File

@@ -1,13 +1,20 @@
package nodes
import (
"context"
"errors"
"github.com/TeaOSLab/EdgeNode/internal/configs"
"github.com/iwind/TeaGo/logs"
"net"
"net/http"
"sync"
)
type Listener struct {
group *configs.ServerGroup
group *configs.ServerGroup
isListening bool
listener interface{} // 监听器
locker sync.RWMutex
}
@@ -34,13 +41,13 @@ func (this *Listener) Listen() error {
}
protocol := this.group.Protocol()
switch protocol {
case configs.ProtocolHTTP:
case configs.ProtocolHTTP, configs.ProtocolHTTP4, configs.ProtocolHTTP6:
return this.listenHTTP()
case configs.ProtocolHTTPS:
case configs.ProtocolHTTPS, configs.ProtocolHTTPS4, configs.ProtocolHTTPS6:
return this.ListenHTTPS()
case configs.ProtocolTCP:
case configs.ProtocolTCP, configs.ProtocolTCP4, configs.ProtocolTCP6:
return this.listenTCP()
case configs.ProtocolTLS:
case configs.ProtocolTLS, configs.ProtocolTLS4, configs.ProtocolTLS6:
return this.listenTLS()
case configs.ProtocolUnix:
return this.listenUnix()
@@ -57,25 +64,66 @@ func (this *Listener) Close() error {
}
func (this *Listener) listenHTTP() error {
listener, err := this.createListener()
if err != nil {
return err
}
mux := http.NewServeMux()
mux.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
_, _ = writer.Write([]byte("Hello, World"))
})
server := &http.Server{
Addr: this.group.Addr(),
Handler: mux,
}
go func() {
err = server.Serve(listener)
if err != nil {
logs.Println("[LISTENER]" + err.Error())
}
}()
return nil
}
func (this *Listener) ListenHTTPS() error {
// TODO 需要实现
return nil
}
func (this *Listener) listenTCP() error {
// TODO 需要实现
return nil
}
func (this *Listener) listenTLS() error {
// TODO 需要实现
return nil
}
func (this *Listener) listenUnix() error {
// TODO 需要实现
return nil
}
func (this *Listener) listenUDP() error {
// TODO 需要实现
return nil
}
func (this *Listener) createListener() (net.Listener, error) {
listenConfig := net.ListenConfig{
Control: nil,
KeepAlive: 0,
}
switch this.group.Protocol() {
case configs.ProtocolHTTP4, configs.ProtocolHTTPS4, configs.ProtocolTLS4:
return listenConfig.Listen(context.Background(), "tcp4", this.group.Addr())
case configs.ProtocolHTTP6, configs.ProtocolHTTPS6, configs.ProtocolTLS6:
return listenConfig.Listen(context.Background(), "tcp6", this.group.Addr())
}
return listenConfig.Listen(context.Background(), "tcp", this.group.Addr())
}

View File

@@ -0,0 +1,18 @@
package nodes
import (
"github.com/TeaOSLab/EdgeNode/internal/configs"
"testing"
)
func TestListener_Listen(t *testing.T) {
listener := NewListener()
group := configs.NewServerGroup("http://:1234")
listener.Reload(group)
err := listener.Listen()
if err != nil {
t.Fatal(err)
}
}

View File

@@ -2,10 +2,12 @@ package nodes
import (
"github.com/TeaOSLab/EdgeNode/internal/configs"
"github.com/TeaOSLab/EdgeNode/internal/utils"
"github.com/iwind/TeaGo/logs"
)
var sharedNodeConfig *configs.NodeConfig = nil
var stop = make(chan bool)
type Node struct {
}
@@ -15,6 +17,7 @@ func NewNode() *Node {
}
func (this *Node) Start() {
// 读取配置
nodeConfig, err := configs.SharedNodeConfig()
if err != nil {
logs.Println("[NODE]start failed: read node config failed: " + err.Error())
@@ -22,5 +25,15 @@ func (this *Node) Start() {
}
sharedNodeConfig = nodeConfig
logs.PrintAsJSON(nodeConfig)
// 设置rlimit
_ = utils.SetRLimit(1024 * 1024)
// 启动端口
err = sharedListenerManager.Start(nodeConfig)
if err != nil {
logs.Println("[NODE]start failed: " + err.Error())
}
// hold住进程
<-stop
}

View File

@@ -0,0 +1,50 @@
package nodes
import (
"context"
"errors"
"github.com/TeaOSLab/EdgeNode/internal/configs"
"github.com/TeaOSLab/EdgeNode/internal/rpc/node"
"github.com/iwind/TeaGo/rands"
"google.golang.org/grpc"
)
type RPCClient struct {
nodeClients []node.ServiceClient
}
func NewRPCClient(apiConfig *configs.APIConfig) (*RPCClient, error) {
nodeClients := []node.ServiceClient{}
conns := []*grpc.ClientConn{}
for _, endpoint := range apiConfig.RPC.Endpoints {
conn, err := grpc.Dial(endpoint, grpc.WithInsecure())
if err != nil {
return nil, err
}
conns = append(conns, conn)
}
if len(conns) == 0 {
return nil, errors.New("[RPC]no available endpoints")
}
// node clients
for _, conn := range conns {
nodeClients = append(nodeClients, node.NewServiceClient(conn))
}
return &RPCClient{
nodeClients: nodeClients,
}, nil
}
func (this *RPCClient) NodeRPC() node.ServiceClient {
if len(this.nodeClients) > 0 {
return this.nodeClients[rands.Int(0, len(this.nodeClients)-1)]
}
return nil
}
func (this *RPCClient) Context() context.Context {
return context.Background()
}

View File

@@ -0,0 +1,30 @@
package nodes
import (
"github.com/TeaOSLab/EdgeNode/internal/configs"
"github.com/TeaOSLab/EdgeNode/internal/rpc/node"
"testing"
"time"
)
func TestRPCClient_NodeRPC(t *testing.T) {
before := time.Now()
defer func() {
t.Log(time.Since(before).Seconds()*1000, "ms")
}()
config, err := configs.LoadAPIConfig()
if err != nil {
t.Fatal(err)
}
rpc, err := NewRPCClient(config)
if err != nil {
t.Fatal(err)
}
resp, err := rpc.NodeRPC().Config(rpc.Context(), &node.ConfigRequest{
NodeId: "123456",
})
if err != nil {
t.Fatal(err)
}
t.Log(resp)
}

View File

@@ -0,0 +1,299 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0
// protoc v3.12.3
// source: node/service.proto
package node
import (
context "context"
proto "github.com/golang/protobuf/proto"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
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
type ConfigRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
NodeId string `protobuf:"bytes,1,opt,name=nodeId,proto3" json:"nodeId,omitempty"`
}
func (x *ConfigRequest) Reset() {
*x = ConfigRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_node_service_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ConfigRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConfigRequest) ProtoMessage() {}
func (x *ConfigRequest) ProtoReflect() protoreflect.Message {
mi := &file_node_service_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 ConfigRequest.ProtoReflect.Descriptor instead.
func (*ConfigRequest) Descriptor() ([]byte, []int) {
return file_node_service_proto_rawDescGZIP(), []int{0}
}
func (x *ConfigRequest) GetNodeId() string {
if x != nil {
return x.NodeId
}
return ""
}
type ConfigResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
}
func (x *ConfigResponse) Reset() {
*x = ConfigResponse{}
if protoimpl.UnsafeEnabled {
mi := &file_node_service_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ConfigResponse) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ConfigResponse) ProtoMessage() {}
func (x *ConfigResponse) ProtoReflect() protoreflect.Message {
mi := &file_node_service_proto_msgTypes[1]
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 ConfigResponse.ProtoReflect.Descriptor instead.
func (*ConfigResponse) Descriptor() ([]byte, []int) {
return file_node_service_proto_rawDescGZIP(), []int{1}
}
func (x *ConfigResponse) GetId() string {
if x != nil {
return x.Id
}
return ""
}
var File_node_service_proto protoreflect.FileDescriptor
var file_node_service_proto_rawDesc = []byte{
0x0a, 0x12, 0x6e, 0x6f, 0x64, 0x65, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x6e, 0x6f, 0x64, 0x65, 0x22, 0x27, 0x0a, 0x0d, 0x43, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6e,
0x6f, 0x64, 0x65, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6e, 0x6f, 0x64,
0x65, 0x49, 0x64, 0x22, 0x20, 0x0a, 0x0e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x02, 0x69, 0x64, 0x32, 0x40, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65,
0x12, 0x35, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x13, 0x2e, 0x6e, 0x6f, 0x64,
0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x14, 0x2e, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x2f, 0x6e, 0x6f, 0x64,
0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
file_node_service_proto_rawDescOnce sync.Once
file_node_service_proto_rawDescData = file_node_service_proto_rawDesc
)
func file_node_service_proto_rawDescGZIP() []byte {
file_node_service_proto_rawDescOnce.Do(func() {
file_node_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_node_service_proto_rawDescData)
})
return file_node_service_proto_rawDescData
}
var file_node_service_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_node_service_proto_goTypes = []interface{}{
(*ConfigRequest)(nil), // 0: node.ConfigRequest
(*ConfigResponse)(nil), // 1: node.ConfigResponse
}
var file_node_service_proto_depIdxs = []int32{
0, // 0: node.Service.config:input_type -> node.ConfigRequest
1, // 1: node.Service.config:output_type -> node.ConfigResponse
1, // [1:2] is the sub-list for method output_type
0, // [0:1] 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_node_service_proto_init() }
func file_node_service_proto_init() {
if File_node_service_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_node_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ConfigRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_node_service_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ConfigResponse); 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_node_service_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_node_service_proto_goTypes,
DependencyIndexes: file_node_service_proto_depIdxs,
MessageInfos: file_node_service_proto_msgTypes,
}.Build()
File_node_service_proto = out.File
file_node_service_proto_rawDesc = nil
file_node_service_proto_goTypes = nil
file_node_service_proto_depIdxs = nil
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConnInterface
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6
// ServiceClient is the client API for Service service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type ServiceClient interface {
Config(ctx context.Context, in *ConfigRequest, opts ...grpc.CallOption) (*ConfigResponse, error)
}
type serviceClient struct {
cc grpc.ClientConnInterface
}
func NewServiceClient(cc grpc.ClientConnInterface) ServiceClient {
return &serviceClient{cc}
}
func (c *serviceClient) Config(ctx context.Context, in *ConfigRequest, opts ...grpc.CallOption) (*ConfigResponse, error) {
out := new(ConfigResponse)
err := c.cc.Invoke(ctx, "/node.Service/config", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ServiceServer is the server API for Service service.
type ServiceServer interface {
Config(context.Context, *ConfigRequest) (*ConfigResponse, error)
}
// UnimplementedServiceServer can be embedded to have forward compatible implementations.
type UnimplementedServiceServer struct {
}
func (*UnimplementedServiceServer) Config(context.Context, *ConfigRequest) (*ConfigResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Config not implemented")
}
func RegisterServiceServer(s *grpc.Server, srv ServiceServer) {
s.RegisterService(&_Service_serviceDesc, srv)
}
func _Service_Config_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ConfigRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ServiceServer).Config(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/node.Service/Config",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ServiceServer).Config(ctx, req.(*ConfigRequest))
}
return interceptor(ctx, in, info, handler)
}
var _Service_serviceDesc = grpc.ServiceDesc{
ServiceName: "node.Service",
HandlerType: (*ServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "config",
Handler: _Service_Config_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "node/service.proto",
}

View File

@@ -0,0 +1,19 @@
syntax = "proto3";
package node;
option go_package = "./node";
service Service {
rpc config (ConfigRequest) returns (ConfigResponse) {
}
}
message ConfigRequest {
string nodeId = 1;
}
message ConfigResponse {
string id = 1;
}

View File

@@ -0,0 +1,29 @@
// +build darwin
package utils
import (
"syscall"
)
// set resource limit
func SetRLimit(limit uint64) error {
rLimit := &syscall.Rlimit{}
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, rLimit)
if err != nil {
return err
}
if rLimit.Cur < limit {
rLimit.Cur = limit
}
if rLimit.Max < limit {
rLimit.Max = limit
}
return syscall.Setrlimit(syscall.RLIMIT_NOFILE, rLimit)
}
// set best resource limit value
func SetSuitableRLimit() {
SetRLimit(4096 * 100) // 1M=100Files
}

View File

@@ -0,0 +1,29 @@
// +build linux
package utils
import (
"syscall"
)
// set resource limit
func SetRLimit(limit uint64) error {
rLimit := &syscall.Rlimit{}
err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, rLimit)
if err != nil {
return err
}
if rLimit.Cur < limit {
rLimit.Cur = limit
}
if rLimit.Max < limit {
rLimit.Max = limit
}
return syscall.Setrlimit(syscall.RLIMIT_NOFILE, rLimit)
}
// set best resource limit value
func SetSuitableRLimit() {
SetRLimit(4096 * 100) // 1M=100Files
}

View File

@@ -0,0 +1,13 @@
// +build !linux,!darwin
package utils
// set resource limit
func SetRLimit(limit uint64) error {
return nil
}
// set best resource limit value
func SetSuitableRLimit() {
}