ic3s/main.go

303 lines
6.7 KiB
Go
Raw Permalink Normal View History

2024-12-27 12:51:34 +01:00
package main
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"github.com/arran4/golang-ical"
"io"
"net/http"
"strings"
"sync"
2024-12-27 12:51:34 +01:00
"time"
)
const (
API_URL = "https://api.events.ccc.de/congress/2024"
)
var (
SCHEDULE_MUTEX sync.Mutex
SCHEDULE []Event
ROOMS []Room
)
2024-12-27 12:51:34 +01:00
type Token struct {
Token string `json:"token"`
}
type Auth struct {
Username string `json:"username"`
Password string `json:"password"`
}
type Event struct {
ID string `json:"id"`
Kind string `json:"kind"`
Name string `json:"name"`
Slug string `json:"slug"`
URL string `json:"url"`
Track string `json:"track"`
Assembly string `json:"assembly"`
Room string `json:"room"`
Location string `json:"location"`
Language string `json:"language"`
Description string `json:"description"`
ScheduleStart time.Time `json:"schedule_start"`
ScheduleDuration string `json:"schedule_duration"`
ScheduleEnd time.Time `json:"schedule_end"`
}
// Link represents the structure of the "links" array in the JSON
type Link struct {
Type string `json:"type"`
Name string `json:"name"`
URI string `json:"uri"`
URL string `json:"url"`
}
// Room represents the structure of the main JSON object
type Room struct {
ID string `json:"id"`
Name string `json:"name"`
Slug string `json:"slug"`
RoomType string `json:"room_type"`
Capacity int `json:"capacity"`
Links []Link `json:"links"`
Assembly string `json:"assembly"`
PublicURL string `json:"public_url"`
}
func scrape_hub() ([]Event, error) {
println("scrape hub")
resp, err := http.Get(fmt.Sprintf("%s/events", API_URL))
if err != nil {
fmt.Println("Error making GET request:", err)
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response body:", err)
return nil, err
}
var events []Event
if err := json.Unmarshal(body, &events); err != nil {
fmt.Println("Error unmarshalling JSON:", err)
return nil, err
}
// Use the events slice here
fmt.Println("Number of events:", len(events))
return events, nil
}
func cron_fetch() {
for {
fmt.Println("starting cron...")
schedule, err := scrape_hub()
if err != nil {
fmt.Println("Cron failed; retrying in a minute")
time.Sleep(1 * time.Minute)
continue
}
SCHEDULE_MUTEX.Lock()
SCHEDULE = schedule
SCHEDULE_MUTEX.Unlock()
time.Sleep(10 * time.Minute)
}
}
2024-12-27 12:51:34 +01:00
func get_rooms() ([]Room, error) {
println("get rooms")
resp, err := http.Get(fmt.Sprintf("%s/rooms", API_URL))
if err != nil {
fmt.Println("Error making GET request:", err)
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response body:", err)
return nil, err
}
var rooms []Room
if err := json.Unmarshal(body, &rooms); err != nil {
fmt.Println("Error unmarshalling JSON:", err)
return nil, err
}
// Use the events slice here
fmt.Println("Number of rooms:", len(rooms))
return rooms, nil
}
func get_token(username string, password string) (string, error) {
println("get token")
jsonBytes, err := json.Marshal(Auth{Username: username, Password: password})
if err != nil {
fmt.Println("Error unmarshalling JSON:", err)
return "", err
}
resp, err := http.Post(
fmt.Sprintf("%s/auth/get-token", API_URL),
"application/json",
bytes.NewBuffer(jsonBytes),
)
if err != nil {
fmt.Println("Error getting Token:", err)
return "", err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response body:", err)
return "", err
}
var token Token
if err := json.Unmarshal(body, &token); err != nil {
fmt.Println("Error unmarshalling JSON:", err)
return "", err
}
println(token.Token)
return token.Token, nil
}
func get_me_events(token string) ([]string, error) {
println("get personal events")
req, err := http.NewRequest(
"GET",
fmt.Sprintf("%s/me/events", API_URL),
nil,
)
req.Header.Set("Authorization", fmt.Sprintf("Token %s", token))
resp, err := (&http.Client{}).Do(req)
if err != nil {
fmt.Println("Error fetching personal events:", err)
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading response body:", err)
return nil, err
}
println(string(body))
var uuids []string
if err := json.Unmarshal(body, &uuids); err != nil {
fmt.Println("Error unmarshalling JSON:", err)
return nil, err
}
return uuids, nil
}
func get_schedule(w http.ResponseWriter, r *http.Request) {
println("/event.ics")
auth_header := r.Header.Get("Authorization")
println(auth_header)
if auth_header == "" {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
credentials_encoded := auth_header[len("Basic "):]
credentials, err := base64.StdEncoding.DecodeString(credentials_encoded)
if err != nil {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
auth := strings.SplitN(string(credentials), ":", 2)
if len(auth) != 2 {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
username := auth[0]
password := auth[1]
println(username, password)
token, err := get_token(username, password)
if err != nil {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
ids, err := get_me_events(token)
if err != nil {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
SCHEDULE_MUTEX.Lock()
defer SCHEDULE_MUTEX.Unlock()
2024-12-27 12:51:34 +01:00
var my_events []Event
for _, event := range SCHEDULE {
2024-12-27 12:51:34 +01:00
for _, id := range ids {
if event.ID == id {
my_events = append(my_events, event)
break
}
}
}
cal := ics.NewCalendar()
cal.SetMethod(ics.MethodRequest)
for _, event := range my_events {
var location = ""
for _, room := range ROOMS {
if event.Room == room.ID {
location = room.Name
}
}
cal_event := cal.AddEvent(event.ID)
cal_event.SetStartAt(event.ScheduleStart)
cal_event.SetEndAt(event.ScheduleEnd)
cal_event.SetSummary(event.Name)
cal_event.SetLocation(location)
cal_event.SetDescription(ics.ToText(strings.ReplaceAll(event.Description, "\r\n", "\n")))
cal_event.SetURL(event.URL)
cal_event.SetOrganizer(event.Assembly)
}
ics := cal.Serialize()
w.Header().Set("Content-Type", "text/calendar; charset=utf-8")
w.Write([]byte(ics))
}
func main() {
rooms, err := get_rooms()
if err != nil {
return
}
ROOMS = rooms
schedule, err := scrape_hub()
if err != nil {
return
}
SCHEDULE = schedule
go cron_fetch()
2024-12-27 12:51:34 +01:00
println("Stating Server")
// Start a web server to serve the iCal file
http.HandleFunc("/events.ics", get_schedule)
err = http.ListenAndServe("127.0.0.1:8080", nil)
if err != nil {
println(err)
}
}