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 ¶
var ( ErrClosed = errors.New("link: connection closed") ErrTooLarge = errors.New("link: frame exceeds maximum size") )
Errors returned by the link layer.
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 ¶
Filter transforms a message on its way out (outgoing=true) or in (outgoing=false) — e.g. MAC insertion/verification, logging, or padding.
type FilterFunc ¶
FilterFunc adapts a function to 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 ¶
LengthPrefix returns a Framer using a big-endian length prefix of width bytes (2 or 4). It panics for other widths.
type Link ¶
type Link struct {
// contains filtered or unexported fields
}
Link is a message-framed connection.
func DialContext ¶
DialContext opens a client Link, honouring ctx for the dial.
func New ¶
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) Receive ¶
Receive reads one frame and applies incoming filters (in reverse order). It is intended to be called by a single reader goroutine.
type Option ¶
type Option func(*config)
Option configures a Link.
func WithDialTimeout ¶
WithDialTimeout sets the dial timeout.
func WithFilters ¶
WithFilters appends ordered filters. On send they run in order; on receive, in reverse — so a filter pair wraps/unwraps symmetrically.
func WithFramer ¶
WithFramer sets the message framer (default: LengthPrefix(2)).
func WithKeepAlive ¶
WithKeepAlive sets the TCP keep-alive period (0 disables).
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.
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.