Giter Club home page Giter Club logo

gd's Introduction

godog gd

Now, maintenance of this project is temporarily suspended. Please go to github.com/chuck1024/gd

GoDoc Go Report Card Release

"go" is the meaning of a dog in Chinese pronunciation, and dog's original intention is also a dog. So godog means "狗狗" in Chinese, which is very cute.


Author

author: Chuck1024
email : [email protected]

Installation

Start with cloning gd:

> go get github.com/gdp-org/gd

Introduction

Godog is a basic framework implemented by golang, which is aiming at helping developers setup feature-rich server quickly.

The framework contains config module,databases module,error module,dlog module,net module,runtime module and server module. You can select any modules according to your practice. More features will be added later. I hope anyone who is interested in this work can join it and let's enhance the system function of this framework together.


Quick start

package main

import (
	"github.com/gdp-org/gd"
	"github.com/gdp-org/gd/net/dhttp"
	"github.com/gdp-org/gd/runtime/inject"
	"github.com/gin-gonic/gin"
	"net/http"
)

func HandlerHttp(c *gin.Context, req interface{}) (code int, message string, err error, ret string) {
	gd.Debug("httpServerTest req:%v", req)
	ret = "ok!!!"
	return http.StatusOK, "ok", nil, ret
}

func main() {
	d := gd.Default()
	inject.RegisterOrFail("httpServerInit", func(g *gin.Engine) error {
		r := g.Group("")
		r.Use(
			dhttp.GlFilter(),
			dhttp.GroupFilter(),
			dhttp.Logger("quick-start"),
		)

		d.HttpServer.GET(r, "test", HandlerHttp)

		if err := d.HttpServer.CheckHandle(); err != nil {
			return err
		}
		return nil
	})

	gd.SetConfig("Server", "httpPort", "10240")

	if err := d.Run(); err != nil {
		gd.Error("Error occurs, error = %s", err.Error())
		return
	}
}

[config]
So far, it only supports configuration with ini in gd. Of course, it supports more and more format configuration in future. What's more, your configuration file must have the necessary parameters, like this:

[Log]
enable = true
level = "DEBUG"

[Process]
maxCPU = 2
healthPort = 9527

[Server]
serverName = "gd"
httpPort = 10240
rpcPort = 10241
grpcPort = 10242

Log.enable: log config, turn on log output. Log.level: log level. Process.maxCPU: a limit of CPU usage. 0 is default, means to use half cores.
Process.maxMemory: a limit of memory usage. Process.healthPort: the port for monitor. If it is 0, monitor server will not run. Server.serverName: server name.
Server.httpPort: http port. If it is 0, http server will not run.
Server.rpcPort: rpc port. If it is 0, rpc server will not run. Server.grpcPort: grpc port. If it is 0, grpc server will not run.

Those items mentioned above are the base need of a server application. And they are defined in config file: sample/conf/conf.json.


[net]
provides golang network server, it is contain http server and rpc server. It is a simple demo that you can develop it on the basis of it. I will import introduce rpc server. Focus on the rpc server.

type Packet interface {
	ID() uint32
	SetErrCode(code uint32)
}

default rpc packet:
type RpcPacket struct {
	Seq       uint32
	ErrCode   uint32
	Cmd       uint32 // also be a string, for dispatch.
	PacketLen uint32
	Body      []byte
}

gd rpc packet:
type DogPacket struct {
	Header
	Body []byte
}

type Header struct {
	PacketLen uint32
	Seq       uint32
	Cmd       uint32
	CheckSum  uint32
	ErrCode   uint32
	Version   uint8
	Padding   uint8
	SOH       uint8
	EOH       uint8
}

The Packet is a interface in rpc server and client. So, you can make your protocol that suits yourself by implementing packet's methods, if you need. You add new RpcPacket according to yourself rule. DogPacket is a protocol that is used by author. Of course, the author encourages the use of DogPacket.


[service]
provides service register and discovery. Load balancing will be provided in the future. Service discovery registration based on etcd and zookeeper implementation.

register :
type DogRegister interface {
    Start() error
    Close()
    SetRootNode(node string) error
    GetRootNode() (root string)
    SetHeartBeat(heartBeat time.Duration)
    SetOffline(offline bool)
}

