diff --git a/channel_config.go b/channel_config.go index 7db8823..faa0708 100644 --- a/channel_config.go +++ b/channel_config.go @@ -1,5 +1,10 @@ package stream_chat +import ( + "strconv" + "time" +) + // ChannelConfig is the configuration for a channel. type ChannelConfig struct { Name string `json:"name"` @@ -34,6 +39,47 @@ type ChannelConfig struct { BlockList string `json:"blocklist"` BlockListBehavior modBehaviour `json:"blocklist_behavior"` AutomodThresholds *Thresholds `json:"automod_thresholds"` + + // Dynamic Partitioning + PartitionSize int `json:"partition_size,omitempty"` + PartitionTTL *DurationString `json:"partition_ttl,omitempty"` +} + +// DurationString is a duration that's encoded to as a string in JSON. +type DurationString time.Duration + +// NewDurationString creates a pointer to a DurationString. +func NewDurationString(d time.Duration) *DurationString { + duration := DurationString(d) + return &duration +} + +// MarshalJSON encodes the duration as a string such as "2h30m". +func (d DurationString) MarshalJSON() ([]byte, error) { + if d == 0 { + return []byte("null"), nil + } + return []byte(`"` + time.Duration(d).String() + `"`), nil +} + +// String returns the duration as a string such as "2h30m". +func (d DurationString) String() string { + return time.Duration(d).String() +} + +// UnmarshalJSON decodes a duration from a string formatted as +// [time.Duration.String()](https://golang.org/pkg/time/#Duration.String) +func (d *DurationString) UnmarshalJSON(b []byte) error { + s, err := strconv.Unquote(string(b)) + if err != nil { + return err + } + dur, err := time.ParseDuration(s) + if err != nil { + return err + } + *d = DurationString(dur) + return nil } type LabelThresholds struct { diff --git a/channel_config_test.go b/channel_config_test.go new file mode 100644 index 0000000..f6417de --- /dev/null +++ b/channel_config_test.go @@ -0,0 +1,86 @@ +package stream_chat + +import ( + "encoding/json" + "testing" + "time" +) + +func TestDuration_MarshalJSON(t *testing.T) { + tests := []struct { + name string + input PartitionTTL + want string + }{ + { + name: "Zero", + input: PartitionTTL(0), + want: `null`, + }, + { + name: "Hours", + input: PartitionTTL(24 * time.Hour), + want: `"24h0m0s"`, + }, + { + name: "Mixed", + input: PartitionTTL(24*time.Hour + 30*time.Minute + 15*time.Second), + want: `"24h30m15s"`, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.input.MarshalJSON() + if err != nil { + t.Fatal(err) + } + if string(got) != tt.want { + t.Errorf("Duration.MarshalJSON() = %q, want %q", string(got), tt.want) + } + }) + } +} + +func TestDuration_UnmarshalJSON(t *testing.T) { + tests := []struct { + name string + input string + want PartitionTTL + wantErr bool + }{ + { + name: "Hours", + input: `"4h"`, + want: PartitionTTL(4 * time.Hour), + }, + { + name: "Mixed", + input: `"2h30m"`, + want: PartitionTTL(2*time.Hour + 30*time.Minute), + }, + { + name: "Full", + input: `"6h0m0s"`, + want: PartitionTTL(6 * time.Hour), + }, + { + name: "Invalid", + input: "daily", + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var got PartitionTTL + err := json.Unmarshal([]byte(tt.input), &got) + if (err != nil) != tt.wantErr { + t.Fatalf("Error = %q, want error: %t", err, tt.wantErr) + } + if got.String() != tt.want.String() { + t.Errorf("Duration.UnmarshalJSON() = %q, want %q", got, tt.want) + } + }) + } +}