Skip to content

Commit de98197

Browse files
authored
Add upload api (#93)
* feat: update upload manager * feat: filepath dir * feat: add config api
1 parent 7573df5 commit de98197

File tree

6 files changed

+137
-49
lines changed

6 files changed

+137
-49
lines changed

go.sum

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@ buf.build/gen/go/coscene-io/coscene-openapi/protocolbuffers/go v1.36.6-202506130
66
buf.build/gen/go/coscene-io/coscene-openapi/protocolbuffers/go v1.36.6-20250613072610-46122efff246.1/go.mod h1:89cE9hg+EVUYFLDK76q58op06UHEe34JeX3ASfRfb+w=
77
buf.build/gen/go/gnostic/gnostic/protocolbuffers/go v1.36.6-20230414000709-087bc8072ce4.1 h1:QZk9F35A+TnMNgUQBlW+7kjUef086s2jux7f6CI8H+w=
88
buf.build/gen/go/gnostic/gnostic/protocolbuffers/go v1.36.6-20230414000709-087bc8072ce4.1/go.mod h1:ZSkBzB0CxHcvK9isqj6cCCJ3hDfEPFCpYAN6Mckzr2M=
9-
cel.dev/expr v0.23.1 h1:K4KOtPCJQjVggkARsjG9RWXP6O4R73aHeJMa/dmCQQg=
10-
cel.dev/expr v0.23.1/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
119
cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
1210
cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
1311
connectrpc.com/connect v1.18.1 h1:PAg7CjSAGvscaf6YZKUefjoih5Z/qYkyaTrBW8xvYPw=
@@ -16,8 +14,6 @@ github.com/ThreeDotsLabs/watermill v1.4.7 h1:LiF4wMP400/psRTdHL/IcV1YIv9htHYFggb
1614
github.com/ThreeDotsLabs/watermill v1.4.7/go.mod h1:Ks20MyglVnqjpha1qq0kjaQ+J9ay7bdnjszQ4cW9FMU=
1715
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
1816
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
19-
github.com/bmatcuk/doublestar/v4 v4.8.1 h1:54Bopc5c2cAvhLRAzqOGCYHYyhcDHsFF4wWIR5wKP38=
20-
github.com/bmatcuk/doublestar/v4 v4.8.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
2117
github.com/bmatcuk/doublestar/v4 v4.9.1 h1:X8jg9rRZmJd4yRy7ZeNDRnM+T3ZfHv15JiBJ/avrEXE=
2218
github.com/bmatcuk/doublestar/v4 v4.9.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
2319
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
@@ -39,14 +35,10 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S
3935
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
4036
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
4137
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
42-
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
43-
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
4438
github.com/go-viper/mapstructure/v2 v2.3.0 h1:27XbWsHIqhbdR5TIC911OfYvgSaW93HM+dX7970Q7jk=
4539
github.com/go-viper/mapstructure/v2 v2.3.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
4640
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
4741
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
48-
github.com/google/cel-go v0.25.0 h1:jsFw9Fhn+3y2kBbltZR4VEz5xKkcIFRPDnuEzAGv5GY=
49-
github.com/google/cel-go v0.25.0/go.mod h1:hjEb6r5SuOSlhCHmFoLzu8HGCERvIsDAbxDAyNU/MmI=
5042
github.com/google/cel-go v0.26.0 h1:DPGjXackMpJWH680oGY4lZhYjIameYmR+/6RBdDGmaI=
5143
github.com/google/cel-go v0.26.0/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM=
5244
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
@@ -63,8 +55,6 @@ github.com/itchyny/timefmt-go v0.1.6/go.mod h1:RRDZYC5s9ErkjQvTvvU7keJjxUYzIISJG
6355
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
6456
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
6557
github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
66-
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
67-
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
6858
github.com/klauspost/cpuid/v2 v2.2.11 h1:0OwqZRYI2rFrjS4kvkDnqJkKHdHaRnCm68/DY4OxRzU=
6959
github.com/klauspost/cpuid/v2 v2.2.11/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
7060
github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo=
@@ -77,8 +67,6 @@ github.com/knadh/koanf/providers/file v1.2.0 h1:hrUJ6Y9YOA49aNu/RSYzOTFlqzXSCpmY
7767
github.com/knadh/koanf/providers/file v1.2.0/go.mod h1:bp1PM5f83Q+TOUu10J/0ApLBd9uIzg+n9UgthfY+nRA=
7868
github.com/knadh/koanf/providers/rawbytes v1.0.0 h1:MrKDh/HksJlKJmaZjgs4r8aVBb/zsJyc/8qaSnzcdNI=
7969
github.com/knadh/koanf/providers/rawbytes v1.0.0/go.mod h1:KxwYJf1uezTKy6PBtfE+m725NGp4GPVA7XoNTJ/PtLo=
80-
github.com/knadh/koanf/v2 v2.2.1 h1:jaleChtw85y3UdBnI0wCqcg1sj1gPoz6D3caGNHtrNE=
81-
github.com/knadh/koanf/v2 v2.2.1/go.mod h1:PSFru3ufQgTsI7IF+95rf9s8XA1+aHxKuO/W+dPoHEY=
8270
github.com/knadh/koanf/v2 v2.2.2 h1:ghbduIkpFui3L587wavneC9e3WIliCgiCgdxYO/wd7A=
8371
github.com/knadh/koanf/v2 v2.2.2/go.mod h1:abWQc0cBXLSF/PSOMCB/SK+T13NXDsPvOksbpi5e/9Q=
8472
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@@ -87,14 +75,10 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
8775
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
8876
github.com/lithammer/shortuuid/v3 v3.0.7 h1:trX0KTHy4Pbwo/6ia8fscyHoGA+mf1jWbPJVuvyJQQ8=
8977
github.com/lithammer/shortuuid/v3 v3.0.7/go.mod h1:vMk8ke37EmiewwolSO1NLW8vP4ZaKlRuDIi8tWWmAts=
90-
github.com/minio/crc64nvme v1.0.1 h1:DHQPrYPdqK7jQG/Ls5CTBZWeex/2FMS3G5XGkycuFrY=
91-
github.com/minio/crc64nvme v1.0.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
9278
github.com/minio/crc64nvme v1.0.2 h1:6uO1UxGAD+kwqWWp7mBFsi5gAse66C4NXO8cmcVculg=
9379
github.com/minio/crc64nvme v1.0.2/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
9480
github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
9581
github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM=
96-
github.com/minio/minio-go/v7 v7.0.94 h1:1ZoksIKPyaSt64AVOyaQvhDOgVC3MfZsWM6mZXRUGtM=
97-
github.com/minio/minio-go/v7 v7.0.94/go.mod h1:71t2CqDt3ThzESgZUlU1rBN54mksGGlkLcFgguDnnAc=
9882
github.com/minio/minio-go/v7 v7.0.95 h1:ywOUPg+PebTMTzn9VDsoFJy32ZuARN9zhB+K3IYEvYU=
9983
github.com/minio/minio-go/v7 v7.0.95/go.mod h1:wOOX3uxS334vImCNRVyIDdXX9OsXDm89ToynKgqUKlo=
10084
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
@@ -105,8 +89,6 @@ github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
10589
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
10690
github.com/oriser/regroup v0.0.0-20240925165441-f6bb0e08289e h1:cL0lMYYEbfEUBghQd4ytnl8B8Ktdm+JremTyAagegZ0=
10791
github.com/oriser/regroup v0.0.0-20240925165441-f6bb0e08289e/go.mod h1:tUOeYZJlwO7jSmM5ko1jTCiQaWQMvh58IENEfjwYzh8=
108-
github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c h1:dAMKvw0MlJT1GshSTtih8C2gDs04w8dReiOGXrGLNoY=
109-
github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
11092
github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
11193
github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
11294
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
@@ -145,26 +127,18 @@ go.etcd.io/bbolt v1.4.2 h1:IrUHp260R8c+zYx/Tm8QZr04CX+qWS5PGfPdevhdm1I=
145127
go.etcd.io/bbolt v1.4.2/go.mod h1:Is8rSHO/b4f3XigBC0lL0+4FwAQv3HXEEIgFMuKHceM=
146128
go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE=
147129
go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI=
148-
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
149-
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
150130
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
151131
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
152132
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU=
153133
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
154-
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
155-
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
156134
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
157135
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
158-
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
159-
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
136+
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
137+
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
160138
golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
161139
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
162-
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
163-
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
164140
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
165141
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
166-
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
167-
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
168142
golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
169143
golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
170144
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=

internal/config/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ type AppConfig struct {
3535
// HttpServer HttpServerConfig `yaml:"http_server"`
3636
HttpServer HttpServerConfig `koanf:"http_server" yaml:"http_server" json:"http_server"`
3737

38+
// PluginConfig other coscene plugin config, such as coEncoder..., which is not cos's config
39+
PluginConfig interface{} `koanf:"plugin_config" yaml:"plugin_config" json:"plugin_config"`
40+
3841
// import other config
3942
Import []string `koanf:"__import__" yaml:"__import__" json:"__import__"`
4043
}

internal/mod/http/handler.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ func (c *CustomHttpHandler) Run(ctx context.Context) {
5050
router := mux.NewRouter()
5151
router.HandleFunc("/ruleEngine/messages", server.RulesHandler(c.pubSub)).Methods("POST")
5252
router.HandleFunc("/ruleEngine/activeTopics", server.ActiveTopicsHandler(ctx, c.pubSub)).Methods("GET")
53+
router.HandleFunc("/config/current", server.CurrentConfigHandler(c.confManager)).Methods("GET")
5354
router.HandleFunc("/config/setLogLevel", server.LogConfigHandler()).Methods("POST")
5455

5556
srv := &http.Server{

internal/mod/http/server/config.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"encoding/json"
1919
"net/http"
2020

21+
"github.com/coscene-io/coscout/internal/config"
2122
log "github.com/sirupsen/logrus"
2223
)
2324

@@ -57,3 +58,28 @@ func LogConfigHandler() func(w http.ResponseWriter, r *http.Request) {
5758
}
5859
}
5960
}
61+
62+
func CurrentConfigHandler(confManager config.ConfManager) func(w http.ResponseWriter, r *http.Request) {
63+
return func(w http.ResponseWriter, r *http.Request) {
64+
appConfig := confManager.LoadWithRemote()
65+
66+
bytes, err := json.Marshal(appConfig)
67+
if err != nil {
68+
log.Errorf("Failed to marshal response: %v", err)
69+
http.Error(w, err.Error(), http.StatusInternalServerError)
70+
return
71+
}
72+
73+
// Respond
74+
w.Header().Set("Content-Type", "application/json")
75+
w.WriteHeader(http.StatusOK)
76+
_, err = w.Write(bytes)
77+
if err != nil {
78+
log.Errorf("Failed to write response: %v", err)
79+
http.Error(w, err.Error(), http.StatusInternalServerError)
80+
return
81+
}
82+
log.Debugf("Current config: %s", string(bytes))
83+
log.Infof("Current config served successfully")
84+
}
85+
}

