Files
apinto/node/grpc-context/context.go
2023-02-10 20:03:00 +08:00

231 lines
5.2 KiB
Go

package grpc_context
import (
"context"
"crypto/tls"
"fmt"
"net"
"time"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/peer"
"github.com/eolinker/eosc/utils/config"
"google.golang.org/grpc"
"github.com/eolinker/eosc/eocontext"
grpc_context "github.com/eolinker/eosc/eocontext/grpc-context"
)
var _ grpc_context.IGrpcContext = (*Context)(nil)
type Context struct {
ctx context.Context
cancel context.CancelFunc
serverStream grpc.ServerStream
addr net.Addr
srv interface{}
acceptTime time.Time
requestId string
request *Request
proxy *Request
response grpc_context.IResponse
completeHandler eocontext.CompleteHandler
finishHandler eocontext.FinishHandler
app eocontext.EoApp
balance eocontext.BalanceHandler
upstreamHostHandler eocontext.UpstreamHostHandler
labels map[string]string
tls bool
insecureCertificateVerify bool
port int
finish bool
}
func (c *Context) EnableTls(b bool) {
c.tls = b
}
func (c *Context) InsecureCertificateVerify(b bool) {
c.insecureCertificateVerify = b
}
func NewContext(srv interface{}, stream grpc.ServerStream) *Context {
ctx, cancel := context.WithCancel(stream.Context())
var addr net.Addr = zeroTCPAddr
p, has := peer.FromContext(ctx)
if has {
addr = p.Addr
}
return &Context{
ctx: ctx,
cancel: cancel,
addr: addr,
srv: srv,
request: NewRequest(stream),
proxy: NewRequest(stream),
response: NewResponse(),
}
}
func (c *Context) RequestId() string {
return c.requestId
}
func (c *Context) AcceptTime() time.Time {
return c.acceptTime
}
func (c *Context) Context() context.Context {
return c.ctx
}
func (c *Context) Value(key interface{}) interface{} {
return c.ctx.Value(key)
}
func (c *Context) WithValue(key, val interface{}) {
c.ctx = context.WithValue(c.ctx, key, val)
}
func (c *Context) Scheme() string {
return "grpc"
}
func (c *Context) Assert(i interface{}) error {
if v, ok := i.(*grpc_context.IGrpcContext); ok {
*v = c
return nil
}
return fmt.Errorf("not suport:%s", config.TypeNameOf(i))
}
func (c *Context) SetLabel(name, value string) {
c.labels[name] = value
}
func (c *Context) GetLabel(name string) string {
return c.labels[name]
}
func (c *Context) Labels() map[string]string {
return c.labels
}
func (c *Context) GetComplete() eocontext.CompleteHandler {
return c.completeHandler
}
func (c *Context) SetCompleteHandler(handler eocontext.CompleteHandler) {
c.completeHandler = handler
}
func (c *Context) GetFinish() eocontext.FinishHandler {
return c.finishHandler
}
func (c *Context) SetFinish(handler eocontext.FinishHandler) {
c.finishHandler = handler
}
func (c *Context) GetApp() eocontext.EoApp {
return c.app
}
func (c *Context) SetApp(app eocontext.EoApp) {
c.app = app
}
func (c *Context) GetBalance() eocontext.BalanceHandler {
return c.balance
}
func (c *Context) SetBalance(handler eocontext.BalanceHandler) {
c.balance = handler
}
func (c *Context) GetUpstreamHostHandler() eocontext.UpstreamHostHandler {
return c.upstreamHostHandler
}
func (c *Context) SetUpstreamHostHandler(handler eocontext.UpstreamHostHandler) {
c.upstreamHostHandler = handler
}
func (c *Context) LocalIP() net.IP {
return addrToIP(c.addr)
}
func (c *Context) LocalAddr() net.Addr {
return c.addr
}
func (c *Context) LocalPort() int {
return c.port
}
func (c *Context) Request() grpc_context.IRequest {
return c.request
}
func (c *Context) Proxy() grpc_context.IRequest {
return c.proxy
}
func (c *Context) Response() grpc_context.IResponse {
return c.response
}
func (c *Context) SetResponse(response grpc_context.IResponse) {
c.response = response
}
func (c *Context) Invoke(address string, timeout time.Duration) error {
outgoingCtx, clientConn, err := c.dial(address, timeout)
if err != nil {
return err
}
go handlerStream(outgoingCtx, c.serverStream, clientConn, c.proxy.FullMethodName(), c.response)
c.finish = true
return nil
}
func (c *Context) FastFinish() {
if c.finish {
return
}
c.serverStream.SendHeader(c.response.Headers())
c.serverStream.SendMsg(c.response.Message())
c.serverStream.SetTrailer(c.response.Trailer())
}
func (c *Context) dial(address string, timeout time.Duration) (context.Context, *grpc.ClientConn, error) {
opts := make([]grpc.DialOption, 0, 3)
if !c.tls {
opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
} else {
opts = append(opts, grpc.WithTransportCredentials(
credentials.NewTLS(
&tls.Config{
InsecureSkipVerify: c.insecureCertificateVerify,
},
)))
}
authorities := c.proxy.Headers().Get(":authority")
if len(authorities) > 0 {
opts = append(opts, grpc.WithAuthority(authorities[0]))
}
opts = append(opts, grpc.WithTimeout(timeout))
conn, err := grpc.DialContext(c.ctx, address, opts...)
return metadata.NewOutgoingContext(c.Context(), c.proxy.Headers().Copy()), conn, err
}