File view with blame information shown in the left gutter beside each line.

barerepo / server / internal/pktline/pktline.go
77 lines · 1.8kb · 133728eaa05486504991b230f9d4c7e986b7defc
log files threads runs releases config jump to file t
133728e barerepo 1mo
1
// Package pktline is git's framing: four hex digits of length, 0000 flush, 0001 delimiter.
133728e barerepo 1mo
2
package pktline
133728e barerepo 1mo
3
133728e barerepo 1mo
4
import (
133728e barerepo 1mo
5
"bufio"
133728e barerepo 1mo
6
"errors"
133728e barerepo 1mo
7
"fmt"
133728e barerepo 1mo
8
"io"
133728e barerepo 1mo
9
"strconv"
133728e barerepo 1mo
10
"strings"
133728e barerepo 1mo
11
)
133728e barerepo 1mo
12
133728e barerepo 1mo
13
const (
133728e barerepo 1mo
14
flush = "0000"
133728e barerepo 1mo
15
delim = "0001"
133728e barerepo 1mo
16
)
133728e barerepo 1mo
17
133728e barerepo 1mo
18
// ErrFlush is returned by Read when it reads a flush packet.
133728e barerepo 1mo
19
var ErrFlush = errors.New("flush")
133728e barerepo 1mo
20
133728e barerepo 1mo
21
// ErrDelim is returned by Read when it reads a delimiter packet.
133728e barerepo 1mo
22
var ErrDelim = errors.New("delim")
133728e barerepo 1mo
23
133728e barerepo 1mo
24
type Reader struct{ r *bufio.Reader }
133728e barerepo 1mo
25
133728e barerepo 1mo
26
func NewReader(r io.Reader) *Reader { return &Reader{bufio.NewReader(r)} }
133728e barerepo 1mo
27
133728e barerepo 1mo
28
// Read returns the next packet's payload, with any trailing newline removed.
133728e barerepo 1mo
29
func (p *Reader) Read() (string, error) {
133728e barerepo 1mo
30
var head [4]byte
133728e barerepo 1mo
31
if _, err := io.ReadFull(p.r, head[:]); err != nil {
133728e barerepo 1mo
32
return "", err
133728e barerepo 1mo
33
}
133728e barerepo 1mo
34
n, err := strconv.ParseUint(string(head[:]), 16, 32)
133728e barerepo 1mo
35
if err != nil {
133728e barerepo 1mo
36
return "", fmt.Errorf("malformed pkt-line length %q", head)
133728e barerepo 1mo
37
}
133728e barerepo 1mo
38
switch n {
133728e barerepo 1mo
39
case 0:
133728e barerepo 1mo
40
return "", ErrFlush
133728e barerepo 1mo
41
case 1:
133728e barerepo 1mo
42
return "", ErrDelim
133728e barerepo 1mo
43
}
133728e barerepo 1mo
44
if n < 4 {
133728e barerepo 1mo
45
return "", fmt.Errorf("impossible pkt-line length %d", n)
133728e barerepo 1mo
46
}
133728e barerepo 1mo
47
body := make([]byte, n-4)
133728e barerepo 1mo
48
if _, err := io.ReadFull(p.r, body); err != nil {
133728e barerepo 1mo
49
return "", err
133728e barerepo 1mo
50
}
133728e barerepo 1mo
51
return strings.TrimSuffix(string(body), "\n"), nil
133728e barerepo 1mo
52
}
133728e barerepo 1mo
53
133728e barerepo 1mo
54
type Writer struct{ w io.Writer }
133728e barerepo 1mo
55
133728e barerepo 1mo
56
func NewWriter(w io.Writer) *Writer { return &Writer{w} }
133728e barerepo 1mo
57
133728e barerepo 1mo
58
// Write sends one packet with a newline, which git expects for these text protocols.
133728e barerepo 1mo
59
func (p *Writer) Write(s string) error {
133728e barerepo 1mo
60
if len(s)+5 > 0xffff {
133728e barerepo 1mo
61
return errors.New("pkt-line too long")
133728e barerepo 1mo
62
}
133728e barerepo 1mo
63
_, err := fmt.Fprintf(p.w, "%04x%s\n", len(s)+5, s)
133728e barerepo 1mo
64
return err
133728e barerepo 1mo
65
}
133728e barerepo 1mo
66
133728e barerepo 1mo
67
// Flush sends a flush packet, which ends a section.
133728e barerepo 1mo
68
func (p *Writer) Flush() error {
133728e barerepo 1mo
69
_, err := io.WriteString(p.w, flush)
133728e barerepo 1mo
70
return err
133728e barerepo 1mo
71
}
133728e barerepo 1mo
72
133728e barerepo 1mo
73
// Delim sends a delimiter packet.
133728e barerepo 1mo
74
func (p *Writer) Delim() error {
133728e barerepo 1mo
75
_, err := io.WriteString(p.w, delim)
133728e barerepo 1mo
76
return err
133728e barerepo 1mo
77
}
history · rawbarerepo 0.1.0