webproxy

package
v0.6.8 Latest Latest
Warning

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

Go to latest
Published: Sep 30, 2026 License: Apache-2.0 Imports: 34 Imported by: 0

Documentation

Overview

Package webproxy implements Telegram WEB proxy capabilities, shared frames, serialized HTTPS sessions, and fixed-backend stream relaying.

Index

Constants

View Source
const (
	FrameHeaderSize     = 8
	MaxFramePayload     = 1024 * 1024
	MaxBatchFrames      = 4096
	MaxStreamID         = 0xFFFFFF
	InitialStreamWindow = 4 * 1024 * 1024
	RelayDataChunk      = 64 * 1024
)
View Source
const (

	// FallbackClassificationHeader marks which exact Nginx fallback contract
	// applies to an internal sentinel response.
	FallbackClassificationHeader = "X-Telego-Fallback"
	FallbackOrdinarySite         = "ordinary-site-v1"
	FallbackSanitizedPublic      = "sanitized-public-v1"

	// NginxPassthroughFallback is the exact Phase 5 contract for ordinary site
	// traffic. The named location must preserve the original method, complete
	// request URI (including args), body, Cookie, and all site request headers.
	NginxPassthroughFallback = "" /* 475-byte string literal not displayed */

	// NginxSanitizedFallback is the exact Phase 5 contract for carrier-shaped
	// traffic that did not authenticate. The named location must force GET; use
	// $uri (never $request_uri) so args are empty; disable the request body; and
	// clear every listed carrier credential/header before proxying.
	NginxSanitizedFallback = "" /* 447-byte string literal not displayed */
)
View Source
const PermissionsPolicy = "" /* 408-byte string literal not displayed */

PermissionsPolicy disables browser features that the HTTPS bridge does not use. It is intentionally exported so an integrating TLS terminator can test that it preserves the header unchanged.

Variables

View Source
var (
	// ErrInvalidHostname reports a hostname that is not the canonical lowercase
	// ASCII/IDNA form required by the WEB proxy protocol.
	ErrInvalidHostname = errors.New("invalid WEB proxy hostname")
	// ErrInvalidSecret reports a secret that is neither a 16-byte base secret nor
	// the same secret with the WEB-compatible dd prefix.
	ErrInvalidSecret = errors.New("invalid WEB proxy secret")
	// ErrInvalidCapability reports a non-canonical bridge capability string.
	ErrInvalidCapability = errors.New("invalid WEB proxy capability")
)
View Source
var (
	ErrEmptyFrameBatch = errors.New("empty WEB frame batch")
	ErrIncompleteFrame = errors.New("incomplete WEB frame")
	ErrTooManyFrames   = errors.New("WEB frame batch contains too many frames")
	ErrPayloadTooLarge = errors.New("WEB frame payload exceeds limit")
	ErrInvalidFrame    = errors.New("invalid WEB frame")
)
View Source
var (
	ErrInvalidHTTPServerConfig = errors.New("invalid WEB HTTP server configuration")
	ErrHTTPServerStarted       = errors.New("WEB HTTP server already started")
)
View Source
var (
	ErrAuthentication = errors.New("WEB authentication failed")
	ErrBackpressure   = errors.New("WEB temporary backpressure")
	ErrLimit          = errors.New("WEB resource limit reached")
	ErrProtocol       = errors.New("WEB protocol error")
	ErrClosed         = errors.New("WEB session closed")
)
View Source
var ErrInvalidManagerConfig = errors.New("invalid WEB session manager configuration")

Functions

func AppendFrame

func AppendFrame(dst []byte, frame Frame) ([]byte, error)

AppendFrame appends one shape-valid frame to dst.

func EncodeFrame

func EncodeFrame(frame Frame) ([]byte, error)

EncodeFrame encodes one shape-valid frame.

func ParseHello

func ParseHello(input []byte) error

ParseHello accepts exactly one v1 HELLO frame and no other bytes.

func ValidateBasePath added in v0.6.8

func ValidateBasePath(basePath string) error

ValidateBasePath rejects aliases instead of normalizing a credential scope.

func ValidateClientFrame

func ValidateClientFrame(frame Frame) error

ValidateClientFrame validates a normal authenticated uplink frame. HELLO is excluded because it is valid only as the standalone session-creation body accepted by ParseHello.

