diff options
Diffstat (limited to 'src/rest-api')
-rw-r--r-- | src/rest-api/cmd/BUILD.bazel | 1 | ||||
-rw-r--r-- | src/rest-api/cmd/main.go | 14 | ||||
-rw-r--r-- | src/rest-api/handler/BUILD.bazel | 27 | ||||
-rw-r--r-- | src/rest-api/handler/db.go | 37 | ||||
-rw-r--r-- | src/rest-api/handler/handler.go | 38 | ||||
-rw-r--r-- | src/rest-api/handler/handler_test.go | 31 | ||||
-rw-r--r-- | src/rest-api/handler/mock_db.go | 56 |
7 files changed, 198 insertions, 6 deletions
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) +} |