Skip to content
Snippets Groups Projects
handler.go 7.33 KiB
Newer Older
  • Learn to ignore specific revisions
  • OZGCloud's avatar
    OZGCloud committed
    /*
     * Copyright (C) 2023-2024
     * 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.
     */
    
    package server
    
    import (
    
    	pb "antragsraum-proxy/gen/go"
    
    OZGCloud's avatar
    OZGCloud committed
    	"context"
    	"fmt"
    	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
    
    	"google.golang.org/grpc"
    
    OZGCloud's avatar
    OZGCloud committed
    	"google.golang.org/grpc/codes"
    
    	"google.golang.org/grpc/credentials/insecure"
    
    OZGCloud's avatar
    OZGCloud committed
    	"google.golang.org/grpc/status"
    
    	"mime/multipart"
    
    OZGCloud's avatar
    OZGCloud committed
    	"net/http"
    )
    
    func RegisterHomeEndpoint(mux *runtime.ServeMux) {
    	err := mux.HandlePath("GET", "/", func(w http.ResponseWriter, r *http.Request, pathParams map[string]string) {
    		defer func() {
    			if err := recover(); err != nil {
    				logger.Error("failed to recover: %v", err)
    				http.Error(w, fmt.Sprintf("failed to recover: %v", err), http.StatusInternalServerError)
    			}
    		}()
    	})
    
    	if err != nil {
    		logger.Fatal("failed to register home endpoint: %v", err)
    	}
    }
    
    
    OZGCloud's avatar
    OZGCloud committed
    func RegisterAntragraumEndpoints(ctx context.Context, mux *runtime.ServeMux, grpcUrl string) {
    	opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
    	err := pb.RegisterAntragraumServiceHandlerFromEndpoint(ctx, mux, grpcUrl, opts)
    	if err != nil {
    		logger.Fatal("failed to register antragraum endpoints: %v", err)
    	}
    }
    
    func RegisterCommandEndpoints(ctx context.Context, mux *runtime.ServeMux, grpcUrl string) {
    	opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
    	err := pb.RegisterCommandServiceHandlerFromEndpoint(ctx, mux, grpcUrl, opts)
    	if err != nil {
    		logger.Fatal("failed to register command endpoints: %v", err)
    	}
    }
    
    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", func(w http.ResponseWriter, r *http.Request, _ map[string]string) {
    		if err := r.ParseMultipartForm(32 << 20); err != nil {
    			http.Error(w, "invalid multipart form", http.StatusBadRequest)
    			return
    		}
    
    		file, header, err := r.FormFile("file")
    		if err != nil {
    			http.Error(w, "file retrieval error", http.StatusBadRequest)
    			return
    		}
    		defer file.Close()
    
    
    OZGCloud's avatar
    OZGCloud committed
    		conn, err := grpc.NewClient(GetGrpcServerUrl(r.Header.Get(GrpcAddressHeader), conf), grpc.WithTransportCredentials(insecure.NewCredentials()))
    
    		if err != nil {
    			http.Error(w, "gRPC connection error", http.StatusInternalServerError)
    			return
    		}
    		defer conn.Close()
    
    		client := pb.NewBinaryFileServiceClient(conn)
    		stream, err := client.UploadBinaryFileAsStream(r.Context())
    		if err != nil {
    			http.Error(w, "stream creation error", http.StatusInternalServerError)
    			return
    		}
    
    		meta := &pb.GrpcUploadBinaryFileRequest{
    			Request: &pb.GrpcUploadBinaryFileRequest_Metadata{
    				Metadata: &pb.GrpcUploadBinaryFileMetaData{
    					FileName: header.Filename,
    				},
    			},
    		}
    		if err := stream.Send(meta); err != nil {
    
    OZGCloud's avatar
    OZGCloud committed
    			http.Error(w, "metadata send error", http.StatusInternalServerError)
    
    			return
    		}
    
    		buf := make([]byte, 1024*1024)
    		for {
    			n, err := file.Read(buf)
    			if err == io.EOF {
    				break
    			}
    			if err != nil {
    
    OZGCloud's avatar
    OZGCloud committed
    				http.Error(w, "file read error", http.StatusInternalServerError)
    
    OZGCloud's avatar
    OZGCloud committed
    
    			req := &pb.GrpcUploadBinaryFileRequest{Request: &pb.GrpcUploadBinaryFileRequest_FileContent{FileContent: buf[:n]}}
    			if err = stream.Send(req); err != nil {
    				http.Error(w, "chunk send error", http.StatusInternalServerError)
    
    				return
    			}
    		}
    
    		resp, err := stream.CloseAndRecv()
    		if err != nil {
    
    OZGCloud's avatar
    OZGCloud committed
    			http.Error(w, "response error", http.StatusInternalServerError)
    
    			return
    		}
    
    		w.WriteHeader(http.StatusOK)
    		w.Write([]byte(resp.FileId))
    	})
    
    	if err != nil {
    
    OZGCloud's avatar
    OZGCloud committed
    		logger.Fatal("endpoint registration failed: %v", err)
    
    func RegisterGetFileEndpoint(mux *runtime.ServeMux) {
    
    OZGCloud's avatar
    OZGCloud committed
    	err := mux.HandlePath("GET", "/api/v1/file/content/{fileId}", func(w http.ResponseWriter, r *http.Request, vars map[string]string) {
    
    		var fileBuffer bytes.Buffer
    
    
    OZGCloud's avatar
    OZGCloud committed
    		conn, err := grpc.NewClient(GetGrpcServerUrl(r.Header.Get(GrpcAddressHeader), conf), grpc.WithTransportCredentials(insecure.NewCredentials()))
    
    		if err != nil {
    			http.Error(w, "gRPC connection error", http.StatusInternalServerError)
    			return
    		}
    		defer conn.Close()
    
    		client := pb.NewBinaryFileServiceClient(conn)
    		req := &pb.GrpcGetBinaryFileDataRequest{FileId: vars["fileId"]}
    		clientStream, err := client.GetBinaryFileContent(r.Context(), req)
    		if err != nil {
    			http.Error(w, "stream creation error", http.StatusInternalServerError)
    			return
    		}
    
    		for {
    			resp, err := clientStream.Recv()
    			if err == io.EOF {
    				break
    			}
    			if err != nil {
    
    OZGCloud's avatar
    OZGCloud committed
    				http.Error(w, "error receiving file chunks", http.StatusInternalServerError)
    
    				return
    			}
    
    			_, err = fileBuffer.Write(resp.FileContent)
    			if err != nil {
    
    OZGCloud's avatar
    OZGCloud committed
    				http.Error(w, "error writing file data", http.StatusInternalServerError)
    
    				return
    			}
    		}
    
    		w.Header().Set("Content-Type", "multipart/form-data")
    		w.Header().Set("Content-Disposition", `attachment; filename="file"`)
    		w.WriteHeader(http.StatusOK)
    
    		mw := multipart.NewWriter(w)
    		part, err := mw.CreateFormFile("file", "file")
    		if err != nil {
    
    OZGCloud's avatar
    OZGCloud committed
    			http.Error(w, "error creating multipart form file", http.StatusInternalServerError)
    
    			return
    		}
    
    		_, err = fileBuffer.WriteTo(part)
    		if err != nil {
    
    OZGCloud's avatar
    OZGCloud committed
    			http.Error(w, "error writing file data to multipart", http.StatusInternalServerError)
    
    			return
    		}
    
    		err = mw.Close()
    		if err != nil {
    
    OZGCloud's avatar
    OZGCloud committed
    			http.Error(w, "error closing multipart writer", http.StatusInternalServerError)
    
    OZGCloud's avatar
    OZGCloud committed
    		logger.Fatal("endpoint registration failed: %v", err)
    
    OZGCloud's avatar
    OZGCloud committed
    func ErrorHandler(ctx context.Context, mux *runtime.ServeMux, marshaler runtime.Marshaler, w http.ResponseWriter, r *http.Request, err error) {
    	st, ok := status.FromError(err)
    	if !ok {
    		runtime.DefaultHTTPErrorHandler(ctx, mux, marshaler, w, r, err)
    		return
    	}
    
    	statusCodeMap := map[codes.Code]int{
    		codes.InvalidArgument: http.StatusBadRequest,
    		codes.AlreadyExists:   http.StatusConflict,
    		codes.Unavailable:     http.StatusServiceUnavailable,
    	}
    
    	httpStatusCode := http.StatusInternalServerError
    
    	if code, exists := statusCodeMap[st.Code()]; exists {
    		httpStatusCode = code
    	}
    
    	w.Header().Set("Content-Type", marshaler.ContentType(r))
    	w.WriteHeader(httpStatusCode)
    
    	_, writeErr := w.Write([]byte(st.Message()))
    	if writeErr != nil {
    		logger.Fatal("failed to handle grpc error: %v", writeErr)
    	}
    }