Skip to content
Snippets Groups Projects
Commit 75d72351 authored by OZGCloud's avatar OZGCloud
Browse files

OZG-6949 rewire file api

parent 3bf2ab85
No related branches found
No related tags found
No related merge requests found
......@@ -12,7 +12,8 @@ http:
- selector: de.ozgcloud.nachrichten.antragraum.AntragraumService.FindRueckfragen
post: "/api/v1/rueckfragen"
body: "*"
- selector: de.ozgcloud.nachrichten.antragraum.AntragraumService.GetAttachmentMetadata
post: "/api/v1/file/metadata"
body: "*"
- selector: de.ozgcloud.vorgang.grpc.command.CommandService.GetCommand
get: "/api/v1/command/{id}"
\ No newline at end of file
- selector: de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileService.FindBinaryFilesMetaData
get: "/api/v1/file/metadata/{fileId}"
\ No newline at end of file
......@@ -108,10 +108,10 @@ openapiOptions:
description: Returned when the resource is temporarily unavailable.
"404":
description: Returned when the resource does not exist.
- method: de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileService.GetBinaryFileContent
- method: de.ozgcloud.nachrichten.antragraum.AntragraumService.GetAttachmentContent
option:
description: "Get the content of a file"
summary: "Summary: GetBinaryFileContent rpc"
summary: "Summary: GetAttachmentContent rpc"
responses:
"200":
description: Returns file content as binary stream.
......@@ -119,10 +119,10 @@ openapiOptions:
description: Returned when the resource is temporarily unavailable.
"404":
description: Returned when the resource does not exist.
- method: de.ozgcloud.vorgang.grpc.binaryFile.BinaryFileService.FindBinaryFilesMetaData
- method: de.ozgcloud.nachrichten.antragraum.AntragraumService.GetAttachmentMetadata
option:
description: "Get the metadata of a file"
summary: "Summary: FindBinaryFilesMetaData rpc"
summary: "Summary: GetAttachmentMetadata rpc"
responses:
"200":
description: Returns file metadata as json.
......
......@@ -89,3 +89,29 @@ message GrpcGetRueckfrageRequest {
message GrpcGetRueckfrageResponse {
GrpcRueckfrage rueckfrage = 1;
}
message GrpcGetAttachmentContentRequest {
string samlToken = 1;
string nachrichtId = 2;
string fileId = 3;
}
message GrpcGetAttachmentContentResponse {
bytes fileContent = 1;
}
message GrpcGetAttachmentMetadataRequest {
string samlToken = 1;
string nachrichtId = 2;
string fileId = 3;
}
message GrpcGetAttachmentMetadataResponse {
GrpcFileMetadata fileMetadata = 1;
}
message GrpcFileMetadata {
string name = 1;
int64 size = 2;
string contentType = 3;
}
\ No newline at end of file
......@@ -26,14 +26,23 @@ syntax = "proto3";
package de.ozgcloud.nachrichten.antragraum;
import "antragraum.model.proto";
import "command.model.proto";
option go_package = "de.ozgcloud.antragraumproxy";
service AntragraumService {
rpc FindRueckfragen(GrpcFindRueckfragenRequest) returns (GrpcFindRueckfragenResponse);
rpc SendRueckfrageAnswer(GrpcSendRueckfrageAnswerRequest) returns (GrpcSendRueckfrageAnswerResponse);
rpc FindRueckfragen(GrpcFindRueckfragenRequest) returns (GrpcFindRueckfragenResponse) {
}
rpc SendRueckfrageAnswer(GrpcSendRueckfrageAnswerRequest) returns (GrpcSendRueckfrageAnswerResponse) {
}
rpc GetRueckfrage(GrpcGetRueckfrageRequest) returns (GrpcGetRueckfrageResponse){
}
rpc GetAttachmentContent(GrpcGetAttachmentContentRequest) returns (stream GrpcGetAttachmentContentResponse){
}
rpc GetRueckfrage(GrpcGetRueckfrageRequest) returns (GrpcGetRueckfrageResponse);
rpc GetAttachmentMetadata(GrpcGetAttachmentMetadataRequest) returns (GrpcGetAttachmentMetadataResponse){
}
}
\ No newline at end of file
......@@ -26,7 +26,6 @@ syntax = "proto3";
package de.ozgcloud.vorgang.grpc.binaryFile;
import "callcontext.proto";
import "filemodel.proto";
option go_package = "de.ozgcloud.antragraumproxy";
......@@ -34,26 +33,6 @@ service BinaryFileService {
rpc UploadBinaryFileAsStream(stream GrpcUploadBinaryFileRequest) returns (GrpcUploadBinaryFileResponse) {
}
rpc GetBinaryFileContent(GrpcGetBinaryFileDataRequest) returns (stream GrpcGetBinaryFileDataResponse) {
}
rpc FindBinaryFilesMetaData(GrpcBinaryFilesRequest) returns (GrpcFindFilesResponse) {
}
}
message GrpcBinaryFilesRequest {
de.ozgcloud.vorgang.grpc.command.GrpcCallContext context = 1;
repeated string fileId = 2;
}
message GrpcFindFilesResponse {
repeated de.ozgcloud.vorgang.grpc.file.GrpcOzgFile file = 1;
}
message GrpcBinaryFileDataRequest {
de.ozgcloud.vorgang.grpc.command.GrpcCallContext context = 1;
string fileId = 2;
}
message GrpcUploadBinaryFileRequest {
......@@ -75,19 +54,3 @@ message GrpcUploadBinaryFileMetaData {
message GrpcUploadBinaryFileResponse {
string fileId = 2;
}
\ No newline at end of file
message GrpcGetBinaryFileDataRequest {
de.ozgcloud.vorgang.grpc.command.GrpcCallContext context = 1;
string fileId = 2;
}
message GrpcGetBinaryFileDataResponse {
bytes fileContent = 1;
}
message GrpcBinaryFile {
string id = 1;
string name = 2;
int64 size = 3;
string contentType = 4;
}
\ No newline at end of file
/*
* Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den
* Ministerpräsidenten des Landes Schleswig-Holstein
* Staatskanzlei
* Abteilung Digitalisierung und zentrales IT-Management der Landesregierung
*
* Lizenziert unter der EUPL, Version 1.2 oder - sobald
* diese von der Europäischen Kommission genehmigt wurden -
* Folgeversionen der EUPL ("Lizenz");
* Sie dürfen dieses Werk ausschließlich gemäß
* dieser Lizenz nutzen.
* Eine Kopie der Lizenz finden Sie hier:
*
* https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
*
* Sofern nicht durch anwendbare Rechtsvorschriften
* gefordert oder in schriftlicher Form vereinbart, wird
* die unter der Lizenz verbreitete Software "so wie sie
* ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN -
* ausdrücklich oder stillschweigend - verbreitet.
* Die sprachspezifischen Genehmigungen und Beschränkungen
* unter der Lizenz sind dem Lizenztext zu entnehmen.
*/
syntax = "proto3";
package de.ozgcloud.vorgang.grpc.file;
import "callcontext.proto";
option go_package = "de.ozgcloud.antragraumproxy";
message GrpcGetAttachmentsRequest {
de.ozgcloud.vorgang.grpc.command.GrpcCallContext context = 1;
string eingangId = 2;
}
message GrpcGetAttachmentsResponse {
repeated GrpcOzgFile file = 1;
}
message GrpcGetRepresentationsRequest {
de.ozgcloud.vorgang.grpc.command.GrpcCallContext context = 1;
string eingangId = 2;
}
message GrpcGetRepresentationsResponse {
repeated GrpcOzgFile file = 1;
}
message GrpcOzgFile {
string id = 1;
string name = 2;
int64 size = 3;
string contentType = 4;
}
\ No newline at end of file
......@@ -75,31 +75,7 @@ func (s *rueckfrageServer) SendRueckfrageAnswer(_ context.Context, _ *pb.GrpcSen
return &pb.GrpcSendRueckfrageAnswerResponse{}, nil
}
type commandServer struct {
pb.UnimplementedCommandServiceServer
}
func (s *commandServer) GetCommand(_ context.Context, in *pb.GrpcGetCommandRequest) (*pb.GrpcCommand, error) {
if in.Id == "" {
return nil, status.Error(codes.InvalidArgument, "Id is missing")
}
return &pb.GrpcCommand{}, nil
}
type binaryFileServer struct {
pb.UnimplementedBinaryFileServiceServer
}
func (s *binaryFileServer) FindBinaryFilesMetaData(_ context.Context, _ *pb.GrpcBinaryFilesRequest) (*pb.GrpcFindFilesResponse, error) {
return &pb.GrpcFindFilesResponse{}, nil
}
func (s *binaryFileServer) GetBinaryFileContent(in *pb.GrpcGetBinaryFileDataRequest, stream pb.BinaryFileService_GetBinaryFileContentServer) error {
if in.FileId == "" {
return status.Error(codes.InvalidArgument, "FileId is missing")
}
func (s *rueckfrageServer) GetAttachmentContent(_ *pb.GrpcGetAttachmentContentRequest, stream pb.AntragraumService_GetAttachmentContentServer) error {
fp := defaultFilePath
if testing.Testing() {
fp = testFilePath
......@@ -121,7 +97,7 @@ func (s *binaryFileServer) GetBinaryFileContent(in *pb.GrpcGetBinaryFileDataRequ
return err
}
chunk := &pb.GrpcGetBinaryFileDataResponse{FileContent: buffer[:bytesRead]}
chunk := &pb.GrpcGetAttachmentContentResponse{FileContent: buffer[:bytesRead]}
if err := stream.Send(chunk); err != nil {
return err
}
......@@ -130,6 +106,30 @@ func (s *binaryFileServer) GetBinaryFileContent(in *pb.GrpcGetBinaryFileDataRequ
return nil
}
func (s *rueckfrageServer) GetAttachmentMetadata(_ context.Context, in *pb.GrpcGetAttachmentMetadataRequest) (*pb.GrpcGetAttachmentMetadataResponse, error) {
if in.FileId == "" {
return nil, status.Error(codes.InvalidArgument, "FileId is missing")
}
return &pb.GrpcGetAttachmentMetadataResponse{}, nil
}
type commandServer struct {
pb.UnimplementedCommandServiceServer
}
func (s *commandServer) GetCommand(_ context.Context, in *pb.GrpcGetCommandRequest) (*pb.GrpcCommand, error) {
if in.Id == "" {
return nil, status.Error(codes.InvalidArgument, "Id is missing")
}
return &pb.GrpcCommand{}, nil
}
type binaryFileServer struct {
pb.UnimplementedBinaryFileServiceServer
}
func (s *binaryFileServer) UploadBinaryFileAsStream(stream pb.BinaryFileService_UploadBinaryFileAsStreamServer) error {
for {
_, err := stream.Recv()
......
......@@ -115,6 +115,39 @@ func TestStartGrpcServer(t *testing.T) {
assert.NoError(t, err)
assert.NotNil(t, resp)
})
t.Run("TestGetAttachmentContent", func(t *testing.T) {
client, cleanUp := setUpGrpcEnv()
defer cleanUp()
resp, err := client.GetAttachmentContent(context.Background(), &pb.GrpcGetAttachmentContentRequest{})
assert.NoError(t, err)
assert.NotNil(t, resp)
})
t.Run("TestGetAttachmentMetadata", func(t *testing.T) {
t.Run("should have no error", func(t *testing.T) {
client, cleanUp := setUpGrpcEnv()
defer cleanUp()
resp, err := client.GetAttachmentMetadata(context.Background(), &pb.GrpcGetAttachmentMetadataRequest{FileId: "testFileId"})
assert.NoError(t, err)
assert.NotNil(t, resp)
})
t.Run("should have error", func(t *testing.T) {
client, cleanUp := setUpGrpcEnv()
defer cleanUp()
resp, err := client.GetAttachmentMetadata(context.Background(), &pb.GrpcGetAttachmentMetadataRequest{})
assert.Error(t, err)
assert.Nil(t, resp)
})
})
})
t.Run("TestCommandEndpoints", func(t *testing.T) {
......@@ -168,26 +201,6 @@ func TestStartGrpcServer(t *testing.T) {
return client, cleanup
}
t.Run("TestFindBinaryFilesMetaData", func(t *testing.T) {
client, cleanUp := setUpGrpcEnv()
defer cleanUp()
resp, err := client.FindBinaryFilesMetaData(context.Background(), &pb.GrpcBinaryFilesRequest{})
assert.NoError(t, err)
assert.NotNil(t, resp)
})
t.Run("TestGetBinaryFileContent", func(t *testing.T) {
client, cleanUp := setUpGrpcEnv()
defer cleanUp()
resp, err := client.GetBinaryFileContent(context.Background(), &pb.GrpcGetBinaryFileDataRequest{})
assert.NoError(t, err)
assert.NotNil(t, resp)
})
t.Run("TestUploadBinaryFileAsStream", func(t *testing.T) {
client, cleanUp := setUpGrpcEnv()
defer cleanUp()
......
......@@ -74,6 +74,18 @@ func (s *rueckfrageRouter) SendRueckfrageAnswer(ctx context.Context, in *pb.Grpc
return response.(*pb.GrpcSendRueckfrageAnswerResponse), err
}
func (s *rueckfrageRouter) GetAttachmentMetadata(ctx context.Context, in *pb.GrpcGetAttachmentMetadataRequest) (*pb.GrpcGetAttachmentMetadataResponse, error) {
response, err := s.handleRequest(ctx, func(client pb.AntragraumServiceClient, ctx context.Context) (interface{}, error) {
return client.GetAttachmentMetadata(ctx, in)
})
if response == nil {
return nil, err
}
return response.(*pb.GrpcGetAttachmentMetadataResponse), err
}
func (s *rueckfrageRouter) handleRequest(ctx context.Context, handler func(pb.AntragraumServiceClient, context.Context) (interface{}, error)) (interface{}, error) {
return handleRequest(ctx, createRueckfrageClient, handler)
}
......@@ -123,38 +135,6 @@ func createCommandClient(grpcAddress string) (pb.CommandServiceClient, func() er
return pb.NewCommandServiceClient(conn), conn.Close, nil
}
type binaryFileRouter struct {
pb.UnimplementedBinaryFileServiceServer
}
func (s *binaryFileRouter) FindBinaryFilesMetaData(ctx context.Context, in *pb.GrpcBinaryFilesRequest) (*pb.GrpcFindFilesResponse, error) {
response, err := s.handleRequest(ctx, func(client pb.BinaryFileServiceClient, ctx context.Context) (interface{}, error) {
return client.FindBinaryFilesMetaData(ctx, in)
})
if response == nil {
return nil, err
}
return response.(*pb.GrpcFindFilesResponse), err
}
func (s *binaryFileRouter) handleRequest(ctx context.Context, handler func(pb.BinaryFileServiceClient, context.Context) (interface{}, error)) (interface{}, error) {
return handleRequest(ctx, createBinaryFileClient, handler)
}
func createBinaryFileClient(grpcAddress string) (pb.BinaryFileServiceClient, func() error, error) {
target := GetGrpcServerUrl(grpcAddress, conf)
conn, err := grpc.NewClient(target, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
logger.Error("binary file router failed to route: %v", err)
return nil, nil, errors.New("binary file router failed to route")
}
return pb.NewBinaryFileServiceClient(conn), conn.Close, nil
}
func GetGrpcServerUrl(grpcAddress string, c config.Config) string {
return fmt.Sprintf("%v:%d", grpcAddress, c.Grpc.Server.Port)
}
......@@ -187,7 +167,6 @@ func StartGrpcRouter() *grpc.Server {
s := grpc.NewServer()
pb.RegisterAntragraumServiceServer(s, &rueckfrageRouter{})
pb.RegisterCommandServiceServer(s, &commandRouter{})
pb.RegisterBinaryFileServiceServer(s, &binaryFileRouter{})
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", conf.Grpc.Router.Port))
if err != nil {
......
......@@ -35,13 +35,13 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/encoding/protojson"
"io"
"mime/multipart"
"net/http"
)
const (
fileIdParam = "fileId"
fileFormKey = "file"
vorgangIdFormKey = "vorgangId"
contentTypeHeaderKey = "Content-Type"
......@@ -80,23 +80,15 @@ func RegisterCommandEndpoints(ctx context.Context, mux *runtime.ServeMux, grpcUr
}
}
func RegisterBinaryFileEndpoints(ctx context.Context, mux *runtime.ServeMux, grpcUrl string) {
opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
err := pb.RegisterBinaryFileServiceHandlerFromEndpoint(ctx, mux, grpcUrl, opts)
if err != nil {
logger.Fatal("failed to register binary file endpoints: %v", err)
}
}
func RegisterFileUploadEndpoint(mux *runtime.ServeMux) {
err := mux.HandlePath("POST", "/api/v1/file", fileUploadHandler)
func RegisterUploadAttachmentEndpoint(mux *runtime.ServeMux) {
err := mux.HandlePath("POST", "/api/v1/file", attachmentUploadHandler)
if err != nil {
logger.Fatal("failed to register file upload endpoint: %v", err)
}
}
func fileUploadHandler(w http.ResponseWriter, r *http.Request, _ map[string]string) {
func attachmentUploadHandler(w http.ResponseWriter, r *http.Request, _ map[string]string) {
if err := r.ParseMultipartForm(maxFileSizeInMB << 20); err != nil {
http.Error(w, "invalid multipart form", http.StatusBadRequest)
return
......@@ -194,16 +186,21 @@ func sendFileChunks(stream pb.BinaryFileService_UploadBinaryFileAsStreamClient,
return nil
}
func RegisterGetFileEndpoint(mux *runtime.ServeMux) {
err := mux.HandlePath("GET", "/api/v1/file/content/{"+fileIdParam+"}", getFileHandler)
func RegisterGetAttachmentContentEndpoint(mux *runtime.ServeMux) {
err := mux.HandlePath("POST", "/api/v1/file/content", getAttachmentContentHandler)
if err != nil {
logger.Fatal("failed to register get file endpoint: %v", err)
}
}
func getFileHandler(w http.ResponseWriter, r *http.Request, vars map[string]string) {
fileBuffer, err := fetchFileFromGrpc(r.Context(), vars[fileIdParam], r.Header.Get(GrpcAddressHeader))
func getAttachmentContentHandler(w http.ResponseWriter, r *http.Request, _ map[string]string) {
requestPayload, err := getGetAttachmentContentRequestPayload(r)
if err != nil {
http.Error(w, "failed to read request body", http.StatusBadRequest)
}
fileBuffer, err := fetchFileFromGrpc(r.Context(), requestPayload, r.Header.Get(GrpcAddressHeader))
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
......@@ -218,7 +215,22 @@ func getFileHandler(w http.ResponseWriter, r *http.Request, vars map[string]stri
}
}
func fetchFileFromGrpc(ctx context.Context, fileId string, grpcAddress string) (*bytes.Buffer, error) {
func getGetAttachmentContentRequestPayload(r *http.Request) (*pb.GrpcGetAttachmentContentRequest, error) {
body, err := io.ReadAll(r.Body)
if err != nil {
return nil, err
}
defer r.Body.Close()
var requestPayload pb.GrpcGetAttachmentContentRequest
if err = protojson.Unmarshal(body, &requestPayload); err != nil {
return nil, err
}
return &requestPayload, nil
}
func fetchFileFromGrpc(ctx context.Context, request *pb.GrpcGetAttachmentContentRequest, grpcAddress string) (*bytes.Buffer, error) {
var fileBuffer bytes.Buffer
target := GetGrpcServerUrl(grpcAddress, conf)
......@@ -228,9 +240,8 @@ func fetchFileFromGrpc(ctx context.Context, fileId string, grpcAddress string) (
}
defer conn.Close()
client := pb.NewBinaryFileServiceClient(conn)
req := &pb.GrpcGetBinaryFileDataRequest{FileId: fileId}
clientStream, err := client.GetBinaryFileContent(ctx, req)
client := pb.NewAntragraumServiceClient(conn)
clientStream, err := client.GetAttachmentContent(ctx, request)
if err != nil {
return nil, fmt.Errorf("stream creation error")
}
......
......@@ -93,15 +93,14 @@ func TestRegisterAntragraumEndpoints(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
})
}
func TestRegisterCommandEndpoints(t *testing.T) {
t.Run("should get attachment metadata", func(t *testing.T) {
mock.SetUpGrpcServer()
SetUpGrpcRouter()
SetUpHttpGateway()
jsonData := []byte(``)
req, err := http.NewRequest("GET", "http://localhost:8082/api/v1/command/testId", bytes.NewBuffer(jsonData))
jsonData := []byte(`{"fileId": "testFileId"}`)
req, err := http.NewRequest("POST", "http://localhost:8082/api/v1/file/metadata", bytes.NewBuffer(jsonData))
req.Header.Set(GrpcAddressHeader, "localhost")
client := &http.Client{}
......@@ -109,15 +108,16 @@ func TestRegisterCommandEndpoints(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
})
}
func TestRegisterBinaryFileEndpoints(t *testing.T) {
func TestRegisterCommandEndpoints(t *testing.T) {
mock.SetUpGrpcServer()
SetUpGrpcRouter()
SetUpHttpGateway()
jsonData := []byte(``)
req, err := http.NewRequest("GET", "http://localhost:8082/api/v1/file/metadata/testId", bytes.NewBuffer(jsonData))
req, err := http.NewRequest("GET", "http://localhost:8082/api/v1/command/testId", bytes.NewBuffer(jsonData))
req.Header.Set(GrpcAddressHeader, "localhost")
client := &http.Client{}
......@@ -127,7 +127,7 @@ func TestRegisterBinaryFileEndpoints(t *testing.T) {
assert.Equal(t, http.StatusOK, resp.StatusCode)
}
func TestRegisterFileUploadEndpoint(t *testing.T) {
func TestRegisterUploadAttachmentEndpoint(t *testing.T) {
mock.SetUpGrpcServer()
SetUpHttpGateway()
......@@ -158,12 +158,12 @@ func TestRegisterFileUploadEndpoint(t *testing.T) {
assert.Equal(t, http.StatusOK, resp.StatusCode)
}
func TestRegisterGetFileEndpoint(t *testing.T) {
func TestRegisterGetAttachmentContentEndpoint(t *testing.T) {
mock.SetUpGrpcServer()
SetUpHttpGateway()
jsonData := []byte(``)
req, err := http.NewRequest("GET", "http://localhost:8082/api/v1/file/content/testId", bytes.NewBuffer(jsonData))
jsonData := []byte(`{}`)
req, err := http.NewRequest("POST", "http://localhost:8082/api/v1/file/content", bytes.NewBuffer(jsonData))
req.Header.Set(GrpcAddressHeader, "localhost")
client := &http.Client{}
......
......@@ -54,9 +54,8 @@ func StartHttpGateway() *http.Server {
RegisterHomeEndpoint(mux)
RegisterAntragraumEndpoints(ctx, mux, grpcRouterUrl)
RegisterCommandEndpoints(ctx, mux, grpcRouterUrl)
RegisterBinaryFileEndpoints(ctx, mux, grpcRouterUrl)
RegisterFileUploadEndpoint(mux)
RegisterGetFileEndpoint(mux)
RegisterUploadAttachmentEndpoint(mux)
RegisterGetAttachmentContentEndpoint(mux)
httpServer := &http.Server{
Addr: fmt.Sprintf(":%d", conf.Http.Server.Port),
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment