first commit
This commit is contained in:
commit
4aa1d57094
7 changed files with 283 additions and 0 deletions
88
README.md
Normal file
88
README.md
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
# ICS to RSS Converter
|
||||||
|
|
||||||
|
Dieses Projekt ist eine Go-Anwendung, die ICS-Kalenderdateien in RSS-Feeds konvertiert. Die Anwendung wird in einem Docker-Container ausgeführt und kann mit Docker Compose einfach bereitgestellt werden.
|
||||||
|
|
||||||
|
## Voraussetzungen
|
||||||
|
|
||||||
|
- [Docker](https://www.docker.com/get-started)
|
||||||
|
- [Docker Compose](https://docs.docker.com/compose/install/)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
1. **Repository klonen:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/dein-benutzername/ics-to-rss.git
|
||||||
|
cd ics-to-rss
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Docker Compose starten:**
|
||||||
|
|
||||||
|
Stelle sicher, dass Docker und Docker Compose installiert sind und führe dann den folgenden Befehl aus:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
Dieser Befehl baut das Docker-Image und startet den Container.
|
||||||
|
|
||||||
|
## Verwendung
|
||||||
|
|
||||||
|
Die Anwendung läuft auf `http://localhost:8080`. Um eine ICS-Datei in einen RSS-Feed zu konvertieren, verwende die folgende URL-Struktur:
|
||||||
|
|
||||||
|
```
|
||||||
|
http://localhost:8080/rss?ics=<ICS_URL>
|
||||||
|
```
|
||||||
|
|
||||||
|
Ersetze `<ICS_URL>` durch die URL deiner ICS-Datei.
|
||||||
|
|
||||||
|
## Docker Compose Datei
|
||||||
|
|
||||||
|
Hier ist der Inhalt der `docker-compose.yml` Datei:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
ics-to-rss:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dockerfile
|
||||||
|
|
||||||
|
Stelle sicher, dass du auch eine `Dockerfile` im selben Verzeichnis hast:
|
||||||
|
|
||||||
|
```dockerfile
|
||||||
|
# Verwende ein offizielles Golang-Image als Build-Umgebung
|
||||||
|
FROM golang:1.20 as builder
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Kopiere den Go-Modul-Dateien und installiere Abhängigkeiten
|
||||||
|
COPY go.mod go.sum ./
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
# Kopiere den Rest des Codes
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Baue die Anwendung
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux go build -o main .
|
||||||
|
|
||||||
|
# Verwende ein schlankes Image für die Produktion
|
||||||
|
FROM alpine:3.18
|
||||||
|
|
||||||
|
WORKDIR /root/
|
||||||
|
|
||||||
|
# Kopiere das gebaute Go-Binary aus der vorherigen Stufe
|
||||||
|
COPY --from=builder /app/main .
|
||||||
|
|
||||||
|
# Exponiere Port 8080 und starte die Anwendung
|
||||||
|
EXPOSE 8080
|
||||||
|
CMD ["./main"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Lizenz
|
||||||
|
|
||||||
|
Dieses Projekt steht unter der MIT-Lizenz. Weitere Informationen findest du in der `LICENSE` Datei.
|
38
docker-compose.yml
Executable file
38
docker-compose.yml
Executable file
|
@ -0,0 +1,38 @@
|
||||||
|
version: "3.9"
|
||||||
|
|
||||||
|
services:
|
||||||
|
|
||||||
|
# Go application service
|
||||||
|
go-app:
|
||||||
|
build:
|
||||||
|
context: go/.
|
||||||
|
args:
|
||||||
|
- GO111MODULE=on
|
||||||
|
#ports:
|
||||||
|
# - "8080:8080"
|
||||||
|
environment:
|
||||||
|
- VIRTUAL_HOST=ics.brothertec.eu
|
||||||
|
- VIRTUAL_PORT=8080
|
||||||
|
- LETSENCRYPT_HOST=ics.brothertec.eu
|
||||||
|
- LETSENCRYPT_EMAIL=admin@brothertec.eu
|
||||||
|
|
||||||
|
restart: always
|
||||||
|
|
||||||
|
labels:
|
||||||
|
- flame.type=application
|
||||||
|
- flame.name=ICS to RSS
|
||||||
|
- flame.url=https://ics.brothertec.eu
|
||||||
|
- flame.icon=image
|
||||||
|
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
proxy:
|
||||||
|
edge-tier:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
proxy:
|
||||||
|
name: nginx-proxy
|
||||||
|
external: true
|
||||||
|
edge-tier:
|
||||||
|
name: edge
|
||||||
|
external: true
|
28
go/Dockerfile
Executable file
28
go/Dockerfile
Executable file
|
@ -0,0 +1,28 @@
|
||||||
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
|
# Build the application from source
|
||||||
|
FROM golang:1.19 AS build-stage
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY * ./
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux go build -o /main
|
||||||
|
|
||||||
|
# Run the tests in the container
|
||||||
|
FROM build-stage AS run-test-stage
|
||||||
|
RUN go test -v ./...
|
||||||
|
|
||||||
|
# Deploy the application binary into a lean image
|
||||||
|
FROM gcr.io/distroless/base-debian12 AS build-release-stage
|
||||||
|
|
||||||
|
WORKDIR /
|
||||||
|
|
||||||
|
COPY --from=build-stage /main /main
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
USER nonroot:nonroot
|
||||||
|
|
||||||
|
ENTRYPOINT ["/main"]
|
22
go/Dockerfile.old
Executable file
22
go/Dockerfile.old
Executable file
|
@ -0,0 +1,22 @@
|
||||||
|
# Use an official Golang runtime as a parent image
|
||||||
|
FROM golang:1.21.4
|
||||||
|
|
||||||
|
# Set the working directory in the container
|
||||||
|
WORKDIR /go/src/app
|
||||||
|
|
||||||
|
# Copy the local package files to the container's workspace
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Download and install any required third-party dependencies into the container.
|
||||||
|
#RUN go get -u github.com/gorilla/mux
|
||||||
|
RUN go get -u github.com/go-sql-driver/mysql
|
||||||
|
RUN go get -u github.com/sirupsen/logrus
|
||||||
|
|
||||||
|
# Build the Go application
|
||||||
|
RUN go build -o main .
|
||||||
|
|
||||||
|
# Expose port 8080 to the outside world
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
# Command to run the application with environment variables
|
||||||
|
CMD ["./main"]
|
13
go/go.mod
Normal file
13
go/go.mod
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
module ICStoRSS
|
||||||
|
|
||||||
|
go 1.19
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/apognu/gocal v0.9.0
|
||||||
|
github.com/gorilla/feeds v1.2.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/ChannelMeter/iso8601duration v0.0.0-20150204201828-8da3af7a2a61 // indirect
|
||||||
|
github.com/stretchr/testify v1.8.1 // indirect
|
||||||
|
)
|
28
go/go.sum
Normal file
28
go/go.sum
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
github.com/ChannelMeter/iso8601duration v0.0.0-20150204201828-8da3af7a2a61 h1:N5Vqww5QISEHsWHOWDEx4PzdIay3Cg0Jp7zItq2ZAro=
|
||||||
|
github.com/ChannelMeter/iso8601duration v0.0.0-20150204201828-8da3af7a2a61/go.mod h1:GnKXcK+7DYNy/8w2Ex//Uql4IgfaU82Cd5rWKb7ah00=
|
||||||
|
github.com/apognu/gocal v0.9.0 h1:2lGdZprjYs9A6l1RTEmapmpE1PiDbXNX8bUVqZt3vm4=
|
||||||
|
github.com/apognu/gocal v0.9.0/go.mod h1:ZOJfNOqpz8aasi3uqzDu+eWTT6VuEa/TvQWiYYWlb80=
|
||||||
|
github.com/channelmeter/iso8601duration v0.0.0-20150204201828-8da3af7a2a61 h1:o64h9XF42kVEUuhuer2ehqrlX8rZmvQSU0+Vpj1rF6Q=
|
||||||
|
github.com/channelmeter/iso8601duration v0.0.0-20150204201828-8da3af7a2a61/go.mod h1:Rp8e0DCtEKwXFOC6JPJQVTz8tuGoGvw6Xfexggh/ed0=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/gorilla/feeds v1.2.0 h1:O6pBiXJ5JHhPvqy53NsjKOThq+dNFm8+DFrxBEdzSCc=
|
||||||
|
github.com/gorilla/feeds v1.2.0/go.mod h1:WMib8uJP3BbY+X8Szd1rA5Pzhdfh+HCCAYT2z7Fza6Y=
|
||||||
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
|
github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||||
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
66
go/main.go
Normal file
66
go/main.go
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/apognu/gocal"
|
||||||
|
"github.com/gorilla/feeds"
|
||||||
|
)
|
||||||
|
|
||||||
|
func convertICStoRSS(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Lese die ICS-URL aus dem Query-Parameter
|
||||||
|
icsURL := r.URL.Query().Get("ics")
|
||||||
|
if icsURL == "" {
|
||||||
|
http.Error(w, "Missing 'ics' query parameter", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ICS-Datei herunterladen
|
||||||
|
resp, err := http.Get(icsURL)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Unable to fetch ICS file", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// ICS-Datei parsen
|
||||||
|
parser := gocal.NewParser(resp.Body)
|
||||||
|
parser.Parse()
|
||||||
|
|
||||||
|
// RSS-Feed erstellen
|
||||||
|
feed := &feeds.Feed{
|
||||||
|
Title: "Converted Calendar Feed",
|
||||||
|
Link: &feeds.Link{Href: icsURL},
|
||||||
|
Description: "This is a converted calendar feed",
|
||||||
|
Created: time.Now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, event := range parser.Events {
|
||||||
|
// Dereferenziere event.Start, um den time.Time Wert zu erhalten
|
||||||
|
item := &feeds.Item{
|
||||||
|
Title: event.Summary,
|
||||||
|
Description: event.Description,
|
||||||
|
Link: &feeds.Link{Href: icsURL},
|
||||||
|
Created: *event.Start,
|
||||||
|
}
|
||||||
|
feed.Items = append(feed.Items, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RSS als HTTP-Antwort senden
|
||||||
|
rssData, err := feed.ToRss()
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Unable to generate RSS feed", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/rss+xml")
|
||||||
|
w.Write([]byte(rssData))
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
http.HandleFunc("/rss", convertICStoRSS)
|
||||||
|
fmt.Println("Server is running at :8080")
|
||||||
|
http.ListenAndServe(":8080", nil)
|
||||||
|
}
|
Loading…
Reference in a new issue