func ValidateFrame

func ValidateFrame(frame Frame, direction Direction) error

ValidateFrame checks both the frame's exact shape and whether its type is valid in the supplied direction.

func ValidateHostname

func ValidateHostname(hostname string) error

ValidateHostname requires the already-canonical hostname spelling used in capability derivation. It deliberately does not trim, lowercase, or convert Unicode input because doing so would silently derive a different URL than the configured value.

func ValidateLocalBackend added in v0.6.1

func ValidateLocalBackend(address string) error

ValidateLocalBackend checks an explicit numeric loopback TCP or Unix target.

func WindowDelta

func WindowDelta(payload []byte) (uint32, error)

WindowDelta decodes a nonzero WINDOW credit delta.

func WindowPayload

func WindowPayload(delta uint32) ([]byte, error)

WindowPayload encodes a nonzero WINDOW credit delta.

Types

type Backend added in v0.6.1

type Backend interface {
	TryWrite([]byte) (int, error)
	TryRead([]byte) (int, error)
	Close() error
}

Backend is a bounded nonblocking stream. TryRead and TryWrite run on the owner supplied to the factory; zero with no error means temporary pressure. Close may be called from another goroutine and completes through OnClosed.

type BackendBudget added in v0.6.1

type BackendBudget struct {
	Reserve func(bytes, items int) bool
	Release func(bytes, items int)
}

BackendBudget accounts retained capacity and queue metadata. Callbacks are concurrency-safe and must never run while the caller holds a session lock.

type BackendDialContextFunc

type BackendDialContextFunc func(ctx context.Context, network, address, clientIP string) (net.Conn, error)

BackendDialContextFunc opens one WEB backend stream with its validated client IP. Integrations use this seam to prepend a trusted internal PROXY header.

type BackendFactory added in v0.6.1

type BackendFactory func(BackendOpenOptions) (Backend, error)

func GnetBackendFactory added in v0.6.1

func GnetBackendFactory(dial BackendDialContextFunc) BackendFactory

GnetBackendFactory keeps explicit TCP/Unix backend overrides on the WEB stream owner. The supplied dialer runs only during bounded establishment; enrolled sockets never have blocking relay readers or writers.

type BackendOpenOptions added in v0.6.1

type BackendOpenOptions struct {
	Context                       context.Context
	Owner                         gnet.EventLoop
	ClientIP                      string
	Network, Address              string
	MaxInputBytes, MaxOutputBytes int
	MaxInputItems, MaxOutputItems int
	InputBudget, OutputBudget     BackendBudget
	Notify                        func()
	OnOpened                      func(error)
	OnClosed                      func(error)
}

BackendOpenOptions gives each stream a stable owner and bounded queues. Notify schedules further work; OnOpened and OnClosed each run exactly once. OnClosed runs after owner cleanup and every budget release has completed.

type BootstrapAuthorization

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

BootstrapAuthorization is an opaque, short-lived proof that a bootstrap bearer authenticated before its request body was read. Create revalidates the bootstrap under the manager lock, including expiry and prior idempotent use.

func (*BootstrapAuthorization) Create

func (a *BootstrapAuthorization) Create(clientIP string, body []byte) (CreateResult, error)

Create parses HELLO only after bootstrap authentication, then atomically creates or retries the session.

func (*BootstrapAuthorization) GoString

func (*BootstrapAuthorization) GoString() string

func (*BootstrapAuthorization) String

func (*BootstrapAuthorization) String() string

type BridgeFailure added in v0.6.6

type BridgeFailure struct {
	BridgeID      uint64      `json:"-"`
	Suppressed    uint64      `json:"-"`
	User          string      `json:"-"`
	Carrier       CarrierMode `json:"-"`
	Delivery      string      `json:"-"`
	Reason        string      `json:"reason"`
	Error         string      `json:"error"`
	LaneID        uint32      `json:"lane_id"`
	CloseCode     uint16      `json:"close_code"`
	ReadyState    uint8       `json:"ready_state"`
	HTTPStatus    uint16      `json:"http_status"`
	ElapsedMS     uint64      `json:"elapsed_ms"`
	OperationMS   uint64      `json:"operation_ms"`
	QueuedBytes   uint64      `json:"queued_bytes"`
	QueuedItems   uint32      `json:"queued_items"`
	BufferedBytes uint64      `json:"buffered_bytes"`
	WasClean      bool        `json:"was_clean,omitzero"`
}

