[MM-26812] Add support for resumable file uploads (#15252)
* Implement AppendFile for FileBackend * Split test into subtests * [MM-26812] Add support for resumable file uploads (#15252) * Implement UploadSession * Implement UploadSessionStore * Add error strings * Implement resumable file uploads * Add UploadType * Fix retry layer tests * Regenerate store layers * Fix store error handling * Use base for filename * Prevent concurrent uploads on the same upload session * Fix erroneus error string * Improve error handling Co-authored-by: Mattermod <mattermod@users.noreply.github.com> * Fix translations Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
6a58834f34
Коммит
9c272f0b20
@@ -47,6 +47,7 @@ type RetryLayer struct {
|
||||
TeamStore store.TeamStore
|
||||
TermsOfServiceStore store.TermsOfServiceStore
|
||||
TokenStore store.TokenStore
|
||||
UploadSessionStore store.UploadSessionStore
|
||||
UserStore store.UserStore
|
||||
UserAccessTokenStore store.UserAccessTokenStore
|
||||
UserTermsOfServiceStore store.UserTermsOfServiceStore
|
||||
@@ -161,6 +162,10 @@ func (s *RetryLayer) Token() store.TokenStore {
|
||||
return s.TokenStore
|
||||
}
|
||||
|
||||
func (s *RetryLayer) UploadSession() store.UploadSessionStore {
|
||||
return s.UploadSessionStore
|
||||
}
|
||||
|
||||
func (s *RetryLayer) User() store.UserStore {
|
||||
return s.UserStore
|
||||
}
|
||||
@@ -312,6 +317,11 @@ type RetryLayerTokenStore struct {
|
||||
Root *RetryLayer
|
||||
}
|
||||
|
||||
type RetryLayerUploadSessionStore struct {
|
||||
store.UploadSessionStore
|
||||
Root *RetryLayer
|
||||
}
|
||||
|
||||
type RetryLayerUserStore struct {
|
||||
store.UserStore
|
||||
Root *RetryLayer
|
||||
@@ -6542,6 +6552,106 @@ func (s *RetryLayerTokenStore) Save(recovery *model.Token) error {
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerUploadSessionStore) Delete(id string) error {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
err := s.UploadSessionStore.Delete(id)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if !isRepeatableError(err) {
|
||||
return err
|
||||
}
|
||||
tries++
|
||||
if tries >= 3 {
|
||||
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerUploadSessionStore) Get(id string) (*model.UploadSession, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.UploadSessionStore.Get(id)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
if !isRepeatableError(err) {
|
||||
return result, err
|
||||
}
|
||||
tries++
|
||||
if tries >= 3 {
|
||||
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
|
||||
return result, err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerUploadSessionStore) GetForUser(userId string) ([]*model.UploadSession, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.UploadSessionStore.GetForUser(userId)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
if !isRepeatableError(err) {
|
||||
return result, err
|
||||
}
|
||||
tries++
|
||||
if tries >= 3 {
|
||||
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
|
||||
return result, err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerUploadSessionStore) Save(session *model.UploadSession) (*model.UploadSession, error) {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
result, err := s.UploadSessionStore.Save(session)
|
||||
if err == nil {
|
||||
return result, nil
|
||||
}
|
||||
if !isRepeatableError(err) {
|
||||
return result, err
|
||||
}
|
||||
tries++
|
||||
if tries >= 3 {
|
||||
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
|
||||
return result, err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerUploadSessionStore) Update(session *model.UploadSession) error {
|
||||
|
||||
tries := 0
|
||||
for {
|
||||
err := s.UploadSessionStore.Update(session)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if !isRepeatableError(err) {
|
||||
return err
|
||||
}
|
||||
tries++
|
||||
if tries >= 3 {
|
||||
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (s *RetryLayerUserStore) AnalyticsActiveCount(time int64, options model.UserCountOptions) (int64, *model.AppError) {
|
||||
|
||||
return s.UserStore.AnalyticsActiveCount(time, options)
|
||||
@@ -7782,6 +7892,7 @@ func New(childStore store.Store) *RetryLayer {
|
||||
newStore.TeamStore = &RetryLayerTeamStore{TeamStore: childStore.Team(), Root: &newStore}
|
||||
newStore.TermsOfServiceStore = &RetryLayerTermsOfServiceStore{TermsOfServiceStore: childStore.TermsOfService(), Root: &newStore}
|
||||
newStore.TokenStore = &RetryLayerTokenStore{TokenStore: childStore.Token(), Root: &newStore}
|
||||
newStore.UploadSessionStore = &RetryLayerUploadSessionStore{UploadSessionStore: childStore.UploadSession(), Root: &newStore}
|
||||
newStore.UserStore = &RetryLayerUserStore{UserStore: childStore.User(), Root: &newStore}
|
||||
newStore.UserAccessTokenStore = &RetryLayerUserAccessTokenStore{UserAccessTokenStore: childStore.UserAccessToken(), Root: &newStore}
|
||||
newStore.UserTermsOfServiceStore = &RetryLayerUserTermsOfServiceStore{UserTermsOfServiceStore: childStore.UserTermsOfService(), Root: &newStore}
|
||||
|
||||
@@ -25,6 +25,7 @@ func genStore() *mocks.Store {
|
||||
mock.On("Compliance").Return(&mocks.ComplianceStore{})
|
||||
mock.On("Emoji").Return(&mocks.EmojiStore{})
|
||||
mock.On("FileInfo").Return(&mocks.FileInfoStore{})
|
||||
mock.On("UploadSession").Return(&mocks.UploadSessionStore{})
|
||||
mock.On("Group").Return(&mocks.GroupStore{})
|
||||
mock.On("Job").Return(&mocks.JobStore{})
|
||||
mock.On("License").Return(&mocks.LicenseStore{})
|
||||
|
||||
Ссылка в новой задаче
Block a user