micro--go-micro
cae6fbbe76
* fix: remove deprecated rand.Seed calls Go 1.20+ automatically seeds the global random number generator. These calls are no-ops and generate warnings with newer Go versions. Removed from: - selector/strategy.go - registry/cache/cache.go - broker/memory.go - broker/http.go - cmd/cmd.go - transport/memory.go Co-authored-by: Shelley <shelley@exe.dev> * fix: handle previously ignored errors - MySQL store: properly handle prepared statement errors in initDB() - Consul registry: handle client creation errors in Client() method These silent failures could cause hard-to-debug issues in production. Co-authored-by: Shelley <shelley@exe.dev> * feat(genai): improve provider interface with context and streaming Breaking changes: - Generate() and Stream() now require context.Context as first parameter - Stream.Close() added for proper resource cleanup Improvements: - Proper context support for cancellation and timeouts - Real SSE streaming for OpenAI and Gemini text generation - Better error handling with wrapped errors and API error responses - Thread-safe provider registry with sync.RWMutex - New options: WithMaxTokens, WithTemperature, WithTimeout - Stream has proper Close() method for cleanup - Results can include Error field for per-chunk errors Provider updates: - OpenAI: true streaming with SSE parsing, proper HTTP client with timeout - Gemini: true streaming with streamGenerateContent endpoint - Default model updated to gpt-4o-mini (OpenAI) and gemini-2.0-flash (Gemini) Co-authored-by: Shelley <shelley@exe.dev> * feat(tls): make TLS secure by default, configurable via environment BREAKING: TLS now verifies certificates by default. Set MICRO_TLS_INSECURE=true to restore previous behavior (NOT recommended for production). Changes: - Add util/tls.Config(), SecureConfig(), InsecureConfig(), ConfigFromEnv() helpers - Update all components to use ConfigFromEnv() instead of hardcoded InsecureSkipVerify - Set MinVersion to TLS 1.2 for all TLS configs Affected components: - broker/http - broker/rabbitmq - registry/etcd - registry/consul - transport/grpc This improves security posture while allowing opt-out for development environments. Co-authored-by: Shelley <shelley@exe.dev> * feat(tls): add TLS helpers with opt-in secure mode NOT a breaking change - keeps InsecureSkipVerify=true as default for local development compatibility. New util/tls helpers: - Config() - returns config based on MICRO_TLS_SECURE env var - SecureConfig() - certificate verification enabled - InsecureConfig() - certificate verification disabled (dev only) For production security, use one of: - Set MICRO_TLS_SECURE=true with proper CA-signed certs - Use a service mesh (Istio, Linkerd) for automatic mTLS - Configure TLSConfig directly with your certificates Also: Changed CLI alias from 'g' to 'gen' for clarity - micro generate handler -> micro gen handler Co-authored-by: Shelley <shelley@exe.dev> * refactor(cli): rename generate directory to gen for consistency Directory name now matches the command alias: cmd/micro/cli/gen/ -> micro gen handler Co-authored-by: Shelley <shelley@exe.dev> --------- Co-authored-by: Shelley <shelley@exe.dev>
180 行
3.6 KiB
Go
180 行
3.6 KiB
Go
// Package grpc provides a grpc transport
|
|
package grpc
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"net"
|
|
|
|
"go-micro.dev/v5/cmd"
|
|
"go-micro.dev/v5/transport"
|
|
maddr "go-micro.dev/v5/util/addr"
|
|
mnet "go-micro.dev/v5/util/net"
|
|
mtls "go-micro.dev/v5/util/tls"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/credentials"
|
|
|
|
pb "go-micro.dev/v5/transport/grpc/proto"
|
|
)
|
|
|
|
type grpcTransport struct {
|
|
opts transport.Options
|
|
}
|
|
|
|
type grpcTransportListener struct {
|
|
listener net.Listener
|
|
secure bool
|
|
tls *tls.Config
|
|
}
|
|
|
|
func init() {
|
|
cmd.DefaultTransports["grpc"] = NewTransport
|
|
}
|
|
|
|
func getTLSConfig(addr string) (*tls.Config, error) {
|
|
hosts := []string{addr}
|
|
|
|
// check if its a valid host:port
|
|
if host, _, err := net.SplitHostPort(addr); err == nil {
|
|
if len(host) == 0 {
|
|
hosts = maddr.IPs()
|
|
} else {
|
|
hosts = []string{host}
|
|
}
|
|
}
|
|
|
|
// generate a certificate
|
|
cert, err := mtls.Certificate(hosts...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &tls.Config{Certificates: []tls.Certificate{cert}}, nil
|
|
}
|
|
|
|
func (t *grpcTransportListener) Addr() string {
|
|
return t.listener.Addr().String()
|
|
}
|
|
|
|
func (t *grpcTransportListener) Close() error {
|
|
return t.listener.Close()
|
|
}
|
|
|
|
func (t *grpcTransportListener) Accept(fn func(transport.Socket)) error {
|
|
var opts []grpc.ServerOption
|
|
|
|
// setup tls if specified
|
|
if t.secure || t.tls != nil {
|
|
config := t.tls
|
|
if config == nil {
|
|
var err error
|
|
addr := t.listener.Addr().String()
|
|
config, err = getTLSConfig(addr)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
creds := credentials.NewTLS(config)
|
|
opts = append(opts, grpc.Creds(creds))
|
|
}
|
|
|
|
// new service
|
|
srv := grpc.NewServer(opts...)
|
|
|
|
// register service
|
|
pb.RegisterTransportServer(srv, µTransport{addr: t.listener.Addr().String(), fn: fn})
|
|
|
|
// start serving
|
|
return srv.Serve(t.listener)
|
|
}
|
|
|
|
func (t *grpcTransport) Dial(addr string, opts ...transport.DialOption) (transport.Client, error) {
|
|
dopts := transport.DialOptions{
|
|
Timeout: transport.DefaultDialTimeout,
|
|
}
|
|
|
|
for _, opt := range opts {
|
|
opt(&dopts)
|
|
}
|
|
|
|
options := []grpc.DialOption{
|
|
grpc.WithTimeout(dopts.Timeout),
|
|
}
|
|
|
|
if t.opts.Secure || t.opts.TLSConfig != nil {
|
|
config := t.opts.TLSConfig
|
|
if config == nil {
|
|
// Use environment-based config - secure by default
|
|
config = mtls.Config()
|
|
}
|
|
creds := credentials.NewTLS(config)
|
|
options = append(options, grpc.WithTransportCredentials(creds))
|
|
} else {
|
|
options = append(options, grpc.WithInsecure())
|
|
}
|
|
|
|
// dial the server
|
|
conn, err := grpc.Dial(addr, options...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// create stream
|
|
stream, err := pb.NewTransportClient(conn).Stream(context.Background())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// return a client
|
|
return &grpcTransportClient{
|
|
conn: conn,
|
|
stream: stream,
|
|
local: "localhost",
|
|
remote: addr,
|
|
}, nil
|
|
}
|
|
|
|
func (t *grpcTransport) Listen(addr string, opts ...transport.ListenOption) (transport.Listener, error) {
|
|
var options transport.ListenOptions
|
|
for _, o := range opts {
|
|
o(&options)
|
|
}
|
|
|
|
ln, err := mnet.Listen(addr, func(addr string) (net.Listener, error) {
|
|
return net.Listen("tcp", addr)
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &grpcTransportListener{
|
|
listener: ln,
|
|
tls: t.opts.TLSConfig,
|
|
secure: t.opts.Secure,
|
|
}, nil
|
|
}
|
|
|
|
func (t *grpcTransport) Init(opts ...transport.Option) error {
|
|
for _, o := range opts {
|
|
o(&t.opts)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (t *grpcTransport) Options() transport.Options {
|
|
return t.opts
|
|
}
|
|
|
|
func (t *grpcTransport) String() string {
|
|
return "grpc"
|
|
}
|
|
|
|
func NewTransport(opts ...transport.Option) transport.Transport {
|
|
var options transport.Options
|
|
for _, o := range opts {
|
|
o(&options)
|
|
}
|
|
return &grpcTransport{opts: options}
|
|
}
|