link

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jun 2, 2026 License: AGPL-3.0 Imports: 9 Imported by: 0

Documentation

Overview

Package link is the ISO-8583 transport edge: a message-framed connection over TCP (optionally TLS). A Link turns a byte stream into discrete message frames via a pluggable Framer (length-prefix by default), applies ordered Filters on the way in and out, and is safe for concurrent Send from many goroutines while a single reader calls Receive. It carries raw message bytes; decoding is the caller's concern (iso8583.Codec), keeping transport and model decoupled.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrClosed   = errors.New("link: connection closed")
	ErrTooLarge = errors.New("link: frame exceeds maximum size")
)

Errors returned by the link layer.

View Source
var (
	ErrNoHealthy  = errors.New("link: no healthy connection in pool")
	ErrPoolClosed = errors.New("link: pool closed")
)

Pool errors.

Functions

This section is empty.

Types

type Filter

type Filter interface {
	Apply(msg []byte, outgoing bool) ([]byte, error)
}

Filter transforms a message on its way out (outgoing=true) or in (outgoing=false) — e.g. MAC insertion/verification, logging, or padding.

type FilterFunc

type FilterFunc func(msg []byte, outgoing bool) ([]byte, error)

FilterFunc adapts a function to Filter.

func (FilterFunc) Apply

func (f FilterFunc) Apply(msg []byte, outgoing bool) ([]byte, error)

Apply implements Filter.

type Framer

type Framer interface {
	// ReadFrame reads exactly one message body from r.
	ReadFrame(r io.Reader) ([]byte, error)
	// WriteFrame writes one message body to w.
	WriteFrame(w io.Writer, msg []byte) error
}

Framer turns a byte stream into discrete message frames. Implementations must be safe for one concurrent reader and one concurrent writer.

func ISOXML added in v0.2.0

func ISOXML() Framer

ISOXML returns a Framer that delimits messages by the isomsg XML element rather than a length prefix — the framing an XML channel uses (jPOS's XMLChannel). A frame is exactly one balanced <isomsg>…</isomsg> element, including any nested <isomsg id="…"> children; WriteFrame appends a trailing newline so a peer reading line-wise sees a record boundary. Pair it with the render/xmlio packager:

l := link.New(conn, link.WithFramer(link.ISOXML()))
l.Send(mustMarshalXML(msg)) // xmlio.Marshal
frame, _ := l.Receive()     // xmlio.Unmarshal(frame, schema)

XML is delimiter-framed, not length-framed, so ReadFrame consumes the stream one byte at a time and stops exactly on the closing tag — it never reads past a frame boundary. That keeps the Framer stateless (safe to share across Links) at the cost of throughput, an acceptable trade for the human-readable XML transport, which is not a hot path.

func LengthPrefix

func LengthPrefix(width int) Framer

LengthPrefix returns a Framer using a big-endian length prefix of width bytes (2 or 4). It panics for other widths.

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

Link is a message-framed connection.

func Dial

func Dial(network, addr string, opts ...Option) (*Link, error)

Dial opens a client Link to addr.

func DialContext

func DialContext(ctx context.Context, network, addr string, opts ...Option) (*Link, error)

DialContext opens a client Link, honouring ctx for the dial.

func New

func New(conn net.Conn, opts ...Option) *Link

New wraps an already-accepted connection (server side). For TLS servers pass a tls.Server connection (or use WithTLS and a *tls.Conn).

func (*Link) Close

func (l *Link) Close() error

Close closes the underlying connection. It is safe to call more than once.

func (*Link) LocalAddr

func (l *Link) LocalAddr() net.Addr

LocalAddr returns the local address.

func (*Link) Receive

func (l *Link) Receive() ([]byte, error)

Receive reads one frame and applies incoming filters (in reverse order). It is intended to be called by a single reader goroutine.

func (*Link) RemoteAddr

func (l *Link) RemoteAddr() net.Addr

RemoteAddr returns the peer address.

func (*Link) Send

func (l *Link) Send(msg []byte) error

Send applies outgoing filters and writes one frame. It is safe to call from multiple goroutines concurrently.

func (*Link) SetReadDeadline

func (l *Link) SetReadDeadline(t time.Time) error

SetReadDeadline sets the deadline for future Receive calls.

type Option

type Option func(*config)

Option configures a Link.

func WithDialTimeout

func WithDialTimeout(d time.Duration) Option

WithDialTimeout sets the dial timeout.

func WithFilters

func WithFilters(f ...Filter) Option

WithFilters appends ordered filters. On send they run in order; on receive, in reverse — so a filter pair wraps/unwraps symmetrically.

func WithFramer

func WithFramer(f Framer) Option

WithFramer sets the message framer (default: LengthPrefix(2)).

func WithKeepAlive

func WithKeepAlive(d time.Duration) Option

WithKeepAlive sets the TCP keep-alive period (0 disables).

func WithTLS

func WithTLS(t *tls.Config) Option

WithTLS enables TLS using the given config (client or server).

type Pool

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

Pool maintains a fixed set of Links to a target, round-robining healthy ones and reconnecting failed slots in the background with exponential backoff.

func NewPool

func NewPool(size int, dial func() (*Link, error), opts ...PoolOption) *Pool

NewPool builds a pool of size connections using dial. Slots that fail to dial initially begin reconnecting immediately.

func (*Pool) Close

func (p *Pool) Close() error

Close shuts the pool, closing all links and stopping reconnection.

func (*Pool) Discard

func (p *Pool) Discard(l *Link)

Discard removes a Link believed to be broken, closes it, and schedules its slot for reconnection. Callers invoke it when a Send/Receive on l fails.

func (*Pool) Get

func (p *Pool) Get() (*Link, error)

Get returns the next healthy Link (round-robin), or ErrNoHealthy if none are currently connected.

type PoolOption

type PoolOption func(*Pool)

PoolOption configures a Pool.

func WithBackoff

func WithBackoff(min, max time.Duration) PoolOption

WithBackoff sets the reconnect backoff bounds.

Jump to

Keyboard shortcuts

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