From 21266286cb08c080f4fb512d06103dbe1707911c Mon Sep 17 00:00:00 2001 From: Jin Hai Date: Wed, 8 Jul 2026 17:49:02 +0800 Subject: [PATCH] Go: add more commands and GCS supports (#16741) ### Summary 1. GCS supports 2. More commands ``` RAGFlow(admin)> ping store; SUCCESS RAGFlow(admin)> ping engine; SUCCESS RAGFlow(admin)> ping cache; SUCCESS ``` --------- Signed-off-by: Jin Hai --- cmd/ragflow_server.go | 5 +- conf/service_conf.yaml | 4 + docker/service_conf.yaml.template | 4 + go.mod | 52 +++-- go.sum | 135 ++++++++----- internal/admin/handler.go | 37 ++++ internal/admin/router.go | 4 + internal/cli/admin_command.go | 61 ++++++ internal/cli/admin_parser.go | 26 ++- internal/cli/cli_http.go | 14 +- internal/cli/common_command.go | 2 +- internal/cli/lexer.go | 4 + internal/cli/types.go | 2 + internal/engine/elasticsearch/client.go | 2 + internal/engine/nats/nats.go | 20 +- internal/server/config.go | 23 +++ internal/service/chunk/chunk_test.go | 6 + internal/service/document_test.go | 4 + internal/service/file_test.go | 6 + internal/storage/gcs.go | 253 ++++++++++++++++++++++++ internal/storage/memory.go | 21 ++ internal/storage/minio.go | 20 ++ internal/storage/oss.go | 24 ++- internal/storage/s3.go | 23 +++ internal/storage/storage_factory.go | 27 ++- internal/storage/types.go | 6 + 26 files changed, 701 insertions(+), 84 deletions(-) create mode 100644 internal/storage/gcs.go diff --git a/cmd/ragflow_server.go b/cmd/ragflow_server.go index 7c40e5956..2fec093ff 100644 --- a/cmd/ragflow_server.go +++ b/cmd/ragflow_server.go @@ -355,11 +355,12 @@ func main() { defer redis.Close() if err = storage.InitStorageFactory(); err != nil { - common.Fatal("Failed to initialize storage factory", zap.Error(err)) + common.Error("Failed to initialize storage factory", err) } + defer storage.CloseStorage() if err = engine.InitMessageQueueEngine(config.TaskExecutor.MessageQueueType); err != nil { - common.Fatal("Failed to initialize message queue engine", zap.Error(err)) + common.Error("Failed to initialize message queue engine", err) } // Initialize server variables (runtime variables that can change during operation) diff --git a/conf/service_conf.yaml b/conf/service_conf.yaml index b51f3f3cc..6e6e48014 100644 --- a/conf/service_conf.yaml +++ b/conf/service_conf.yaml @@ -63,6 +63,10 @@ user_default_llm: factory: 'xxxx' api_key: 'xxx' base_url: 'http://localhost:6380' +gcs: + bucket: '${GCS_BUCKET:-ragflow}' + prefix_path: '${GCS_PREFIX_PATH:-}' + endpoint_url: '${GCS_ENDPOINT:-}' # postgres: # name: 'rag_flow' # user: 'rag_flow' diff --git a/docker/service_conf.yaml.template b/docker/service_conf.yaml.template index ec051ae00..b2668f74d 100644 --- a/docker/service_conf.yaml.template +++ b/docker/service_conf.yaml.template @@ -111,6 +111,10 @@ user_default_llm: # tenant_id: 'tenant_id' # container_name: 'container_name' # cloud: 'public' # Azure cloud: 'public', 'china', 'government', or 'germany' +# gcs: +# bucket: '${GCS_BUCKET:-ragflow}' +# prefix_path: '${GCS_PREFIX_PATH:-}' +# endpoint_url: '${GCS_ENDPOINT:-}' # The OSS object storage uses the MySQL configuration above by default. If you need to switch to another object storage service, please uncomment and configure the following parameters. # opendal: # scheme: 'mysql' # Storage type, such as s3, oss, azure, etc. diff --git a/go.mod b/go.mod index 744940628..e76511df3 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module ragflow go 1.26.4 require ( + cloud.google.com/go/storage v1.63.0 github.com/DATA-DOG/go-sqlmock v1.5.2 github.com/alibabacloud-go/agentrun-20250910/v5 v5.8.4 github.com/alibabacloud-go/darabonba-openapi/v2 v2.2.1 @@ -55,13 +56,14 @@ require ( go.opentelemetry.io/otel/sdk v1.44.0 go.opentelemetry.io/otel/trace v1.44.0 go.uber.org/zap v1.27.1 - golang.org/x/crypto v0.52.0 - golang.org/x/net v0.55.0 - golang.org/x/sync v0.20.0 - golang.org/x/term v0.43.0 - golang.org/x/text v0.37.0 + golang.org/x/crypto v0.53.0 + golang.org/x/net v0.56.0 + golang.org/x/sync v0.21.0 + golang.org/x/term v0.44.0 + golang.org/x/text v0.38.0 + google.golang.org/api v0.287.1 google.golang.org/genai v1.54.0 - google.golang.org/grpc v1.81.1 + google.golang.org/grpc v1.82.0 gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/yaml.v3 v3.0.1 gorm.io/driver/mysql v1.5.2 @@ -69,10 +71,17 @@ require ( ) require ( - cloud.google.com/go v0.116.0 // indirect - cloud.google.com/go/auth v0.9.3 // indirect + cel.dev/expr v0.25.1 // indirect + cloud.google.com/go v0.123.0 // indirect + cloud.google.com/go/auth v0.21.0 // indirect + cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.9.0 // indirect + cloud.google.com/go/iam v1.11.0 // indirect + cloud.google.com/go/monitoring v1.29.0 // indirect connectrpc.com/connect v1.19.2 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.57.0 // indirect + github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.57.0 // indirect github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect github.com/alibabacloud-go/debug v1.0.1 // indirect github.com/alibabacloud-go/tea v1.5.0 // indirect @@ -100,18 +109,22 @@ require ( github.com/bytedance/sonic/loader v0.5.0 // indirect github.com/clbanning/mxj/v2 v2.7.0 // indirect github.com/cloudwego/base64x v0.1.6 // indirect + github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dlclark/regexp2 v1.10.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect github.com/ebitengine/purego v0.10.1 // indirect github.com/eino-contrib/jsonschema v1.0.3 // indirect github.com/elastic/elastic-transport-go/v8 v8.8.0 // indirect + github.com/envoyproxy/go-control-plane/envoy v1.37.0 // indirect + github.com/envoyproxy/protoc-gen-validate v1.3.3 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect github.com/glebarez/go-sqlite v1.21.2 // indirect github.com/go-ini/ini v1.67.0 // indirect + github.com/go-jose/go-jose/v4 v4.1.4 // indirect github.com/go-json-experiment/json v0.0.0-20260601182631-00ed12fed2a6 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -120,10 +133,10 @@ require ( github.com/go-playground/validator/v10 v10.20.0 // indirect github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect - github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/s2a-go v0.1.8 // indirect - github.com/googleapis/enterprise-certificate-proxy v0.3.4 // indirect + github.com/google/s2a-go v0.1.9 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.3.17 // indirect + github.com/googleapis/gax-go/v2 v2.23.0 // indirect github.com/goph/emperror v0.17.2 // indirect github.com/gorilla/websocket v1.5.3 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0 // indirect @@ -152,6 +165,7 @@ require ( github.com/philhofer/fwd v1.2.0 // indirect github.com/phpdave11/gofpdi v1.0.14-0.20211212211723-1f10f9844311 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/prometheus/common v0.66.1 // indirect github.com/prometheus/procfs v0.16.1 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect @@ -163,9 +177,10 @@ require ( github.com/sirupsen/logrus v1.9.3 // indirect github.com/slongfield/pyfmt v0.0.0-20220222012616-ea85ff4c361f // indirect github.com/sourcegraph/conc v0.3.0 // indirect - github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/spiffe/go-spiffe/v2 v2.6.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/tidwall/gjson v1.18.0 // indirect github.com/tidwall/match v1.1.1 // indirect @@ -181,9 +196,11 @@ require ( github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 // indirect github.com/yargevad/filepathx v1.0.0 // indirect github.com/yuin/gopher-lua v1.1.1 // indirect - go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/contrib/detectors/gcp v1.43.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.68.0 // indirect go.opentelemetry.io/otel/metric v1.44.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.44.0 // indirect go.opentelemetry.io/proto/otlp v1.10.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.10.0 // indirect @@ -191,9 +208,12 @@ require ( go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/arch v0.11.0 // indirect golang.org/x/exp v0.0.0-20231226003508-02704c960a9b // indirect - golang.org/x/sys v0.45.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect + golang.org/x/oauth2 v0.36.0 // indirect + golang.org/x/sys v0.46.0 // indirect + golang.org/x/time v0.15.0 // indirect + google.golang.org/genproto v0.0.0-20260519071638-aa98bba5eb94 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260630182238-925bb5da69e7 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260630182238-925bb5da69e7 // indirect google.golang.org/protobuf v1.36.11 // indirect gopkg.in/ini.v1 v1.67.0 // indirect modernc.org/libc v1.22.5 // indirect diff --git a/go.sum b/go.sum index 7a99afe24..ac6e8a7d7 100644 --- a/go.sum +++ b/go.sum @@ -1,10 +1,26 @@ +cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= +cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.116.0 h1:B3fRrSDkLRt5qSHWe40ERJvhvnQwdZiHu0bJOpldweE= -cloud.google.com/go v0.116.0/go.mod h1:cEPSRWPzZEswwdr9BxE6ChEn01dWlTaF05LiC2Xs70U= -cloud.google.com/go/auth v0.9.3 h1:VOEUIAADkkLtyfr3BLa3R8Ed/j6w1jTBmARx+wb5w5U= -cloud.google.com/go/auth v0.9.3/go.mod h1:7z6VY+7h3KUdRov5F1i8NDP5ZzWKYmEPO842BgCsmTk= +cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE= +cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU= +cloud.google.com/go/auth v0.21.0 h1:g/QwYfYb2Ai6HH8oomAOyBaIHLbscZ4+T/F/f5JZHkE= +cloud.google.com/go/auth v0.21.0/go.mod h1:M9o2Oz+YI2jAfxewJgb1vyI3vceHF+eohmxyzmrl+9s= +cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= +cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs= cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10= +cloud.google.com/go/iam v1.11.0 h1:KieQ9Pb+LLPak1O3Rv3GgCxhnmkYf7Xyh0P5HfF1jFM= +cloud.google.com/go/iam v1.11.0/go.mod h1:KP+nKGugNJW4LcLx1uEZcq1ok5sQHFaQehQNl4QDgV4= +cloud.google.com/go/logging v1.18.0 h1:KhzZq+1cSkPH9YUaKLLhLtQxIHitVayBmk0sGfoM9+k= +cloud.google.com/go/logging v1.18.0/go.mod h1:ZGKnpBaURITh+g/uom2VhbiFoFWvejcrHPDhxFtU/gI= +cloud.google.com/go/longrunning v1.0.0 h1:lwzWEYD8+NkYV7dhexOz6kmlvajZA70+bW/xMhRVVdY= +cloud.google.com/go/longrunning v1.0.0/go.mod h1:8nqFBPOO1U/XkhWl0I19AMZEphrHi73VNABIpKYaTwM= +cloud.google.com/go/monitoring v1.29.0 h1:AHhDsFaSax1/4k+qlIDX/SDGe6hggnfXJ9dkgD9qBPY= +cloud.google.com/go/monitoring v1.29.0/go.mod h1:72NOVjJXHY/HBfoLT0+qlCZBT059+9VXLeAnL2PeeVM= +cloud.google.com/go/storage v1.63.0 h1:hvXF2xfg9I32bjujggxgkEZn/Ej6sJ9pieFgeueBLrQ= +cloud.google.com/go/storage v1.63.0/go.mod h1:tirWVptrFNo5GEX2DQ47JooF7yaweJdAJ1hYAVMvKzE= +cloud.google.com/go/trace v1.16.0 h1:GmQovzFc5F0CNfl0VLgL64aoTtu7xsM0YajW2GlG9+E= +cloud.google.com/go/trace v1.16.0/go.mod h1:r+bdAn16dKLSV1G2D5v3e58IlQlizfxWrUfjx7kM7X0= connectrpc.com/connect v1.19.2 h1:McQ83FGdzL+t60peksi0gXC7MQ/iLKgLduAnThbM0mo= connectrpc.com/connect v1.19.2/go.mod h1:tN20fjdGlewnSFeZxLKb0xwIZ6ozc3OQs2hTXy4du9w= github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0/go.mod h1:h6H6c8enJmmocHUbLiiGY6sx7f9i+X3m1CHdd5c6Rdw= @@ -13,6 +29,14 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0 h1:rIkQfkCOVKc1OiRCNcSDD8ml5RJlZbH/Xsq7lbpynwc= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0/go.mod h1:RD2SsorTmYhF6HkTmDw7KmPYQk8OBYwTkuasChwv7R4= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.57.0 h1:jLdiS1vO+XJFyDSWRHBx56r4s/NNtcl5J6KyCcWUX/w= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.57.0/go.mod h1:8lmpHY+1VRoteiOwyrQMDt1YGXOrFKCz+1wJW7n3ODY= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.57.0 h1:cSjUzZ7KU8hicTgzaSv9NmSyM9fTVK3y5lsBUl3wOis= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/cloudmock v0.57.0/go.mod h1:dzcEjy1WJ0Q4u9twNR3LcLhNoYMRCrMCMafpxa0TjPQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.57.0 h1:RoO5+d7uCmDqovLrHCr2/BuViUXvdcrNxyNM1pN9dDQ= +github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.57.0/go.mod h1:YqwkQPrWSC7+byyc1VlKbWLBF5JsW5IoL6xUkemYSXk= github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= github.com/airbrake/gobrake v3.6.1+incompatible/go.mod h1:wM4gu3Cn0W0K7GUuVWnlXZU11AGBXMILnrdOU8Kn00o= github.com/alibabacloud-go/agentrun-20250910/v5 v5.8.4 h1:hiAsm9pz6aICOPLI1FC54vga10xwd/XxfNj06ow5jVM= @@ -142,6 +166,8 @@ github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gE github.com/cloudwego/eino v0.9.9 h1:x63hvRif6ANPh9YEPoTIrp1potEeoLQFAjOclKaX/Kg= github.com/cloudwego/eino v0.9.9/go.mod h1:OBD1mrkfkt/pJa4rkg1P0VnaMeOVl7l8IAdEqY//3IQ= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os8IaYg++6uMOdKK83QtkkvJik= +github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2/go.mod h1:qwXFYgsP6T7XnJtbKlf1HP8AjxZZyzxMmc+Lq5GjlU4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -164,9 +190,16 @@ github.com/elastic/elastic-transport-go/v8 v8.8.0/go.mod h1:YLHer5cj0csTzNFXoNQ8 github.com/elastic/go-elasticsearch/v8 v8.19.1 h1:0iEGt5/Ds9MNVxEp3hqLsXdbe6SjleaVHONg/FuR09Q= github.com/elastic/go-elasticsearch/v8 v8.19.1/go.mod h1:tHJQdInFa6abmDbDCEH2LJja07l/SIpaGpJcm13nt7s= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA= +github.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU= +github.com/envoyproxy/go-control-plane/envoy v1.37.0 h1:u3riX6BoYRfF4Dr7dwSOroNfdSbEPe9Yyl09/B6wBrQ= +github.com/envoyproxy/go-control-plane/envoy v1.37.0/go.mod h1:DReE9MMrmecPy+YvQOAOHNYMALuowAnbjjEMkkWOi6A= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0 h1:/G9QYbddjL25KvtKTv3an9lx6VBE2cnb8wp1vEGNYGI= +github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/envoyproxy/protoc-gen-validate v1.3.3 h1:MVQghNeW+LZcmXe7SY1V36Z+WFMDjpqGAGacLe2T0ds= +github.com/envoyproxy/protoc-gen-validate v1.3.3/go.mod h1:TsndJ/ngyIdQRhMcVVGDDHINPLWB7C82oDArY51KfB0= github.com/eric642/e2b-go-sdk v0.1.3 h1:gTwHbkuKU3F7a+gXl01GfBJdvJ+WRDIwP7UinMb7dfI= github.com/eric642/e2b-go-sdk v0.1.3/go.mod h1:SBYlJST6v+9U3gXeAXg1LXl2cJzYohmfrduwXZmMi+o= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= @@ -191,6 +224,8 @@ github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJY github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98= 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/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= +github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-json-experiment/json v0.0.0-20260601182631-00ed12fed2a6 h1:nxP4pPoyqOAgX8lYDFCfl3DyKeXErCvSvhcyzwGV9CE= github.com/go-json-experiment/json v0.0.0-20260601182631-00ed12fed2a6/go.mod h1:tphK2c80bpPhMOI4v6bIc2xWywPfbqi1Z06+RcrMkDg= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -218,9 +253,6 @@ github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2V github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= -github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -230,9 +262,7 @@ github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:x github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/gomarkdown/markdown v0.0.0-20260614204949-e08cff860f76 h1:Ltt9ldIaSYEsjA7sPY2c8r9dOmnKM1vlzhh3dxlhBHM= @@ -241,21 +271,22 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= +github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= -github.com/google/s2a-go v0.1.8 h1:zZDs9gcbt9ZPLV0ndSyQk6Kacx2g/X+SKYovpnz3SMM= -github.com/google/s2a-go v0.1.8/go.mod h1:6iNWHTpQ+nfNRN5E00MSdfDwVesa8hhS32PhPO8deJA= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= +github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= 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/googleapis/enterprise-certificate-proxy v0.3.4 h1:XYIDZApgAnrN1c855gTgghdIA6Stxb52D5RnLI1SLyw= -github.com/googleapis/enterprise-certificate-proxy v0.3.4/go.mod h1:YKe7cfqYXjKGpGvmSg28/fFvhNzinZQm8DGnaburhGA= +github.com/googleapis/enterprise-certificate-proxy v0.3.17 h1:73NfMHdiqo9JFU9+7a5ExpVa10/R29pXfZIaW559nrg= +github.com/googleapis/enterprise-certificate-proxy v0.3.17/go.mod h1:rSEsBUemEBZEexP2y6jPp16LUmUbjmSbcPMQizR0o4k= +github.com/googleapis/gax-go/v2 v2.23.0 h1:Tchl7qkvE7Ip3y+ztvNufYFvkfqTe7NfLTYGIdJRLuE= +github.com/googleapis/gax-go/v2 v2.23.0/go.mod h1:rBQKOVJCdb8IFEzg+FCwlt1LP/xMDGuqUXhUG+XMXEg= github.com/goph/emperror v0.17.2 h1:yLapQcmEsO0ipe9p5TaN22djm3OFV/TfM/fcYP0/J18= github.com/goph/emperror v0.17.2/go.mod h1:+ZbQ+fUNO/6FNiUo0ujtMjhgad9Xa6fQL9KhH4LNHic= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -368,6 +399,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkoukk/tiktoken-go v0.1.8 h1:85ENo+3FpWgAACBaEUVp+lctuTcYUO7BtmfhlN/QTRo= github.com/pkoukk/tiktoken-go v0.1.8/go.mod h1:9NiV+i9mJKGj1rYOT+njbv+ZwA/zJxYdewGl6qVatpg= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -416,14 +449,16 @@ github.com/smartystreets/goconvey v1.8.1 h1:qGjIddxOk4grTu9JPOU31tVfq3cNdBlNa5sS github.com/smartystreets/goconvey v1.8.1/go.mod h1:+/u4qLyY6x1jReYOp7GOM2FSt8aP9CzCZL03bI28W60= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= -github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= -github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= +github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/spiffe/go-spiffe/v2 v2.6.0 h1:l+DolpxNWYgruGQVV0xsfeya3CsC7m8iBzDnMpsbLuo= +github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs= github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -437,7 +472,6 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= @@ -491,10 +525,12 @@ github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0= github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA= -go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= -go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/detectors/gcp v1.43.0 h1:62yY3dT7/ShwOxzA0RsKRgshBmfElKI4d/Myu2OxDFU= +go.opentelemetry.io/contrib/detectors/gcp v1.43.0/go.mod h1:RyaZMFY7yi1kAs45S6mbFGz8O8rqB0dTY14uzvG4LCs= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.68.0 h1:0Qx7VGBacMm9ZENQ7TnNObTYI4ShC+lHI16seduaxZo= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.68.0/go.mod h1:Sje3i3MjSPKTSPvVWCaL8ugBzJwik3u4smCjUeuupqg= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI= go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= @@ -503,8 +539,12 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 h1:4YsVu3B8+3qtWYYrsUY go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0/go.mod h1:+wnlSn0mD1ADVMe3v9Z/WIaiz6q6gL2J/ejaAmdmv80= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0 h1:lgh3PiVrRUWMLOVSkQicxzZll5NjF1r+AtsX1XRIHw0= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.44.0/go.mod h1:5Cnhth3m/AgOeTgE3ex12pPmiu/gGtZit03kSzx9X7s= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.44.0 h1:hqxVTu/GtBF+vJ8d1fzW7fRxZFvgoDjWcxwwCaFDYpU= +go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.44.0/go.mod h1:z5fVEF4X5v0ESvlJqBrrFlBVoj5EQuefZpzsu7R+x5Q= go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= +go.opentelemetry.io/otel/metric/x v0.66.0 h1:YkCrx1zLOChi9ZcZ6euupOcsgzbVlec7D/xoEU1+cTA= +go.opentelemetry.io/otel/metric/x v0.66.0/go.mod h1:d1+BDj9t96do0/1LoU1ayfCv79ZgNE41qbhBvnMOBZk= go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58= go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0= go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= @@ -546,8 +586,8 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= -golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= -golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= +golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= +golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20231226003508-02704c960a9b h1:kLiC65FbiHWFAOu+lxwNPujcsl8VYyTYYEZnsOO1WK4= golang.org/x/exp v0.0.0-20231226003508-02704c960a9b/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= @@ -572,7 +612,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -587,9 +626,11 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= -golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= -golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= +golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= +golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= +golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -600,8 +641,8 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= -golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= +golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -627,8 +668,8 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= -golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= +golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -641,8 +682,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= -golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= -golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= +golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= +golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -654,8 +695,10 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= -golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= -golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= +golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= +golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= +golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= +golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -673,34 +716,32 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= +google.golang.org/api v0.287.1 h1:LiyJx32VU3cwQfLchn/513qKhc25hq0pEANYJoWNnnI= +google.golang.org/api v0.287.1/go.mod h1:lM2kYRzYUCBY91P9h6VF1PYmvhxii3O5hji37qRvIcY= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genai v1.54.0 h1:ZQCa70WMTJDI11FdqWCzGvZ5PanpcpfoO6jl/lrSnGU= google.golang.org/genai v1.54.0/go.mod h1:A3kkl0nyBjyFlNjgxIwKq70julKbIxpSxqKO5gw/gmk= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa h1:Kjn0N0tCrDgiAFW+lGO4JZ3ck44CehvJQMAwj9QF0G8= -google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:q4lMZS6kskjT5HvCPrnnypcDPVJqT/f4nfxmkE7gryY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/genproto v0.0.0-20260519071638-aa98bba5eb94 h1:YJjbgu+dkp5kUJLfpMyCLfBIWZb/FcJyuLeo1gVBOuo= +google.golang.org/genproto v0.0.0-20260519071638-aa98bba5eb94/go.mod h1:RRHjglSYABVCWpQ7USCpdfhcd9t4PkajvVwyynZizTc= +google.golang.org/genproto/googleapis/api v0.0.0-20260630182238-925bb5da69e7 h1:jQ9p21COKWjP3VwuFrNRiiOTMh3mPpN45R7SLrH/HUU= +google.golang.org/genproto/googleapis/api v0.0.0-20260630182238-925bb5da69e7/go.mod h1:KqHwBx2upmfa1XSi1WuRvC+2VGCLtooKkfmyvRbUmqA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260630182238-925bb5da69e7 h1:eM/YSd5bBFagF51o1E745Ta7RwzpW0h+z+QDNZOgmQ8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260630182238-925bb5da69e7/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ= -google.golang.org/grpc v1.81.1/go.mod h1:xGH9GfzOyMTGIOXBJmXt+BX/V0kcdQbdcuwQ/zNw42I= +google.golang.org/grpc v1.82.0 h1:vguDnZUPjE26w09A63VoxZPnvPjB5Riyc0mkXPFmAIU= +google.golang.org/grpc v1.82.0/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/internal/admin/handler.go b/internal/admin/handler.go index a4d0fd724..ed6b082ae 100644 --- a/internal/admin/handler.go +++ b/internal/admin/handler.go @@ -17,6 +17,7 @@ package admin import ( + "context" "encoding/json" "errors" "fmt" @@ -26,6 +27,7 @@ import ( "ragflow/internal/engine/redis" "ragflow/internal/server" "ragflow/internal/service" + "ragflow/internal/storage" "ragflow/internal/utility" "strconv" "time" @@ -1250,3 +1252,38 @@ func (h *Handler) ShowModel(c *gin.Context) { common.SuccessWithData(c, model, "") } + +func (h *Handler) PingStore(c *gin.Context) { + storageImpl := storage.GetStorageFactory().GetStorage() + if storageImpl == nil { + common.ErrorWithCode(c, int(common.CodeServerError), "storage not initialized") + return + } + + if storageImpl.Health() { + common.SuccessNoMessage(c, "SUCCESS") + } else { + common.ErrorWithCode(c, int(common.CodeServerError), "storage health check failed") + } +} + +func (h *Handler) PingCache(c *gin.Context) { + redisClient := redis.Get() + if redisClient.Health() { + common.SuccessNoMessage(c, "SUCCESS") + } else { + common.ErrorWithCode(c, int(common.CodeServerError), "cache health check failed") + } +} + +func (h *Handler) PingEngine(c *gin.Context) { + + docEngine := engine.Get() + ctx := context.Background() + if err := docEngine.Ping(ctx); err != nil { + common.ErrorWithCode(c, 500, err.Error()) + return + } + + common.SuccessNoMessage(c, "SUCCESS") +} diff --git a/internal/admin/router.go b/internal/admin/router.go index 87f0a06ce..5b065d7f2 100644 --- a/internal/admin/router.go +++ b/internal/admin/router.go @@ -102,6 +102,10 @@ func (r *Router) Setup(engine *gin.Engine) { queue.PUT("/messages", r.handler.PullMessageFromQueue) } + protected.GET("/store", r.handler.PingStore) + protected.GET("/cache", r.handler.PingCache) + protected.GET("/engine", r.handler.PingEngine) + protected.GET("/ingestors", r.handler.ListIngestors) protected.DELETE("/ingestors", r.handler.ShutdownIngestor) diff --git a/internal/cli/admin_command.go b/internal/cli/admin_command.go index 7b2352522..13e1a80cf 100644 --- a/internal/cli/admin_command.go +++ b/internal/cli/admin_command.go @@ -47,6 +47,46 @@ func (c *CLI) PingAdmin(cmd *Command) (ResponseIf, error) { return HandleSimpleResponse(resp, "ping admin") } +// AdminPingStoreCommand ping object store +func (c *CLI) AdminPingStoreCommand(cmd *Command) (ResponseIf, error) { + resp, err := c.AdminServerClient.Request("GET", "/admin/store", "admin", nil, nil) + if err != nil { + return nil, fmt.Errorf("failed to ping object store: %w", err) + } + + return HandleSimpleResponse(resp, fmt.Sprintf("ping object store")) +} + +// AdminPingEngineCommand ping document engine +func (c *CLI) AdminPingEngineCommand(cmd *Command) (ResponseIf, error) { + resp, err := c.AdminServerClient.Request("GET", "/admin/engine", "admin", nil, nil) + if err != nil { + return nil, fmt.Errorf("failed to ping document engine: %w", err) + } + + return HandleSimpleResponse(resp, fmt.Sprintf("ping document engine")) +} + +// AdminPingMQCommand ping message queue +func (c *CLI) AdminPingMQCommand(cmd *Command) (ResponseIf, error) { + resp, err := c.AdminServerClient.Request("GET", "/admin/queue", "admin", nil, nil) + if err != nil { + return nil, fmt.Errorf("failed to ping message queue: %w", err) + } + + return HandleSimpleResponse(resp, fmt.Sprintf("ping message queue")) +} + +// AdminPingCacheCommand ping cache +func (c *CLI) AdminPingCacheCommand(cmd *Command) (ResponseIf, error) { + resp, err := c.AdminServerClient.Request("GET", "/admin/cache", "web", nil, nil) + if err != nil { + return nil, fmt.Errorf("failed to ping cache: %w", err) + } + + return HandleSimpleResponse(resp, fmt.Sprintf("ping cache")) +} + // AdminShowVersionCommand show RAGFlow admin version func (c *CLI) AdminShowVersionCommand(cmd *Command) (ResponseIf, error) { resp, err := c.AdminServerClient.Request("GET", "/admin/version", "web", nil, nil) @@ -2633,3 +2673,24 @@ func (c *CLI) AdminShowLogLevelCommand(cmd *Command) (ResponseIf, error) { return HandleCommonDataResponse(resp, fmt.Sprintf("get log level config")) } + +func (c *CLI) AdminListBucketObjects(cmd *Command) (ResponseIf, error) { + + if c.Config.CLIMode != AdminMode { + return nil, fmt.Errorf("this command is only allowed in ADMIN mode or already login") + } + + bucketID, ok := cmd.Params["bucket_id"].(string) + if !ok { + return nil, fmt.Errorf("bucket_id not provided") + } + + endPoint := fmt.Sprintf("/admin/bucket/%s/objects", bucketID) + + resp, err := c.AdminServerClient.Request("GET", endPoint, "web", nil, nil) + if err != nil { + return nil, fmt.Errorf("failed to get bucket objects: %w", err) + } + + return HandleCommonResponse(resp, fmt.Sprintf("get bucket objects")) +} diff --git a/internal/cli/admin_parser.go b/internal/cli/admin_parser.go index c35595302..29db84089 100644 --- a/internal/cli/admin_parser.go +++ b/internal/cli/admin_parser.go @@ -70,12 +70,30 @@ func (p *Parser) parseAdminLogout() (*Command, error) { } func (p *Parser) parseAdminPingServer() (*Command, error) { - cmd := NewCommand("admin_ping_server") - p.nextToken() - // Semicolon is optional - if p.curToken.Type == TokenSemicolon { + p.nextToken() // consume PING + + var cmd *Command + + switch p.curToken.Type { + case TokenStore: p.nextToken() + cmd = NewCommand("admin_ping_store") + case TokenEngine: + p.nextToken() + cmd = NewCommand("admin_ping_engine") + case TokenMQ: + p.nextToken() + cmd = NewCommand("admin_ping_mq") + case TokenCache: + p.nextToken() + cmd = NewCommand("admin_ping_cache") + case TokenSemicolon, TokenEOF: + p.nextToken() + cmd = NewCommand("admin_ping_server") + default: + return nil, fmt.Errorf("expected semicolon after PING") } + return cmd, nil } diff --git a/internal/cli/cli_http.go b/internal/cli/cli_http.go index 1370aacb2..176b8f78f 100644 --- a/internal/cli/cli_http.go +++ b/internal/cli/cli_http.go @@ -41,8 +41,16 @@ func (c *CLI) ExecuteAdminCommand(cmd *Command) (ResponseIf, error) { return c.LoginUserByCommand(cmd) case "admin_logout": return c.Logout() + case "admin_ping_store": + return c.AdminPingStoreCommand(cmd) + case "admin_ping_engine": + return c.AdminPingEngineCommand(cmd) + case "admin_ping_mq": + return c.AdminPingMQCommand(cmd) + case "admin_ping_cache": + return c.AdminPingCacheCommand(cmd) case "admin_ping_server": - return c.PingByCommand(cmd) + return c.PingServerByCommand(cmd) case "benchmark": return c.RunBenchmark(cmd) case "admin_list_services": @@ -281,6 +289,8 @@ func (c *CLI) ExecuteAdminCommand(cmd *Command) (ResponseIf, error) { return c.CommonUseAPIServerCommand(cmd) case "admin_use_admin_server": return c.CommonUseAdminServerCommand(cmd) + case "admin_list_bucket_objects": + return c.AdminListBucketObjects(cmd) default: return nil, fmt.Errorf("command '%s' would be executed with API", cmd.Type) } @@ -294,7 +304,7 @@ func (c *CLI) ExecuteUserCommand(cmd *Command) (ResponseIf, error) { case "api_logout": return c.Logout() case "api_ping_server": - return c.PingByCommand(cmd) + return c.PingServerByCommand(cmd) case "api_list_configs": return c.ListConfigs(cmd) case "api_set_log_level": diff --git a/internal/cli/common_command.go b/internal/cli/common_command.go index 9b3fa4cdf..6fcf0a0ab 100644 --- a/internal/cli/common_command.go +++ b/internal/cli/common_command.go @@ -109,7 +109,7 @@ func (c *CLI) LoginUserInteractive(email, password string) error { return nil } -func (c *CLI) PingByCommand(cmd *Command) (ResponseIf, error) { +func (c *CLI) PingServerByCommand(cmd *Command) (ResponseIf, error) { iterations := 1 if iterationsParam, ok := cmd.Params["iterations"]; ok { iterations = int(iterationsParam.(float64)) diff --git a/internal/cli/lexer.go b/internal/cli/lexer.go index 767939bf2..7d9174f5a 100644 --- a/internal/cli/lexer.go +++ b/internal/cli/lexer.go @@ -335,6 +335,8 @@ func (l *Lexer) lookupIdent(ident string) Token { return Token{Type: TokenMax, Value: ident} case "STORE": return Token{Type: TokenStore, Value: ident} + case "ENGINE": + return Token{Type: TokenEngine, Value: ident} case "STREAM": return Token{Type: TokenStream, Value: ident} case "LS": @@ -491,6 +493,8 @@ func (l *Lexer) lookupIdent(ident string) Token { return Token{Type: TokenIngestors, Value: ident} case "INGESTION": return Token{Type: TokenIngestion, Value: ident} + case "CACHE": + return Token{Type: TokenCache, Value: ident} case "MQ": return Token{Type: TokenMQ, Value: ident} case "PUBLISH": diff --git a/internal/cli/types.go b/internal/cli/types.go index 46a6a9c31..bba51e27f 100644 --- a/internal/cli/types.go +++ b/internal/cli/types.go @@ -135,6 +135,7 @@ const ( TokenVector TokenSize TokenStore + TokenEngine TokenName // For ALTER PROVIDER NAME TokenBalance TokenInstance @@ -176,6 +177,7 @@ const ( TokenStart TokenStop TokenIngestion + TokenCache TokenMQ TokenPublish TokenPull diff --git a/internal/engine/elasticsearch/client.go b/internal/engine/elasticsearch/client.go index c69c9ae58..87f34d29f 100644 --- a/internal/engine/elasticsearch/client.go +++ b/internal/engine/elasticsearch/client.go @@ -19,6 +19,7 @@ package elasticsearch import ( "bytes" "context" + "crypto/tls" "encoding/json" "fmt" "io" @@ -59,6 +60,7 @@ func NewEngine(cfg interface{}) (*elasticsearchEngine, error) { Transport: &http.Transport{ MaxIdleConnsPerHost: 10, ResponseHeaderTimeout: 30 * time.Second, + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, }, }) if err != nil { diff --git a/internal/engine/nats/nats.go b/internal/engine/nats/nats.go index 55eaf41c0..ad4f68f14 100644 --- a/internal/engine/nats/nats.go +++ b/internal/engine/nats/nats.go @@ -123,18 +123,18 @@ func (n *NatsEngine) ShowMessageQueue() (map[string]string, error) { result["message_count"] = strconv.FormatUint(info.State.Msgs, 10) consumer, err := n.stream.Consumer(ctx, "RAGFLOW_CONSUMER") - if err != nil { - return nil, fmt.Errorf("failed to get existing consumer: %w", err) + if err == nil { + var consumerInfo *jetstream.ConsumerInfo + consumerInfo, err = consumer.Info(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get consumer info: %w", err) + } + result["pending_count"] = strconv.FormatUint(consumerInfo.NumPending, 10) + result["waiting_count"] = strconv.Itoa(consumerInfo.NumWaiting) + result["ack_pending_count"] = strconv.Itoa(consumerInfo.NumAckPending) + result["redelivered_count"] = strconv.Itoa(consumerInfo.NumRedelivered) } - consumerInfo, err := consumer.Info(ctx) - if err != nil { - return nil, fmt.Errorf("failed to get consumer info: %w", err) - } - result["pending_count"] = strconv.FormatUint(consumerInfo.NumPending, 10) - result["waiting_count"] = strconv.Itoa(consumerInfo.NumWaiting) - result["ack_pending_count"] = strconv.Itoa(consumerInfo.NumAckPending) - result["redelivered_count"] = strconv.Itoa(consumerInfo.NumRedelivered) return result, nil } diff --git a/internal/server/config.go b/internal/server/config.go index 61b8a0983..90e997208 100644 --- a/internal/server/config.go +++ b/internal/server/config.go @@ -210,12 +210,14 @@ type StorageConfig struct { Minio *MinioConfig `mapstructure:"minio"` S3 *S3Config `mapstructure:"s3"` OSS *OSSConfig `mapstructure:"oss"` + GCS *GCSConfig `mapstructure:"gcs"` } const ( StorageOSS StorageType = "oss" StorageS3 StorageType = "s3" StorageMinio StorageType = "minio" + StorageGCS StorageType = "gcs" ) // OSSConfig holds Aliyun OSS storage configuration @@ -231,6 +233,12 @@ type OSSConfig struct { AddressingStyle string `mapstructure:"addressing_style"` // Addressing style } +type GCSConfig struct { + Bucket string `mapstructure:"bucket"` // Default bucket (optional) + PrefixPath string `mapstructure:"prefix_path"` // Path prefix (optional) + EndpointURL string `mapstructure:"endpoint_url"` // Custom endpoint (optional) +} + // MinioConfig holds MinIO storage configuration type MinioConfig struct { Host string `mapstructure:"host"` // MinIO server host (e.g., "localhost:9000") @@ -534,6 +542,8 @@ func FromEnvironments() error { globalConfig.StorageEngine.Type = StorageS3 case "oss": globalConfig.StorageEngine.Type = StorageOSS + case "gcs": + globalConfig.StorageEngine.Type = StorageGCS case "": // Default if globalConfig.StorageEngine.Type == "" { @@ -788,6 +798,19 @@ func FromConfigFile(configPath string) error { } } + if v.IsSet("gcs") { + gcsConfig := v.Sub("gcs") + if gcsConfig != nil { + if globalConfig.StorageEngine.GCS == nil { + globalConfig.StorageEngine.GCS = &GCSConfig{ + Bucket: gcsConfig.GetString("bucket"), + PrefixPath: gcsConfig.GetString("prefix_path"), + EndpointURL: gcsConfig.GetString("endpoint_url"), + } + } + } + } + if v.IsSet("minio_0") { minioConfig := v.Sub("minio_0") if minioConfig != nil { diff --git a/internal/service/chunk/chunk_test.go b/internal/service/chunk/chunk_test.go index 3397fcd67..a18e62485 100644 --- a/internal/service/chunk/chunk_test.go +++ b/internal/service/chunk/chunk_test.go @@ -1226,6 +1226,11 @@ func (s *chunkImageStorage) Get(bucket, fnm string, tenantID ...string) ([]byte, } func (s *chunkImageStorage) Remove(bucket, fnm string, tenantID ...string) error { return nil } func (s *chunkImageStorage) ObjExist(bucket, fnm string, tenantID ...string) bool { return s.exists } + +// ListObjects lists all objects in a bucket +func (s *chunkImageStorage) ListObjects(bucket string, tenantID ...string) ([]string, error) { + return []string{}, nil +} func (s *chunkImageStorage) GetPresignedURL(bucket, fnm string, expires time.Duration, tenantID ...string) (string, error) { return "", nil } @@ -1233,6 +1238,7 @@ func (s *chunkImageStorage) BucketExists(bucket string) bool func (s *chunkImageStorage) RemoveBucket(bucket string) error { return nil } func (s *chunkImageStorage) Copy(srcBucket, srcPath, destBucket, destPath string) bool { return false } func (s *chunkImageStorage) Move(srcBucket, srcPath, destBucket, destPath string) bool { return false } +func (s *chunkImageStorage) Close() error { return nil } func mustEncodePNG(t *testing.T, rect image.Rectangle) []byte { t.Helper() diff --git a/internal/service/document_test.go b/internal/service/document_test.go index 7b1128283..f620bd442 100644 --- a/internal/service/document_test.go +++ b/internal/service/document_test.go @@ -70,6 +70,9 @@ func (f *fakeUploadStorage) ObjExist(bucket, fnm string, tenantID ...string) boo _, ok := f.objects[f.key(bucket, fnm)] return ok } +func (f *fakeUploadStorage) ListObjects(bucket string, tenantID ...string) ([]string, error) { + return []string{}, nil +} func (f *fakeUploadStorage) GetPresignedURL(bucket, fnm string, expires time.Duration, tenantID ...string) (string, error) { return "", nil } @@ -90,6 +93,7 @@ func (f *fakeUploadStorage) Move(srcBucket, srcPath, destBucket, destPath string delete(f.objects, f.key(srcBucket, srcPath)) return true } +func (f *fakeUploadStorage) Close() error { return nil } type fakeChatDocEngine struct{} diff --git a/internal/service/file_test.go b/internal/service/file_test.go index 2e9664e41..cf814e646 100644 --- a/internal/service/file_test.go +++ b/internal/service/file_test.go @@ -72,6 +72,10 @@ func (f *fakeStorage) BucketExists(bucket string) bool { panic("not implemented in fakeStorage") } +func (f *fakeStorage) ListObjects(bucket string, tenantID ...string) ([]string, error) { + panic("not implemented in fakeStorage") +} + func (f *fakeStorage) RemoveBucket(bucket string) error { panic("not implemented in fakeStorage") } @@ -84,6 +88,8 @@ func (f *fakeStorage) Move(srcBucket, srcPath, destBucket, destPath string) bool panic("not implemented in fakeStorage") } +func (f *fakeStorage) Close() error { return nil } + func setupFileContentPermissionDB(t *testing.T, accessible bool) { t.Helper() diff --git a/internal/storage/gcs.go b/internal/storage/gcs.go new file mode 100644 index 000000000..2d23ef86c --- /dev/null +++ b/internal/storage/gcs.go @@ -0,0 +1,253 @@ +// +// Copyright 2026 The InfiniFlow Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package storage + +import ( + "context" + "errors" + "fmt" + "io" + "ragflow/internal/common" + "ragflow/internal/server" + "time" + + "cloud.google.com/go/storage" + "go.uber.org/zap" + "google.golang.org/api/iterator" +) + +// GCSStorage implements Storage interface for GCS +type GCSStorage struct { + client *storage.Client + config *server.GCSConfig +} + +// NewGCSStorage creates a new GCS storage instance +func NewGCSStorage(config *server.GCSConfig) (*GCSStorage, error) { + gcsStorage := &GCSStorage{ + config: config, + } + + if err := gcsStorage.connect(); err != nil { + return nil, err + } + + return gcsStorage, nil +} + +func (m *GCSStorage) connect() error { + + ctx := context.Background() + + client, err := storage.NewClient(ctx) + if err != nil { + common.Fatal(fmt.Sprintf("Failed to create client: %s", err.Error())) + } + + m.client = client + return nil +} + +func (m *GCSStorage) reconnect() { + if err := m.connect(); err != nil { + common.Fatal(fmt.Sprintf("Failed to reconnect to GCS, %s", err.Error())) + } +} + +// Health checks GCS service availability +func (m *GCSStorage) Health() bool { + return m.BucketExists(m.config.Bucket) +} + +// Put uploads an object to GCS +func (m *GCSStorage) Put(bucket, fnm string, binary []byte, tenantID ...string) error { + ctx := context.Background() + + obj := m.client.Bucket(bucket).Object(fnm) + w := obj.NewWriter(ctx) + + if _, err := w.Write(binary); err != nil { + return err + } + if err := w.Close(); err != nil { + return err + } + + return nil +} + +// Get retrieves an object from GCS +func (m *GCSStorage) Get(bucket, fnm string, tenantID ...string) ([]byte, error) { + ctx := context.Background() + + r, err := m.client.Bucket(bucket).Object(fnm).NewReader(ctx) + if err != nil { + return nil, err + } + defer r.Close() + + data, err := io.ReadAll(r) + if err != nil { + return nil, err + } + + return data, nil +} + +// Remove removes an object from GCS +func (m *GCSStorage) Remove(bucketName, objectName string, tenantID ...string) error { + ctx := context.Background() + + obj := m.client.Bucket(bucketName).Object(objectName) + if err := obj.Delete(ctx); err != nil { + return fmt.Errorf("fail to delete object: %v", err) + } + + return nil +} + +// ObjExist checks if an object exists in GCS +func (m *GCSStorage) ObjExist(bucketName, objectName string, tenantID ...string) bool { + ctx := context.Background() + + obj := m.client.Bucket(bucketName).Object(objectName) + + _, err := obj.Attrs(ctx) + if err != nil { + return false + } + + return true +} + +func (m *GCSStorage) ListObjects(bucket string, tenantID ...string) ([]string, error) { + ctx := context.Background() + + bucketObject := m.client.Bucket(bucket) + it := bucketObject.Objects(ctx, nil) + + var objects []string + for { + attrs, err := it.Next() + if errors.Is(err, iterator.Done) { + break + } + if err != nil { + return nil, err + } + + objects = append(objects, attrs.Name) + } + + return objects, nil +} + +// GetPresignedURL generates a presigned URL for accessing an object +func (m *GCSStorage) GetPresignedURL(bucket, fnm string, expires time.Duration, tenantID ...string) (string, error) { + + bucketObject := m.client.Bucket(bucket) + objectPath := fmt.Sprintf("%s/%s", bucket, fnm) + opts := &storage.SignedURLOptions{ + Method: "GET", + Expires: time.Now().Add(expires * time.Second), + } + url, err := bucketObject.SignedURL(objectPath, opts) + if err != nil { + return "", err + } + return url, nil +} + +// BucketExists checks if a bucket exists +func (m *GCSStorage) BucketExists(bucket string) bool { + actualBucket := bucket + if m.config.Bucket != "" { + actualBucket = m.config.Bucket + } + + ctx := context.Background() + + _, err := m.client.Bucket(actualBucket).Attrs(ctx) + if err != nil { + return false + } + + return true +} + +// RemoveBucket removes a bucket and all its objects +func (m *GCSStorage) RemoveBucket(bucketName string) error { + if bucketName == "" { + return fmt.Errorf("attempt to delete bucket without name") + } + + ctx := context.Background() + + bucket := m.client.Bucket(bucketName) + + it := bucket.Objects(ctx, nil) + for { + attrs, err := it.Next() + if errors.Is(err, iterator.Done) { + break + } + if err != nil { + return err + } + + if err = bucket.Object(attrs.Name).Delete(ctx); err != nil { + return err + } + } + + if err := bucket.Delete(ctx); err != nil { + return err + } + + return nil +} + +// Copy copies an object from source to destination +func (m *GCSStorage) Copy(srcBucket, srcObject, destBucket, destObject string) bool { + ctx := context.Background() + src := m.client.Bucket(srcBucket).Object(srcObject) + dst := m.client.Bucket(destBucket).Object(destObject) + copier := dst.CopierFrom(src) + _, err := copier.Run(ctx) + if err != nil { + return false + } + + return true +} + +// Move moves an object from source to destination +func (m *GCSStorage) Move(srcBucket, srcPath, destBucket, destPath string) bool { + if m.Copy(srcBucket, srcPath, destBucket, destPath) { + if err := m.Remove(srcBucket, srcPath); err != nil { + common.Warn("Failed to remove source object after copy", zap.String("bucket", srcBucket), zap.String("key", srcPath), zap.Error(err)) + return false + } + return true + } + return false +} + +func (m *GCSStorage) Close() error { + common.Info("Closing GCS client") + return m.client.Close() +} diff --git a/internal/storage/memory.go b/internal/storage/memory.go index 210147c36..d5bd273b4 100644 --- a/internal/storage/memory.go +++ b/internal/storage/memory.go @@ -123,6 +123,25 @@ func (m *MemoryStorage) ObjExist(bucket, fnm string, tenantID ...string) bool { return ok } +func (m *MemoryStorage) ListObjects(bucket string, tenantID ...string) ([]string, error) { + m.mu.RLock() + defer m.mu.RUnlock() + + bucketMap, ok := m.objects[bucket] + if !ok { + return nil, fmt.Errorf("memory storage: bucket %q: %w", bucket, ErrMemoryNotFound) + } + + var objects []string + for k := range bucketMap { + objects = append(objects, k) + } + + return objects, nil +} + +// ListObjects lists all objects in a bucket + // GetPresignedURL returns a deterministic, non-network URL string for tests. // Format: memory:///?exp= func (m *MemoryStorage) GetPresignedURL(bucket, fnm string, expires time.Duration, tenantID ...string) (string, error) { @@ -202,6 +221,8 @@ func (m *MemoryStorage) Move(srcBucket, srcPath, destBucket, destPath string) bo return true } +func (m *MemoryStorage) Close() error { return nil } + // Inspect returns a stable snapshot of all (bucket, key, size) entries // currently held by the backend. Intended for test diagnostics and // cleanup assertions. The slice is freshly allocated and safe to mutate. diff --git a/internal/storage/minio.go b/internal/storage/minio.go index bc9a37a50..d29cfe83a 100644 --- a/internal/storage/minio.go +++ b/internal/storage/minio.go @@ -273,6 +273,24 @@ func (m *MinioStorage) BucketExists(bucket string) bool { return exists } +func (m *MinioStorage) ListObjects(bucket string, tenantID ...string) ([]string, error) { + ctx := context.Background() + + var objects []string + for obj := range m.client.ListObjects(ctx, bucket, minio.ListObjectsOptions{ + Prefix: "", + Recursive: true, + }) { + if obj.Err != nil { + common.Warn("Failed to list objects", zap.Error(obj.Err)) + return nil, obj.Err + } + objects = append(objects, obj.Key) + } + + return objects, nil +} + // RemoveBucket removes a bucket and all its objects func (m *MinioStorage) RemoveBucket(bucket string) error { actualBucket := bucket @@ -384,3 +402,5 @@ func (m *MinioStorage) Move(srcBucket, srcPath, destBucket, destPath string) boo } return false } + +func (m *MinioStorage) Close() error { return nil } diff --git a/internal/storage/oss.go b/internal/storage/oss.go index 8c3c52bb5..31f7b23ca 100644 --- a/internal/storage/oss.go +++ b/internal/storage/oss.go @@ -256,7 +256,27 @@ func (o *OSSStorage) ObjExist(bucket, fnm string, tenantID ...string) bool { return true } -// GetPresignedURL generates a presigned URL for accessing an object +func (o *OSSStorage) ListObjects(bucket string, tenantID ...string) ([]string, error) { + ctx := context.Background() + + listInput := &s3.ListObjectsV2Input{ + Bucket: aws.String(bucket), + } + + result, err := o.client.ListObjectsV2(ctx, listInput) + if err != nil { + return nil, err + } + + var objects []string + + for _, obj := range result.Contents { + objects = append(objects, *obj.Key) + } + + return objects, nil +} + func (o *OSSStorage) GetPresignedURL(bucket, fnm string, expires time.Duration, tenantID ...string) (string, error) { bucket, fnm = o.resolveBucketAndPath(bucket, fnm) @@ -390,6 +410,8 @@ func (o *OSSStorage) Move(srcBucket, srcPath, destBucket, destPath string) bool return false } +func (o *OSSStorage) Close() error { return nil } + // Helper functions func isOSSNotFound(err error) bool { if err == nil { diff --git a/internal/storage/s3.go b/internal/storage/s3.go index 45b234726..1b9da5474 100644 --- a/internal/storage/s3.go +++ b/internal/storage/s3.go @@ -264,6 +264,27 @@ func (s *S3Storage) ObjExist(bucket, fnm string, tenantID ...string) bool { return true } +func (s *S3Storage) ListObjects(bucket string, tenantID ...string) ([]string, error) { + ctx := context.Background() + + listInput := &s3.ListObjectsV2Input{ + Bucket: aws.String(bucket), + } + + result, err := s.client.ListObjectsV2(ctx, listInput) + if err != nil { + return nil, err + } + + var objects []string + + for _, obj := range result.Contents { + objects = append(objects, *obj.Key) + } + + return objects, nil +} + // GetPresignedURL generates a presigned URL for accessing an object func (s *S3Storage) GetPresignedURL(bucket, fnm string, expires time.Duration, tenantID ...string) (string, error) { bucket, fnm = s.resolveBucketAndPath(bucket, fnm) @@ -398,6 +419,8 @@ func (s *S3Storage) Move(srcBucket, srcPath, destBucket, destPath string) bool { return false } +func (s *S3Storage) Close() error { return nil } + // isNotFound checks if the error is a not found error func isS3NotFound(err error) bool { if err == nil { diff --git a/internal/storage/storage_factory.go b/internal/storage/storage_factory.go index 147d00352..c6673fb7d 100644 --- a/internal/storage/storage_factory.go +++ b/internal/storage/storage_factory.go @@ -60,7 +60,14 @@ func InitStorageFactory() error { return nil } -// initStorage initializes the specific storage implementation +// CloseStorage closes the storage connection +func CloseStorage() error { + factory := GetStorageFactory() + factory.mu.Lock() + defer factory.mu.Unlock() + return factory.storage.Close() +} + func (f *StorageFactory) initStorage() error { switch f.config.Type { case "minio": @@ -69,6 +76,8 @@ func (f *StorageFactory) initStorage() error { return f.initS3(f.config.S3) case "oss": return f.initOSS(f.config.OSS) + case "gcs": + return f.initGCS(f.config.GCS) default: return fmt.Errorf("unsupported storage type: %s", f.config.Type) } @@ -120,6 +129,22 @@ func (f *StorageFactory) initOSS(ossConfig *server.OSSConfig) error { return nil } +func (f *StorageFactory) initGCS(gcsConfig *server.GCSConfig) error { + + storage, err := NewGCSStorage(gcsConfig) + if err != nil { + return fmt.Errorf("failed to create GCS storage: %w", err) + } + + f.mu.Lock() + defer f.mu.Unlock() + f.storageType = StorageGCS + f.storage = storage + f.config.GCS = gcsConfig + + return nil +} + // GetStorage returns the current storage instance func (f *StorageFactory) GetStorage() Storage { f.mu.RLock() diff --git a/internal/storage/types.go b/internal/storage/types.go index 4d48ea8ac..cdee2b71c 100644 --- a/internal/storage/types.go +++ b/internal/storage/types.go @@ -76,6 +76,9 @@ type Storage interface { // ObjExist checks if an object exists ObjExist(bucket, fnm string, tenantID ...string) bool + // ListObjects list all objects of the bucket + ListObjects(bucket string, tenantID ...string) ([]string, error) + // GetPresignedURL generates a presigned URL for accessing an object // expires: duration until the URL expires GetPresignedURL(bucket, fnm string, expires time.Duration, tenantID ...string) (string, error) @@ -91,4 +94,7 @@ type Storage interface { // Move moves an object from source to destination Move(srcBucket, srcPath, destBucket, destPath string) bool + + // Close closes the storage connection + Close() error }