aboutsummaryrefslogtreecommitdiff
path: root/network/protocol/v0v1/server/session.go
blob: 2381801414dc3072764b8e688a31ac4b0d3f0d83 (about) (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package server

import (
	"io"

	"codeberg.org/lindenii/furgit/common/iowrap"
	"codeberg.org/lindenii/furgit/network/protocol/pktline"
	"codeberg.org/lindenii/furgit/network/protocol/sideband64k"
	objectid "codeberg.org/lindenii/furgit/object/id"
)

// 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 iowrap.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)
}

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

	return session.enc.WriteFlushPacket()
}

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

	return session.enc.Flush()
}

// ProgressWriter returns one chunking writer for sideband progress output.
//
// When side-band-64k was not negotiated, writes are discarded.
func (session *Session) ProgressWriter() iowrap.WriteFlusher {
	if !session.useSideBand {
		return iowrap.NopFlush(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() iowrap.WriteFlusher {
	if !session.useSideBand {
		return iowrap.NopFlush(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() iowrap.WriteFlusher {
	if session.useSideBand {
		return sideband64k.NewChunkWriter(session.sideband, sideband64k.BandData)
	}

	return pktline.NewChunkWriter(session.enc)
}