protoutil

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 3, 2026 License: MIT Imports: 7 Imported by: 0

Documentation

Overview

Package protoutil provides helpers for working with Temporal's protobuf request types at the gRPC boundary, without the caller needing to know the concrete message type for a given method.

Extractor reads the namespace from an encoded request by resolving its message type from a descriptor registry and a type registry.

Translator rewrites namespace names inside decoded messages, driven by a direction function, using a per-message-type plan cache that WarmService pre-populates. The package is free of any gRPC dependency; callers apply a Translator on a connection themselves.

Module wires both an Extractor and a Translator into an fx application, defaulting the descriptor and type registries to google.golang.org/protobuf/reflect/protoregistry.GlobalFiles and google.golang.org/protobuf/reflect/protoregistry.GlobalTypes when they are not supplied, and warming the translator for the services the application lists in ExtractorParams.TranslatorServices.

Index

Constants

This section is empty.

Variables

View Source
var Module = fx.Options(
	fx.Provide(
		func(p ExtractorParams) *Translator {
			return NewTranslator(filesOrGlobal(p.Files))
		},
		func(p ExtractorParams) *Extractor {
			return NewExtractor(filesOrGlobal(p.Files), typesOrGlobal(p.Types))
		},
	),
	fx.Invoke(func(t *Translator, p ExtractorParams) error {
		for _, svc := range p.TranslatorServices {
			if err := t.WarmService(svc); err != nil {
				return fmt.Errorf("failed to set up translations for %s: %w", svc, err)
			}
		}

		return nil
	}),
)

Module provides an *Extractor and a *Translator, and warms the translator's plan cache for every service in TranslatorServices at startup. Files and Types default to the global protobuf registries when the application supplies neither. TranslatorServices is optional: when empty, no plans are pre-populated and the translator builds them lazily on first use.

Functions

This section is empty.

Types

type Extractor

type Extractor struct {
	// contains filtered or unexported fields
}

Extractor reads the namespace from an encoded gRPC request. It resolves the concrete request message type for a full method name from the descriptor and type registries it was given, decodes the payload into it, and reads the namespace via the generated accessor. Resolved types are cached per method, so repeat calls for the same method skip the lookup. Construct one with NewExtractor; an Extractor is safe for concurrent use.

func NewExtractor

func NewExtractor(files Files, types Types) *Extractor

NewExtractor returns an Extractor that resolves request types using files and types. Production callers pass protoregistry.GlobalFiles and protoregistry.GlobalTypes; tests may pass fakes. Resolution only succeeds for message types registered in the given registries, so the relevant service packages (e.g. go.temporal.io/api/workflowservice/v1) must be imported into the binary.

func (*Extractor) Namespace

func (e *Extractor) Namespace(fullMethod string, payload []byte) string

Namespace returns the namespace carried by an encoded request for fullMethod, or the empty string when the method is unknown, the request type carries no namespace, or the payload cannot be decoded.

type ExtractorParams

type ExtractorParams struct {
	fx.In

	Files              Files                   `optional:"true"`
	Types              Types                   `optional:"true"`
	TranslatorServices []protoreflect.FullName `optional:"true"`
}

ExtractorParams collects the dependencies used to build the *Extractor and the Translator. Files and Types are optional: when absent, Module falls back to the global protobuf registries. TranslatorServices is optional and lists the gRPC services whose request and response types are pre-warmed at startup.

type Files

type Files interface {
	FindDescriptorByName(protoreflect.FullName) (protoreflect.Descriptor, error)
}

Files resolves a descriptor by its fully qualified name. *protoregistry.Files, and in particular protoregistry.GlobalFiles, implements it.

type Translator

type Translator struct {
	// contains filtered or unexported fields
}

Translator rewrites namespace names inside decoded protobuf messages. It caches a translation plan per message type, so repeat translations of the same type skip descriptor traversal. Plans may be pre-populated with WarmService or built lazily on first use. A Translator is safe for concurrent use.

func NewTranslator

func NewTranslator(files Files) *Translator

NewTranslator returns a Translator that resolves service descriptors for warming through files. Production callers pass protoregistry.GlobalFiles.

func (*Translator) IsWarm

func (t *Translator) IsWarm(name protoreflect.FullName) bool

IsWarm reports whether a plan for the named message type is already cached.

func (*Translator) Translate

func (t *Translator) Translate(m proto.Message, fn func(string) string)

Translate rewrites every namespace name in m using fn. It is a no-op when m is nil, invalid, or carries no namespace field. fn maps a namespace name to its translated form (local to remote, or remote to local).

func (*Translator) WarmService

func (t *Translator) WarmService(name protoreflect.FullName) error

WarmService pre-computes and caches the plan for every method input and output type of the named gRPC service, so no request pays first-touch plan construction. It fails when the name does not resolve to a service.

type Types

type Types interface {
	FindMessageByName(protoreflect.FullName) (protoreflect.MessageType, error)
}

Types resolves a message type by its fully qualified name. *protoregistry.Types, and in particular protoregistry.GlobalTypes, implements it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL