mirror of
https://github.com/gusaul/grpcox.git
synced 2024-11-17 06:26:56 +00:00
161 lines
3.7 KiB
Go
161 lines
3.7 KiB
Go
package core
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/fullstorydev/grpcurl"
|
|
"github.com/jhump/protoreflect/grpcreflect"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/credentials"
|
|
"google.golang.org/grpc/keepalive"
|
|
"google.golang.org/grpc/metadata"
|
|
reflectpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha"
|
|
)
|
|
|
|
// GrpCox - main object
|
|
type GrpCox struct {
|
|
KeepAlive float64
|
|
|
|
activeConn *ConnStore
|
|
maxLifeConn time.Duration
|
|
|
|
// TODO : utilize below args
|
|
headers []string
|
|
reflectHeaders []string
|
|
authority string
|
|
insecure bool
|
|
cacert string
|
|
cert string
|
|
key string
|
|
serverName string
|
|
isUnixSocket func() bool
|
|
}
|
|
|
|
// InitGrpCox constructor
|
|
func InitGrpCox() *GrpCox {
|
|
maxLife, tick := 10, 3
|
|
|
|
if val, err := strconv.Atoi(os.Getenv("MAX_LIFE_CONN")); err == nil {
|
|
maxLife = val
|
|
}
|
|
|
|
if val, err := strconv.Atoi(os.Getenv("TICK_CLOSE_CONN")); err == nil {
|
|
tick = val
|
|
}
|
|
|
|
c := NewConnectionStore()
|
|
g := &GrpCox{
|
|
activeConn: c,
|
|
}
|
|
|
|
if maxLife > 0 && tick > 0 {
|
|
g.maxLifeConn = time.Duration(maxLife) * time.Minute
|
|
c.StartGC(time.Duration(tick) * time.Second)
|
|
}
|
|
|
|
return g
|
|
}
|
|
|
|
// GetResource - open resource to targeted grpc server
|
|
func (g *GrpCox) GetResource(ctx context.Context, target string, plainText, isRestartConn bool) (*Resource, error) {
|
|
if conn, ok := g.activeConn.getConnection(target); ok {
|
|
if !isRestartConn && conn.isValid() {
|
|
return conn, nil
|
|
}
|
|
g.CloseActiveConns(target)
|
|
}
|
|
|
|
var err error
|
|
r := new(Resource)
|
|
h := append(g.headers, g.reflectHeaders...)
|
|
md := grpcurl.MetadataFromHeaders(h)
|
|
refCtx := metadata.NewOutgoingContext(ctx, md)
|
|
r.clientConn, err = g.dial(ctx, target, plainText)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
r.refClient = grpcreflect.NewClient(refCtx, reflectpb.NewServerReflectionClient(r.clientConn))
|
|
r.descSource = grpcurl.DescriptorSourceFromServer(ctx, r.refClient)
|
|
r.headers = h
|
|
|
|
g.activeConn.addConnection(target, r, g.maxLifeConn)
|
|
return r, nil
|
|
}
|
|
|
|
// GetActiveConns - get all saved active connection
|
|
func (g *GrpCox) GetActiveConns(ctx context.Context) []string {
|
|
active := g.activeConn.getAllConn()
|
|
result := make([]string, len(active))
|
|
i := 0
|
|
for k := range active {
|
|
result[i] = k
|
|
i++
|
|
}
|
|
return result
|
|
}
|
|
|
|
// CloseActiveConns - close conn by host or all
|
|
func (g *GrpCox) CloseActiveConns(host string) error {
|
|
if host == "all" {
|
|
for k := range g.activeConn.getAllConn() {
|
|
g.activeConn.delete(k)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
g.activeConn.delete(host)
|
|
return nil
|
|
}
|
|
|
|
// Extend extend connection based on setting max life
|
|
func (g *GrpCox) Extend(host string) {
|
|
g.activeConn.extend(host, g.maxLifeConn)
|
|
}
|
|
|
|
func (g *GrpCox) dial(ctx context.Context, target string, plainText bool) (*grpc.ClientConn, error) {
|
|
dialTime := 10 * time.Second
|
|
ctx, cancel := context.WithTimeout(ctx, dialTime)
|
|
defer cancel()
|
|
var opts []grpc.DialOption
|
|
|
|
// keep alive
|
|
if g.KeepAlive > 0 {
|
|
timeout := time.Duration(g.KeepAlive * float64(time.Second))
|
|
opts = append(opts, grpc.WithKeepaliveParams(keepalive.ClientParameters{
|
|
Time: timeout,
|
|
Timeout: timeout,
|
|
}))
|
|
}
|
|
|
|
if g.authority != "" {
|
|
opts = append(opts, grpc.WithAuthority(g.authority))
|
|
}
|
|
|
|
var creds credentials.TransportCredentials
|
|
if !plainText {
|
|
var err error
|
|
creds, err = grpcurl.ClientTransportCredentials(g.insecure, g.cacert, g.cert, g.key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if g.serverName != "" {
|
|
if err := creds.OverrideServerName(g.serverName); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
}
|
|
network := "tcp"
|
|
if g.isUnixSocket != nil && g.isUnixSocket() {
|
|
network = "unix"
|
|
}
|
|
cc, err := grpcurl.BlockingDial(ctx, network, target, creds, opts...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return cc, nil
|
|
}
|