2020-08-18 07:23:45 +03:00
// Copyright 2020 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2020-08-18 07:23:45 +03:00
package storage
import (
"context"
"errors"
"fmt"
"io"
"net/url"
2020-09-29 12:05:13 +03:00
"os"
2020-08-18 07:23:45 +03:00
2020-10-16 06:51:06 +03:00
"code.gitea.io/gitea/modules/log"
2020-08-18 07:23:45 +03:00
"code.gitea.io/gitea/modules/setting"
)
2022-01-20 20:46:10 +03:00
// ErrURLNotSupported represents url is not supported
var ErrURLNotSupported = errors . New ( "url method not supported" )
2020-08-18 07:23:45 +03:00
2020-10-13 06:58:34 +03:00
// ErrInvalidConfiguration is called when there is invalid configuration for a storage
type ErrInvalidConfiguration struct {
cfg interface { }
err error
}
func ( err ErrInvalidConfiguration ) Error ( ) string {
if err . err != nil {
return fmt . Sprintf ( "Invalid Configuration Argument: %v: Error: %v" , err . cfg , err . err )
}
return fmt . Sprintf ( "Invalid Configuration Argument: %v" , err . cfg )
}
// IsErrInvalidConfiguration checks if an error is an ErrInvalidConfiguration
func IsErrInvalidConfiguration ( err error ) bool {
_ , ok := err . ( ErrInvalidConfiguration )
return ok
}
// Type is a type of Storage
type Type string
// NewStorageFunc is a function that creates a storage
type NewStorageFunc func ( ctx context . Context , cfg interface { } ) ( ObjectStorage , error )
var storageMap = map [ Type ] NewStorageFunc { }
// RegisterStorageType registers a provided storage type with a function to create it
func RegisterStorageType ( typ Type , fn func ( ctx context . Context , cfg interface { } ) ( ObjectStorage , error ) ) {
storageMap [ typ ] = fn
}
2020-09-08 18:45:10 +03:00
// Object represents the object on the storage
type Object interface {
io . ReadCloser
io . Seeker
2020-09-29 12:05:13 +03:00
Stat ( ) ( os . FileInfo , error )
2020-09-08 18:45:10 +03:00
}
2020-08-18 07:23:45 +03:00
// ObjectStorage represents an object storage to handle a bucket and files
type ObjectStorage interface {
2020-09-08 18:45:10 +03:00
Open ( path string ) ( Object , error )
2021-04-03 19:19:59 +03:00
// Save store a object, if size is unknown set -1
Save ( path string , r io . Reader , size int64 ) ( int64 , error )
2020-09-29 12:05:13 +03:00
Stat ( path string ) ( os . FileInfo , error )
2020-08-18 07:23:45 +03:00
Delete ( path string ) error
URL ( path , name string ) ( * url . URL , error )
2020-09-29 12:05:13 +03:00
IterateObjects ( func ( path string , obj Object ) error ) error
2020-08-18 07:23:45 +03:00
}
2021-07-08 14:38:13 +03:00
// Copy copies a file from source ObjectStorage to dest ObjectStorage
2020-08-18 07:23:45 +03:00
func Copy ( dstStorage ObjectStorage , dstPath string , srcStorage ObjectStorage , srcPath string ) ( int64 , error ) {
f , err := srcStorage . Open ( srcPath )
if err != nil {
return 0 , err
}
defer f . Close ( )
2021-04-03 19:19:59 +03:00
size := int64 ( - 1 )
fsinfo , err := f . Stat ( )
if err == nil {
size = fsinfo . Size ( )
}
return dstStorage . Save ( dstPath , f , size )
2020-08-18 07:23:45 +03:00
}
2021-07-13 15:16:31 +03:00
// Clean delete all the objects in this storage
func Clean ( storage ObjectStorage ) error {
return storage . IterateObjects ( func ( path string , obj Object ) error {
2021-09-03 13:48:49 +03:00
_ = obj . Close ( )
2021-07-13 15:16:31 +03:00
return storage . Delete ( path )
} )
}
2020-10-14 16:07:51 +03:00
// SaveFrom saves data to the ObjectStorage with path p from the callback
func SaveFrom ( objStorage ObjectStorage , p string , callback func ( w io . Writer ) error ) error {
pr , pw := io . Pipe ( )
defer pr . Close ( )
go func ( ) {
defer pw . Close ( )
if err := callback ( pw ) ; err != nil {
_ = pw . CloseWithError ( err )
}
} ( )
2021-04-03 19:19:59 +03:00
_ , err := objStorage . Save ( p , pr , - 1 )
2020-10-14 16:07:51 +03:00
return err
}
2020-08-18 07:23:45 +03:00
var (
// Attachments represents attachments storage
Attachments ObjectStorage
2020-09-08 18:45:10 +03:00
// LFS represents lfs storage
LFS ObjectStorage
2020-10-14 16:07:51 +03:00
// Avatars represents user avatars storage
Avatars ObjectStorage
// RepoAvatars represents repository avatars storage
RepoAvatars ObjectStorage
2021-06-24 00:12:38 +03:00
// RepoArchives represents repository archives storage
RepoArchives ObjectStorage
2022-03-30 11:42:47 +03:00
// Packages represents packages storage
Packages ObjectStorage
2020-08-18 07:23:45 +03:00
)
// Init init the stoarge
func Init ( ) error {
2020-09-08 18:45:10 +03:00
if err := initAttachments ( ) ; err != nil {
return err
}
2020-10-14 16:07:51 +03:00
if err := initAvatars ( ) ; err != nil {
return err
}
if err := initRepoAvatars ( ) ; err != nil {
return err
}
2021-06-24 00:12:38 +03:00
if err := initLFS ( ) ; err != nil {
return err
}
2022-03-30 11:42:47 +03:00
if err := initRepoArchives ( ) ; err != nil {
return err
}
return initPackages ( )
2020-09-08 18:45:10 +03:00
}
2020-10-13 06:58:34 +03:00
// NewStorage takes a storage type and some config and returns an ObjectStorage or an error
func NewStorage ( typStr string , cfg interface { } ) ( ObjectStorage , error ) {
if len ( typStr ) == 0 {
typStr = string ( LocalStorageType )
2020-08-18 07:23:45 +03:00
}
2020-10-13 06:58:34 +03:00
fn , ok := storageMap [ Type ( typStr ) ]
if ! ok {
return nil , fmt . Errorf ( "Unsupported storage type: %s" , typStr )
2020-08-18 07:23:45 +03:00
}
2020-10-13 06:58:34 +03:00
return fn ( context . Background ( ) , cfg )
2020-08-18 07:23:45 +03:00
}
2020-09-08 18:45:10 +03:00
2020-10-14 16:07:51 +03:00
func initAvatars ( ) ( err error ) {
2020-10-16 06:51:06 +03:00
log . Info ( "Initialising Avatar storage with type: %s" , setting . Avatar . Storage . Type )
2020-10-25 20:19:06 +03:00
Avatars , err = NewStorage ( setting . Avatar . Storage . Type , & setting . Avatar . Storage )
2022-06-20 13:02:49 +03:00
return err
2020-10-14 16:07:51 +03:00
}
2020-09-29 12:05:13 +03:00
func initAttachments ( ) ( err error ) {
2020-10-16 06:51:06 +03:00
log . Info ( "Initialising Attachment storage with type: %s" , setting . Attachment . Storage . Type )
2020-10-25 20:19:06 +03:00
Attachments , err = NewStorage ( setting . Attachment . Storage . Type , & setting . Attachment . Storage )
2022-06-20 13:02:49 +03:00
return err
2020-09-29 12:05:13 +03:00
}
2020-09-08 18:45:10 +03:00
2020-09-29 12:05:13 +03:00
func initLFS ( ) ( err error ) {
2020-10-16 06:51:06 +03:00
log . Info ( "Initialising LFS storage with type: %s" , setting . LFS . Storage . Type )
2020-10-25 20:19:06 +03:00
LFS , err = NewStorage ( setting . LFS . Storage . Type , & setting . LFS . Storage )
2022-06-20 13:02:49 +03:00
return err
2020-09-08 18:45:10 +03:00
}
2020-10-14 16:07:51 +03:00
func initRepoAvatars ( ) ( err error ) {
2020-10-16 06:51:06 +03:00
log . Info ( "Initialising Repository Avatar storage with type: %s" , setting . RepoAvatar . Storage . Type )
2020-10-25 20:19:06 +03:00
RepoAvatars , err = NewStorage ( setting . RepoAvatar . Storage . Type , & setting . RepoAvatar . Storage )
2022-06-20 13:02:49 +03:00
return err
2020-10-14 16:07:51 +03:00
}
2021-06-24 00:12:38 +03:00
func initRepoArchives ( ) ( err error ) {
log . Info ( "Initialising Repository Archive storage with type: %s" , setting . RepoArchive . Storage . Type )
RepoArchives , err = NewStorage ( setting . RepoArchive . Storage . Type , & setting . RepoArchive . Storage )
2022-06-20 13:02:49 +03:00
return err
2021-06-24 00:12:38 +03:00
}
2022-03-30 11:42:47 +03:00
func initPackages ( ) ( err error ) {
log . Info ( "Initialising Packages storage with type: %s" , setting . Packages . Storage . Type )
Packages , err = NewStorage ( setting . Packages . Storage . Type , & setting . Packages . Storage )
2022-06-20 13:02:49 +03:00
return err
2022-03-30 11:42:47 +03:00
}