[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>
Этот коммит содержится в:
Claudio Costa
2020-09-15 21:28:25 +02:00
коммит произвёл GitHub
родитель 6a58834f34
Коммит 9c272f0b20
40 изменённых файлов: 2523 добавлений и 18 удалений

Просмотреть файл

@@ -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{})