mirror of
https://github.com/MizuchiLabs/mantrae.git
synced 2026-01-06 06:19:57 -06:00
fix: adding back agent cleanup
This commit is contained in:
36
go.mod
36
go.mod
@@ -6,6 +6,9 @@ require (
|
||||
connectrpc.com/connect v1.18.1
|
||||
connectrpc.com/grpchealth v1.3.0
|
||||
connectrpc.com/grpcreflect v1.3.0
|
||||
github.com/aws/aws-sdk-go-v2 v1.32.7
|
||||
github.com/aws/aws-sdk-go-v2/config v1.28.7
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.71.1
|
||||
github.com/caarlos0/env/v11 v11.3.1
|
||||
github.com/cloudflare/cloudflare-go v0.115.0
|
||||
github.com/docker/docker v27.4.1+incompatible
|
||||
@@ -17,10 +20,10 @@ require (
|
||||
github.com/pressly/goose/v3 v3.24.1
|
||||
github.com/traefik/paerser v0.2.1
|
||||
github.com/traefik/traefik/v3 v3.3.3
|
||||
golang.org/x/crypto v0.32.0
|
||||
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c
|
||||
golang.org/x/net v0.34.0
|
||||
google.golang.org/protobuf v1.36.4
|
||||
golang.org/x/crypto v0.33.0
|
||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac
|
||||
golang.org/x/net v0.35.0
|
||||
google.golang.org/protobuf v1.36.5
|
||||
modernc.org/sqlite v1.34.5
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
)
|
||||
@@ -28,6 +31,21 @@ require (
|
||||
require (
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/aws/aws-sdk-go v1.55.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.48 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.26 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.3 // indirect
|
||||
github.com/aws/smithy-go v1.22.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/docker/go-connections v0.5.0 // indirect
|
||||
@@ -46,7 +64,7 @@ require (
|
||||
github.com/google/go-github/v28 v28.1.1 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/gorilla/mux v1.8.1 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
|
||||
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||
github.com/http-wasm/http-wasm-host-go v0.7.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
@@ -83,12 +101,12 @@ require (
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
golang.org/x/time v0.10.0 // indirect
|
||||
golang.org/x/tools v0.29.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250204164813-702378808489 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250204164813-702378808489 // indirect
|
||||
golang.org/x/tools v0.30.0 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b // indirect
|
||||
google.golang.org/grpc v1.70.0 // indirect
|
||||
gotest.tools/v3 v3.5.1 // indirect
|
||||
modernc.org/libc v1.61.11 // indirect
|
||||
modernc.org/libc v1.61.13 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.8.2 // indirect
|
||||
)
|
||||
|
||||
80
go.sum
80
go.sum
@@ -12,6 +12,42 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/aws/aws-sdk-go v1.55.6 h1:cSg4pvZ3m8dgYcgqB97MrcdjUmZ1BeMYKUxMMB89IPk=
|
||||
github.com/aws/aws-sdk-go v1.55.6/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
|
||||
github.com/aws/aws-sdk-go-v2 v1.32.7 h1:ky5o35oENWi0JYWUZkB7WYvVPP+bcRF5/Iq7JWSb5Rw=
|
||||
github.com/aws/aws-sdk-go-v2 v1.32.7/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7 h1:lL7IfaFzngfx0ZwUGOZdsFFnQ5uLvR0hWqqhyE7Q9M8=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.7/go.mod h1:QraP0UcVlQJsmHfioCrveWOC1nbiWUl3ej08h4mXWoc=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.28.7 h1:GduUnoTXlhkgnxTD93g1nv4tVPILbdNQOzav+Wpg7AE=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.28.7/go.mod h1:vZGX6GVkIE8uECSUHB6MWAUsd4ZcG2Yq/dMa4refR3M=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.48 h1:IYdLD1qTJ0zanRavulofmqut4afs45mOWEI+MzZtTfQ=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.17.48/go.mod h1:tOscxHN3CGmuX9idQ3+qbkzrjVIx32lqDSU1/0d/qXs=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22 h1:kqOrpojG71DxJm/KDPO+Z/y1phm1JlC8/iT+5XRmAn8=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.22/go.mod h1:NtSFajXVVL8TA2QNngagVZmUtXciyrHOt7xgz4faS/M=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26 h1:I/5wmGMffY4happ8NOCuIUEWGUvvFp5NSeQcXl9RHcI=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.26/go.mod h1:FR8f4turZtNy6baO0KJ5FJUmXH/cSkI9fOngs0yl6mA=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26 h1:zXFLuEuMMUOvEARXFUVJdfqZ4bvvSgdGRq/ATcrQxzM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.26/go.mod h1:3o2Wpy0bogG1kyOPrgkXA8pgIfEEv0+m19O9D5+W8y8=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.26 h1:GeNJsIFHB+WW5ap2Tec4K6dzcVTsRbsT1Lra46Hv9ME=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.26/go.mod h1:zfgMpwHDXX2WGoG84xG2H+ZlPTkJUU4YUvx2svLQYWo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.7 h1:tB4tNw83KcajNAzaIMhkhVI2Nt8fAZd5A5ro113FEMY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.4.7/go.mod h1:lvpyBGkZ3tZ9iSsUIcC2EWp+0ywa7aK3BLT+FwZi+mQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7 h1:8eUsivBQzZHqe/3FE+cqwfH+0p5Jo8PFM/QYQSmeZ+M=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.7/go.mod h1:kLPQvGUmxn/fqiCrDeohwG33bq2pQpGeY62yRO6Nrh0=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.7 h1:Hi0KGbrnr57bEHWM0bJ1QcBzxLrL/k2DHvGYhb8+W1w=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.7/go.mod h1:wKNgWgExdjjrm4qvfbTorkvocEstaoDl4WCvGfeCy9c=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.71.1 h1:aOVVZJgWbaH+EJYPvEgkNhCEbXXvH7+oML36oaPK3zE=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.71.1/go.mod h1:r+xl5yzMk9083rMR+sJ5TYj9Tihvf/l1oxzZXDgGj2Q=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.8 h1:CvuUmnXI7ebaUAhbJcDy9YQx8wHR69eZ9I7q5hszt/g=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.24.8/go.mod h1:XDeGv1opzwm8ubxddF0cgqkZWsyOtw4lr6dxwmb6YQg=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7 h1:F2rBfNAL5UyswqoeWv9zs74N/NanhK16ydHW1pahX6E=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.7/go.mod h1:JfyQ0g2JG8+Krq0EuZNnRwX0mU0HrwY/tG6JNfcqh4k=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.3 h1:Xgv/hyNgvLda/M9l9qxXc4UFSgppnRczLxlMs5Ae/QY=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.33.3/go.mod h1:5Gn+d+VaaRgsjewpMvGazt0WfcFO+Md4wLOuBfGR9Bc=
|
||||
github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro=
|
||||
github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
|
||||
github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA=
|
||||
github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U=
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||
@@ -77,8 +113,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
|
||||
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.0 h1:VD1gqscl4nYs1YxVuSdemTrSgTKrwOWDK0FVFMqm+Cg=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.0/go.mod h1:4EgsQoS4TOhJizV+JTFg40qx1Ofh3XmXEQNBpgvNT40=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M=
|
||||
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
|
||||
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/http-wasm/http-wasm-host-go v0.7.0 h1:+1KrRyOO6tWiDB24QrtSYyDmzFLBBs3jioKaUT0mq1c=
|
||||
@@ -194,10 +230,10 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c h1:KL/ZBHXgKGVmuZBZ01Lt57yE5ws8ZPSkkihmEyq7FXc=
|
||||
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
|
||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac h1:l5+whBCLH3iH2ZNHYLbAe58bo7yrN4mVcnkHDYz5vvs=
|
||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac/go.mod h1:hH+7mtFmImwwcMvScyxUhjuVHR3HGaDPMn9rMSUUbxo=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
|
||||
@@ -207,8 +243,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -234,21 +270,21 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
|
||||
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
|
||||
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
|
||||
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250204164813-702378808489 h1:fCuMM4fowGzigT89NCIsW57Pk9k2D12MMi2ODn+Nk+o=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250204164813-702378808489/go.mod h1:iYONQfRdizDB8JJBybql13nArx91jcUk7zCXEsOofM4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250204164813-702378808489 h1:5bKytslY8ViY0Cj/ewmRtrWHW64bNF03cAatUUFCdFI=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250204164813-702378808489/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b h1:i+d0RZa8Hs2L/MuaOQYI+krthcxdEbEM2N+Tf3kJ4zk=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250212204824-5a70512c5d8b/go.mod h1:iYONQfRdizDB8JJBybql13nArx91jcUk7zCXEsOofM4=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b h1:FQtJ1MxbXoIIrZHZ33M+w5+dAP9o86rgpjoKr/ZmT7k=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250212204824-5a70512c5d8b/go.mod h1:8BS3B93F/U1juMFq9+EDk+qOT5CO1R9IzXxG3PTqiRk=
|
||||
google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
|
||||
google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
|
||||
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
|
||||
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
@@ -258,14 +294,14 @@ gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU=
|
||||
gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU=
|
||||
modernc.org/cc/v4 v4.24.4 h1:TFkx1s6dCkQpd6dKurBNmpo+G8Zl4Sq/ztJ+2+DEsh0=
|
||||
modernc.org/cc/v4 v4.24.4/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0=
|
||||
modernc.org/ccgo/v4 v4.23.15 h1:wFDan71KnYqeHz4eF63vmGE6Q6Pc0PUGDpP0PRMYjDc=
|
||||
modernc.org/ccgo/v4 v4.23.15/go.mod h1:nJX30dks/IWuBOnVa7VRii9Me4/9TZ1SC9GNtmARTy0=
|
||||
modernc.org/ccgo/v4 v4.23.16 h1:Z2N+kk38b7SfySC1ZkpGLN2vthNJP1+ZzGZIlH7uBxo=
|
||||
modernc.org/ccgo/v4 v4.23.16/go.mod h1:nNma8goMTY7aQZQNTyN9AIoJfxav4nvTnvKThAeMDdo=
|
||||
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
|
||||
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
|
||||
modernc.org/gc/v2 v2.6.2 h1:YBXi5Kqp6aCK3fIxwKQ3/fErvawVKwjOLItxj1brGds=
|
||||
modernc.org/gc/v2 v2.6.2/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||
modernc.org/libc v1.61.11 h1:6sZG8uB6EMMG7iTLPTndi8jyTdgAQNIeLGjCFICACZw=
|
||||
modernc.org/libc v1.61.11/go.mod h1:HHX+srFdn839oaJRd0W8hBM3eg+mieyZCAjWwB08/nM=
|
||||
modernc.org/gc/v2 v2.6.3 h1:aJVhcqAte49LF+mGveZ5KPlsp4tdGdAOT4sipJXADjw=
|
||||
modernc.org/gc/v2 v2.6.3/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||
modernc.org/libc v1.61.13 h1:3LRd6ZO1ezsFiX1y+bHd1ipyEHIJKvuprv0sLTBwLW8=
|
||||
modernc.org/libc v1.61.13/go.mod h1:8F/uJWL/3nNil0Lgt1Dpz+GgkApWh04N3el3hxJcA6E=
|
||||
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||
modernc.org/memory v1.8.2 h1:cL9L4bcoAObu4NkxOlKWBWtNHIsnnACGF/TbqQ6sbcI=
|
||||
|
||||
@@ -56,10 +56,7 @@ func (s *Server) Start(ctx context.Context) error {
|
||||
|
||||
// Start server in a goroutine
|
||||
go func() {
|
||||
slog.Info("Server starting",
|
||||
"host", host,
|
||||
"port", port,
|
||||
)
|
||||
slog.Info("Server starting", "host", host, "port", port)
|
||||
if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
serverErr <- err
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ type BackupConfig struct {
|
||||
type BackgroundJobs struct {
|
||||
Traefik int64 `env:"BACKGROUND_JOBS_TRAEFIK" envDefault:"20"`
|
||||
DNS int64 `env:"BACKGROUND_JOBS_DNS" envDefault:"300"`
|
||||
Agent int64 `env:"BACKGROUND_JOBS_AGENT" envDefault:"180"`
|
||||
}
|
||||
|
||||
func ReadConfig() (*Config, error) {
|
||||
|
||||
@@ -13,26 +13,13 @@ import (
|
||||
|
||||
"github.com/MizuchiLabs/mantrae/internal/app"
|
||||
"github.com/MizuchiLabs/mantrae/internal/db"
|
||||
"github.com/MizuchiLabs/mantrae/internal/storage"
|
||||
)
|
||||
|
||||
// StorageBackend defines interface for different storage solutions
|
||||
type StorageBackend interface {
|
||||
Store(ctx context.Context, name string, data io.Reader) error
|
||||
Retrieve(ctx context.Context, name string) (io.ReadCloser, error)
|
||||
List(ctx context.Context) ([]BackupFile, error)
|
||||
Delete(ctx context.Context, name string) error
|
||||
}
|
||||
|
||||
type BackupFile struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Timestamp time.Time `json:"timestamp,omitempty"`
|
||||
Size int64 `json:"size,omitempty"`
|
||||
}
|
||||
|
||||
type BackupManager struct {
|
||||
Conn *db.Connection
|
||||
Config *app.BackupConfig
|
||||
Backend StorageBackend
|
||||
Backend storage.Backend
|
||||
stopChan chan struct{}
|
||||
waitGroup sync.WaitGroup
|
||||
mu sync.Mutex
|
||||
@@ -41,7 +28,7 @@ type BackupManager struct {
|
||||
func NewManager(
|
||||
conn *db.Connection,
|
||||
config app.BackupConfig,
|
||||
backend StorageBackend,
|
||||
backend storage.Backend,
|
||||
) *BackupManager {
|
||||
return &BackupManager{
|
||||
Conn: conn,
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package backup
|
||||
|
||||
// type S3Storage struct {
|
||||
// bucket string
|
||||
// prefix string
|
||||
// s3Client *s3.Client
|
||||
// }
|
||||
//
|
||||
// func NewS3Storage(bucket, prefix string, s3Client *s3.Client) *S3Storage {
|
||||
// return &S3Storage{
|
||||
// bucket: bucket,
|
||||
// prefix: prefix,
|
||||
// s3Client: s3Client,
|
||||
// }
|
||||
// }
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/MizuchiLabs/mantrae/internal/backup"
|
||||
"github.com/MizuchiLabs/mantrae/internal/db"
|
||||
"github.com/MizuchiLabs/mantrae/internal/source"
|
||||
"github.com/MizuchiLabs/mantrae/internal/storage"
|
||||
"github.com/MizuchiLabs/mantrae/internal/util"
|
||||
"github.com/lmittmann/tint"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
@@ -41,8 +42,7 @@ func Setup(ctx context.Context) (*App, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Setup backup manager
|
||||
storage, err := backup.NewLocalStorage(config.Backup.BackupPath)
|
||||
storage, err := storage.NewLocalStorage(config.Backup.BackupPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -192,6 +192,13 @@ func (a *App) setDefaultProfile(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if profile.Url == a.Config.Traefik.URL &&
|
||||
profile.Username == &a.Config.Traefik.Username &&
|
||||
profile.Password == &a.Config.Traefik.Password &&
|
||||
profile.Tls == a.Config.Traefik.TLS {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := q.UpdateProfile(ctx, db.UpdateProfileParams{
|
||||
ID: profile.ID,
|
||||
Name: a.Config.Traefik.Profile,
|
||||
|
||||
@@ -7,15 +7,14 @@ import (
|
||||
|
||||
"github.com/MizuchiLabs/mantrae/internal/dns"
|
||||
"github.com/MizuchiLabs/mantrae/internal/traefik"
|
||||
"github.com/MizuchiLabs/mantrae/internal/util"
|
||||
)
|
||||
|
||||
func (a *App) setupBackgroundJobs(ctx context.Context) {
|
||||
slog.Info("Starting background tasks...")
|
||||
go a.traefikSync(ctx)
|
||||
go a.syncDNS(ctx)
|
||||
// go sslCheck(ctx)
|
||||
// go cleanupAgents(ctx)
|
||||
// go cleanupRouters(ctx)
|
||||
go a.cleanupAgents(ctx)
|
||||
}
|
||||
|
||||
// traefikSync periodically syncs the Traefik configuration
|
||||
@@ -54,151 +53,80 @@ func (a *App) syncDNS(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// func sslCheck(ctx context.Context) {
|
||||
// ticker := time.NewTicker(time.Second * time.Duration(util.App.SSLInterval))
|
||||
// defer ticker.Stop()
|
||||
func (a *App) cleanupAgents(ctx context.Context) {
|
||||
ticker := time.NewTicker(time.Second * time.Duration(a.Config.Background.Agent))
|
||||
defer ticker.Stop()
|
||||
|
||||
// for {
|
||||
// select {
|
||||
// case <-ctx.Done():
|
||||
// return
|
||||
// case <-ticker.C:
|
||||
// // Fetch new router list
|
||||
// routers, err := db.Query.ListRouters(context.Background())
|
||||
// if err != nil {
|
||||
// slog.Error("Failed to get routers", "error", err)
|
||||
// }
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
q := a.Conn.GetQuery()
|
||||
enabled, err := q.GetSetting(ctx, "agent_cleanup_enabled")
|
||||
if err != nil {
|
||||
slog.Error("failed to get agent_cleanup_enabled", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
// for _, router := range routers {
|
||||
// router.SSLCheck()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
if enabled.Value != "true" {
|
||||
return
|
||||
}
|
||||
|
||||
// func cleanupAgents(ctx context.Context) {
|
||||
// enabled, err := db.Query.GetSetting(context.Background(), "agent-cleanup-enabled")
|
||||
// if err != nil {
|
||||
// slog.Error("failed to get agent cleanup timeout", "error", err)
|
||||
// return
|
||||
// }
|
||||
// Timeout to delete old agents
|
||||
timeout, err := q.GetSetting(ctx, "agent_cleanup_interval")
|
||||
if err != nil {
|
||||
slog.Error("failed to get agent_cleanup_interval", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
// if enabled.Value != "true" {
|
||||
// return
|
||||
// }
|
||||
timeoutDuration, err := time.ParseDuration(timeout.Value)
|
||||
if err != nil {
|
||||
slog.Error("failed to parse agent_cleanup_interval", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
// // Timeout to delete old agents
|
||||
// timeout, err := db.Query.GetSetting(context.Background(), "agent-cleanup-timeout")
|
||||
// if err != nil {
|
||||
// slog.Error("failed to get agent cleanup timeout", "error", err)
|
||||
// return
|
||||
// }
|
||||
now := time.Now()
|
||||
agents, err := q.ListAgents(ctx)
|
||||
if err != nil {
|
||||
slog.Error("failed to list agents", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
// timeoutDuration, err := time.ParseDuration(timeout.Value)
|
||||
// if err != nil {
|
||||
// slog.Error("failed to parse timeout cleanup duration", "error", err)
|
||||
// }
|
||||
for _, agent := range agents {
|
||||
if agent.UpdatedAt == nil || agent.Hostname == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// ticker := time.NewTicker(timeoutDuration)
|
||||
// defer ticker.Stop()
|
||||
|
||||
// for {
|
||||
// select {
|
||||
// case <-ctx.Done():
|
||||
// return
|
||||
// case <-ticker.C:
|
||||
// now := time.Now()
|
||||
// agents, err := db.Query.ListAgents(context.Background())
|
||||
// if err != nil {
|
||||
// slog.Error("failed to query disconnected agents", "error", err)
|
||||
// continue
|
||||
// }
|
||||
|
||||
// for _, agent := range agents {
|
||||
// if agent.LastSeen == nil {
|
||||
// continue
|
||||
// }
|
||||
|
||||
// if now.Sub(*agent.LastSeen) > timeoutDuration {
|
||||
// if err := db.Query.DeleteAgent(context.Background(), agent.ID); err != nil {
|
||||
// slog.Error(
|
||||
// "failed to delete disconnected agent",
|
||||
// "id",
|
||||
// agent.ID,
|
||||
// "error",
|
||||
// err,
|
||||
// )
|
||||
// } else {
|
||||
// slog.Info("Deleted disconnected agent", "id", agent.ID)
|
||||
// util.Broadcast <- util.EventMessage{
|
||||
// Type: "agent_updated",
|
||||
// Message: "Deleted disconnected agent",
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Delete all connected routers
|
||||
// routers, err := db.Query.ListRoutersByAgentID(context.Background(), &agent.ID)
|
||||
// if err != nil {
|
||||
// slog.Error("Failed to get routers", "error", err)
|
||||
// continue
|
||||
// }
|
||||
// for _, router := range routers {
|
||||
// if err := db.Query.DeleteRouter(context.Background(), router.ID); err != nil {
|
||||
// slog.Error("Failed to delete router", "id", router.ID, "error", err)
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// cleanupRouters periodically deletes routers from offline/deleted agents
|
||||
// func (a *App) cleanupRouters(ctx context.Context) {
|
||||
// q := db.New(a.DB)
|
||||
// // Timeout to delete old agents
|
||||
// timeout, err := q.GetSetting(context.Background(), "agent-cleanup-timeout")
|
||||
// if err != nil {
|
||||
// slog.Error("failed to get agent cleanup timeout", "error", err)
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// timeoutDuration, err := time.ParseDuration(timeout.Value)
|
||||
// if err != nil {
|
||||
// slog.Error("failed to parse timeout cleanup duration", "error", err)
|
||||
// }
|
||||
//
|
||||
// ticker := time.NewTicker(timeoutDuration)
|
||||
// defer ticker.Stop()
|
||||
//
|
||||
// for {
|
||||
// select {
|
||||
// case <-ctx.Done():
|
||||
// return
|
||||
// case <-ticker.C:
|
||||
// q := db.New(a.DB)
|
||||
//
|
||||
// profiles, err := q.ListProfiles(ctx)
|
||||
// if err != nil {
|
||||
// slog.Error("failed to query disconnected agents", "error", err)
|
||||
// continue
|
||||
// }
|
||||
//
|
||||
// for _, profile := range profiles {
|
||||
// config, err := q.GetTraefikConfigBySource(ctx, db.GetTraefikConfigBySourceParams{
|
||||
// ProfileID: profile.ID,
|
||||
// Source: source.Agent,
|
||||
// })
|
||||
// if err != nil {
|
||||
// slog.Error("failed to get agent config", "error", err)
|
||||
// continue
|
||||
// }
|
||||
// if config.Config == nil {
|
||||
// continue
|
||||
// }
|
||||
// // TODO
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
if now.Sub(*agent.UpdatedAt) > timeoutDuration {
|
||||
if err := q.DeleteTraefikConfigByAgent(ctx, &agent.ID); err != nil {
|
||||
slog.Error(
|
||||
"failed to delete agent config",
|
||||
"id",
|
||||
agent.ID,
|
||||
"error",
|
||||
err,
|
||||
)
|
||||
continue
|
||||
}
|
||||
if err := q.DeleteAgent(ctx, agent.ID); err != nil {
|
||||
slog.Error(
|
||||
"failed to delete disconnected agent",
|
||||
"id",
|
||||
agent.ID,
|
||||
"error",
|
||||
err,
|
||||
)
|
||||
continue
|
||||
} else {
|
||||
slog.Info("Deleted disconnected agent", "id", agent.ID)
|
||||
util.Broadcast <- util.EventMessage{
|
||||
Type: util.EventTypeDelete,
|
||||
Message: "agent",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
-- name: CreateAgent :exec
|
||||
INSERT INTO
|
||||
agents (id, profile_id, token)
|
||||
agents (id, profile_id, token, created_at)
|
||||
VALUES
|
||||
(?, ?, ?);
|
||||
(?, ?, ?, CURRENT_TIMESTAMP);
|
||||
|
||||
-- name: GetAgent :one
|
||||
SELECT
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package backup
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -40,8 +40,8 @@ func (ls *LocalStorage) Retrieve(ctx context.Context, name string) (io.ReadClose
|
||||
return os.Open(path)
|
||||
}
|
||||
|
||||
func (ls *LocalStorage) List(ctx context.Context) ([]BackupFile, error) {
|
||||
var files []BackupFile
|
||||
func (ls *LocalStorage) List(ctx context.Context) ([]StoredFile, error) {
|
||||
var files []StoredFile
|
||||
entries, err := os.ReadDir(ls.basePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read storage directory: %w", err)
|
||||
@@ -52,7 +52,7 @@ func (ls *LocalStorage) List(ctx context.Context) ([]BackupFile, error) {
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
files = append(files, BackupFile{
|
||||
files = append(files, StoredFile{
|
||||
Name: entry.Name(),
|
||||
Timestamp: info.ModTime(),
|
||||
Size: info.Size(),
|
||||
126
internal/storage/s3.go
Normal file
126
internal/storage/s3.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go-v2/aws"
|
||||
"github.com/aws/aws-sdk-go-v2/config"
|
||||
"github.com/aws/aws-sdk-go-v2/service/s3"
|
||||
)
|
||||
|
||||
// S3Storage implements StorageBackend for AWS S3
|
||||
type S3Storage struct {
|
||||
client *s3.Client
|
||||
bucket string
|
||||
}
|
||||
|
||||
// NewS3Storage creates a new S3Storage instance
|
||||
func NewS3Storage(
|
||||
ctx context.Context,
|
||||
bucket string,
|
||||
awsConfig aws.Config,
|
||||
) (*S3Storage, error) {
|
||||
if bucket == "" {
|
||||
return nil, fmt.Errorf("bucket name cannot be empty")
|
||||
}
|
||||
|
||||
var cfg aws.Config
|
||||
var err error
|
||||
|
||||
if awsConfig.Region == "" {
|
||||
cfg, err = config.LoadDefaultConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to load AWS config: %w", err)
|
||||
}
|
||||
} else {
|
||||
cfg = awsConfig
|
||||
}
|
||||
|
||||
return &S3Storage{
|
||||
bucket: bucket,
|
||||
client: s3.NewFromConfig(cfg),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *S3Storage) Store(ctx context.Context, name string, data io.Reader) error {
|
||||
_, err := s.client.PutObject(ctx, &s3.PutObjectInput{
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: aws.String(name),
|
||||
Body: data,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to store object in S3: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *S3Storage) Retrieve(ctx context.Context, name string) (io.ReadCloser, error) {
|
||||
output, err := s.client.GetObject(ctx, &s3.GetObjectInput{
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: aws.String(name),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to retrieve object from S3: %w", err)
|
||||
}
|
||||
return output.Body, nil
|
||||
}
|
||||
|
||||
// List lists the files in S3
|
||||
func (s *S3Storage) List(ctx context.Context) ([]StoredFile, error) {
|
||||
var files []StoredFile
|
||||
var nextToken *string
|
||||
|
||||
for {
|
||||
output, err := s.client.ListObjectsV2(ctx, &s3.ListObjectsV2Input{
|
||||
Bucket: aws.String(s.bucket),
|
||||
ContinuationToken: nextToken,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to list objects from S3: %w", err)
|
||||
}
|
||||
|
||||
for _, object := range output.Contents {
|
||||
// Safely dereference pointers.
|
||||
key := ""
|
||||
if object.Key != nil {
|
||||
key = *object.Key
|
||||
}
|
||||
var ts time.Time
|
||||
if object.LastModified != nil {
|
||||
ts = *object.LastModified
|
||||
}
|
||||
files = append(files, StoredFile{
|
||||
Name: key,
|
||||
Timestamp: ts,
|
||||
Size: *object.Size,
|
||||
})
|
||||
}
|
||||
|
||||
nextToken = output.NextContinuationToken
|
||||
|
||||
if nextToken == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(files, func(i, j int) bool {
|
||||
return files[i].Timestamp.After(files[j].Timestamp)
|
||||
})
|
||||
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func (s *S3Storage) Delete(ctx context.Context, name string) error {
|
||||
_, err := s.client.DeleteObject(ctx, &s3.DeleteObjectInput{
|
||||
Bucket: aws.String(s.bucket),
|
||||
Key: aws.String(name),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete object from S3: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
21
internal/storage/types.go
Normal file
21
internal/storage/types.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"time"
|
||||
)
|
||||
|
||||
// StorageBackend defines interface for different storage solutions
|
||||
type Backend interface {
|
||||
Store(ctx context.Context, name string, data io.Reader) error
|
||||
Retrieve(ctx context.Context, name string) (io.ReadCloser, error)
|
||||
List(ctx context.Context) ([]StoredFile, error)
|
||||
Delete(ctx context.Context, name string) error
|
||||
}
|
||||
|
||||
type StoredFile struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Timestamp time.Time `json:"timestamp,omitempty"`
|
||||
Size int64 `json:"size,omitempty"`
|
||||
}
|
||||
Reference in New Issue
Block a user