about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBaitinq <manuelpalenzuelamerino@gmail.com>2024-05-27 21:30:54 +0200
committerBaitinq <manuelpalenzuelamerino@gmail.com>2024-05-27 23:52:44 +0200
commit81621c4f64f4a1c29906643f53314e2f71a014ae (patch)
tree503cc56b609dcad8f8eca6e64b6b9b15b02fd4fd
parentpayload-processor: fmt (diff)
downloadfs-tracer-backend-81621c4f64f4a1c29906643f53314e2f71a014ae.tar.gz
fs-tracer-backend-81621c4f64f4a1c29906643f53314e2f71a014ae.tar.bz2
fs-tracer-backend-81621c4f64f4a1c29906643f53314e2f71a014ae.zip
rest-api: connect to db and add /file/ GET endpoint
TODO: Only get files for your specific user
-rw-r--r--k8s/rest-api/BUILD.bazel5
-rw-r--r--k8s/rest-api/templates/deployment.yaml2
-rw-r--r--k8s/rest-api/values.yaml3
-rw-r--r--lib/BUILD.bazel8
-rw-r--r--lib/model.go (renamed from src/payload-processor/processor/model.go)3
-rw-r--r--src/payload-processor/processor/BUILD.bazel3
-rw-r--r--src/payload-processor/processor/db.go5
-rw-r--r--src/payload-processor/processor/mock_db.go3
-rw-r--r--src/payload-processor/processor/processor.go3
-rw-r--r--src/payload-processor/processor/processor_test.go3
-rw-r--r--src/rest-api/cmd/BUILD.bazel1
-rw-r--r--src/rest-api/cmd/main.go14
-rw-r--r--src/rest-api/handler/BUILD.bazel27
-rw-r--r--src/rest-api/handler/db.go37
-rw-r--r--src/rest-api/handler/handler.go38
-rw-r--r--src/rest-api/handler/handler_test.go31
-rw-r--r--src/rest-api/handler/mock_db.go56
17 files changed, 228 insertions, 14 deletions
diff --git a/k8s/rest-api/BUILD.bazel b/k8s/rest-api/BUILD.bazel
index 9ebdaf9..1364361 100644
--- a/k8s/rest-api/BUILD.bazel
+++ b/k8s/rest-api/BUILD.bazel
@@ -6,6 +6,9 @@ helm_chart(
     images = ["//src/rest-api/cmd:push"],
     install_name = "rest-api",
     stamp = 1,
-    substitutions = {"IMAGE_TAG": "rest-api-{STABLE_GIT_SHA}"},
+    substitutions = {
+        "IMAGE_TAG": "rest-api-{STABLE_GIT_SHA}",
+        "DB_PASSWORD": "{DB_PASSWORD}",
+    },
     values = "values.yaml",
 )
diff --git a/k8s/rest-api/templates/deployment.yaml b/k8s/rest-api/templates/deployment.yaml
index f2b15d8..aa61cb6 100644
--- a/k8s/rest-api/templates/deployment.yaml
+++ b/k8s/rest-api/templates/deployment.yaml
@@ -50,6 +50,8 @@ spec:
               secretKeyRef:
                 name: kafka-user-passwords
                 key: client-passwords
+          - name: DB_PASSWORD
+            value: {{ .Values.db.password }}
       {{- with .Values.nodeSelector }}
       nodeSelector:
         {{- toYaml . | nindent 8 }}
diff --git a/k8s/rest-api/values.yaml b/k8s/rest-api/values.yaml
index f79e04f..3d85a51 100644
--- a/k8s/rest-api/values.yaml
+++ b/k8s/rest-api/values.yaml
@@ -7,6 +7,9 @@
 
 replicaCount: 1
 
+db:
+  password: "{DB_PASSWORD}"
+
 image:
   repository: docker.io/baitinq/fs-tracer
   pullPolicy: IfNotPresent
