mapping.go raw
1 package selfhostde
2
3 import (
4 "errors"
5 "fmt"
6 "strings"
7 )
8
9 const (
10 lineSep = ","
11 recordSep = ":"
12 )
13
14 type Seq struct {
15 cursor int
16 ids []string
17 }
18
19 func NewSeq(ids ...string) *Seq {
20 return &Seq{ids: ids}
21 }
22
23 func (s *Seq) Next() string {
24 if len(s.ids) == 1 {
25 return s.ids[0]
26 }
27
28 v := s.ids[s.cursor]
29
30 if s.cursor < len(s.ids)-1 {
31 s.cursor++
32 } else {
33 s.cursor = 0
34 }
35
36 return v
37 }
38
39 func parseRecordsMapping(raw string) (map[string]*Seq, error) {
40 raw = strings.ReplaceAll(raw, " ", "")
41
42 if raw == "" {
43 return nil, errors.New("empty mapping")
44 }
45
46 acc := map[string]*Seq{}
47
48 for {
49 index, err := safeIndex(raw, lineSep)
50 if err != nil {
51 return nil, err
52 }
53
54 if index != -1 {
55 name, seq, err := parseLine(raw[:index])
56 if err != nil {
57 return nil, err
58 }
59
60 acc[name] = seq
61
62 // Data for the next iteration.
63 raw = raw[index+1:]
64
65 continue
66 }
67
68 name, seq, errP := parseLine(raw)
69 if errP != nil {
70 return nil, errP
71 }
72
73 acc[name] = seq
74
75 return acc, nil
76 }
77 }
78
79 func parseLine(line string) (string, *Seq, error) {
80 idx, err := safeIndex(line, recordSep)
81 if err != nil {
82 return "", nil, err
83 }
84
85 if idx == -1 {
86 return "", nil, fmt.Errorf("missing %q: %s", recordSep, line)
87 }
88
89 name, rawIDs := line[:idx], line[idx+1:]
90
91 var (
92 ids []string
93 count int
94 )
95
96 for {
97 idx, err = safeIndex(rawIDs, recordSep)
98 if err != nil {
99 return "", nil, err
100 }
101
102 if count == 2 {
103 return "", nil, fmt.Errorf("too many record IDs for one domain: %s", line)
104 }
105
106 if idx != -1 {
107 ids = append(ids, rawIDs[:idx])
108 count++
109
110 // Data for the next iteration.
111 rawIDs = rawIDs[idx+1:]
112
113 continue
114 }
115
116 ids = append(ids, rawIDs)
117
118 return name, NewSeq(ids...), nil
119 }
120 }
121
122 func safeIndex(v, sep string) (int, error) {
123 index := strings.Index(v, sep)
124 if index == 0 {
125 return 0, fmt.Errorf("first char is %q: %s", sep, v)
126 }
127
128 if index == len(v)-1 {
129 return 0, fmt.Errorf("last char is %q: %s", sep, v)
130 }
131
132 return index, nil
133 }
134