mirror of
https://github.com/ScuroNeko/mtg.git
synced 2026-08-31 21:14:01 +03:00
Rework events
This commit is contained in:
+5
-16
@@ -6,27 +6,21 @@ import (
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type connTraffic struct {
|
||||
net.Conn
|
||||
|
||||
connID string
|
||||
stream EventStream
|
||||
ctx context.Context
|
||||
streamID string
|
||||
stream EventStream
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
func (c connTraffic) Read(b []byte) (int, error) {
|
||||
n, err := c.Conn.Read(b)
|
||||
|
||||
if n > 0 {
|
||||
c.stream.Send(c.ctx, EventTraffic{
|
||||
CreatedAt: time.Now(),
|
||||
ConnID: c.connID,
|
||||
Traffic: uint(n),
|
||||
IsRead: true,
|
||||
})
|
||||
c.stream.Send(c.ctx, NewEventTraffic(c.streamID, uint(n), true))
|
||||
}
|
||||
|
||||
return n, err // nolint: wrapcheck
|
||||
@@ -36,12 +30,7 @@ func (c connTraffic) Write(b []byte) (int, error) {
|
||||
n, err := c.Conn.Write(b)
|
||||
|
||||
if n > 0 {
|
||||
c.stream.Send(c.ctx, EventTraffic{
|
||||
CreatedAt: time.Now(),
|
||||
ConnID: c.connID,
|
||||
Traffic: uint(n),
|
||||
IsRead: false,
|
||||
})
|
||||
c.stream.Send(c.ctx, NewEventTraffic(c.streamID, uint(n), false))
|
||||
}
|
||||
|
||||
return n, err // nolint: wrapcheck
|
||||
|
||||
@@ -37,10 +37,10 @@ func (suite *ConnTrafficTestSuite) SetupTest() {
|
||||
suite.eventStreamMock = &EventStreamMock{}
|
||||
suite.connMock = &testlib.NetConnMock{}
|
||||
suite.conn = connTraffic{
|
||||
Conn: suite.connMock,
|
||||
connID: "CONNID",
|
||||
ctx: context.Background(),
|
||||
stream: suite.eventStreamMock,
|
||||
Conn: suite.connMock,
|
||||
streamID: "CONNID",
|
||||
ctx: context.Background(),
|
||||
stream: suite.eventStreamMock,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+99
-76
@@ -5,110 +5,133 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type eventBase struct {
|
||||
streamID string
|
||||
timestamp time.Time
|
||||
}
|
||||
|
||||
func (e eventBase) StreamID() string {
|
||||
return e.streamID
|
||||
}
|
||||
|
||||
func (e eventBase) Timestamp() time.Time {
|
||||
return e.timestamp
|
||||
}
|
||||
|
||||
type EventStart struct {
|
||||
CreatedAt time.Time
|
||||
ConnID string
|
||||
RemoteIP net.IP
|
||||
}
|
||||
eventBase
|
||||
|
||||
func (e EventStart) StreamID() string {
|
||||
return e.ConnID
|
||||
}
|
||||
|
||||
func (e EventStart) Timestamp() time.Time {
|
||||
return e.CreatedAt
|
||||
RemoteIP net.IP
|
||||
}
|
||||
|
||||
type EventConnectedToDC struct {
|
||||
CreatedAt time.Time
|
||||
ConnID string
|
||||
RemoteIP net.IP
|
||||
DC int
|
||||
}
|
||||
eventBase
|
||||
|
||||
func (e EventConnectedToDC) StreamID() string {
|
||||
return e.ConnID
|
||||
}
|
||||
|
||||
func (e EventConnectedToDC) Timestamp() time.Time {
|
||||
return e.CreatedAt
|
||||
RemoteIP net.IP
|
||||
DC int
|
||||
}
|
||||
|
||||
type EventTraffic struct {
|
||||
CreatedAt time.Time
|
||||
ConnID string
|
||||
Traffic uint
|
||||
IsRead bool
|
||||
}
|
||||
eventBase
|
||||
|
||||
func (e EventTraffic) StreamID() string {
|
||||
return e.ConnID
|
||||
}
|
||||
|
||||
func (e EventTraffic) Timestamp() time.Time {
|
||||
return e.CreatedAt
|
||||
Traffic uint
|
||||
IsRead bool
|
||||
}
|
||||
|
||||
type EventFinish struct {
|
||||
CreatedAt time.Time
|
||||
ConnID string
|
||||
}
|
||||
|
||||
func (e EventFinish) StreamID() string {
|
||||
return e.ConnID
|
||||
}
|
||||
|
||||
func (e EventFinish) Timestamp() time.Time {
|
||||
return e.CreatedAt
|
||||
eventBase
|
||||
}
|
||||
|
||||
type EventDomainFronting struct {
|
||||
CreatedAt time.Time
|
||||
ConnID string
|
||||
}
|
||||
|
||||
func (e EventDomainFronting) StreamID() string {
|
||||
return e.ConnID
|
||||
}
|
||||
|
||||
func (e EventDomainFronting) Timestamp() time.Time {
|
||||
return e.CreatedAt
|
||||
eventBase
|
||||
}
|
||||
|
||||
type EventConcurrencyLimited struct {
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
func (e EventConcurrencyLimited) StreamID() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (e EventConcurrencyLimited) Timestamp() time.Time {
|
||||
return e.CreatedAt
|
||||
eventBase
|
||||
}
|
||||
|
||||
type EventIPBlocklisted struct {
|
||||
CreatedAt time.Time
|
||||
RemoteIP net.IP
|
||||
}
|
||||
eventBase
|
||||
|
||||
func (e EventIPBlocklisted) StreamID() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (e EventIPBlocklisted) Timestamp() time.Time {
|
||||
return e.CreatedAt
|
||||
RemoteIP net.IP
|
||||
}
|
||||
|
||||
type EventReplayAttack struct {
|
||||
CreatedAt time.Time
|
||||
ConnID string
|
||||
eventBase
|
||||
}
|
||||
|
||||
func (e EventReplayAttack) StreamID() string {
|
||||
return e.ConnID
|
||||
func NewEventStart(streamID string, remoteIP net.IP) EventStart {
|
||||
return EventStart{
|
||||
eventBase: eventBase{
|
||||
timestamp: time.Now(),
|
||||
streamID: streamID,
|
||||
},
|
||||
RemoteIP: remoteIP,
|
||||
}
|
||||
}
|
||||
|
||||
func (e EventReplayAttack) Timestamp() time.Time {
|
||||
return e.CreatedAt
|
||||
func NewEventConnectedToDC(streamID string, remoteIP net.IP, dc int) EventConnectedToDC {
|
||||
return EventConnectedToDC{
|
||||
eventBase: eventBase{
|
||||
timestamp: time.Now(),
|
||||
streamID: streamID,
|
||||
},
|
||||
RemoteIP: remoteIP,
|
||||
DC: dc,
|
||||
}
|
||||
}
|
||||
|
||||
func NewEventTraffic(streamID string, traffic uint, isRead bool) EventTraffic {
|
||||
return EventTraffic{
|
||||
eventBase: eventBase{
|
||||
timestamp: time.Now(),
|
||||
streamID: streamID,
|
||||
},
|
||||
Traffic: traffic,
|
||||
IsRead: isRead,
|
||||
}
|
||||
}
|
||||
|
||||
func NewEventFinish(streamID string) EventFinish {
|
||||
return EventFinish{
|
||||
eventBase: eventBase{
|
||||
timestamp: time.Now(),
|
||||
streamID: streamID,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewEventDomainFronting(streamID string) EventDomainFronting {
|
||||
return EventDomainFronting{
|
||||
eventBase: eventBase{
|
||||
timestamp: time.Now(),
|
||||
streamID: streamID,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewEventConcurrencyLimited() EventConcurrencyLimited {
|
||||
return EventConcurrencyLimited{
|
||||
eventBase: eventBase{
|
||||
timestamp: time.Now(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func NewEventIPBlocklisted(remoteIP net.IP) EventIPBlocklisted {
|
||||
return EventIPBlocklisted{
|
||||
eventBase: eventBase{
|
||||
timestamp: time.Now(),
|
||||
},
|
||||
RemoteIP: remoteIP,
|
||||
}
|
||||
}
|
||||
|
||||
func NewEventReplayAttack(streamID string) EventReplayAttack {
|
||||
return EventReplayAttack{
|
||||
eventBase: eventBase{
|
||||
timestamp: time.Now(),
|
||||
streamID: streamID,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
+8
-36
@@ -14,84 +14,56 @@ type EventsTestSuite struct {
|
||||
}
|
||||
|
||||
func (suite *EventsTestSuite) TestEventStart() {
|
||||
evt := mtglib.EventStart{
|
||||
CreatedAt: time.Now(),
|
||||
ConnID: "CONNID",
|
||||
RemoteIP: net.ParseIP("10.0.0.10"),
|
||||
}
|
||||
evt := mtglib.NewEventStart("CONNID", net.ParseIP("10.0.0.10"))
|
||||
|
||||
suite.Equal("CONNID", evt.StreamID())
|
||||
suite.WithinDuration(time.Now(), evt.Timestamp(), 10*time.Millisecond)
|
||||
}
|
||||
|
||||
func (suite *EventsTestSuite) TestEventFinish() {
|
||||
evt := mtglib.EventFinish{
|
||||
CreatedAt: time.Now(),
|
||||
ConnID: "CONNID",
|
||||
}
|
||||
evt := mtglib.NewEventFinish("CONNID")
|
||||
|
||||
suite.Equal("CONNID", evt.StreamID())
|
||||
suite.WithinDuration(time.Now(), evt.Timestamp(), 10*time.Millisecond)
|
||||
}
|
||||
|
||||
func (suite *EventsTestSuite) TestEventConnectedToDC() {
|
||||
evt := mtglib.EventConnectedToDC{
|
||||
CreatedAt: time.Now(),
|
||||
ConnID: "CONNID",
|
||||
RemoteIP: net.ParseIP("10.0.0.10"),
|
||||
DC: 3,
|
||||
}
|
||||
evt := mtglib.NewEventConnectedToDC("CONNID", net.ParseIP("10.0.0.10"), 3)
|
||||
|
||||
suite.Equal("CONNID", evt.StreamID())
|
||||
suite.WithinDuration(time.Now(), evt.Timestamp(), 10*time.Millisecond)
|
||||
}
|
||||
|
||||
func (suite *EventsTestSuite) TestEventTraffic() {
|
||||
evt := mtglib.EventTraffic{
|
||||
CreatedAt: time.Now(),
|
||||
ConnID: "CONNID",
|
||||
Traffic: 3,
|
||||
IsRead: true,
|
||||
}
|
||||
evt := mtglib.NewEventTraffic("CONNID", 1000, true)
|
||||
|
||||
suite.Equal("CONNID", evt.StreamID())
|
||||
suite.WithinDuration(time.Now(), evt.Timestamp(), 10*time.Millisecond)
|
||||
}
|
||||
|
||||
func (suite *EventsTestSuite) TestEventDomainFronting() {
|
||||
evt := mtglib.EventDomainFronting{
|
||||
CreatedAt: time.Now(),
|
||||
ConnID: "CONNID",
|
||||
}
|
||||
evt := mtglib.NewEventDomainFronting("CONNID")
|
||||
|
||||
suite.Equal("CONNID", evt.StreamID())
|
||||
suite.WithinDuration(time.Now(), evt.Timestamp(), 10*time.Millisecond)
|
||||
}
|
||||
|
||||
func (suite *EventsTestSuite) TestEventConcurrencyLimited() {
|
||||
evt := mtglib.EventConcurrencyLimited{
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
evt := mtglib.NewEventConcurrencyLimited()
|
||||
|
||||
suite.Empty(evt.StreamID())
|
||||
suite.WithinDuration(time.Now(), evt.Timestamp(), 10*time.Millisecond)
|
||||
}
|
||||
|
||||
func (suite *EventsTestSuite) TestEventIPBlocklisted() {
|
||||
evt := mtglib.EventIPBlocklisted{
|
||||
CreatedAt: time.Now(),
|
||||
RemoteIP: net.ParseIP("10.0.0.10"),
|
||||
}
|
||||
evt := mtglib.NewEventIPBlocklisted(net.ParseIP("10.0.0.10"))
|
||||
|
||||
suite.Empty(evt.StreamID())
|
||||
suite.WithinDuration(time.Now(), evt.Timestamp(), 10*time.Millisecond)
|
||||
}
|
||||
|
||||
func (suite *EventsTestSuite) TestEventReplayAttack() {
|
||||
evt := mtglib.EventReplayAttack{
|
||||
CreatedAt: time.Now(),
|
||||
ConnID: "CONNID",
|
||||
}
|
||||
evt := mtglib.NewEventReplayAttack("CONNID")
|
||||
|
||||
suite.Equal("CONNID", evt.StreamID())
|
||||
suite.WithinDuration(time.Now(), evt.Timestamp(), 10*time.Millisecond)
|
||||
|
||||
+71
-11
@@ -9,22 +9,66 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
ErrSecretEmpty = errors.New("secret is empty")
|
||||
ErrSecretInvalid = errors.New("secret is invalid")
|
||||
ErrNetworkIsNotDefined = errors.New("network is not defined")
|
||||
ErrAntiReplayCacheIsNotDefined = errors.New("anti-replay cache is not defined")
|
||||
// ErrSecretEmpty is returned if you are trying to create a proxy
|
||||
// but do not provide a secret.
|
||||
ErrSecretEmpty = errors.New("secret is empty")
|
||||
|
||||
// ErrSecretInvalid is returned if you are trying to create a proxy
|
||||
// but secret value is invalid (no host or payload are zeroes).
|
||||
ErrSecretInvalid = errors.New("secret is invalid")
|
||||
|
||||
// ErrNetworkIsNotDefined is returned if you are trying to create a
|
||||
// proxy but network value is undefined.
|
||||
ErrNetworkIsNotDefined = errors.New("network is not defined")
|
||||
|
||||
// ErrAntiReplayCacheIsNotDefined is returned if you are trying to
|
||||
// create a proxy but anti replay cache value is undefined.
|
||||
ErrAntiReplayCacheIsNotDefined = errors.New("anti-replay cache is not defined")
|
||||
|
||||
// ErrTimeAttackDetectorIsNotDefined is returned if you are trying to
|
||||
// create a proxy but time attack detector is not defined.
|
||||
ErrTimeAttackDetectorIsNotDefined = errors.New("time attack detector is not defined")
|
||||
ErrIPBlocklistIsNotDefined = errors.New("ip blocklist is not defined")
|
||||
ErrEventStreamIsNotDefined = errors.New("event stream is not defined")
|
||||
ErrLoggerIsNotDefined = errors.New("logger is not defined")
|
||||
|
||||
// ErrIPBlocklistIsNotDefined is returned if you are trying to
|
||||
// create a proxy but ip blocklist instance is not defined.
|
||||
ErrIPBlocklistIsNotDefined = errors.New("ip blocklist is not defined")
|
||||
|
||||
// ErrEventStreamIsNotDefined is returned if you are trying to create a
|
||||
// proxy but event stream instance is not defined.
|
||||
ErrEventStreamIsNotDefined = errors.New("event stream is not defined")
|
||||
|
||||
// ErrLoggerIsNotDefined is returned if you are trying to
|
||||
// create a proxy but logger is not defined.
|
||||
ErrLoggerIsNotDefined = errors.New("logger is not defined")
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultConcurrency = 4096
|
||||
DefaultBufferSize = 16 * 1024 // 16 kib
|
||||
// DefaultConcurrency is a default max count of simultaneously
|
||||
// connected clients.
|
||||
DefaultConcurrency = 4096
|
||||
|
||||
// DefaultBufferSize is a default size of a copy buffer.
|
||||
DefaultBufferSize = 16 * 1024 // 16 kib
|
||||
|
||||
// DefaultDomainFrontingPort is a default port (HTTPS) to connect to in
|
||||
// case of probe-resistance activity.
|
||||
DefaultDomainFrontingPort = 443
|
||||
DefaultIdleTimeout = time.Minute
|
||||
DefaultPreferIP = "prefer-ipv6"
|
||||
|
||||
// DefaultIdleTimeout is a default timeout for closing a connection
|
||||
// in case of idling.
|
||||
DefaultIdleTimeout = time.Minute
|
||||
|
||||
// DefaultPreferIP is a default value for Telegram IP connectivity
|
||||
// preference.
|
||||
DefaultPreferIP = "prefer-ipv6"
|
||||
|
||||
// SecretKeyLength defines a length of the secret bytes used
|
||||
// by Telegram and a proxy.
|
||||
SecretKeyLength = 16
|
||||
|
||||
// ConnectionIDBytesLength defines a count of random bytes
|
||||
// used to generate a stream/connection ids.
|
||||
ConnectionIDBytesLength = 16
|
||||
)
|
||||
|
||||
// Network defines a knowledge how to work with a network. It may sound
|
||||
@@ -105,8 +149,24 @@ type IPBlocklist interface {
|
||||
Contains(net.IP) bool
|
||||
}
|
||||
|
||||
// Event is a data structure which is populated during mtg request
|
||||
// processing lifecycle. Each request popluates many events:
|
||||
//
|
||||
// 1. Client connected
|
||||
//
|
||||
// 2. Request is finished
|
||||
//
|
||||
// 3. Connection to Telegram server is established
|
||||
//
|
||||
// and so on. All these events are data structures but all of them
|
||||
// must conform the same interface.
|
||||
type Event interface {
|
||||
// StreamID returns an identifier of the stream, connection,
|
||||
// request, you name it. All events within the same stream returns
|
||||
// the same stream id.
|
||||
StreamID() string
|
||||
|
||||
// Timestamp returns a timestamp when this event was generated.
|
||||
Timestamp() time.Time
|
||||
}
|
||||
|
||||
|
||||
+16
-39
@@ -53,18 +53,11 @@ func (p *Proxy) ServeConn(conn net.Conn) {
|
||||
ctx.Close()
|
||||
}()
|
||||
|
||||
p.eventStream.Send(ctx, EventStart{
|
||||
CreatedAt: time.Now(),
|
||||
ConnID: ctx.connID,
|
||||
RemoteIP: ctx.ClientIP(),
|
||||
})
|
||||
p.eventStream.Send(ctx, NewEventStart(ctx.streamID, ctx.ClientIP()))
|
||||
ctx.logger.Info("Stream has been started")
|
||||
|
||||
defer func() {
|
||||
p.eventStream.Send(ctx, EventFinish{
|
||||
CreatedAt: time.Now(),
|
||||
ConnID: ctx.connID,
|
||||
})
|
||||
p.eventStream.Send(ctx, NewEventFinish(ctx.streamID))
|
||||
ctx.logger.Info("Stream has been finished")
|
||||
}()
|
||||
|
||||
@@ -109,10 +102,7 @@ func (p *Proxy) Serve(listener net.Listener) error {
|
||||
if p.ipBlocklist.Contains(ipAddr) {
|
||||
conn.Close()
|
||||
logger.Info("ip was blacklisted")
|
||||
p.eventStream.Send(p.ctx, EventIPBlocklisted{
|
||||
CreatedAt: time.Now(),
|
||||
RemoteIP: ipAddr,
|
||||
})
|
||||
p.eventStream.Send(p.ctx, NewEventIPBlocklisted(ipAddr))
|
||||
|
||||
continue
|
||||
}
|
||||
@@ -125,9 +115,7 @@ func (p *Proxy) Serve(listener net.Listener) error {
|
||||
return nil
|
||||
case errors.Is(err, ants.ErrPoolOverload):
|
||||
logger.Info("connection was concurrency limited")
|
||||
p.eventStream.Send(p.ctx, EventConcurrencyLimited{
|
||||
CreatedAt: time.Now(),
|
||||
})
|
||||
p.eventStream.Send(p.ctx, NewEventConcurrencyLimited())
|
||||
}
|
||||
|
||||
select {
|
||||
@@ -181,10 +169,7 @@ func (p *Proxy) doFakeTLSHandshake(ctx *streamContext) bool {
|
||||
|
||||
if p.antiReplayCache.SeenBefore(hello.SessionID) {
|
||||
p.logger.Warning("replay attack has been detected!")
|
||||
p.eventStream.Send(p.ctx, EventReplayAttack{
|
||||
CreatedAt: time.Now(),
|
||||
ConnID: ctx.connID,
|
||||
})
|
||||
p.eventStream.Send(p.ctx, NewEventReplayAttack(ctx.streamID))
|
||||
p.doDomainFronting(ctx, rewind)
|
||||
|
||||
return false
|
||||
@@ -235,31 +220,23 @@ func (p *Proxy) doTelegramCall(ctx *streamContext) error {
|
||||
|
||||
ctx.telegramConn = obfuscated2.Conn{
|
||||
Conn: connTraffic{
|
||||
Conn: conn,
|
||||
connID: ctx.connID,
|
||||
stream: p.eventStream,
|
||||
ctx: ctx,
|
||||
Conn: conn,
|
||||
streamID: ctx.streamID,
|
||||
stream: p.eventStream,
|
||||
ctx: ctx,
|
||||
},
|
||||
Encryptor: encryptor,
|
||||
Decryptor: decryptor,
|
||||
}
|
||||
|
||||
p.eventStream.Send(ctx, EventConnectedToDC{
|
||||
CreatedAt: time.Now(),
|
||||
ConnID: ctx.connID,
|
||||
RemoteIP: conn.RemoteAddr().(*net.TCPAddr).IP,
|
||||
DC: ctx.dc,
|
||||
})
|
||||
p.eventStream.Send(ctx,
|
||||
NewEventConnectedToDC(ctx.streamID, conn.RemoteAddr().(*net.TCPAddr).IP, ctx.dc))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Proxy) doDomainFronting(ctx *streamContext, conn *connRewind) {
|
||||
p.eventStream.Send(p.ctx, EventDomainFronting{
|
||||
CreatedAt: time.Now(),
|
||||
ConnID: ctx.connID,
|
||||
})
|
||||
|
||||
p.eventStream.Send(p.ctx, NewEventDomainFronting(ctx.streamID))
|
||||
conn.Rewind()
|
||||
|
||||
frontConn, err := p.network.DialContext(ctx, "tcp", p.DomainFrontingAddress())
|
||||
@@ -270,10 +247,10 @@ func (p *Proxy) doDomainFronting(ctx *streamContext, conn *connRewind) {
|
||||
}
|
||||
|
||||
frontConn = connTraffic{
|
||||
Conn: frontConn,
|
||||
ctx: ctx,
|
||||
connID: ctx.connID,
|
||||
stream: p.eventStream,
|
||||
Conn: frontConn,
|
||||
ctx: ctx,
|
||||
streamID: ctx.streamID,
|
||||
stream: p.eventStream,
|
||||
}
|
||||
|
||||
rel := relay.AcquireRelay(ctx,
|
||||
|
||||
+1
-5
@@ -7,11 +7,7 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
SecretKeyLength = 16
|
||||
|
||||
secretFakeTLSFirstByte byte = 0xee
|
||||
)
|
||||
const secretFakeTLSFirstByte byte = 0xee
|
||||
|
||||
var secretEmptyKey [SecretKeyLength]byte
|
||||
|
||||
|
||||
@@ -8,14 +8,12 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const ConnectionIDBytesLength = 16
|
||||
|
||||
type streamContext struct {
|
||||
ctx context.Context
|
||||
ctxCancel context.CancelFunc
|
||||
clientConn net.Conn
|
||||
telegramConn net.Conn
|
||||
connID string
|
||||
streamID string
|
||||
dc int
|
||||
logger Logger
|
||||
}
|
||||
@@ -64,10 +62,10 @@ func newStreamContext(ctx context.Context, logger Logger, clientConn net.Conn) *
|
||||
ctx: ctx,
|
||||
ctxCancel: cancel,
|
||||
clientConn: clientConn,
|
||||
connID: base64.RawURLEncoding.EncodeToString(connIDBytes),
|
||||
streamID: base64.RawURLEncoding.EncodeToString(connIDBytes),
|
||||
}
|
||||
streamCtx.logger = logger.
|
||||
BindStr("stream-id", streamCtx.connID).
|
||||
BindStr("stream-id", streamCtx.streamID).
|
||||
BindStr("client-ip", streamCtx.ClientIP().String())
|
||||
|
||||
return streamCtx
|
||||
|
||||
Reference in New Issue
Block a user