From 967be9e750221ab2ab783f95df79bb26d290a45e Mon Sep 17 00:00:00 2001
From: Martial Simon
Date: Mon, 15 Sep 2025 01:07:58 +0200
Subject: add: added projects
---
idvoc-2025/CommentsInteractor/.gitignore | 1 +
idvoc-2025/CommentsInteractor/Dockerfile | 24 +++++
idvoc-2025/CommentsInteractor/README.md | 5 ++
idvoc-2025/CommentsInteractor/go.mod | 18 ++++
idvoc-2025/CommentsInteractor/go.sum | 26 ++++++
idvoc-2025/CommentsInteractor/main.go | 147 +++++++++++++++++++++++++++++++
6 files changed, 221 insertions(+)
create mode 100644 idvoc-2025/CommentsInteractor/.gitignore
create mode 100644 idvoc-2025/CommentsInteractor/Dockerfile
create mode 100644 idvoc-2025/CommentsInteractor/README.md
create mode 100644 idvoc-2025/CommentsInteractor/go.mod
create mode 100644 idvoc-2025/CommentsInteractor/go.sum
create mode 100644 idvoc-2025/CommentsInteractor/main.go
(limited to 'idvoc-2025/CommentsInteractor')
diff --git a/idvoc-2025/CommentsInteractor/.gitignore b/idvoc-2025/CommentsInteractor/.gitignore
new file mode 100644
index 0000000..f832480
--- /dev/null
+++ b/idvoc-2025/CommentsInteractor/.gitignore
@@ -0,0 +1 @@
+CommentsInteractor
diff --git a/idvoc-2025/CommentsInteractor/Dockerfile b/idvoc-2025/CommentsInteractor/Dockerfile
new file mode 100644
index 0000000..15f9412
--- /dev/null
+++ b/idvoc-2025/CommentsInteractor/Dockerfile
@@ -0,0 +1,24 @@
+FROM reg.undercloud.cri.epita.fr/docker/golang:1.24.3-alpine
+
+LABEL org.opencontainers.image.authors="martial.simon@epita.fr"
+
+RUN apk --no-cache add curl bash
+
+WORKDIR /usr/local/app
+
+COPY go.mod go.sum main.go ./
+
+RUN go install
+
+# Setup an app user so the container doesn't run as the root user
+RUN adduser -D app
+USER app
+
+EXPOSE 9000
+
+ENV COMMENTS_ENGINE_ENDPOINT="commentsengine:8000"
+ENV HOST="0.0.0.0"
+ENV PORT=9000
+
+# Run the app when starting a container
+CMD ["CommentsInteractor"]
diff --git a/idvoc-2025/CommentsInteractor/README.md b/idvoc-2025/CommentsInteractor/README.md
new file mode 100644
index 0000000..0d896bc
--- /dev/null
+++ b/idvoc-2025/CommentsInteractor/README.md
@@ -0,0 +1,5 @@
+## Env variables
+
+`COMMENTS_ENGINE_ENDPOINT`: The endpoint (host + port) where to find CommentsEngine
+`HOST`: The host on which to bind+listen to
+`PORT`: The port on which to bind+listen to
diff --git a/idvoc-2025/CommentsInteractor/go.mod b/idvoc-2025/CommentsInteractor/go.mod
new file mode 100644
index 0000000..dcebe1f
--- /dev/null
+++ b/idvoc-2025/CommentsInteractor/go.mod
@@ -0,0 +1,18 @@
+module CommentsInteractor
+
+go 1.21.5
+
+require github.com/gorilla/handlers v1.5.2
+
+require (
+ github.com/beorn7/perks v1.0.1 // indirect
+ github.com/cespare/xxhash/v2 v2.2.0 // indirect
+ github.com/felixge/httpsnoop v1.0.3 // indirect
+ github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
+ github.com/prometheus/client_golang v1.18.0 // indirect
+ github.com/prometheus/client_model v0.5.0 // indirect
+ github.com/prometheus/common v0.45.0 // indirect
+ github.com/prometheus/procfs v0.12.0 // indirect
+ golang.org/x/sys v0.15.0 // indirect
+ google.golang.org/protobuf v1.31.0 // indirect
+)
diff --git a/idvoc-2025/CommentsInteractor/go.sum b/idvoc-2025/CommentsInteractor/go.sum
new file mode 100644
index 0000000..33b6970
--- /dev/null
+++ b/idvoc-2025/CommentsInteractor/go.sum
@@ -0,0 +1,26 @@
+github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
+github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
+github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk=
+github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
+github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE=
+github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w=
+github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
+github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
+github.com/prometheus/client_golang v1.18.0 h1:HzFfmkOzH5Q8L8G+kSJKUx5dtG87sewO+FoDDqP5Tbk=
+github.com/prometheus/client_golang v1.18.0/go.mod h1:T+GXkCk5wSJyOqMIzVgvvjFDlkOQntgjkJWKrN5txjA=
+github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
+github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
+github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
+github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
+github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
+github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
+golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
+golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
+google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
diff --git a/idvoc-2025/CommentsInteractor/main.go b/idvoc-2025/CommentsInteractor/main.go
new file mode 100644
index 0000000..9a19243
--- /dev/null
+++ b/idvoc-2025/CommentsInteractor/main.go
@@ -0,0 +1,147 @@
+package main
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "github.com/gorilla/handlers"
+ "github.com/prometheus/client_golang/prometheus"
+ "github.com/prometheus/client_golang/prometheus/promauto"
+ "github.com/prometheus/client_golang/prometheus/promhttp"
+ "io"
+ "log"
+ "net/http"
+ "os"
+ "strconv"
+)
+
+func getenv(key, fallback string) string {
+ value := os.Getenv(key)
+ if len(value) == 0 {
+ return fallback
+ }
+ return value
+}
+
+type Comment struct {
+ Comment string `json:"comment"`
+}
+
+type EngineError struct {
+ Message string `json:"message"`
+ AdditionalInfo string `json:"additionalInfo"`
+}
+
+var comments_engine_endpoint string
+var (
+ httpHits = promauto.NewCounterVec(prometheus.CounterOpts{
+ Name: "comments_interactor_http_hits_total",
+ Help: "The total number of hits on a given route",
+ }, []string{"route", "method"})
+ commentsReceived = promauto.NewCounter(prometheus.CounterOpts{
+ Name: "comments_interactor_comments_received_total",
+ Help: "The total number of comments received (successfully posted or not)",
+ })
+ commentsPosted = promauto.NewCounter(prometheus.CounterOpts{
+ Name: "comments_interactor_comments_posted_total",
+ Help: "The total number of comments posted (successfully posted)",
+ })
+)
+
+func sendComment(w http.ResponseWriter, r *http.Request) {
+ commentsReceived.Inc()
+ if err := r.ParseForm(); err != nil {
+ fmt.Fprintf(w, "error
ParseForm() err: %v
", err)
+ return
+ }
+ var comment Comment
+ comment.Comment = r.FormValue("comment")
+ if comment.Comment == "" {
+ fmt.Fprintf(w, "error
Empty comment or malformed
")
+ return
+ }
+ obj, err := json.Marshal(comment)
+ if err != nil {
+ fmt.Fprintf(w, "error
Empty comment or malformed
")
+ return
+ }
+ _, err = http.Post("http://"+comments_engine_endpoint+"/comment", "application/json", bytes.NewReader(obj))
+ if err == nil {
+ fmt.Fprintf(w, "Success !
Comment posted
")
+ commentsPosted.Inc()
+ } else {
+ fmt.Fprintf(w, "Error
Error while trying to send a comment: %s", err)
+ }
+}
+
+func showDashboard(w http.ResponseWriter, r *http.Request) {
+ io.WriteString(w, "
Latest comments
")
+ io.WriteString(w, "")
+ resp, err := http.Get("http://" + comments_engine_endpoint + "/latest")
+ if err != nil {
+ log.Printf("Could not HTTP get on CommentsEngine: %s", err)
+ io.WriteString(w, fmt.Sprintf("Error contacting the backend, %s", err))
+ } else {
+ defer resp.Body.Close()
+ body, err := io.ReadAll(resp.Body)
+ var comments []string
+ err = json.Unmarshal(body, &comments)
+ if err != nil {
+ var engineError EngineError
+ err = json.Unmarshal(body, &engineError)
+ if err != nil {
+ log.Printf("CommentsEngine returned unexpected value: %s", err)
+ io.WriteString(w, fmt.Sprintf("CommentsEngine returned badly formated values, %s", err))
+ } else {
+ io.WriteString(w, fmt.Sprintf("CommentsEngine returned an error: %s
Additional info: %s", engineError.Message, engineError.AdditionalInfo))
+ }
+ } else {
+ for i, comment := range comments {
+ io.WriteString(w, "
comment "+strconv.Itoa(i)+"
"+comment+"
")
+ }
+ }
+ }
+ io.WriteString(w, "
")
+ io.WriteString(w, "Send comment
")
+ io.WriteString(w, "")
+}
+
+func getRoot(w http.ResponseWriter, r *http.Request) {
+ httpHits.With(prometheus.Labels{"route": "/", "method": r.Method}).Inc()
+ io.WriteString(w, "CommentsInteractor")
+ if r.Method == http.MethodPost {
+ sendComment(w, r)
+ }
+ showDashboard(w, r)
+ io.WriteString(w, "")
+}
+
+func sendError(w http.ResponseWriter, err error, additionalInfo string) {
+ w.WriteHeader(http.StatusInternalServerError)
+ resp := make(map[string]string)
+ resp["message"] = fmt.Sprint(err)
+ resp["additionalInfo"] = additionalInfo
+ jsonResp, err := json.Marshal(resp)
+ if err != nil {
+ log.Fatalf("Error happened in JSON marshal. Err: %s", err)
+ }
+ w.Write(jsonResp)
+}
+
+func main() {
+ http.HandleFunc("/", getRoot)
+ prometheus.Unregister(prometheus.NewGoCollector())
+ http.Handle("/metrics", promhttp.Handler())
+
+ listeningHostPort := getenv("HOST", "127.0.0.1") + ":" + getenv("PORT", "9000")
+ comments_engine_endpoint = getenv("COMMENTS_ENGINE_ENDPOINT", "127.0.0.1:8000")
+ fmt.Printf("Starting the server on %s\n", listeningHostPort)
+ err := http.ListenAndServe(listeningHostPort, handlers.LoggingHandler(os.Stdout, http.DefaultServeMux))
+ if errors.Is(err, http.ErrServerClosed) {
+ fmt.Printf("server closed\n")
+ } else if err != nil {
+ fmt.Printf("error starting server: %s\n", err)
+ os.Exit(1)
+ }
+}
--
cgit v1.2.3