BridgeFailure contains client-reported diagnostics, never exception text, URLs, credentials, frame contents, or WebSocket close reason strings.

func (BridgeFailure) IsLaneClosure added in v0.6.6

func (f BridgeFailure) IsLaneClosure() bool

type BridgePage

type BridgePage struct {
	Body  []byte
	Nonce string
	CSP   string
}

BridgePage is one self-contained, per-request HTTPS carrier document.

func RenderBridge

func RenderBridge(hostname, bootstrapToken string, batchBytes int) (BridgePage, error)

RenderBridge constructs the backward-compatible serialized HTTPS bridge.

func RenderBridgeForCarrier added in v0.5.2

func RenderBridgeForCarrier(
	hostname string,
	bootstrapToken string,
	batchBytes int,
	carrier CarrierMode,
) (BridgePage, error)

RenderBridgeForCarrier constructs one WEB bridge for the selected carrier. The bootstrap token exists only in this no-store response, never in a URL.

type Capability

type Capability [sha256.Size]byte

Capability is the binary HMAC-SHA256 bridge capability.

func DeriveCapability

func DeriveCapability(hostname string, secret []byte) (Capability, error)

DeriveCapability derives a bridge capability from a canonical hostname and a decoded 16-byte plain or 17-byte dd-prefixed secret.

func DeriveCapabilityForPath added in v0.6.8

func DeriveCapabilityForPath(hostname, basePath string, secret []byte) (Capability, error)

DeriveCapabilityForPath uses v1 at the root and v2 for a nonempty base path.

func ParseCapability

func ParseCapability(value string) (Capability, error)

ParseCapability decodes one canonical 43-character unpadded base64url capability.

func (Capability) Equal

func (c Capability) Equal(other Capability) bool

Equal compares two capabilities in constant time.

func (Capability) String

func (c Capability) String() string

String returns the canonical unpadded base64url representation.

type Capacity

type Capacity struct {
	Bootstraps   int
	Sessions     int
	ClosedTokens int
	Streams      int
	BackendDials int
	PendingBytes int64
	PendingItems int64
}

Capacity is a point-in-time view of the manager's bounded resources.

type CarrierMode added in v0.5.2

type CarrierMode string

CarrierMode selects the HTTP transport for one WEB relay session.

const (
	CarrierHTTPS          CarrierMode = "https"
	CarrierHTTPSLanes     CarrierMode = "https-lanes"
	CarrierWebSocket      CarrierMode = "websocket"
	CarrierWebSocketLanes CarrierMode = "websocket-lanes"
)

func ParseCarrierMode added in v0.5.2

func ParseCarrierMode(value string) (CarrierMode, error)

ParseCarrierMode returns a supported carrier mode. An empty value preserves the serialized HTTPS mode used before carrier selection was configurable.

type CreateResult

type CreateResult struct {
	Token   string
	Welcome []byte
	Session *Session
}

CreateResult is the idempotent HELLO/WELCOME session exchange.

type DialContextFunc

type DialContextFunc func(ctx context.Context, network, address string) (net.Conn, error)

DialContextFunc opens the fixed backend connection for one WEB stream.

type Direction

type Direction uint8

Direction identifies the sender of a shared frame.

const (
	ClientToRelay Direction = iota
	RelayToClient
)

type Frame

type Frame struct {
	Type     FrameType
	StreamID uint32
	Payload  []byte
}

Frame is one complete WEB shared frame. Payload returned by ParseBatch aliases the input buffer and must not outlive or mutate independently from it.

func ParseBatch

func ParseBatch(input []byte) ([]Frame, error)

ParseBatch parses and shape-validates one nonempty frame batch. Payload slices in the result alias input.

type FrameType

type FrameType uint8

FrameType identifies a WEB shared-frame message.

const (
	FrameOpen    FrameType = 0x01
	FrameData    FrameType = 0x02
	FrameClose   FrameType = 0x03
	FrameWindow  FrameType = 0x04
	FramePing    FrameType = 0x05
	FramePong    FrameType = 0x06
	FrameHello   FrameType = 0x10
	FrameWelcome FrameType = 0x11
	FrameBye     FrameType = 0x1f
)

type HTTPServer

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

HTTPServer is an independent gnet engine for HTTPS WEB carriers. Constructing it has no listener or process-global side effects.

func NewHTTPServer

func NewHTTPServer(config HTTPServerConfig) (*HTTPServer, error)

NewHTTPServer validates a WEB HTTP engine without starting it.

func (*HTTPServer) Errors

func (s *HTTPServer) Errors() <-chan error

Errors reports an unexpected gnet exit and then closes. A normal Stop closes the channel without sending a value.

func (*HTTPServer) Start

func (s *HTTPServer) Start(ctx context.Context) error

Start launches the independent gnet engine and waits until its listener is accepting or startup fails.

func (*HTTPServer) Stop

func (s *HTTPServer) Stop(ctx context.Context) error

Stop stops admission, closes carrier connections, and waits for the gnet engine. Manager shutdown remains the caller's responsibility.

type HTTPServerConfig

type HTTPServerConfig struct {
	// OnBridgeFailure receives one failure plus bounded lane-close reports per bridge.
	OnBridgeFailure         func(BridgeFailure)
	OnWebSocketClose        func(WebSocketClose)
	Bind                    string
	Hostname                string
	BasePath                string
	Manager                 *Manager
	PassthroughStatus       int
	SanitizedFallbackStatus int
	Multicore               bool
	ReusePort               bool
	LockOSThread            bool
	NumEventLoop            int
	SocketSendBuffer        int
	HeaderTimeout           time.Duration
	BodyTimeout             time.Duration
	IdleTimeout             time.Duration
	WriteTimeout            time.Duration
	TrustedProxyCIDRs       []string
	// contains filtered or unexported fields
}

HTTPServerConfig configures the private HTTP/1.1 origin placed behind the deployment's TLS-terminating Nginx. It does not alter the public MTProxy gnet engine or own Manager shutdown.

type Limits

type Limits struct {
	CarrierBatchBytes         int
	MaxBodyBytes              int
	MaxStreamsPerSession      int
	MaxClosedStreamIDs        int
	MaxPendingPerSession      int
	MaxPendingGlobal          int
	MaxPendingItemsPerSession int
	MaxPendingItemsGlobal     int
	MaxBootstraps             int
	MaxSessions               int
	MaxClosedTokens           int
	MaxStreams                int
	MaxBackendDialsInFlight   int
}

Limits bounds every resource owned by the serialized HTTPS session manager. Start with DefaultLimits and change only values that an operator needs to tune.

func DefaultLimits

func DefaultLimits() Limits

DefaultLimits returns the protocol reference defaults for serialized HTTPS.

type Manager

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

Manager owns WEB bootstrap tokens, authenticated sessions, and process-wide stream and queue budgets.

func NewManager

func NewManager(config ManagerConfig) (*Manager, error)

NewManager validates and copies config before starting its expiry worker.

func (*Manager) AuthenticateBootstrap

func (m *Manager) AuthenticateBootstrap(token string) (*BootstrapAuthorization, error)

AuthenticateBootstrap authenticates a canonical bootstrap bearer without reading or parsing a request body. Unknown and malformed bearers return the same authentication error.

func (*Manager) Capacity

func (m *Manager) Capacity() Capacity

Capacity returns resource accounting without exposing session tokens.

func (*Manager) CarrierMode added in v0.5.2

func (m *Manager) CarrierMode() CarrierMode

CarrierMode returns the transport used for newly created sessions.

func (*Manager) Close

func (m *Manager) Close(token string) error

Close terminates the authenticated session. A recently closed valid token is idempotent; an unknown token remains indistinguishable from bad authentication.

func (*Manager) Create

func (m *Manager) Create(token, clientIP string, body []byte) (CreateResult, error)

Create atomically consumes a bootstrap for one exact HELLO body. Retrying the same token and identical body returns the original token and Session pointer. Authentication always completes before body parsing.

func (*Manager) Get

func (m *Manager) Get(token string) (*Session, error)

Get authenticates a canonical session bearer.

func (*Manager) IssueBootstrap

func (m *Manager) IssueBootstrap(capability Capability, clientIP string) (string, error)

