mirror of
https://github.com/go-gost/x.git
synced 2026-10-19 16:16:32 +00:00
Handlers write one recorder entry when a session ends, so long-lived SOCKS5 tunnels, streaming HTTP responses and UDP associations stay invisible while they run and report their traffic as one late record. With recorder.period set, a session now emits interim records on the interval while it is active and one final record when it ends. Each record carries the cumulative counters alongside the increments since the previous one, so a consumer sums records instead of replacing them, plus sessionID, recordIndex and phase. A session that ends inside one period still writes a single record, as it does today. One goroutine per handler samples every live session on the tick and writes its record straight to the recorder. There is no queue and no retry loop, and none is needed: a session moves its cursor past a record only once the recorder has taken it, so a refused write costs no bytes. They stay in the delta and go out with the next record. Holding on to what the sink cannot take right now is the sink's job. Interim and Finish take a context and return an error, so a handler learns what became of every record it asked for. Start writes nothing, so it takes neither. Close stops the sampling and reports the sessions its owner had not finished; nothing is buffered, so there is nothing to drain. With recorder.period unset or non-positive the previous behaviour is kept: one record per session, written inline, in the old shape. An object its handler never stamped, and one whose record mode is off, is dropped in both modes.
78 lines
2.5 KiB
Go
78 lines
2.5 KiB
Go
// Package ctx provides typed context value helpers for passing per-request
|
|
// data (buffer, logger, metadata, recorder objects) through the handler chain.
|
|
package ctx
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
|
|
"github.com/go-gost/core/logger"
|
|
"github.com/go-gost/core/metadata"
|
|
xrecorder "github.com/go-gost/x/recorder"
|
|
)
|
|
|
|
type bufferKey struct{}
|
|
|
|
// ContextWithBuffer returns a copy of ctx with the given buffer stored.
|
|
// The buffer is used by dialers and connectors to reuse a *bytes.Buffer
|
|
// for protocol handshake data (e.g. TLS ClientHello, HTTP requests).
|
|
func ContextWithBuffer(ctx context.Context, buffer *bytes.Buffer) context.Context {
|
|
return context.WithValue(ctx, bufferKey{}, buffer)
|
|
}
|
|
|
|
// BufferFromContext returns the *bytes.Buffer stored in ctx, or nil.
|
|
func BufferFromContext(ctx context.Context) *bytes.Buffer {
|
|
v, _ := ctx.Value(bufferKey{}).(*bytes.Buffer)
|
|
return v
|
|
}
|
|
|
|
type loggerKey struct{}
|
|
|
|
// ContextWithLogger returns a copy of ctx with the given logger stored.
|
|
func ContextWithLogger(ctx context.Context, log logger.Logger) context.Context {
|
|
return context.WithValue(ctx, loggerKey{}, log)
|
|
}
|
|
|
|
// LoggerFromContext returns the logger stored in ctx, or nil.
|
|
func LoggerFromContext(ctx context.Context) logger.Logger {
|
|
v, _ := ctx.Value(loggerKey{}).(logger.Logger)
|
|
return v
|
|
}
|
|
|
|
type mdKey struct{}
|
|
|
|
// ContextWithMetadata returns a copy of ctx with the given metadata stored.
|
|
func ContextWithMetadata(ctx context.Context, md metadata.Metadata) context.Context {
|
|
return context.WithValue(ctx, mdKey{}, md)
|
|
}
|
|
|
|
// MetadataFromContext returns the metadata stored in ctx, or nil.
|
|
func MetadataFromContext(ctx context.Context) metadata.Metadata {
|
|
v, _ := ctx.Value(mdKey{}).(metadata.Metadata)
|
|
return v
|
|
}
|
|
|
|
type recorderObjectCtxKey struct{}
|
|
|
|
// ContextWithRecorderObject returns a copy of ctx with the given recorder object stored.
|
|
func ContextWithRecorderObject(ctx context.Context, ro *xrecorder.HandlerRecorderObject) context.Context {
|
|
return context.WithValue(ctx, recorderObjectCtxKey{}, ro)
|
|
}
|
|
|
|
// RecorderObjectFromContext returns the recorder object stored in ctx, or nil.
|
|
func RecorderObjectFromContext(ctx context.Context) *xrecorder.HandlerRecorderObject {
|
|
v, _ := ctx.Value(recorderObjectCtxKey{}).(*xrecorder.HandlerRecorderObject)
|
|
return v
|
|
}
|
|
|
|
type sessionCtxKey struct{}
|
|
|
|
func ContextWithSession(ctx context.Context, s *xrecorder.Session) context.Context {
|
|
return context.WithValue(ctx, sessionCtxKey{}, s)
|
|
}
|
|
|
|
func SessionFromContext(ctx context.Context) *xrecorder.Session {
|
|
v, _ := ctx.Value(sessionCtxKey{}).(*xrecorder.Session)
|
|
return v
|
|
}
|