package proto import ( "fmt" octopus "gordenko.dev/dima/diploma" "gordenko.dev/dima/diploma/bin" "gordenko.dev/dima/diploma/bufreader" ) const ( TypeDeleteMeasures byte = 1 TypeListCurrentValues byte = 2 TypeListInstantMeasures byte = 3 TypeListCumulativeMeasures byte = 33 TypeListInstantPeriods byte = 4 TypeListCumulativePeriods byte = 44 TypeGetMetric byte = 5 TypeAddMetric byte = 6 TypeListAllInstantMeasures byte = 8 TypeListAllCumulativeMeasures byte = 88 TypeRangeTotal byte = 9 TypeAppendMeasure byte = 10 TypeAppendMeasures byte = 11 TypeDeleteMetric byte = 12 RespPartOfValue byte = 255 RespEndOfValue byte = 254 RespError byte = 253 RespSuccess byte = 252 RespValue byte = 251 ErrNoMetric = 1 ErrDuplicate = 2 ErrWrongMetricType = 3 ErrWrongFracDigits = 4 ErrExpiredMeasure = 5 ErrNonMonotonicValue = 6 ErrEmptyMetricID = 7 ErrInvalidRange = 8 ErrUnexpected = 9 ) func ErrorCodeToText(code uint16) string { switch code { case ErrNoMetric: return "NoMetric" case ErrDuplicate: return "Duplicate" case ErrWrongMetricType: return "WrongMetricType" case ErrWrongFracDigits: return "WrongFracDigits" case ErrExpiredMeasure: return "ExpiredMeasure" case ErrNonMonotonicValue: return "NonMonotonicValue" case ErrEmptyMetricID: return "EmptyMetricID" case ErrInvalidRange: return "InvalidRange" case ErrUnexpected: return "Unexpected" default: return "" } } type GetMetricReq struct { MetricID uint32 } type ListCurrentValuesReq struct { MetricIDs []uint32 } type AddMetricReq struct { MetricID uint32 MetricType octopus.MetricType FracDigits int } type UpdateMetricReq struct { MetricID uint32 MetricType octopus.MetricType FracDigits int } type DeleteMetricReq struct { MetricID uint32 } type DeleteMeasuresReq struct { MetricID uint32 Since uint32 // timestamp (optional) } type AppendMeasureReq struct { MetricID uint32 Timestamp uint32 Value float64 } type ListAllInstantMetricMeasuresReq struct { MetricID uint32 } type ListAllCumulativeMeasuresReq struct { MetricID uint32 } type ListInstantMeasuresReq struct { MetricID uint32 Since uint32 Until uint32 FirstHourOfDay int } type ListCumulativeMeasuresReq struct { MetricID uint32 Since uint32 Until uint32 FirstHourOfDay int } type ListInstantPeriodsReq struct { MetricID uint32 Since uint32 Until uint32 GroupBy octopus.GroupBy AggregateFuncs byte FirstHourOfDay int } type ListCumulativePeriodsReq struct { MetricID uint32 Since uint32 Until uint32 GroupBy octopus.GroupBy FirstHourOfDay int } type Metric struct { MetricID uint32 MetricType octopus.MetricType FracDigits int } type RangeTotalReq struct { MetricID uint32 Since uint32 Until uint32 } func PackAddMetricReq(req AddMetricReq) []byte { arr := []byte{ TypeAddMetric, 0, 0, 0, 0, // byte(req.MetricType), byte(req.FracDigits), } bin.PutUint32(arr[1:], req.MetricID) return arr } func PackDeleteMetricReq(req DeleteMetricReq) []byte { arr := []byte{ TypeDeleteMetric, 0, 0, 0, 0, // metricID } bin.PutUint32(arr[1:], req.MetricID) return arr } func PackAppendMeasure(req AppendMeasureReq) []byte { arr := []byte{ TypeAppendMeasure, 0, 0, 0, 0, // metricID 0, 0, 0, 0, // timestamp 0, 0, 0, 0, 0, 0, 0, 0, // value } bin.PutUint32(arr[1:], req.MetricID) bin.PutUint32(arr[5:], uint32(req.Timestamp)) bin.PutFloat64(arr[9:], req.Value) return arr } func PackDeleteMeasuresReq(req DeleteMeasuresReq) []byte { arr := []byte{ TypeDeleteMeasures, 0, 0, 0, 0, // metricID 0, 0, 0, 0, // since } bin.PutUint32(arr[1:], req.MetricID) bin.PutUint32(arr[5:], uint32(req.Since)) return arr } // UNPACK reqs func UnpackAddMetricReq(arr []byte) (m AddMetricReq) { m.MetricID = bin.GetUint32(arr) m.MetricType = octopus.MetricType(arr[4]) m.FracDigits = int(arr[5]) return } func UnpackUpdateMetricReq(arr []byte) (m UpdateMetricReq) { m.MetricID = bin.GetUint32(arr) m.MetricType = octopus.MetricType(arr[4]) m.FracDigits = int(arr[5]) return } func UnpackDeleteMetricReq(arr []byte) (m DeleteMetricReq) { m.MetricID = bin.GetUint32(arr) return } func UnpackAppendMeasureReq(arr []byte) (m AppendMeasureReq) { m.MetricID = bin.GetUint32(arr) m.Timestamp = bin.GetUint32(arr[4:]) m.Value = bin.GetFloat64(arr[8:]) return } func UnpackDeleteMeasuresReq(arr []byte) (m DeleteMeasuresReq) { m.MetricID = bin.GetUint32(arr) m.Since = bin.GetUint32(arr[4:]) return } func UnpackListInstantMeasuresReq(arr []byte) (m ListInstantMeasuresReq) { m.MetricID = bin.GetUint32(arr[0:]) m.Since = bin.GetUint32(arr[4:]) m.Until = bin.GetUint32(arr[8:]) m.FirstHourOfDay = int(arr[12]) return } func UnpackListCumulativeMeasuresReq(arr []byte) (m ListCumulativeMeasuresReq) { m.MetricID = bin.GetUint32(arr) m.Since = bin.GetUint32(arr[4:]) m.Until = bin.GetUint32(arr[8:]) m.FirstHourOfDay = int(arr[12]) return } func UnpackListInstantPeriodsReq(arr []byte) (m ListInstantPeriodsReq) { m.MetricID = bin.GetUint32(arr) m.Since = bin.GetUint32(arr[4:]) m.Until = bin.GetUint32(arr[8:]) m.GroupBy = octopus.GroupBy(arr[12]) m.AggregateFuncs = arr[13] m.FirstHourOfDay = int(arr[14]) return } func UnpackListCumulativePeriodsReq(arr []byte) (m ListCumulativePeriodsReq) { m.MetricID = bin.GetUint32(arr[0:]) m.Since = bin.GetUint32(arr[4:]) m.Until = bin.GetUint32(arr[8:]) m.GroupBy = octopus.GroupBy(arr[12]) m.FirstHourOfDay = int(arr[13]) return } func UnpackRangeTotalReq(arr []byte) (m RangeTotalReq) { m.MetricID = bin.GetUint32(arr) m.Since = bin.GetUint32(arr[4:]) m.Until = bin.GetUint32(arr[8:]) return } // READ reqs func ReadGetMetricReq(r *bufreader.BufferedReader) (m GetMetricReq, err error) { m.MetricID, err = bin.ReadUint32(r) if err != nil { err = fmt.Errorf("read req: %s", err) return } return } func ReadAddMetricReq(r *bufreader.BufferedReader) (m AddMetricReq, err error) { arr, err := r.ReadN(6) if err != nil { err = fmt.Errorf("read req: %s", err) return } return UnpackAddMetricReq(arr), nil } func ReadUpdateMetricReq(r *bufreader.BufferedReader) (m UpdateMetricReq, err error) { arr, err := r.ReadN(6) if err != nil { err = fmt.Errorf("read req: %s", err) return } return UnpackUpdateMetricReq(arr), nil } func ReadDeleteMetricReq(r *bufreader.BufferedReader) (m DeleteMetricReq, err error) { m.MetricID, err = bin.ReadUint32(r) if err != nil { err = fmt.Errorf("read req: %s", err) return } return } func ReadAppendMeasureReq(r *bufreader.BufferedReader) (m AppendMeasureReq, err error) { arr, err := r.ReadN(16) if err != nil { err = fmt.Errorf("read req: %s", err) return } return UnpackAppendMeasureReq(arr), nil } func ReadDeleteMeasuresReq(r *bufreader.BufferedReader) (m DeleteMeasuresReq, err error) { arr, err := r.ReadN(8) if err != nil { err = fmt.Errorf("read req: %s", err) return } return UnpackDeleteMeasuresReq(arr), nil } func ReadListAllInstantMeasuresReq(r *bufreader.BufferedReader) (m ListAllInstantMetricMeasuresReq, err error) { m.MetricID, err = bin.ReadUint32(r) if err != nil { err = fmt.Errorf("read req: %s", err) return } return } func ReadListAllCumulativeMeasuresReq(r *bufreader.BufferedReader) (m ListAllCumulativeMeasuresReq, err error) { m.MetricID, err = bin.ReadUint32(r) if err != nil { err = fmt.Errorf("read req: %s", err) return } return } func ReadListInstantMeasuresReq(r *bufreader.BufferedReader) (m ListInstantMeasuresReq, err error) { arr, err := r.ReadN(13) if err != nil { err = fmt.Errorf("read req: %s", err) return } return UnpackListInstantMeasuresReq(arr), nil } func ReadListCumulativeMeasuresReq(r *bufreader.BufferedReader) (m ListCumulativeMeasuresReq, err error) { arr, err := r.ReadN(13) if err != nil { err = fmt.Errorf("read req: %s", err) return } return UnpackListCumulativeMeasuresReq(arr), nil } func ReadListInstantPeriodsReq(r *bufreader.BufferedReader) (m ListInstantPeriodsReq, err error) { arr, err := r.ReadN(15) if err != nil { err = fmt.Errorf("read req: %s", err) return } return UnpackListInstantPeriodsReq(arr), nil } func ReadListCumulativePeriodsReq(r *bufreader.BufferedReader) (m ListCumulativePeriodsReq, err error) { arr, err := r.ReadN(14) if err != nil { err = fmt.Errorf("read req: %s", err) return } return UnpackListCumulativePeriodsReq(arr), nil } func ReadRangeTotalReq(r *bufreader.BufferedReader) (m RangeTotalReq, err error) { arr, err := r.ReadN(12) if err != nil { err = fmt.Errorf("read req: %s", err) return } return UnpackRangeTotalReq(arr), nil } func ReadListCurrentValuesReq(r *bufreader.BufferedReader) (m ListCurrentValuesReq, err error) { qty, err := bin.ReadUint16(r) if err != nil { err = fmt.Errorf("read req: %s", err) return } for i := range int(qty) { var metricID uint32 metricID, err = bin.ReadUint32(r) if err != nil { err = fmt.Errorf("read metricID (#%d): %s", i, err) return } m.MetricIDs = append(m.MetricIDs, metricID) } return } type AppendMeasuresReq struct { MetricID uint32 Measures []Measure } type Measure struct { Timestamp uint32 Value float64 } func PackAppendMeasures(req AppendMeasuresReq) []byte { if len(req.Measures) > 65535 { panic(fmt.Errorf("wrong measures qty: %d", len(req.Measures))) } var ( prefixSize = 7 recordSize = 12 arr = make([]byte, prefixSize+len(req.Measures)*recordSize) ) arr[0] = TypeAppendMeasures bin.PutUint32(arr[1:], req.MetricID) bin.PutUint16(arr[5:], uint16(len(req.Measures))) pos := prefixSize for _, measure := range req.Measures { bin.PutUint32(arr[pos:], measure.Timestamp) bin.PutFloat64(arr[pos+4:], measure.Value) pos += recordSize } return arr } func ReadAppendMeasuresReq(r *bufreader.BufferedReader) (m AppendMeasuresReq, err error) { prefix, err := bin.ReadN(r, 6) // metricID + measures qty if err != nil { err = fmt.Errorf("read prefix: %s", err) return } m.MetricID = bin.GetUint32(prefix[0:]) qty := bin.GetUint16(prefix[4:]) for i := range int(qty) { var measure Measure measure.Timestamp, err = bin.ReadUint32(r) if err != nil { err = fmt.Errorf("read timestamp (#%d): %s", i, err) return } measure.Value, err = bin.ReadFloat64(r) if err != nil { err = fmt.Errorf("read value (#%d): %s", i, err) return } m.Measures = append(m.Measures, measure) } return }