Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

View File

@@ -0,0 +1,49 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_binary",
)
go_library(
name = "go_default_library",
srcs = [
"grpc.go",
"http.go",
"main.go",
],
importpath = "go-common/app/tool/grpc-http-proxy",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/naming/discovery:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/time:go_default_library",
"@com_github_gogo_protobuf//jsonpb:go_default_library",
"@org_golang_google_grpc//:go_default_library",
"@org_golang_google_grpc//encoding:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_binary(
name = "grpc-http-proxy",
embed = [":go_default_library"],
tags = ["automanaged"],
)

View File

@@ -0,0 +1,6 @@
#### grpc http proxy
##### Version 1.0.1
1. 增加说明
##### Version 1.0.0
1. 初始化项目

View File

@@ -0,0 +1,8 @@
# Owner
wangxu01
# Author
wangxu01
# Reviewer
wangxu01

View File

@@ -0,0 +1,10 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- wangxu01
labels:
- tool
options:
no_parent_owners: true
reviewers:
- wangxu01

View File

@@ -0,0 +1,23 @@
#### grpc http proxy
##### 项目简介
由于命令行调试工具需要手动输入json 字符串 调试不太方便 有些场景下用http调试工具(paw/postman) 更方便 也更符合大家的习惯 于是就有了这个工具
功能:
* 支持节点IP直连
* 支持discovery
* 支持params参数
* 支持json body
* 优化params错误时的提示
* 优化discovery错误时的提示
* 优化path错误时的提示
* 支持params数组
* 支持枚举
##### 使用方式:
[文档](http://info.bilibili.co/pages/viewpage.action?pageId=12877366)

View File

@@ -0,0 +1,110 @@
package main
import (
"context"
"fmt"
"strings"
"time"
"go-common/library/log"
"go-common/library/naming/discovery"
"github.com/gogo/protobuf/jsonpb"
"google.golang.org/grpc"
"google.golang.org/grpc/encoding"
)
// Reply .
type Reply struct {
res []byte
}
// Reference https://jbrandhorst.com/post/grpc-json/
func init() {
encoding.RegisterCodec(JSON{
Marshaler: jsonpb.Marshaler{
EmitDefaults: true,
OrigName: true,
},
})
}
func ipFromDiscovery(appid string) (ip string, err error) {
d := discovery.New(nil)
defer d.Close()
b := d.Build(appid)
defer b.Close()
ch := b.Watch()
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*100)
defer cancel()
select {
case <-ch:
case <-ctx.Done():
err = fmt.Errorf("查找节点超时 请检查appid是否填写正确")
return
}
ins, ok := b.Fetch(context.Background())
if !ok {
err = fmt.Errorf("discovery 拉取:%s 失败", appid)
return
}
for _, vs := range ins {
for _, v := range vs {
for _, addr := range v.Addrs {
if strings.Contains(addr, "grpc://") {
ip = strings.Replace(addr, "grpc://", "", -1)
return
}
}
}
}
err = fmt.Errorf("discovery 找不到服务节点:%s", appid)
return
}
func callGrpc(addr, method string, body []byte) (res []byte, err error) {
opts := []grpc.DialOption{
grpc.WithInsecure(),
grpc.WithDefaultCallOptions(grpc.CallContentSubtype(JSON{}.Name())),
}
var conn *grpc.ClientConn
if !strings.Contains(addr, ":") {
addr, err = ipFromDiscovery(addr)
}
if err != nil {
return
}
conn, err = grpc.Dial(addr, opts...)
if err != nil {
return
}
var reply Reply
log.Info("callrpc method: %s body: %s", method, body)
if err = conn.Invoke(context.Background(), method, body, &reply); err != nil {
return
}
res = reply.res
return
}
// JSON is impl of encoding.Codec
type JSON struct {
jsonpb.Marshaler
jsonpb.Unmarshaler
}
// Name is name of JSON
func (j JSON) Name() string {
return "json"
}
// Marshal is json marshal
func (j JSON) Marshal(v interface{}) (out []byte, err error) {
return v.([]byte), nil
}
// Unmarshal is json unmarshal
func (j JSON) Unmarshal(data []byte, v interface{}) (err error) {
v.(*Reply).res = data
return nil
}

View File

@@ -0,0 +1,74 @@
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strings"
"go-common/library/ecode"
bm "go-common/library/net/http/blademaster"
)
var jsonFormat = "application/json; charset=utf-8"
func splitURL(url string) (addr, path string, err error) {
arrs := strings.Split(url, "/")
if len(arrs) < 3 {
err = ecode.RequestErr
return
}
addr = arrs[1]
path = fmt.Sprintf("/%s", strings.Join(arrs[2:], "/"))
return
}
func formatRequest(req url.Values) (res map[string]interface{}) {
res = map[string]interface{}{}
for k, v := range req {
value := v[0]
res[k] = value
// 支持数组
if len(value) > 2 && value[0] == '[' && value[len(value)-1] == ']' {
value = value[1 : len(value)-1]
res[k] = strings.Split(value, ",")
}
}
return
}
func handle(c *bm.Context) {
addr, path, err := splitURL(c.Request.URL.Path)
if err != nil {
c.JSON(nil, ecode.RequestErr)
return
}
var body []byte
body, _ = ioutil.ReadAll(c.Request.Body)
if len(body) == 0 || string(body) == "{}" {
data := formatRequest(c.Request.Form)
body, err = json.Marshal(data)
if err != nil {
c.JSONMap(map[string]interface{}{"message": err.Error()}, err)
return
}
}
resp, err := callGrpc(addr, path, body)
if err != nil {
var intro string
if strings.Contains(err.Error(), "error unmarshalling request") {
intro = "由于params都是string没有类型信息 如果含有int/int32等类型 请复制\"请求数据\"到body中 并修改请求的字段类型, 注意Content-Type 不能为 multipart/form-data 不然body无效 还有问题@wangxu01"
}
c.JSONMap(map[string]interface{}{
"错误": err.Error(),
"请求目标": addr,
"请求方法": path,
"请求数据": string(body),
"额外说明": intro,
}, err)
return
}
c.Bytes(http.StatusOK, jsonFormat, resp)
}

View File

@@ -0,0 +1,42 @@
package main
import (
"flag"
"os"
"os/signal"
"syscall"
"time"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
xtime "go-common/library/time"
)
var bind = flag.String("bind", "localhost:10010", "bind addr example: localhost:10010")
func main() {
flag.Parse()
engineOuter := bm.DefaultServer(&bm.ServerConfig{
Addr: *bind,
Timeout: xtime.Duration(time.Second),
})
// bm不支持 get post 绑定一个路径 为了获取body只能用post
engineOuter.POST("/", handle)
if err := engineOuter.Start(); err != nil {
log.Error("engine.Start error(%v)", err)
panic(err)
}
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGHUP, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT)
for {
s := <-c
log.Info("get a signal %s", s.String())
switch s {
case syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGINT:
log.Info("exit")
return
default:
return
}
}
}