1/*
2 * Copyright 2019 gRPC authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//go:generate protoc -I ./orca_v1 --go_out=plugins=grpc:./orca_v1 ./orca_v1/orca.proto
18
19// Package orca implements Open Request Cost Aggregation.
20package orca
21
22import (
23	"github.com/golang/protobuf/proto"
24	"google.golang.org/grpc/grpclog"
25	"google.golang.org/grpc/internal/balancerload"
26	orcapb "google.golang.org/grpc/internal/balancerload/orca/orca_v1"
27	"google.golang.org/grpc/metadata"
28)
29
30const mdKey = "X-Endpoint-Load-Metrics-Bin"
31
32// toBytes converts a orca load report into bytes.
33func toBytes(r *orcapb.LoadReport) []byte {
34	if r == nil {
35		return nil
36	}
37
38	b, err := proto.Marshal(r)
39	if err != nil {
40		grpclog.Warningf("orca: failed to marshal load report: %v", err)
41		return nil
42	}
43	return b
44}
45
46// ToMetadata converts a orca load report into grpc metadata.
47func ToMetadata(r *orcapb.LoadReport) metadata.MD {
48	b := toBytes(r)
49	if b == nil {
50		return nil
51	}
52	return metadata.Pairs(mdKey, string(b))
53}
54
55// fromBytes reads load report bytes and converts it to orca.
56func fromBytes(b []byte) *orcapb.LoadReport {
57	ret := new(orcapb.LoadReport)
58	if err := proto.Unmarshal(b, ret); err != nil {
59		grpclog.Warningf("orca: failed to unmarshal load report: %v", err)
60		return nil
61	}
62	return ret
63}
64
65// FromMetadata reads load report from metadata and converts it to orca.
66//
67// It returns nil if report is not found in metadata.
68func FromMetadata(md metadata.MD) *orcapb.LoadReport {
69	vs := md.Get(mdKey)
70	if len(vs) == 0 {
71		return nil
72	}
73	return fromBytes([]byte(vs[0]))
74}
75
76type loadParser struct{}
77
78func (*loadParser) Parse(md metadata.MD) interface{} {
79	return FromMetadata(md)
80}
81
82func init() {
83	balancerload.SetParser(&loadParser{})
84}
85