1package protocol
2
3import (
4	"bytes"
5	"errors"
6	"strconv"
7	"time"
8)
9
10// MetricHandler implements the Handler interface and produces Metric.
11type MetricHandler struct {
12	timePrecision time.Duration
13	timeFunc      TimeFunc
14	metric        MutableMetric
15}
16
17func NewMetricHandler() *MetricHandler {
18	return &MetricHandler{
19		timePrecision: time.Nanosecond,
20		timeFunc:      time.Now,
21	}
22}
23
24func (h *MetricHandler) SetTimePrecision(p time.Duration) {
25	h.timePrecision = p
26	// When the timestamp is omitted from the metric, the timestamp
27	// comes from the server clock, truncated to the nearest unit of
28	// measurement provided in precision.
29	//
30	// When a timestamp is provided in the metric, precsision is
31	// overloaded to hold the unit of measurement of the timestamp.
32}
33
34func (h *MetricHandler) SetTimeFunc(f TimeFunc) {
35	h.timeFunc = f
36}
37
38func (h *MetricHandler) Metric() (Metric, error) {
39	if h.metric.Time().IsZero() {
40		h.metric.SetTime(h.timeFunc().Truncate(h.timePrecision))
41	}
42	return h.metric, nil
43}
44
45func (h *MetricHandler) SetMeasurement(name []byte) error {
46	var err error
47	h.metric, err = New(nameUnescape(name),
48		nil, nil, time.Time{})
49	return err
50}
51
52func (h *MetricHandler) AddTag(key []byte, value []byte) error {
53	tk := unescape(key)
54	tv := unescape(value)
55	h.metric.AddTag(tk, tv)
56	return nil
57}
58
59func (h *MetricHandler) AddInt(key []byte, value []byte) error {
60	fk := unescape(key)
61	fv, err := parseIntBytes(bytes.TrimSuffix(value, []byte("i")), 10, 64)
62	if err != nil {
63		if numerr, ok := err.(*strconv.NumError); ok {
64			return numerr.Err
65		}
66		return err
67	}
68	h.metric.AddField(fk, fv)
69	return nil
70}
71
72func (h *MetricHandler) AddUint(key []byte, value []byte) error {
73	fk := unescape(key)
74	fv, err := parseUintBytes(bytes.TrimSuffix(value, []byte("u")), 10, 64)
75	if err != nil {
76		if numerr, ok := err.(*strconv.NumError); ok {
77			return numerr.Err
78		}
79		return err
80	}
81	h.metric.AddField(fk, fv)
82	return nil
83}
84
85func (h *MetricHandler) AddFloat(key []byte, value []byte) error {
86	fk := unescape(key)
87	fv, err := parseFloatBytes(value, 64)
88	if err != nil {
89		if numerr, ok := err.(*strconv.NumError); ok {
90			return numerr.Err
91		}
92		return err
93	}
94	h.metric.AddField(fk, fv)
95	return nil
96}
97
98func (h *MetricHandler) AddString(key []byte, value []byte) error {
99	fk := unescape(key)
100	fv := stringFieldUnescape(value)
101	h.metric.AddField(fk, fv)
102	return nil
103}
104
105func (h *MetricHandler) AddBool(key []byte, value []byte) error {
106	fk := unescape(key)
107	fv, err := parseBoolBytes(value)
108	if err != nil {
109		return errors.New("unparseable bool")
110	}
111	h.metric.AddField(fk, fv)
112	return nil
113}
114
115func (h *MetricHandler) SetTimestamp(tm []byte) error {
116	v, err := parseIntBytes(tm, 10, 64)
117	if err != nil {
118		if numerr, ok := err.(*strconv.NumError); ok {
119			return numerr.Err
120		}
121		return err
122	}
123
124	//time precision is overloaded to mean time unit here
125	ns := v * int64(h.timePrecision)
126	h.metric.SetTime(time.Unix(0, ns))
127	return nil
128}
129