commit 8ae2d5f55410939e12a2700f335a44af8881d25a Author: matst80 Date: Tue May 13 20:42:20 2025 +0200 initial diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d35b569 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,17 @@ +# syntax=docker/dockerfile:1 + +FROM golang:alpine AS build-stage +WORKDIR /app +COPY go.mod go.sum ./ +RUN go mod download + +COPY proto ./proto +COPY *.go ./ + +RUN CGO_ENABLED=0 GOOS=linux go build -o /go-order-manager + +FROM gcr.io/distroless/base-debian11 +WORKDIR / + +COPY --from=build-stage /go-order-manager /go-order-manager +ENTRYPOINT ["/go-order-manager"] \ No newline at end of file diff --git a/main.go b/main.go new file mode 100644 index 0000000..6a6c6a6 --- /dev/null +++ b/main.go @@ -0,0 +1,135 @@ +package main + +import ( + "compress/gzip" + "encoding/gob" + "encoding/json" + "log" + "net/http" + "os" + "runtime" + "sync" +) + +var amqpUrl = os.Getenv("AMQP_URL") + +func init() { + gob.Register([]Order{}) + if amqpUrl == "" { + log.Fatal("AMQP_URL environment variable is not set") + } +} + +type PersistingOrderHandler struct { + mu sync.RWMutex + Orders []Order `json:"orders"` + fileName string +} + +func (h *PersistingOrderHandler) Load() error { + file, err := os.Open(h.fileName) + if err != nil { + return err + } + defer runtime.GC() + defer file.Close() + + zipReader, err := gzip.NewReader(file) + if err != nil { + return err + } + + enc := json.NewDecoder(zipReader) + defer zipReader.Close() + + h.mu.Lock() + defer h.mu.Unlock() + tmp := Order{} + for err == nil { + if err = enc.Decode(&tmp); err == nil { + h.Orders = append(h.Orders, tmp) + } + } + enc = nil + + if err.Error() == "EOF" { + return nil + } + + return err +} + +func (h *PersistingOrderHandler) Save() error { + file, err := os.Create(h.fileName + ".tmp") + if err != nil { + return err + } + + defer runtime.GC() + defer file.Close() + zipWriter := gzip.NewWriter(file) + enc := json.NewEncoder(zipWriter) + defer zipWriter.Close() + h.mu.Lock() + defer h.mu.Unlock() + + for _, order := range h.Orders { + err = enc.Encode(order) + if err != nil { + return err + } + } + + enc = nil + return os.Rename(h.fileName+".tmp", h.fileName) +} + +func (h *PersistingOrderHandler) OrderPlaced(order Order) { + // Here you would implement the logic to persist the order + log.Printf("Order placed: %s", order.ID) + h.mu.Lock() + h.Orders = append(h.Orders, order) + h.mu.Unlock() + go func() { + err := h.Save() + if err != nil { + log.Printf("error saving: %v", err) + } + }() + +} + +func main() { + handler := &PersistingOrderHandler{ + Orders: make([]Order, 0), + mu: sync.RWMutex{}, + fileName: "data/order.dbz", + } + err := handler.Load() + if err != nil { + //log.Fatal(err) + } + client := &RabbitTransportClient{ + Url: amqpUrl, + OrderTopic: "order-placed", + ClientName: "OrderClient", + } + + err = client.Connect(handler) + if err != nil { + log.Fatalf("Failed to connect to RabbitMQ: %v", err) + } + defer client.Close() + + mux := http.NewServeMux() + mux.HandleFunc("GET /orders", func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + handler.mu.RLock() + defer handler.mu.RUnlock() + json.NewEncoder(w).Encode(handler.Orders) + }) + if err := http.ListenAndServe(":8080", mux); err != nil { + log.Fatalf("Failed to start server: %v", err) + } +}