Simple API to access files using link

This commit is contained in:
Alex Borisov 2024-02-01 17:47:50 +03:00
commit 5f0f91adcf
7 changed files with 269 additions and 0 deletions

View File

@ -0,0 +1,70 @@
name: Actions Build Docker Image
run-name: ${{ gitea.actor }} is building new image 🚀
on: push
jobs:
Build-Docker-Image:
runs-on: soaska
steps:
- run: echo "🎉 The job was automatically triggered by a ${{ gitea.event_name }} event."
- name: Install Node.js
run: |
apk add --no-cache nodejs
- name: Check out repository code
uses: actions/checkout@v3
- name: List files in the repository
run: |
ls ${{ gitea.workspace }}
- run: echo "🍏 This job's status is ${{ job.status }}."
- name: Install Docker
run: |
apk add --no-cache docker
- name: Start Docker service
run: |
dockerd &
sleep 5
docker info
- name: Build Dockerfile
run: |
docker build -t $(basename ${{ github.repository }}) .
- name: Upload Docker image to soaska.ru
run: |
package_name=$(basename ${{ github.repository }})
branch_name=$(git rev-parse --abbrev-ref HEAD)
docker login -u ${{ secrets.username }} -p ${{ secrets.password }} soaska.ru
docker tag $package_name soaska.ru/soaska/$package_name:$branch_name
docker tag $package_name soaska.ru/soaska/$package_name:latest
docker push soaska.ru/soaska/$package_name:$branch_name
docker push soaska.ru/soaska/$package_name:latest
Build-Binary:
runs-on: soaska
steps:
- run: echo "🎉 The job was automatically triggered by a ${{ gitea.event_name }} event."
- name: Install Node.js
run: |
apk add --no-cache nodejs
- name: Check out repository code
uses: actions/checkout@v3
- name: List files in the repository
run: |
ls ${{ gitea.workspace }}
- run: echo "🍏 This job's status is ${{ job.status }}."
- name: Install go
run: |
apk add --no-cache go
- name: Install go dependencies
run: |
go mod download
- name: Build Binary
run: |
go build -o $(basename ${{ gitea.repository }}) .
- name: Upload binary to soaska.ru
run: |
package_name=$(basename ${{ gitea.repository }})
branch_name=$(git rev-parse --abbrev-ref HEAD)
current_date=$(date +%Y-%m-%d-%H-%M-%S)
curl --user ${{ secrets.username }}:${{ secrets.password }} \
--upload-file $package_name \
https://soaska.ru/api/packages/${{ secrets.username }}/generic/$package_name-$branch_name/&current_date/$package_name

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.env
.vscode
readme.md

16
Dockerfile Normal file
View File

@ -0,0 +1,16 @@
# Stage 1: Build the Rod application
FROM golang AS builder
WORKDIR /app
COPY go.mod go.sum /app/
RUN go mod download
COPY *.go /app/
## RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .
# Stage 2: Use a slim image for the runnable container
FROM alpine as runtime
WORKDIR /root/
COPY --from=builder /app/main .
CMD ["./main"]

6
example.env Normal file
View File

@ -0,0 +1,6 @@
# Примеры переменных
S3_ACCESS_KEY_ID=your_access_key_id
S3_SECRET_ACCESS_KEY=your_secret_access_key
S3_BUCKET_NAME=your_bucket_name
S3_ENDPOINT_URL=your_endpoint
PORT=8080

20
go.mod Normal file
View File

@ -0,0 +1,20 @@
module soaska.ru/soaska/MinIO-Share-S3
go 1.21.6
require (
github.com/gorilla/mux v1.8.1
github.com/minio/minio-go v6.0.14+incompatible
)
require github.com/stretchr/testify v1.8.4 // indirect
require (
github.com/go-ini/ini v1.67.0 // indirect
github.com/joho/godotenv v1.5.1
github.com/mitchellh/go-homedir v1.1.0 // indirect
golang.org/x/crypto v0.18.0 // indirect
golang.org/x/net v0.20.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
)

26
go.sum Normal file
View File

@ -0,0 +1,26 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/minio/minio-go v6.0.14+incompatible h1:fnV+GD28LeqdN6vT2XdGKW8Qe/IfjJDswNVuni6km9o=
github.com/minio/minio-go v6.0.14+incompatible/go.mod h1:7guKYtitv8dktvNUGrhzmNlA5wrAABTQXCoesZdFQO8=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

128
run.go Normal file
View File

@ -0,0 +1,128 @@
package main
import (
"fmt"
"io"
"log"
"net/http"
"os"
"time"
"github.com/gorilla/mux"
"github.com/joho/godotenv"
"github.com/minio/minio-go"
)
func main() {
// Get environment variables
accessKeyID, secretAccessKey, bucketName, endpoint, port := getEnv()
// Initialize MinIO client
minioClient, err := minio.New(endpoint, accessKeyID, secretAccessKey, true)
if err != nil {
log.Fatal(err)
}
// Create a new router
router := mux.NewRouter()
// Define the file handler
router.HandleFunc("/{path:.*}", func(w http.ResponseWriter, r *http.Request) {
log.Printf("Received request: %s %s", r.Method, r.RequestURI)
vars := mux.Vars(r)
path := vars["path"]
log.Print("Path: ", path)
// Get the file from S3
object, err := minioClient.GetObject(bucketName, path, minio.GetObjectOptions{})
if err != nil {
if minio.ToErrorResponse(err).Code == "NoSuchKey" {
log.Printf("Object not found in S3: %s", err)
http.Error(w, "Object not found", http.StatusNotFound)
return
}
log.Printf("Error getting object from S3: %s", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Get the object info
info, err := object.Stat()
if err != nil {
if minio.ToErrorResponse(err).Code == "NoSuchKey" {
log.Printf("Object not found in S3: %s", err)
http.Error(w, "Object not found", http.StatusNotFound)
return
}
log.Printf("Error getting object info: %s", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// Set the content type header
contentType := info.ContentType
w.Header().Set("Content-Type", contentType)
// Copy the file to the response writer
_, err = io.Copy(w, object)
if err != nil {
log.Printf("Error copying file to response writer: %s", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}).Methods("GET")
router.Use(loggingMiddleware)
// Start the server
if port == "" {
port = "8080"
}
addr := fmt.Sprintf(":%s", port)
log.Printf("Server listening on %s", addr)
log.Fatal(http.ListenAndServe(addr, router))
}
func getEnv() (string, string, string, string, string) {
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
// Get environment variables
port := os.Getenv("PORT")
accessKeyID := os.Getenv("S3_ACCESS_KEY_ID")
secretAccessKey := os.Getenv("S3_SECRET_ACCESS_KEY")
bucketName := os.Getenv("S3_BUCKET_NAME")
endpoint := os.Getenv("S3_ENDPOINT_URL")
return accessKeyID, secretAccessKey, bucketName, endpoint, port
}
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
startTime := time.Now()
next.ServeHTTP(w, r)
duration := time.Since(startTime)
log.Printf("Processed request: %s %s. Duration: %v\n", r.Method, r.RequestURI, duration)
})
}
func GetObjectList(bucketName string, minioClient *minio.Client) ([]string, error) {
var objectList []string
// Get the list of objects
objectCh := minioClient.ListObjects(bucketName, "", true, nil)
for object := range objectCh {
if object.Err != nil {
return nil, object.Err
}
objectList = append(objectList, object.Key)
}
return objectList, nil
}