internal/mod/task/handler.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,10 @@ func (c *CustomTaskHandler) handleUploadTask(task *openDpsV1alpha1Resource.Task)
344344
continue
345345
}
346346

347-
parentFolder := filepath.Dir(file)
347+
// Clean the file path to handle trailing slashes correctly
348+
cleanFile := filepath.Clean(file)
349+
parentFolder := filepath.Dir(cleanFile)
350+
348351
filePaths, err := utils.GetAllFilePaths(file, &utils.SymWalkOptions{
349352
FollowSymlinks: true,
350353
SkipPermissionErrors: true,

pkg/upload/upload_manager.go

Lines changed: 101 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,50 @@ func (u *Manager) FMultipartPutObject(ctx context.Context, bucket string, key st
165165
c := minio.Core{Client: u.client}
166166

167167
// ----------------- Start fetching previous upload info from db -----------------
168-
// Fetch upload id. If not found, initiate a new multipart upload.
168+
// Fetch uploaded size
169169
var uploadId string
170+
var uploadedSize int64
171+
170172
uploadIdKey := fmt.Sprintf(uploadIdKeyTemplate, filePath)
173+
uploadedSizeKey := fmt.Sprintf(uploadedSizeKeyTemplate, filePath)
174+
partsKey := fmt.Sprintf(partsKeyTemplate, filePath)
175+
176+
uploadedSizeBytes, err := (*u.storage).Get([]byte(u.cacheBucket), []byte(uploadedSizeKey))
177+
if err != nil {
178+
log.Debugf("Get uploaded size by: %s warn: %v", uploadedSizeKey, err)
179+
}
180+
//nolint: nestif // readability
181+
if uploadedSizeBytes != nil {
182+
uploadedSize, err = strconv.ParseInt(string(uploadedSizeBytes), 10, 64)
183+
if err != nil {
184+
uploadedSize = 0
185+
}
186+
// Validate cached uploaded size doesn't exceed file size
187+
if uploadedSize > fileSize {
188+
log.Warnf("Cached uploaded size %d exceeds file size %d, resetting to 0", uploadedSize, fileSize)
189+
uploadedSize = 0
190+
191+
err = (*u.storage).Delete([]byte(u.cacheBucket), []byte(uploadedSizeKey))
192+
if err != nil {
193+
log.Errorf("Delete uploaded size failed: %v", err)
194+
}
195+
196+
// Reset uploadId and parts as well
197+
err = (*u.storage).Delete([]byte(u.cacheBucket), []byte(uploadIdKey))
198+
if err != nil {
199+
log.Errorf("Delete upload id failed: %v", err)
200+
}
201+
202+
err = (*u.storage).Delete([]byte(u.cacheBucket), []byte(partsKey))
203+
if err != nil {
204+
log.Errorf("Delete parts failed: %v", err)
205+
}
206+
}
207+
} else {
208+
uploadedSize = 0
209+
}
210+
211+
// Fetch upload id. If not found, initiate a new multipart upload.
171212
uploadIdBytes, err := (*u.storage).Get([]byte(u.cacheBucket), []byte(uploadIdKey))
172213
if err != nil {
173214
log.Debugf("Get upload id by: %s warn: %v", uploadIdKey, err)
@@ -183,28 +224,11 @@ func (u *Manager) FMultipartPutObject(ctx context.Context, bucket string, key st
183224
}
184225
log.Debugf("Get upload id: %s by: %s", uploadId, uploadIdKey)
185226

186-
// Fetch uploaded size
187-
var uploadedSize int64
188-
uploadedSizeKey := fmt.Sprintf(uploadedSizeKeyTemplate, filePath)
189-
uploadedSizeBytes, err := (*u.storage).Get([]byte(u.cacheBucket), []byte(uploadedSizeKey))
190-
if err != nil {
191-
log.Debugf("Get uploaded size by: %s warn: %v", uploadedSizeKey, err)
192-
}
193-
if uploadedSizeBytes != nil {
194-
uploadedSize, err = strconv.ParseInt(string(uploadedSizeBytes), 10, 64)
195-
if err != nil {
196-
uploadedSize = 0
197-
}
198-
} else {
199-
uploadedSize = 0
200-
}
201-
202227
u.uploadProgressChan <- FileUploadProgress{Name: filePath, Uploaded: uploadedSize, TotalSize: -1}
203228
log.Debugf("Get uploaded size: %d by: %s", uploadedSize, uploadedSizeKey)
204229

205230
// Fetch uploaded parts
206231
var parts []minio.CompletePart
207-
partsKey := fmt.Sprintf(partsKeyTemplate, filePath)
208232
partsBytes, err := (*u.storage).Get([]byte(u.cacheBucket), []byte(partsKey))
209233
if err != nil {
210234
log.Debugf("Get uploaded parts by: %s warn: %v", partsKey, err)
@@ -242,10 +266,67 @@ func (u *Manager) FMultipartPutObject(ctx context.Context, bucket string, key st
242266
return errors.Wrap(err, "Optimal part info failed")
243267
}
244268

269+
// Check if all parts are already uploaded
270+
partsToUpload := totalPartsCount - len(partNumbers)
271+
//nolint: nestif // readability
272+
if partsToUpload <= 0 {
273+
if totalPartsCount == len(partNumbers) && uploadedSize == fileSize {
274+
// All parts are uploaded and size matches - complete the upload
275+
log.Infof("File: %s, all parts already uploaded, completing multipart upload", filePath)
276+
277+
// Sort all completed parts.
278+
slices.SortFunc(parts, func(i, j minio.CompletePart) int {
279+
return i.PartNumber - j.PartNumber
280+
})
281+
282+
_, err = c.CompleteMultipartUpload(ctx, bucket, key, uploadId, parts, opts)
283+
if err != nil {
284+
log.Errorf("Complete multipart upload failed: %v", err)
285+
return errors.Wrapf(err, "Complete multipart upload failed")
286+
}
287+
288+
// Clean up cache entries
289+
err = (*u.storage).Delete([]byte(u.cacheBucket), []byte(uploadIdKey))
290+
if err != nil {
291+
log.Errorf("Delete upload id failed: %v", err)
292+
}
293+
err = (*u.storage).Delete([]byte(u.cacheBucket), []byte(partsKey))
294+
if err != nil {
295+
log.Errorf("Delete parts failed: %v", err)
296+
}
297+
err = (*u.storage).Delete([]byte(u.cacheBucket), []byte(uploadedSizeKey))
298+
if err != nil {
299+
log.Errorf("Delete uploaded size failed: %v", err)
300+
}
301+
302+
return nil
303+
} else {
304+
// Parts count or size mismatch - need to re-upload
305+
log.Warnf("File: %s, parts/size mismatch (total parts: %d, uploaded parts: %d, uploaded size: %d, file size: %d), clearing cache",
306+
filePath, totalPartsCount, len(partNumbers), uploadedSize, fileSize)
307+
308+
err = (*u.storage).Delete([]byte(u.cacheBucket), []byte(uploadedSizeKey))
309+
if err != nil {
310+
log.Errorf("Delete uploaded size failed: %v", err)
311+
}
312+
313+
err = (*u.storage).Delete([]byte(u.cacheBucket), []byte(uploadIdKey))
314+
if err != nil {
315+
log.Errorf("Delete upload id failed: %v", err)
316+
}
317+
318+
err = (*u.storage).Delete([]byte(u.cacheBucket), []byte(partsKey))
319+
if err != nil {
320+
log.Errorf("Delete parts failed: %v", err)
321+
}
322+
return errors.New("File parts/size mismatch, need to re-upload all parts")
323+
}
324+
}
325+
245326
// Declare a channel that sends the next part number to be uploaded.
246327
uploadPartsCh := make(chan int)
247328
// Declare a channel that sends back the response of a part upload.
248-
uploadedPartsCh := make(chan uploadedPartRes, totalPartsCount-len(partNumbers))
329+
uploadedPartsCh := make(chan uploadedPartRes, partsToUpload)
249330
// Used for readability, lastPartNumber is always totalPartsCount.
250331
lastPartNumber := totalPartsCount
251332

@@ -362,7 +443,7 @@ func (u *Manager) FMultipartPutObject(ctx context.Context, bucket string, key st
362443
}
363444
return uploadRes.Error
364445
}
365-
// Update the uploadedSize.
446+
// Update the uploadedSize with the current part size
366447
uploadedSize += uploadRes.Part.Size
367448
parts = append(parts, minio.CompletePart{
368449
ETag: uploadRes.Part.ETag,

0 commit comments

Comments
 (0)