diff options
Diffstat (limited to 'pkg/schedule/service.go')
| -rw-r--r-- | pkg/schedule/service.go | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/pkg/schedule/service.go b/pkg/schedule/service.go new file mode 100644 index 0000000..70587ef --- /dev/null +++ b/pkg/schedule/service.go @@ -0,0 +1,146 @@ +package schedule + +import ( + "bufio" + "encoding/xml" + "fmt" + "net/http" + "sync" + "time" +) + +type Service interface { + GetSchedule() (*Schedule, *time.Time, error) +} + +type Schedule struct { + XMLName xml.Name `json:"-" xml:"schedule"` + Conference Conference `json:"conference" xml:"conference"` + Tracks []Track `json:"tracks" xml:"tracks>track"` + Days []Day `json:"days" xml:"day"` +} + +type Conference struct { + Title string `json:"title" xml:"title"` + Venue string `json:"venue" xml:"venue"` + City string `json:"city" xml:"city"` + Start string `json:"start" xml:"start"` + End string `json:"end" xml:"end"` + Days int `json:"days" xml:"days"` + DayChange string `json:"dayChange" xml:"day_change"` + TimeslotDuration string `json:"timeslotDuration" xml:"timeslot_duration"` + BaseURL string `json:"baseUrl" xml:"base_url"` + TimeZoneName string `json:"timeZoneName" xml:"time_zone_name"` +} + +type Track struct { + Name string `json:"name" xml:",chardata"` +} + +type Day struct { + Date string `json:"date" xml:"date,attr"` + Start string `json:"start" xml:"start"` + End string `json:"end" xml:"end"` + Rooms []Room `json:"rooms" xml:"room"` +} + +type Room struct { + Name string `json:"name" xml:"name,attr"` + Events []Event `json:"events" xml:"event"` +} + +type Event struct { + ID int `json:"id" xml:"id,attr"` + GUID string `json:"guid" xml:"guid,attr"` + Date string `json:"date" xml:"date"` + Start string `json:"start" xml:"start"` + Duration string `json:"duration" xml:"duration"` + Room string `json:"room" xml:"room"` + URL string `json:"url" xml:"url"` + Track string `json:"track" xml:"track"` + Type string `json:"type" xml:"type"` + Title string `json:"title" xml:"title"` + Abstract string `json:"abstract" xml:"abstract"` + Persons []Person `json:"persons" xml:"persons>person"` + Attachments []Attachment `json:"attachments" xml:"attachments>attachment"` + Links []Link `json:"links" xml:"links>link"` +} + +type Person struct { + ID int `json:"id" xml:"id,attr"` + Name string `json:"name" xml:",chardata"` +} + +type Attachment struct { + Type string `json:"string" xml:"id,attr"` + Href string `json:"href" xml:"href,attr"` + Name string `json:"name" xml:",chardata"` +} + +type Link struct { + Href string `json:"href" xml:"href,attr"` + Name string `json:"name" xml:",chardata"` +} + +type service struct { + schedule *Schedule + pentabarfUrl string + lastUpdated time.Time + lock sync.Mutex +} + +func NewService(pentabarfUrl string) (Service, error) { + service := &service{ + pentabarfUrl: pentabarfUrl, + lastUpdated: time.Unix(0, 0), + } + + err := service.updateSchedule() + if err != nil { + return nil, fmt.Errorf("could not read schedule from '%s' (is it a valid pentabarf XML file?): %w", pentabarfUrl, err) + } + return service, nil +} + +func (s *service) GetSchedule() (*Schedule, *time.Time, error) { + if s.hasScheduleExpired() { + err := s.updateSchedule() + if err != nil { + return nil, nil, err + } + } + + return s.schedule, &s.lastUpdated, nil +} + +func (s *service) hasScheduleExpired() bool { + expire := s.lastUpdated.Add(15 * time.Minute) + return time.Now().After(expire) +} + +func (s *service) updateSchedule() error { + s.lock.Lock() + defer s.lock.Unlock() + + if !s.hasScheduleExpired() { + return nil + } + + res, err := http.Get(s.pentabarfUrl) + if err != nil { + return err + } + + reader := bufio.NewReader(res.Body) + + var schedule Schedule + + decoder := xml.NewDecoder(reader) + if err := decoder.Decode(&schedule); err != nil { + return fmt.Errorf("failed to decode XML: %w", err) + } + + s.schedule = &schedule + s.lastUpdated = time.Now() + return nil +} |
