shithub: furgit

ref: 27ef9a7e1f2589d1a0eeee4cd6d36d1926989cf2
dir: /protocol/v0v1/server/session.go/

View raw version
package server

import (
	"io"

	"codeberg.org/lindenii/furgit/format/pktline"
	"codeberg.org/lindenii/furgit/format/sideband64k"
	"codeberg.org/lindenii/furgit/objectid"
)

// Options configures one server-side v0/v1 session.
type Options struct {
	// Version selects protocol v0 or v1 framing.
	Version Version
	// Algorithm is the repository object ID algorithm for this session.
	Algorithm objectid.Algorithm
}

// Session is one stateful server-side v0/v1 server protocol session.
type Session struct {
	dec         *pktline.Decoder
	enc         *pktline.Encoder
	sideband    *sideband64k.Encoder
	opts        Options
	useSideBand bool
}

// NewSession creates one v0/v1 server session over r and w.
func NewSession(r io.Reader, w pktline.WriteFlusher, opts Options) *Session {
	return &Session{
		dec:      pktline.NewDecoder(r, pktline.ReadOptions{}),
		enc:      pktline.NewEncoder(w),
		sideband: sideband64k.NewEncoder(w),
		opts:     opts,
	}
}

// Algorithm returns the session object ID algorithm.
func (session *Session) Algorithm() objectid.Algorithm {
	return session.opts.Algorithm
}

// ReadFrame reads one low-level pkt-line frame from the session input.
func (session *Session) ReadFrame() (Frame, error) {
	return session.dec.ReadFrame()
}

// EnableSideBand64K enables side-band-64k output framing for subsequent data,
// progress, error, and flush writes.
func (session *Session) EnableSideBand64K() {
	session.useSideBand = true
}

// WriteData writes one primary output packet.
func (session *Session) WriteData(p []byte) error {
	if session.useSideBand {
		return session.sideband.WriteData(p)
	}

	return session.enc.WriteData(p)
}

// WriteProgress writes one progress packet.
func (session *Session) WriteProgress(p []byte) error {
	if !session.useSideBand {
		return ErrSideBandNotEnabled
	}

	return session.sideband.WriteProgress(p)
}

// WriteError writes one fatal error packet.
func (session *Session) WriteError(p []byte) error {
	if !session.useSideBand {
		return ErrSideBandNotEnabled
	}

	return session.sideband.WriteError(p)
}

// WriteFlush writes one trailing flush packet.
func (session *Session) WriteFlush() error {
	if session.useSideBand {
		return session.sideband.WriteFlush()
	}

	return session.enc.WriteFlush()
}

// FlushIO flushes buffered transport output without emitting pkt-line frames.
func (session *Session) FlushIO() error {
	if session.useSideBand {
		return session.sideband.FlushIO()
	}

	return session.enc.FlushIO()
}

// ProgressWriter returns one chunking writer for sideband progress output.
//
// When side-band-64k was not negotiated, writes are discarded.
func (session *Session) ProgressWriter() io.Writer {
	if !session.useSideBand {
		return io.Discard
	}

	return sideband64k.NewChunkWriter(session.sideband, sideband64k.BandProgress)
}

// ErrorWriter returns one chunking writer for sideband error output.
//
// When side-band-64k was not negotiated, writes are discarded.
func (session *Session) ErrorWriter() io.Writer {
	if !session.useSideBand {
		return io.Discard
	}

	return sideband64k.NewChunkWriter(session.sideband, sideband64k.BandError)
}

// PrimaryDataWriter returns one chunking writer for primary output bytes.
//
// When side-band-64k is enabled, writes are chunked into band-1 sideband
// frames. Otherwise writes are chunked into direct pkt-line data frames.
func (session *Session) PrimaryDataWriter() io.Writer {
	if session.useSideBand {
		return sideband64k.NewChunkWriter(session.sideband, sideband64k.BandData)
	}

	return pktline.NewChunkWriter(session.enc)
}