IssueBootstrap authenticates a profile capability and issues a canonical two-minute bootstrap bearer.

func (*Manager) MatchCapability

func (m *Manager) MatchCapability(capability Capability) (Profile, bool)

MatchCapability scans the complete profile set and never returns manager-owned profile storage.

func (*Manager) RuntimeStats added in v0.5.2

func (m *Manager) RuntimeStats() RuntimeStats

RuntimeStats returns WEB diagnostics without bearer or client identifiers.

func (*Manager) Shutdown

func (m *Manager) Shutdown(ctx context.Context) error

Shutdown stops admission, closes all sessions, and waits for backend workers and the cleanup worker. The wait may be bounded by ctx.

type ManagerConfig

type ManagerConfig struct {
	// DebugDiagnostics enables bounded reconnect diagnostics. Disabled by default.
	DebugDiagnostics   bool
	Profiles           []Profile
	Backend            string
	Carrier            CarrierMode
	Limits             Limits
	Timeouts           Timeouts
	DialContext        DialContextFunc
	BackendDialContext BackendDialContextFunc
	BackendFactory     BackendFactory
}

ManagerConfig supplies the already-derived WEB profiles and the one local backend accepted for every logical stream. Backend can be numeric loopback TCP or an absolute Unix-socket path, with an optional unix:// prefix.

func DefaultManagerConfig

func DefaultManagerConfig(profiles []Profile, backend string) ManagerConfig

DefaultManagerConfig constructs a complete configuration using the protocol reference limits and the standard library TCP dialer.

type PollLease

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

PollLease keeps one completed carrier response as the active downlink poll until the HTTP layer has drained that response. A newer poll supersedes it.

func (*PollLease) Release

func (l *PollLease) Release()

Release ends this response's claim if it is still the newest poll.

func (*PollLease) Superseded

func (l *PollLease) Superseded() bool

Superseded reports whether a newer downlink poll replaced this response.

type Profile

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

Profile is one immutable WEB credential derived from a named Telego secret. A single 16-byte base secret produces a plain profile and a dd profile.

func DeriveProfiles

func DeriveProfiles(name, hostname string, baseSecret []byte) ([2]Profile, error)

DeriveProfiles creates the plain and dd WEB credentials for an existing Telego 16-byte base secret. The returned order is always plain, then dd.

func DeriveProfilesForPath added in v0.6.8

func DeriveProfilesForPath(name, hostname, basePath string, baseSecret []byte) ([2]Profile, error)

DeriveProfilesForPath binds both credentials to one canonical WEB base path.

func (Profile) Capability

func (p Profile) Capability() Capability

func (Profile) Mode

func (p Profile) Mode() SecretMode

func (Profile) Name

func (p Profile) Name() string

func (Profile) SecretBytes

func (p Profile) SecretBytes() []byte

SecretBytes returns a copy of the decoded credential, including the leading dd byte for a SecretDD profile.

func (Profile) SecretHex

func (p Profile) SecretHex() string

SecretHex returns the credential in the form accepted by Telegram proxy links.

type RuntimeCounter added in v0.5.2

type RuntimeCounter struct {
	Label string
	Total uint64
}

RuntimeCounter is one labeled cumulative WEB counter.

type RuntimeStats added in v0.5.2

type RuntimeStats struct {
	Capacity         Capacity
	WebSocketsActive int64
	SessionsCreated  uint64
	SessionsClosed   []RuntimeCounter
	CarrierRetries   []RuntimeCounter
	Backpressure     []RuntimeCounter
}

RuntimeStats is a point-in-time view of WEB capacity and cumulative events.

type SecretMode

type SecretMode uint8

SecretMode identifies the MTProxy secret spelling used to derive a WEB profile capability.

const (
	SecretPlain SecretMode = iota
	SecretDD
)

func (SecretMode) String

func (m SecretMode) String() string

type Session

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

Session is one authenticated HTTPS carrier session. The serialized carrier permits one uplink and downlink. The lanes carrier permits one pair per lane.

func (*Session) AcquireWebSocket added in v0.5.3

func (s *Session) AcquireWebSocket() bool

AcquireWebSocket reserves the single multiplexed WebSocket for this session.

func (*Session) AcquireWebSocketLane added in v0.5.3

func (s *Session) AcquireWebSocketLane(laneID uint32) *WebSocketLaneLease

