1package protocol
2
3import (
4	"fmt"
5	"time"
6)
7
8// Write writes out data to a line protocol encoder.  Note: it does no sorting.  It assumes you have done your own sorting for tagValues
9func (e *Encoder) Write(name []byte, ts time.Time, tagKeys, tagVals, fieldKeys [][]byte, fieldVals []interface{}) (int, error) {
10	e.header = e.header[:0]
11	if len(name) == 0 || name[len(name)-1] == byte('\\') {
12		return 0, ErrInvalidName
13	}
14	nameEscapeBytes(&e.header, name)
15	for i := range tagKeys {
16		// Some keys and values are not encodeable as line protocol, such as
17		// those with a trailing '\' or empty strings.
18		if len(tagKeys[i]) == 0 || len(tagVals[i]) == 0 || tagKeys[i][len(tagKeys[i])-1] == byte('\\') {
19			if e.failOnFieldError {
20				return 0, fmt.Errorf("invalid field: key \"%s\", val \"%s\"", tagKeys[i], tagVals[i])
21			}
22			continue
23		}
24		e.header = append(e.header, byte(','))
25		escapeBytes(&e.header, tagKeys[i])
26		e.header = append(e.header, byte('='))
27		escapeBytes(&e.header, tagVals[i])
28	}
29	e.header = append(e.header, byte(' '))
30	e.buildFooter(ts)
31
32	i := 0
33	totalWritten := 0
34	pairsLen := 0
35	firstField := true
36	for i := range fieldKeys {
37		e.pair = e.pair[:0]
38		key := fieldKeys[i]
39		if len(key) == 0 || key[len(key)-1] == byte('\\') {
40			if e.failOnFieldError {
41				return 0, &FieldError{"invalid field key"}
42			}
43			continue
44		}
45		escapeBytes(&e.pair, key)
46		// Some keys are not encodeable as line protocol, such as those with a
47		// trailing '\' or empty strings.
48		e.pair = append(e.pair, byte('='))
49		err := e.buildFieldVal(fieldVals[i])
50		if err != nil {
51			if e.failOnFieldError {
52				return 0, err
53			}
54			continue
55		}
56
57		bytesNeeded := len(e.header) + pairsLen + len(e.pair) + len(e.footer)
58
59		// Additional length needed for field separator `,`
60		if !firstField {
61			bytesNeeded++
62		}
63
64		if e.maxLineBytes > 0 && bytesNeeded > e.maxLineBytes {
65			// Need at least one field per line
66			if firstField {
67				return 0, ErrNeedMoreSpace
68			}
69
70			i, err = e.w.Write(e.footer)
71			if err != nil {
72				return 0, err
73			}
74			totalWritten += i
75
76			bytesNeeded = len(e.header) + len(e.pair) + len(e.footer)
77
78			if e.maxLineBytes > 0 && bytesNeeded > e.maxLineBytes {
79				return 0, ErrNeedMoreSpace
80			}
81
82			i, err = e.w.Write(e.header)
83			if err != nil {
84				return 0, err
85			}
86			totalWritten += i
87
88			i, err = e.w.Write(e.pair)
89			if err != nil {
90				return 0, err
91			}
92			totalWritten += i
93
94			pairsLen += len(e.pair)
95			firstField = false
96			continue
97		}
98
99		if firstField {
100			i, err = e.w.Write(e.header)
101			if err != nil {
102				return 0, err
103			}
104			totalWritten += i
105
106		} else {
107			i, err = e.w.Write(comma)
108			if err != nil {
109				return 0, err
110			}
111			totalWritten += i
112
113		}
114
115		e.w.Write(e.pair)
116
117		pairsLen += len(e.pair)
118		firstField = false
119	}
120
121	if firstField {
122		return 0, ErrNoFields
123	}
124	i, err := e.w.Write(e.footer)
125	if err != nil {
126		return 0, err
127	}
128	totalWritten += i
129	return totalWritten, nil
130}
131