discovery:
type DogDiscovery interface {
    Start() error
    Close()
    Watch(key, node string) error
    WatchMulti(nodes map[string]string) error
    AddNode(key string, info service.NodeInfo)
    DelNode(key string, addr string)
    GetNodeInfo(key string) (nodesInfo []service.NodeInfo)
}

nodeInfo:
type NodeInfo interface {
	GetIp() string
	GetPort() int
	GetOffline() bool
	GetWeight() uint64
}

type DefaultNodeInfo struct {
	Ip      string `json:"ip"`
	Port    int    `json:"port"`
	Offline bool   `json:"offline"`
	Weight  uint64 `json:"weight"`
}

The DogRegister and DogDiscovery are interface, gd supports zookeeper and etcd, so you can use others. The NodeInfo is info of node.


Usage

This example simply demonstrates the use of the gd. of course, you need to make conf.json in conf Folder. The example use service discovery with etcd. So, you can install etcd in your computer. Of course, you can choose to comment out these lines of code.

server:

package main

import (
 "context"
 "github.com/gdp-org/gd"
 de "github.com/gdp-org/gd/derror"
 "github.com/gdp-org/gd/net/dhttp"
 "github.com/gdp-org/gd/net/dogrpc"
 "github.com/gdp-org/gd/runtime/inject"
 pb "github.com/gdp-org/gd/sample/helloworld"
 "github.com/gin-gonic/gin"
 "google.golang.org/grpc"
 "net/http"
)

type TestReq struct {
	Data string
}

type TestResp struct {
	Ret string
}

func HandlerHttpTest(c *gin.Context, req *TestReq) (code int, message string, err error, ret *TestResp) {
	gd.Debug("httpServerTest req:%v", req)
	
	ret = &TestResp{
		Ret: "ok!!!",
	}

	return http.StatusOK, "ok", nil, ret
}

func HandlerRpcTest(req *TestReq) (code uint32, message string, err error, ret *TestResp) {
	gd.Debug("rpc sever req:%v", req)
	
	ret = &TestResp{
		Ret: "ok!!!",
	}

	return uint32(de.RpcSuccess), "ok", nil, ret
}

type reg struct {
	handler pb.GreeterServer
}

func (r *reg) RegisterHandler(s *grpc.Server) error {
	pb.RegisterGreeterServer(s, r.handler)
	return nil
}

// server is used to implement hello world.GreeterServer.
type server struct{}

// SayHello implements hello world.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
	return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}

func Register(e *gd.Engine) {
 // http 
	inject.RegisterOrFail("httpServerInit", func(g *gin.Engine) error {
		r := g.Group("")
		r.Use(
			dhttp.GlFilter(), 
			dhttp.StatFilter(), 
			dhttp.GroupFilter(), 
			dhttp.Logger("sample"), 
		)
		
		e.HttpServer.POST(r, "test", HandlerHttpTest)
		
		if err := e.HttpServer.CheckHandle(); err != nil {
			return err
		}
		return nil
 })
	
	// Rpc 
	inject.RegisterOrFail("register", &register.EtcdRegister{})
	e.RpcServer.AddDogHandler(1024, HandlerRpcTest)
	if err := e.RpcServer.DogRpcRegister(); err != nil {
		gd.Error("DogRpcRegister occur error:%s", err)
		return
	}
	dogrpc.Use([]dogrpc.Filter{&dogrpc.GlFilter{}, &dogrpc.LogFilter{}})
	
	// grpc 
	inject.RegisterOrFail("registerHandler", &reg{handler: &server{}})
}

func main() {
	d := gd.Default()
	
	Register(d)
	
	err := d.Run()
	if err != nil {
		gd.Error("Error occurs, error = %s", err.Error())
		return
	}
}

// you can use command to test http service.
// curl -X POST http://127.0.0.1:10240/test -H "Content-Type: application/json" --data '{"Data":"test"}'
  • You can find it in "sample/service.go"
  • use control+c to stop process

rpc client:

package main

import (
	"fmt"
	"github.com/gdp-org/gd"
	"github.com/gdp-org/gd/dlog"
	"github.com/gdp-org/gd/service/discovery"
	"time"
)