AcquireWebSocketLane reserves one nonzero stream lane for a WebSocket.

func (*Session) CarrierMode added in v0.5.2

func (s *Session) CarrierMode() CarrierMode

CarrierMode returns the immutable transport selected for this session.

func (*Session) Close

func (s *Session) Close()

Close aborts all logical streams and wakes parked carrier operations.

func (*Session) LastActivity

func (s *Session) LastActivity() time.Time

LastActivity returns the last carrier activity used for reconnect expiry.

func (*Session) Poll

func (s *Session) Poll(ctx context.Context, cursor uint64) ([]byte, uint64, error)

Poll acknowledges cursor, replays any unacknowledged batch, or waits for the next batch. Direct callers release the response claim before Poll returns.

func (*Session) PollCarrier

func (s *Session) PollCarrier(ctx context.Context, cursor uint64) ([]byte, uint64, *PollLease, error)

PollCarrier retains the newest-poll claim until the returned lease is released by the carrier after its HTTP response drains.

func (*Session) PollCarrierLane added in v0.5.2

func (s *Session) PollCarrierLane(
	ctx context.Context,
	laneID uint32,
	cursor uint64,
) ([]byte, uint64, bool, *PollLease, error)

PollCarrierLane retains the per-lane response claim until HTTP drains it.

func (*Session) PollLane added in v0.5.2

func (s *Session) PollLane(ctx context.Context, laneID uint32, cursor uint64) ([]byte, uint64, bool, error)

PollLane acknowledges and polls one independent stream lane.

func (*Session) ProcessUp

func (s *Session) ProcessUp(sequence uint64, body []byte) (uint64, error)

ProcessUp applies the next serialized uplink batch or acknowledges a byte-identical retry of the last committed sequence.

func (*Session) ProcessUpLane added in v0.5.2

func (s *Session) ProcessUpLane(laneID uint32, sequence uint64, body []byte) (uint64, error)

ProcessUpLane applies one uplink batch to an independent stream lane.

func (*Session) Profile

func (s *Session) Profile() Profile

Profile returns the immutable WEB credential associated with the session.

type Timeouts

type Timeouts struct {
	BackendDial       time.Duration
	LongPoll          time.Duration
	ReconnectGrace    time.Duration
	BootstrapLifetime time.Duration
}

Timeouts controls backend establishment, long polling, and disconnected session retention.

func DefaultTimeouts

func DefaultTimeouts() Timeouts

DefaultTimeouts returns the protocol reference defaults.

type WebSocketClose added in v0.6.6

type WebSocketClose struct {
	User          string
	Carrier       CarrierMode
	BridgeID      uint64
	LaneID        uint32
	Reason        string
	StreamOrigin  string
	ErrorCategory string
	CloseCode     uint16
	PeerCloseCode uint16
	AgeMS         int64
	ReceivedBytes uint64
	SentBytes     uint64
	Suppressed    uint64
}

WebSocketClose describes an observed server-side close. It contains no addresses, tokens, payloads, or peer-supplied reason text.

type WebSocketLaneLease added in v0.5.3

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

WebSocketLaneLease owns one WebSocket-lanes attachment. Its identity keeps stale cleanup from affecting a later attachment that reuses the same ID.

func (*WebSocketLaneLease) Poll added in v0.5.3

func (l *WebSocketLaneLease) Poll(
	ctx context.Context,
	cursor uint64,
) ([]byte, uint64, bool, error)

Poll acknowledges and polls downlink through this acquired lane.

func (*WebSocketLaneLease) PollCarrier added in v0.5.3

func (l *WebSocketLaneLease) PollCarrier(
	ctx context.Context,
	cursor uint64,
) ([]byte, uint64, bool, *PollLease, error)

PollCarrier retains the downlink claim until the caller releases it.

func (*WebSocketLaneLease) ProcessUp added in v0.5.3

func (l *WebSocketLaneLease) ProcessUp(sequence uint64, body []byte) (uint64, error)

ProcessUp applies one uplink message through this acquired lane.

func (*WebSocketLaneLease) Release added in v0.5.3

func (l *WebSocketLaneLease) Release()

Release idempotently detaches this lane and closes only its backend stream.

Jump to

Keyboard shortcuts

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