diff --git a/lib/BUILD.bazel b/lib/BUILD.bazel
new file mode 100644
index 0000000..a9a0e52
--- /dev/null
+++ b/lib/BUILD.bazel
@@ -0,0 +1,8 @@
+load("@io_bazel_rules_go//go:def.bzl", "go_library")
+
+go_library(
+    name = "lib",
+    srcs = ["model.go"],
+    importpath = "github.com/Baitinq/fs-tracer-backend/lib",
+    visibility = ["//visibility:public"],
+)
diff --git a/src/payload-processor/processor/model.go b/lib/model.go
index 4921f3d..be86378 100644
--- a/src/payload-processor/processor/model.go
+++ b/lib/model.go
@@ -1,8 +1,9 @@
-package processor
+package lib
 
 import "time"
 
 type File struct {
+	Id            int       `db:"id"`
 	User_id       string    `db:"user_id"`
 	Absolute_path string    `db:"absolute_path"`
 	Contents      string    `db:"contents"`
diff --git a/src/payload-processor/processor/BUILD.bazel b/src/payload-processor/processor/BUILD.bazel
index d8d8afe..411300d 100644
--- a/src/payload-processor/processor/BUILD.bazel
+++ b/src/payload-processor/processor/BUILD.bazel
@@ -5,12 +5,12 @@ go_library(
     srcs = [
         "db.go",
         "mock_db.go",
-        "model.go",
         "processor.go",
     ],
     importpath = "github.com/Baitinq/fs-tracer-backend/src/payload-processor/processor",
     visibility = ["//visibility:public"],
     deps = [
+        "//lib",
         "@com_github_google_uuid//:uuid",
         "@com_github_jmoiron_sqlx//:sqlx",
         "@com_github_segmentio_kafka_go//:kafka-go",
@@ -23,6 +23,7 @@ go_test(
     srcs = ["processor_test.go"],
     embed = [":processor"],
     deps = [
+        "//lib",
         "@com_github_segmentio_kafka_go//:kafka-go",
         "@com_github_stretchr_testify//require",
         "@org_uber_go_mock//gomock",
diff --git a/src/payload-processor/processor/db.go b/src/payload-processor/processor/db.go
index ce7d5bb..45ec484 100644
--- a/src/payload-processor/processor/db.go
+++ b/src/payload-processor/processor/db.go
@@ -3,12 +3,13 @@ package processor
 import (
 	"context"
 
+	"github.com/Baitinq/fs-tracer-backend/lib"
 	"github.com/jmoiron/sqlx"
 )
 
 //go:generate mockgen -source=$GOFILE -package=$GOPACKAGE -destination=mock_$GOFILE
 type DB interface {
-	InsertFile(ctx context.Context, file File) error
+	InsertFile(ctx context.Context, file lib.File) error
 }
 
 type DBImpl struct {
@@ -21,7 +22,7 @@ func NewDB(db *sqlx.DB) DB {
 	return &DBImpl{db: db}
 }
 
-func (db DBImpl) InsertFile(ctx context.Context, file File) error {
+func (db DBImpl) InsertFile(ctx context.Context, file lib.File) error {
 	_, err := db.db.NamedExecContext(ctx, "INSERT INTO private.file (user_id, absolute_path, contents, timestamp) VALUES (:user_id, :absolute_path, :contents, :timestamp)", file)
 	return err
 }
diff --git a/src/payload-processor/processor/mock_db.go b/src/payload-processor/processor/mock_db.go
index 53e5491..1b283bd 100644
--- a/src/payload-processor/processor/mock_db.go
+++ b/src/payload-processor/processor/mock_db.go
@@ -13,6 +13,7 @@ import (
 	context "context"
 	reflect "reflect"
 
+	lib "github.com/Baitinq/fs-tracer-backend/lib"
 	gomock "go.uber.org/mock/gomock"
 )
 
@@ -40,7 +41,7 @@ func (m *MockDB) EXPECT() *MockDBMockRecorder {
 }
 
 // InsertFile mocks base method.
-func (m *MockDB) InsertFile(ctx context.Context, file File) error {
+func (m *MockDB) InsertFile(ctx context.Context, file lib.File) error {
 	m.ctrl.T.Helper()
 	ret := m.ctrl.Call(m, "InsertFile", ctx, file)
 	ret0, _ := ret[0].(error)
diff --git a/src/payload-processor/processor/processor.go b/src/payload-processor/processor/processor.go
index 889f4c0..ab128cb 100644
--- a/src/payload-processor/processor/processor.go
+++ b/src/payload-processor/processor/processor.go
@@ -11,6 +11,7 @@ import (
 	"syscall"
 	"time"
 
+	"github.com/Baitinq/fs-tracer-backend/lib"
 	"github.com/google/uuid"
 	"github.com/jmoiron/sqlx"
 	"github.com/segmentio/kafka-go"
@@ -92,7 +93,7 @@ func (p Processor) process(ctx context.Context, cancel context.CancelFunc) {
 func (p Processor) handleMessage(ctx context.Context, m kafka.Message) error {
 	fmt.Printf("(%s): message at paritition %d: offset %d: %s = %s\n", time.Now().String(), m.Partition, m.Offset, string(m.Key), string(m.Value))
 
-	var file File
+	var file lib.File
 	err := json.Unmarshal(m.Value, &file)
 	if err != nil {
 		return err
diff --git a/src/payload-processor/processor/processor_test.go b/src/payload-processor/processor/processor_test.go
index d3778de..39e965e 100644
--- a/src/payload-processor/processor/processor_test.go
+++ b/src/payload-processor/processor/processor_test.go
@@ -5,6 +5,7 @@ import (
 	"testing"
 	"time"
 
+	"github.com/Baitinq/fs-tracer-backend/lib"
 	"github.com/segmentio/kafka-go"
 	"github.com/stretchr/testify/require"
 	gomock "go.uber.org/mock/gomock"
@@ -28,7 +29,7 @@ func TestProcessMessage(t *testing.T) {
 
 	ctx := context.Background()
 
-	mockdb.EXPECT().InsertFile(ctx, File{
+	mockdb.EXPECT().InsertFile(ctx, lib.File{
 		User_id:       "1",
 		Absolute_path: "/tmp/file.txt",
 		Contents:      "hello world",
diff --git a/src/rest-api/cmd/BUILD.bazel b/src/rest-api/cmd/BUILD.bazel
index 4ecded7..0d96a1f 100644
--- a/src/rest-api/cmd/BUILD.bazel
+++ b/src/rest-api/cmd/BUILD.bazel
@@ -11,6 +11,7 @@ go_library(
     visibility = ["//visibility:private"],
     deps = [
         "//src/rest-api/handler",
+        "@com_github_jmoiron_sqlx//:sqlx",
         "@com_github_segmentio_kafka_go//:kafka-go",
         "@com_github_segmentio_kafka_go//sasl/plain",
     ],
diff --git a/src/rest-api/cmd/main.go b/src/rest-api/cmd/main.go
index d1e44b3..98f3722 100644
--- a/src/rest-api/cmd/main.go
+++ b/src/rest-api/cmd/main.go
@@ -9,6 +9,7 @@ import (
 	"time"
 
 	"github.com/Baitinq/fs-tracer-backend/src/rest-api/handler"
+	"github.com/jmoiron/sqlx"
 	"github.com/segmentio/kafka-go"
 	"github.com/segmentio/kafka-go/sasl/plain"
 )
@@ -47,13 +48,22 @@ func main() {
 		AllowAutoTopicCreation: true,
 	}
 
-	handler := handler.NewHandler(kafka_writer)
+	db_password, ok := os.LookupEnv("DB_PASSWORD")
+	if !ok {
+		log.Fatal("DB_PASSWORD not set")
+	}
+	db, err := sqlx.Connect("postgres", fmt.Sprintf("postgres://postgres.slpoocycjgqsuoedhkbn:%s@aws-0-eu-central-1.pooler.supabase.com:5432/postgres", db_password))
+	if err != nil {
+		log.Fatal("cannot initalize db client", err)
+	}
+
+	handler := handler.NewHandler(db, kafka_writer)
 
 	mux := http.NewServeMux()
 	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
 		fmt.Fprint(w, "Hello folks!")
 	})
-	mux.Handle("/payload", handler)
+	mux.Handle("/file/", handler)
 
 	http.ListenAndServe(":8080", mux)
 }
diff --git a/src/rest-api/handler/BUILD.bazel b/src/rest-api/handler/BUILD.bazel
index 89adc69..e588929 100644
--- a/src/rest-api/handler/BUILD.bazel
+++ b/src/rest-api/handler/BUILD.bazel
@@ -1,9 +1,30 @@
-load("@io_bazel_rules_go//go:def.bzl", "go_library")
+load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
 
 go_library(
     name = "handler",
-    srcs = ["handler.go"],
+    srcs = [
+        "db.go",
+        "handler.go",
+        "mock_db.go",
+    ],
     importpath = "github.com/Baitinq/fs-tracer-backend/src/rest-api/handler",
     visibility = ["//visibility:public"],
-    deps = ["@com_github_segmentio_kafka_go//:kafka-go"],
+    deps = [
+        "//lib",
+        "@com_github_jmoiron_sqlx//:sqlx",
+        "@com_github_lib_pq//:pq",
+        "@com_github_segmentio_kafka_go//:kafka-go",
+        "@org_uber_go_mock//gomock",
+    ],
+)
+
+go_test(
+    name = "handler_test",
+    srcs = ["handler_test.go"],
+    embed = [":handler"],
+    deps = [
+        "//lib",
+        "@com_github_stretchr_testify//require",
+        "@org_uber_go_mock//gomock",
+    ],
 )
diff --git a/src/rest-api/handler/db.go b/src/rest-api/handler/db.go
new file mode 100644
index 0000000..0093c41
--- /dev/null
+++ b/src/rest-api/handler/db.go
@@ -0,0 +1,37 @@
+package handler
+
+import (
+	"context"
+
+	"github.com/Baitinq/fs-tracer-backend/lib"
+	"github.com/jmoiron/sqlx"
+)
+
+//go:generate mockgen -source=$GOFILE -package=$GOPACKAGE -destination=mock_$GOFILE
+type DB interface {
+	GetLatestFileByPath(ctx context.Context, path string) (*lib.File, error)
+}
+
+type DBImpl struct {
+	db *sqlx.DB
+}
+
+var _ DB = (*DBImpl)(nil)
+
+func NewDB(db *sqlx.DB) DB {
+	return &DBImpl{db: db}
+}
+
+func (db DBImpl) GetLatestFileByPath(ctx context.Context, path string) (*lib.File, error) {
+	var file lib.File
+	err := db.db.GetContext(ctx, &file, `
+		SELECT * FROM private.file
+		WHERE absolute_path = $1
+		ORDER BY timestamp DESC
+		LIMIT 1
+	`, path)
+	if err != nil {
+		return nil, err
+	}
+	return &file, nil
+}
diff --git a/src/rest-api/handler/handler.go b/src/rest-api/handler/handler.go
index 9e44612..558e773 100644
--- a/src/rest-api/handler/handler.go
+++ b/src/rest-api/handler/handler.go
@@ -6,22 +6,58 @@ import (
 	"io"
 	"log"
 	"net/http"
+	"strings"
 	"time"
 
+	"github.com/jmoiron/sqlx"
+	_ "github.com/lib/pq"
 	"github.com/segmentio/kafka-go"
 )
 
 type Handler struct {
+	db           DB
 	kafka_writer *kafka.Writer
 }
 
-func NewHandler(kafka_writer *kafka.Writer) Handler {
+func NewHandler(db *sqlx.DB, kafka_writer *kafka.Writer) Handler {
 	return Handler{
+		db:           NewDB(db),
 		kafka_writer: kafka_writer,
 	}
 }
 
 func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	switch r.Method {
+	case http.MethodGet:
+		h.handleGet(w, r)
+	case http.MethodPost:
+		h.handlePost(w, r)
+	default:
+		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
+	}
+}
+
+func (h Handler) handleGet(w http.ResponseWriter, r *http.Request) {
+	_, filePath, ok := strings.Cut(r.URL.Path, "/file/")
+	if !ok {
+		http.Error(w, "Invalid file path", http.StatusBadRequest)
+		return
+	}
+
+	log.Println("File path: ", filePath)
+
+	ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
+	defer cancel()
+	file, err := h.db.GetLatestFileByPath(ctx, filePath)
+	if err != nil {
+		http.Error(w, fmt.Sprintf("Internal server error: %s", err), http.StatusInternalServerError)
+		return
+	}
+
+	fmt.Fprintln(w, "File: ", file)
+}
+
+func (h Handler) handlePost(w http.ResponseWriter, r *http.Request) {
 	bytes, err := io.ReadAll(io.Reader(r.Body))
 	if err != nil {
 		log.Fatal(err)
diff --git a/src/rest-api/handler/handler_test.go b/src/rest-api/handler/handler_test.go
new file mode 100644
index 0000000..94b58e4
--- /dev/null
+++ b/src/rest-api/handler/handler_test.go
@@ -0,0 +1,31 @@
+package handler
+
+import (
+	"fmt"
+	"net/http"
+	"net/http/httptest"
+	"strings"
+	"testing"
+
+	"github.com/Baitinq/fs-tracer-backend/lib"
+	"github.com/stretchr/testify/require"
+	gomock "go.uber.org/mock/gomock"
+)
+
+func TestHandleGet(t *testing.T) {
+	ctrl := gomock.NewController(t)
+	db := NewMockDB(ctrl)
+	recorder := httptest.NewRecorder()
+
+	handler := Handler{db: db}
+
+	file := &lib.File{
+		Absolute_path: "/tmp/file.txt",
+	}
+	db.EXPECT().GetLatestFileByPath(gomock.Any(), "/tmp/file.txt").Return(file, nil)
+
+	handler.handleGet(recorder, httptest.NewRequest(http.MethodGet, "/file/%2ftmp%2Ffile.txt", nil))
+
+	require.Equal(t, http.StatusOK, recorder.Code)
+	require.Equal(t, fmt.Sprintln("File: ", file), recorder.Body.String())
+}
diff --git a/src/rest-api/handler/mock_db.go b/src/rest-api/handler/mock_db.go
new file mode 100644
index 0000000..2d51a8f
--- /dev/null
+++ b/src/rest-api/handler/mock_db.go
@@ -0,0 +1,56 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: src/rest-api/handler/db.go
+//
+// Generated by this command:
+//
+//	mockgen -source src/rest-api/handler/db.go -package handler -destination=src/rest-api/handler/mock_db.go
+//
+
+// Package handler is a generated GoMock package.
+package handler
+
+import (
+	context "context"
+	reflect "reflect"
+
+	lib "github.com/Baitinq/fs-tracer-backend/lib"
+	gomock "go.uber.org/mock/gomock"
+)
+
+// MockDB is a mock of DB interface.
+type MockDB struct {
+	ctrl     *gomock.Controller
+	recorder *MockDBMockRecorder
+}
+
+// MockDBMockRecorder is the mock recorder for MockDB.
+type MockDBMockRecorder struct {
+	mock *MockDB
+}
+
+// NewMockDB creates a new mock instance.
+func NewMockDB(ctrl *gomock.Controller) *MockDB {
+	mock := &MockDB{ctrl: ctrl}
+	mock.recorder = &MockDBMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockDB) EXPECT() *MockDBMockRecorder {
+	return m.recorder
+}
+
+// GetLatestFileByPath mocks base method.
+func (m *MockDB) GetLatestFileByPath(ctx context.Context, path string) (*lib.File, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "GetLatestFileByPath", ctx, path)
+	ret0, _ := ret[0].(*lib.File)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// GetLatestFileByPath indicates an expected call of GetLatestFileByPath.
+func (mr *MockDBMockRecorder) GetLatestFileByPath(ctx, path any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLatestFileByPath", reflect.TypeOf((*MockDB)(nil).GetLatestFileByPath), ctx, path)
+}