func main() {
	defer dlog.Close()
	c := gd.NewRpcClient(time.Duration(500*time.Millisecond), 0)
	// discovery
	var r discovery.DogDiscovery

	r = &discovery.EtcdDiscovery{}
	if err := r.Start(); err != nil {
		dlog.Error("err:%s", err)
		return
	}

	if err := r.Watch("test", "/root/github/gd/prod/pool"); err != nil {
		dlog.Error("err:%s", err)
		return
	}
	time.Sleep(100 * time.Millisecond)

	hosts := r.GetNodeInfo("test")
	for _, v := range hosts {
		dlog.Debug("%s:%d", v.GetIp(), v.GetPort())
	}

	// you can choose one or use load balance algorithm to choose best one.
	// or put all to c.Addr
	for _, v := range hosts {
		if !v.GetOffline() {
			c.AddAddr(fmt.Sprintf("%s:%d", v.GetIp(), v.GetPort()))
		}
	}

	body := &struct {
		Data string
	}{
		Data: "How are you?",
	}

	code, rsp, err := c.DogInvoke(1024, body)
	if err != nil {
		dlog.Error("Error when sending request to server: %s", err)
	}

	// or use rpc protocol
	//rsp, err = c.Invoke(1024, body)
	//if err != nil {
	//t.Logf("Error when sending request to server: %s", err)
	//}

	dlog.Debug("code=%d,resp=%s", code, string(rsp))
}
  • It contained "sample/rpc_client.go"

net module you also use it to do something if you want to use net module only. Here's how it's used.

rpc_server show how to start rpc server

package dogrpc_test

import (
	"github.com/gdp-org/gd/net/dogrpc"
	"testing"
)

func TestRpcServer(t *testing.T) {
	var i chan struct{}
	d := dogrpc.NewRpcServer()
	d.Addr = 10241
	// Tcp
	d.AddHandler(1024, func(req []byte) (uint32, []byte) {
		t.Logf("rpc server request: %s", string(req))
		code := uint32(0)
		resp := []byte("Are you ok?")
		return code, resp
	})

	err := d.Start()
	if err != nil {
		t.Logf("Error occurs, derror = %s", err.Error())
		return
	}
	<-i
}
  • You can find it in "net/dogrpc/rpc_server_test.go"

rpc_clientshow how to call rpc server

package dogrpc_test

import (
	"github.com/gdp-org/gd"
	"github.com/gdp-org/gd/utls/network"
	"testing"
	"time"
)

func TestRpcClient(t *testing.T) {
	c := gd.NewRpcClient(time.Duration(500*time.Millisecond), 0)
	c.AddAddr(network.GetLocalIP() + ":10241")

	body := []byte("How are you?")

	code, rsp, err := c.Invoke(1024, body)
	if err != nil {
		t.Logf("Error when sending request to server: %s", err)
	}

	t.Logf("code=%d, resp=%s", code, string(rsp))
}
  • You can find it in "net/dogrpc/rpc_client_test.go"

derror module provides the relation usages of error. It supports the structs of CodeError which contains code, error type, and error msg.

package derror

type CodeError struct {
	errCode int
	errType string
	errMsg  string
}

var (
	RpcSuccess             = 0
	Success                = 200
	BadRequest             = 400
	Unauthorized           = 401
	Forbidden              = 403
	NotFound               = 404
	SystemError            = 500
	ParameterError         = 600
	DBError                = 701
	CacheError             = 702
	RpcTimeout             = 10001
	RpcOverflow            = 10002
	RpcInternalServerError = 10003
	RpcInvalidParam        = 10004
	UnknownError           = "unknown error"

	ErrMap = map[int]string{
		RpcSuccess:             "ok",
		Success:                "ok",
		BadRequest:             "bad request",
		Unauthorized:           "Unauthorized",
		Forbidden:              "Forbidden",
		NotFound:               "not found",
		SystemError:            "system error",
		ParameterError:         "Parameter error",
		DBError:                "db error",
		CacheError:             "cache error",
		RpcTimeout:             "timeout error",
		RpcOverflow:            "overflow error",
		RpcInternalServerError: "interval server error",
		RpcInvalidParam:        "invalid param",
	}
)

