Documentation ¶
Overview ¶
Package goics is a toolkit for encoding and decoding ics/Ical/icalendar files.
This is a work in progress project, that will try to incorporate as many exceptions and variants of the format.
This is a toolkit because user has to define the way it needs the data. The idea is builded with something similar to the consumer/provider pattern.
We want to decode a stream of vevents from a .ics file into a custom type Events
type Event struct { Start, End time.Time Id, Summary string } type Events []Event func (e *Events) ConsumeICal(c *goics.Calendar, err error) error { for _, el := range c.Events { node := el.Data dtstart, err := node["DTSTART"].DateDecode() if err != nil { return err } dtend, err := node["DTEND"].DateDecode() if err != nil { return err } d := Event{ Start: dtstart, End: dtend, Id: node["UID"].Val, Summary: node["SUMMARY"].Val, } *e = append(*e, d) } return nil }
Our custom type, will need to implement ICalConsumer interface, where, the type will pick up data from the format. The decoding process will be somthing like this:
d := goics.NewDecoder(strings.NewReader(testConsumer)) consumer := Events{} err := d.Decode(&consumer)
I have choosed this model, because, this format is a pain and also I don't like a lot the reflect package.
For encoding objects to iCal format, something similar has to be done:
The object emitting elements for the encoder, will have to implement the ICalEmiter, returning a Component structure to be encoded. This also had been done, because every package could require to encode vals and keys their way. Just for encoding time, I found more than three types of lines.
type EventTest struct { component goics.Componenter } func (evt *EventTest) EmitICal() goics.Componenter { return evt.component }
The Componenter, is an interface that every Component that can be encoded to ical implements.
c := goics.NewComponent() c.SetType("VCALENDAR") c.AddProperty("CALSCAL", "GREGORIAN") c.AddProperty("PRODID", "-//tmpo.io/src/goics") m := goics.NewComponent() m.SetType("VEVENT") m.AddProperty("UID", "testing") c.AddComponent(m)
Properties, had to be stored as strings, the conversion from origin type to string format, must be done, on the emmiter. There are some helpers for date conversion and on the future I will add more, for encoding params on the string, and also for handling lists and recurrent events.
A simple example not functional used for testing:
c := goics.NewComponent() c.SetType("VCALENDAR") c.AddProperty("CALSCAL", "GREGORIAN") ins := &EventTest{ component: c, } w := &bytes.Buffer{} enc := goics.NewICalEncode(w) enc.Encode(ins)
Index ¶
- Constants
- Variables
- func FormatDateField(key string, val time.Time) (string, string)
- func FormatDateTime(key string, val time.Time) (string, string)
- func FormatDateTimeField(key string, val time.Time) (string, string)
- func NewDecoder(r io.Reader) *decoder
- func WriteStringField(key string, val string) string
- type Calendar
- type Component
- type Componenter
- type Event
- type ICalConsumer
- type ICalEmiter
- type ICalEncode
- type IcsNode
Constants ¶
const ( CRLF = "\r\n" CRLFSP = "\r\n " )
Line endings
Variables ¶
var ( ErrCalendarNotFound = errors.New("vCalendar not found") ErrParseEndCalendar = errors.New("wrong format END:VCALENDAR not Found") )
Errors
var LineSize = 75
LineSize of the ics format
Functions ¶
func FormatDateField ¶
FormatDateField returns a formated date: "DTEND;VALUE=DATE:20140406"
func FormatDateTime ¶
FormatDateTime as "DTSTART:19980119T070000Z"
func FormatDateTimeField ¶
FormatDateTimeField in the form "X-MYDATETIME;VALUE=DATE-TIME:20120901T130000"
func NewDecoder ¶
NewDecoder creates an instance of de decoder
func WriteStringField ¶
WriteStringField UID:asdfasdfаs@dfasdf.com
Types ¶
type Calendar ¶
type Calendar struct { Data map[string]*IcsNode // map of every property found on ics file Events []*Event // slice of events founds in file }
Calendar holds the base struct for a Component VCALENDAR
type Component ¶
type Component struct { Tipo string Elements []Componenter Properties map[string][]string }
Component is the base type for holding a ICal datatree before serilizing it
func NewComponent ¶
func NewComponent() *Component
NewComponent returns a new Component and setups and setups Properties map for the component and also allows more Components inside it. VCALENDAR is a Component that has VEVENTS, VEVENTS can hold VALARMS
func (*Component) AddComponent ¶
func (c *Component) AddComponent(cc Componenter)
AddComponent to the base component, just for building the component tree
func (*Component) AddProperty ¶
AddProperty adds a property to the component.
func (*Component) Write ¶
func (c *Component) Write(w *ICalEncode)
Writes the component to the Writer
type Componenter ¶
type Componenter interface { Write(w *ICalEncode) AddComponent(c Componenter) SetType(t string) AddProperty(string, string) }
Componenter defines what should be a component that can be rendered with others components inside and some properties CALENDAR >> VEVENT ALARM VTODO
type Event ¶
type Event struct { Data map[string]*IcsNode Alarms []*map[string]*IcsNode // Stores multiple keys for the same property... ( a list ) List map[string][]*IcsNode }
Event holds the base struct for a Event Component during decoding
type ICalConsumer ¶
ICalConsumer is the realy important part of the decoder lib The decoder is organized around the Provider/Consumer pattern. the decoder acts as a consummer producing IcsNode's and Every data type that wants to receive data, must implement the consumer pattern.
type ICalEmiter ¶
type ICalEmiter interface {
EmitICal() Componenter
}
ICalEmiter must be implemented in order to allow objects to be serialized It should return a *goics.Calendar and optional a map of fields and their serializers, if no serializer is defined, it will serialize as string..
type ICalEncode ¶
type ICalEncode struct {
// contains filtered or unexported fields
}
ICalEncode is the real writer, that wraps every line, in 75 chars length... Also gets the component from the emmiter and starts the iteration.
func NewICalEncode ¶
func NewICalEncode(w io.Writer) *ICalEncode
NewICalEncode generates a new encoder, and needs a writer
func (*ICalEncode) Encode ¶
func (enc *ICalEncode) Encode(c ICalEmiter)
Encode the Component into the ical format
func (*ICalEncode) WriteLine ¶
func (enc *ICalEncode) WriteLine(s string)
WriteLine in ics format max length = LineSize continuation lines start with a space.
type IcsNode ¶
IcsNode is a basic token.., with, key, val, and extra params to define the type of val.
func DecodeLine ¶
DecodeLine extracts key, val and extra params from a line
func (*IcsNode) DateDecode ¶
DateDecode Decodes a date in the distincts formats
func (*IcsNode) GetOneParam ¶
GetOneParam resturns the first param found usefull when you know that there is a only one param token