package spec import ( "fmt" "time" "github.com/cloudevents/sdk-go/v2/event" "github.com/cloudevents/sdk-go/v2/types" ) // Kind is a version-independent identifier for a CloudEvent context attribute. type Kind uint8 const ( // Required cloudevents attributes ID Kind = iota Source SpecVersion Type // Optional cloudevents attributes DataContentType DataSchema Subject Time ) const nAttrs = int(Time) + 1 var kindNames = [nAttrs]string{ "id", "source", "specversion", "type", "datacontenttype", "dataschema", "subject", "time", } // String is a human-readable string, for a valid attribute name use Attribute.Name func (k Kind) String() string { return kindNames[k] } // IsRequired returns true for attributes defined as "required" by the CE spec. func (k Kind) IsRequired() bool { return k < DataContentType } // Attribute is a named attribute accessor. // The attribute name is specific to a Version. type Attribute interface { Kind() Kind // Name of the attribute with respect to the current spec Version() with prefix PrefixedName() string // Name of the attribute with respect to the current spec Version() Name() string // Version of the spec that this attribute belongs to Version() Version // Get the value of this attribute from an event context Get(event.EventContextReader) interface{} // Set the value of this attribute on an event context Set(event.EventContextWriter, interface{}) error // Delete this attribute from and event context, when possible Delete(event.EventContextWriter) error } // accessor provides Kind, Get, Set. type accessor interface { Kind() Kind Get(event.EventContextReader) interface{} Set(event.EventContextWriter, interface{}) error Delete(event.EventContextWriter) error } var acc = [nAttrs]accessor{ &aStr{aKind(ID), event.EventContextReader.GetID, event.EventContextWriter.SetID}, &aStr{aKind(Source), event.EventContextReader.GetSource, event.EventContextWriter.SetSource}, &aStr{aKind(SpecVersion), event.EventContextReader.GetSpecVersion, func(writer event.EventContextWriter, s string) error { return nil }}, &aStr{aKind(Type), event.EventContextReader.GetType, event.EventContextWriter.SetType}, &aStr{aKind(DataContentType), event.EventContextReader.GetDataContentType, event.EventContextWriter.SetDataContentType}, &aStr{aKind(DataSchema), event.EventContextReader.GetDataSchema, event.EventContextWriter.SetDataSchema}, &aStr{aKind(Subject), event.EventContextReader.GetSubject, event.EventContextWriter.SetSubject}, &aTime{aKind(Time), event.EventContextReader.GetTime, event.EventContextWriter.SetTime}, } // aKind implements Kind() type aKind Kind func (kind aKind) Kind() Kind { return Kind(kind) } type aStr struct { aKind get func(event.EventContextReader) string set func(event.EventContextWriter, string) error } func (a *aStr) Get(c event.EventContextReader) interface{} { if s := a.get(c); s != "" { return s } return nil // Treat blank as missing } func (a *aStr) Set(c event.EventContextWriter, v interface{}) error { s, err := types.ToString(v) if err != nil { return fmt.Errorf("invalid value for %s: %#v", a.Kind(), v) } return a.set(c, s) } func (a *aStr) Delete(c event.EventContextWriter) error { return a.set(c, "") } type aTime struct { aKind get func(event.EventContextReader) time.Time set func(event.EventContextWriter, time.Time) error } func (a *aTime) Get(c event.EventContextReader) interface{} { if v := a.get(c); !v.IsZero() { return v } return nil // Treat zero time as missing. } func (a *aTime) Set(c event.EventContextWriter, v interface{}) error { t, err := types.ToTime(v) if err != nil { return fmt.Errorf("invalid value for %s: %#v", a.Kind(), v) } return a.set(c, t) } func (a *aTime) Delete(c event.EventContextWriter) error { return a.set(c, time.Time{}) }