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