From b5a7b9bbcd3ee74857f5e7216af373c332e6d4b1 Mon Sep 17 00:00:00 2001 From: Alexandre Iooss Date: Mon, 21 Sep 2020 17:29:50 +0200 Subject: [PATCH] Initial Golang project --- build/Dockerfile | 14 ++++++ init/ghostream.service | 12 +++++ main.go | 51 +++++++++++++++++++++ web/static/style.css | 98 ++++++++++++++++++++++++++++++++++++++++ web/template/base.tmpl | 18 ++++++++ web/template/index.tmpl | 75 ++++++++++++++++++++++++++++++ web/template/viewer.tmpl | 67 +++++++++++++++++++++++++++ 7 files changed, 335 insertions(+) create mode 100644 build/Dockerfile create mode 100644 init/ghostream.service create mode 100644 main.go create mode 100644 web/static/style.css create mode 100644 web/template/base.tmpl create mode 100644 web/template/index.tmpl create mode 100644 web/template/viewer.tmpl diff --git a/build/Dockerfile b/build/Dockerfile new file mode 100644 index 0000000..7ac56d6 --- /dev/null +++ b/build/Dockerfile @@ -0,0 +1,14 @@ +# Install dependencies and build +FROM golang:1.15-alpine AS build_base +RUN apk add --no-cache git +WORKDIR /code +COPY . . +RUN go mod download +RUN go build -o ./out/ghostream . + +# Production image +FROM alpine:3.12 +RUN apk add ca-certificates +COPY --from=build_base /code/out/ghostream /app/ghostream +EXPOSE 8080 +CMD ["/app/ghostream"] \ No newline at end of file diff --git a/init/ghostream.service b/init/ghostream.service new file mode 100644 index 0000000..1a9487a --- /dev/null +++ b/init/ghostream.service @@ -0,0 +1,12 @@ +[Unit] +Description=Simple streaming server +After=syslog.target + +[Service] +User=www-data +EnvironmentFile=-/etc/default/ghostream +ExecStart=/usr/bin/ghostream +Restart=on-failure + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/main.go b/main.go new file mode 100644 index 0000000..e92dc23 --- /dev/null +++ b/main.go @@ -0,0 +1,51 @@ +package main + +import ( + "os" + "log" + "net/http" + "html/template" +) + +// Preload templates +var templates = template.Must(template.ParseGlob("web/template/*.tmpl")) + +// Handle site index and viewer pages +func handlerViewer(w http.ResponseWriter, r *http.Request) { + // Remove traling slash + //path := r.URL.Path[1:] + + // Render template + err := templates.ExecuteTemplate(w, "base", nil) + if err != nil { + log.Println(err.Error()) + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + } +} + +// Auth incoming stream +func handleStreamAuth(w http.ResponseWriter, r *http.Request) { + // FIXME POST request only with "name" and "pass" + // if name or pass missing => 400 Malformed request + // else login in against LDAP or static users + http.Error(w, "Not implemented", 400) +} + +// Handle static files +// We do not use http.FileServer as we do not want directory listing +func handleStatic(w http.ResponseWriter, r *http.Request) { + path := "./" + r.URL.Path + if f, err := os.Stat(path); err == nil && !f.IsDir() { + http.ServeFile(w, r, path) + } else { + http.NotFound(w, r) + } +} + +func main() { + // Set up HTTP router and server + http.HandleFunc("/", handlerViewer) + http.HandleFunc("/rtmp/auth", handleStreamAuth) + http.HandleFunc("/static/", handleStatic) + log.Fatal(http.ListenAndServe(":8080", nil)) +} diff --git a/web/static/style.css b/web/static/style.css new file mode 100644 index 0000000..03e310e --- /dev/null +++ b/web/static/style.css @@ -0,0 +1,98 @@ +body, html { + height: 100%; + margin: 0; +} + +body { + background-color: #3b4b5b; + font-family: "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif; + font-size: 1rem; + font-weight: 400; + line-height: 1.5; + color: #bbb; + text-align: justify; + user-select: none; +} + +p { + margin-top: 0; + margin-bottom: 1rem; +} + +code { + font-size: 87.5%; + word-break: break-word; + user-select: text; +} + +svg { + overflow: hidden; + vertical-align: middle; +} + +a { + text-decoration: underline; + text-decoration-style: dotted; + color: inherit; +} + +img { + max-width: 100%; +} + +h1, h2, h3, h4 { + color: #ddd; +} + +.container { + height: 100%; + width: 100%; + display: flex; + flex-wrap: wrap; + height: 100%; +} + +.col-video { + padding: 1rem; + flex-basis: 0; + flex-grow: 1; + position: relative; + width: 100%; + text-align: right; + max-height: 90vh; +} + +.col-chat { + position: relative; + width: 100%; + height: 100%; + box-shadow: 0 1rem 3rem rgba(0,0,0,0.175); +} + +.col-chat iframe { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + border: 0; +} + +/* Hide chat toggler on small screen */ +#chatToggle { + margin-left: 0.5rem; + display: none; +} + +/* On large screen, put chat on left */ +@media(min-width:1000px){ + .col-chat { + width: 33.33333%; + flex: 0 0 33.33333%; + } + + #chatToggle { + display: inline; + } +} diff --git a/web/template/base.tmpl b/web/template/base.tmpl new file mode 100644 index 0000000..56a336c --- /dev/null +++ b/web/template/base.tmpl @@ -0,0 +1,18 @@ +{{define "base"}} + + + + + {{if .Path}}{{.Path}} - {{end}}SITE_NAME + + + + + {{if .Path}} + {{template "viewer" .}} + {{else}} + {{template "index" .}} + {{end}} + + +{{end}} diff --git a/web/template/index.tmpl b/web/template/index.tmpl new file mode 100644 index 0000000..668c9a3 --- /dev/null +++ b/web/template/index.tmpl @@ -0,0 +1,75 @@ +{{define "index"}} +
+

