-
Notifications
You must be signed in to change notification settings - Fork 31
/
binding.go
144 lines (119 loc) · 3.71 KB
/
binding.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package types
import (
"encoding/json"
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)
// NewServiceBinding creates a new ServiceBinding instance
func NewServiceBinding(
serviceName string,
provider sdk.AccAddress,
deposit sdk.Coins,
pricing string,
qos uint64,
options string,
available bool,
disabledTime time.Time,
owner sdk.AccAddress,
) ServiceBinding {
return ServiceBinding{
ServiceName: serviceName,
Provider: provider.String(),
Deposit: deposit,
Pricing: pricing,
QoS: qos,
Options: options,
Available: available,
DisabledTime: disabledTime,
Owner: owner.String(),
}
}
// RawPricing represents the raw pricing of a service binding
type RawPricing struct {
Price string `json:"price"` // base price string
PromotionsByTime []PromotionByTime `json:"promotions_by_time"` // promotions by time
PromotionsByVolume []PromotionByVolume `json:"promotions_by_volume"` // promotions by volume
}
// GetDiscountByTime gets the discount level by the specified time
func GetDiscountByTime(pricing Pricing, time time.Time) sdk.Dec {
for _, p := range pricing.PromotionsByTime {
if !time.Before(p.StartTime) && time.Before(p.EndTime) {
return p.Discount
}
}
return sdk.OneDec()
}
// GetDiscountByVolume gets the discount level by the specified volume
// Note: make sure that the promotions by volume are sorted in ascending order
func GetDiscountByVolume(pricing Pricing, volume uint64) sdk.Dec {
promotionsByVol := pricing.PromotionsByVolume
for i, p := range promotionsByVol {
if volume < p.Volume {
if i == 0 {
return sdk.OneDec()
}
return promotionsByVol[i-1].Discount
}
if i == len(promotionsByVol)-1 {
return p.Discount
}
}
return sdk.OneDec()
}
// ParsePricing parses the given string to Pricing
func ParsePricing(pricing string) (p Pricing, err error) {
var rawPricing RawPricing
if err := json.Unmarshal([]byte(pricing), &rawPricing); err != nil {
return p, sdkerrors.Wrapf(ErrInvalidPricing, "failed to unmarshal the pricing: %s", err.Error())
}
priceCoin, err := sdk.ParseCoinNormalized(rawPricing.Price)
if err != nil {
return p, sdkerrors.Wrapf(ErrInvalidPricing, "invalid price: %s", err.Error())
}
p.Price = sdk.Coins{priceCoin}
p.PromotionsByTime = rawPricing.PromotionsByTime
p.PromotionsByVolume = rawPricing.PromotionsByVolume
return p, nil
}
// CheckPricing checks if the given pricing complies with the specific rules
func CheckPricing(pricing Pricing) error {
// CONTRACT:
// p.EndTime > p.StartTime
// p[i].StartTime >= p[i-1].EndTime
for i, p := range pricing.PromotionsByTime {
if !p.EndTime.After(p.StartTime) || (i > 0 && p.StartTime.Before(pricing.PromotionsByTime[i-1].EndTime)) {
return sdkerrors.Wrapf(ErrInvalidPricing, "invalid timing promotion %d", i)
}
}
// CONTRACT:
// p[i].Volume > p[i-1].Volume
for i, p := range pricing.PromotionsByVolume {
if i > 0 && p.Volume < pricing.PromotionsByVolume[i-1].Volume {
return sdkerrors.Wrapf(ErrInvalidPricing, "invalid volume promotion %d", i)
}
}
return nil
}
// Validate validates the service binding
func (binding ServiceBinding) Validate() error {
if err := ValidateProvider(binding.Provider); err != nil {
return err
}
if err := ValidateOwner(binding.Owner); err != nil {
return err
}
if err := ValidateServiceName(binding.ServiceName); err != nil {
return err
}
if err := ValidateServiceDeposit(binding.Deposit); err != nil {
return err
}
if err := ValidateQoS(binding.QoS); err != nil {
return err
}
if err := ValidateOptions(binding.Options); err != nil {
return err
}
return ValidateBindingPricing(binding.Pricing)
}