aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/schedule/service.go
diff options
context:
space:
mode:
authorLeonardo Bishop <me@leonardobishop.com>2025-01-17 13:21:24 +0000
committerLeonardo Bishop <me@leonardobishop.com>2025-01-17 13:21:24 +0000
commitc00b690bd6f600554a1404e692bd9e4373325d27 (patch)
tree4488b625e1c24af52fced6f60ac1b3ddff1383bc /pkg/schedule/service.go
Initial commit
Diffstat (limited to 'pkg/schedule/service.go')
-rw-r--r--pkg/schedule/service.go146
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
+}