SITE_NAME

+

+ SITE_NAME est un service maintenu par le + Crans permettant de diffuser + un contenu vidéo. Il a pour but d'être utilisé pour diffuser + des séminaires ou évènements. +

+ +

Comment je diffuse ?

+

Pour diffuser un contenu vous devez être adhérent Crans.

+ +

Avec Open Broadcaster Software

+

+ Open Broadcaster Software + est une solution libre et open source de diffusion vidéo. + Pour diffuser sur cette plateforme, allez dans les paramètres + « Stream (flux) » : +

+ + + +

+ Pour éviter les saccades, changez vos paramètres d'encodage dans + « Sortie » avec un profil baseline et un + règlage fin zerolatency. +

+ + +

+ Votre stream sera alors disponible sur + https://SITE_HOSTNAME/IDENTIFIANT. +

+ +

Avec FFmpeg

+

+ + ffmpeg -re -i mavideo.webm -vcodec libx264 -vprofile baseline + -acodec aac -strict -2 -f flv + rtmps://SITE_HOSTNAME:1935/stream/IDENTIFIANT?pass=MOT_DE_PASSE + +

+ +

Mentions légales

+

+ Le service de diffusion vidéo du Crans est un service d'hébergement + au sens de l'article 6, I, 2e de la loi 2004-575 du 21 juin 2004. + Conformément aux dispositions de l'article 6, II du même, + l'association Crans conserve les données de nature à permettre + l'identification des auteurs du contenu diffusé. + Ce service est hébergé par l'association Crans, au + 61 Avenue du Président Wilson, 94235 Cachan Cedex, France. +

+

+ En cas de réclamation sur le contenu diffusé, + la loi vous autorise à contacter directement l'hébergeur à + l'adresse suivante : +

Association Cr@ns - ENS Paris-Saclay
Notification de Contenus Illicites
4, avenue des Sciences
91190 Gif-sur-Yvette
France
+ Vous pouvez également envoyer directement vos réclamations par + courrier électronique à l'adresse bureau[at]crans.org. +

+
+{{end}} diff --git a/web/template/viewer.tmpl b/web/template/viewer.tmpl new file mode 100644 index 0000000..4d32fc6 --- /dev/null +++ b/web/template/viewer.tmpl @@ -0,0 +1,67 @@ +{{define "viewer"}} +
+
+ + + + +

+ + + + + rtmps://SITE_HOSTNAME:1935/play/{{.path}} + » +

+
+ + +
+ +
+
+ + + +{{end}}