// get derror type. you can also add type to ErrMap.
func GetErrorType(code int) string {
	t, ok := ErrMap[code]
	if !ok {
		t = UnknownError
	}
	return t
}

service module

  • if you use etcd, you must download etcd module
  • go get go.etcd.io/etcd/client/v3
  • you can find it usage on "server/register/register_test.go" and "server/discovery/discovery.go"
package main

import (
	"github.com/gdp-org/gd/dlog"
	"github.com/gdp-org/gd/service/register"
)

func etcd(){
	var r register.DogRegister
	r = &register.EtcdRegister{}
	if err := r.Start(); err != nil {
		dlog.Error("err:%s", err)
		return
	}
}

func zk(){
	var r register.DogRegister
	r = &register.ZkRegister{}
	if err := r.Start(); err != nil {
		dlog.Error("err:%s", err)
		return
	}
}

func main(){
	defer dlog.Close()
	etcd()
}
package main

import (
	"github.com/gdp-org/gd/dlog"
	"github.com/gdp-org/gd/service/discovery"
	"time"
)

func etcdDis() {
	var r discovery.DogDiscovery

	r = &discovery.EtcdDiscovery{}
	if err := r.Start(); err != nil {
		dlog.Error("err:%s", err)
		return
	}

	r.Watch("test", "/root/github/gd/prod/pool")
	time.Sleep(100 * time.Millisecond)

	n1 := r.GetNodeInfo("test")
	for _, v := range n1 {
		dlog.Info("%s:%d", v.GetIp(), v.GetPort())
	}
}

func zkDis() {
	var r discovery.DogDiscovery
	r = &discovery.ZkDiscovery{}
	if err := r.Start(); err != nil {
		dlog.Error("err:%s", err)
		return
	}

	r.Watch("test", "/root/github/gd/prod/pool")

	time.Sleep(100 * time.Millisecond)
	n1 := r.GetNodeInfo("test")
	for _, v := range n1 {
		dlog.Info("%s:%d", v.GetIp(), v.GetPort())
	}
}

func main() {
	defer dlog.Close()
	etcdDis()
}

PS: More information can be obtained in the source code


License

gd is released under the MIT LICENSE.

gd's People

Contributors

chuck1024 avatar denggongcai avatar dependabot[bot] avatar xxianglei avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

gd's Issues

runtime helper模块提示内容与实现不匹配,导致配置无效

  • 1、runtime helper模块的提示字符,配置log级别时,提示的是输入dlog
--------------------------------------------------------------
  add           <id> <key> <sec> <min> <hour> <day> <month> <week> <year>
  del           <id> <key> <sec> <min> <hour> <day> <month> <week> <year>
  status        return status
  find          <id> <key>
  trace n               dump n second trace info to prof/trace_xxx.out
  heap <nogc>           dump current heap to prof/heap_xxx.prof
  dlog          -1:CURRENT,0:FNST,1:FINE,2:DEBG,3:TRAC,4:INFO,5:WARN,6:EROR,7:CRIT
  deploy        <file1> <file2> ;"deploy all" means deploy all accessable file
<ok

而dealCommand处理部分解析的是log,导致输入dlog时,配置失效。

  • 2、dealCommand实现中包含profile处理,helper的提示字符中不包含该项目

IsLocalIP 判断本地IP包含局域网地址

该函数检查是否为本地IP时,是否包含局域网内网地址段?

// IsLocalIP, 检查是否为本地 IP
func IsLocalIP(request *http.Request) (bool, error) {
	ip, err := GetRealIP(request)
	if err != nil {
		return false, err
	}
	if (len(ip) >= 3 && ip[0:3] == "10.") || ip == "127.0.0.1" {
		return true, nil
	}
	return false, nil

如果包含局域网地址段的话,是否应该同样包含其他两个内网的网段地址

10.0.0.0-10.255.255.255
172.16.0.0-172.31.255.255
192.168.0.0-192.168.255.255

如果不需要包含这部分地址的话,该函数的实现是不是应该删除10网段的判断,只保留127的环回地址。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.