diff --git a/config.sample.yaml b/config.sample.yaml index dffa03aaa78c8a7e2aa18bdefe7a500c9f8247a2..f4be43712b2ca35ce0ebe256c096d29bc7bba807 100644 --- a/config.sample.yaml +++ b/config.sample.yaml @@ -43,8 +43,25 @@ uploads: # This is intended for larger deployments where media should be distributed among other # directories, drives, servers, etc. For smaller deployments, a single entry in this list # is recommended. - storagePaths: - - /var/matrix/media + # DEPRECATED. + #storagePaths: + # - /var/matrix/media + + datastores: + - type: file + enabled: false # Enable this to set up data storage. + priority: 1 + opts: + path: /var/matrix/media + - type: s3 + enabled: false + priority: 1 + opts: + endpoint: sfo2.digitaloceanspaces.com + accessKeyId: "" + accessSecret: "" + ssl: true + bucketName: "your-media-bucket" # An optional list of file types that are allowed to be uploaded. If */* or nothing is # supplied here, then all file types are allowed. Asterisks (*) are wildcards and can be diff --git a/src/github.com/turt2live/matrix-media-repo/cmd/media_repo/main.go b/src/github.com/turt2live/matrix-media-repo/cmd/media_repo/main.go index f64f51d77956ebda79347f63a79028c373fa2ec8..b3d0a79bfcdb99ef25ef88ea61dc5c71f646d4c1 100644 --- a/src/github.com/turt2live/matrix-media-repo/cmd/media_repo/main.go +++ b/src/github.com/turt2live/matrix-media-repo/cmd/media_repo/main.go @@ -26,10 +26,43 @@ func main() { panic(err) } - logrus.Info("Starting media repository...") + mediaStore := storage.GetDatabase().GetMediaStore(context.TODO(), &logrus.Entry{}) + + logrus.Info("Initializing datastores...") + enabledDatastores := 0 + for _, ds:=range config.Get().Uploads.DataStores { + if !ds.Enabled { + continue + } + + enabledDatastores++ + + uri := "" + if ds.Type == "file" { + path, pathFound := ds.Options["path"] + if !pathFound { + logrus.Fatal("Missing 'path' on file datastore") + } + uri = path + } else if ds.Type == "s3" { + endpoint, epFound := ds.Options["endpoint"] + bucket, bucketFound := ds.Options["bucketName"] + if !epFound || !bucketFound { + logrus.Fatal("Missing 'endpoint' or 'bucketName' on s3 datastore") + } + uri = fmt.Sprintf("s3://%s/%s", endpoint, bucket) + } else { + logrus.Fatal("Unknown datastore type: ", ds.Type) + } + + _, err := storage.GetOrCreateDatastoreOfType(context.TODO(), &logrus.Entry{}, ds.Type, uri) + if err != nil { + logrus.Fatal(err) + } + } // Print all the known datastores at startup. Doubles as a way to initialize the database. - datastores, err := storage.GetDatabase().GetMediaStore(context.TODO(), &logrus.Entry{}).GetAllDatastores() + datastores, err := mediaStore.GetAllDatastores() if err != nil { logrus.Fatal(err) } @@ -38,6 +71,9 @@ func main() { logrus.Info(fmt.Sprintf("\t%s (%s): %s", ds.Type, ds.DatastoreId, ds.Uri)) } + // TODO: https://github.com/minio/minio-go support + + logrus.Info("Starting media repository...") metrics.Init() webserver.Init() // blocks to listen for requests } diff --git a/src/github.com/turt2live/matrix-media-repo/common/config/config.go b/src/github.com/turt2live/matrix-media-repo/common/config/config.go index ac3d8f37656db9c171ea32a4a0b208f9141afa06..446b6b3e6c427e18bb68411b1eaea1fa69718159 100644 --- a/src/github.com/turt2live/matrix-media-repo/common/config/config.go +++ b/src/github.com/turt2live/matrix-media-repo/common/config/config.go @@ -33,6 +33,7 @@ type DatabaseConfig struct { type UploadsConfig struct { StoragePaths []string `yaml:"storagePaths,flow"` + DataStores []DatastoreConfig `yaml:"datastores"` MaxSizeBytes int64 `yaml:"maxBytes"` MinSizeBytes int64 `yaml:"minBytes"` AllowedTypes []string `yaml:"allowedTypes,flow"` @@ -40,6 +41,13 @@ type UploadsConfig struct { ReportedMaxSizeBytes int64 `yaml:"reportedMaxBytes"` } +type DatastoreConfig struct { + Type string `yaml:"type"` + Enabled bool `yaml:"enabled"` + Priority int `yaml:"priority"` + Options map[string]string `yaml:"opts,flow"` +} + type DownloadsConfig struct { MaxSizeBytes int64 `yaml:"maxBytes"` NumWorkers int `yaml:"numWorkers"` @@ -209,6 +217,7 @@ func NewDefaultConfig() *MediaRepoConfig { MinSizeBytes: 100, ReportedMaxSizeBytes: 0, StoragePaths: []string{}, + DataStores: []DatastoreConfig{}, AllowedTypes: []string{"*/*"}, }, Downloads: &DownloadsConfig{ diff --git a/src/github.com/turt2live/matrix-media-repo/storage/datastore/datastore.go b/src/github.com/turt2live/matrix-media-repo/storage/datastore/datastore.go new file mode 100644 index 0000000000000000000000000000000000000000..f141945857ad6683ca6401460d1d8aad10cbd4ab --- /dev/null +++ b/src/github.com/turt2live/matrix-media-repo/storage/datastore/datastore.go @@ -0,0 +1,4 @@ +package datastore + +// TODO: Upload to DS +// TODO: Download (get stream) from DS diff --git a/src/github.com/turt2live/matrix-media-repo/storage/ds_utils.go b/src/github.com/turt2live/matrix-media-repo/storage/ds_utils.go index eddbe348c4b6cd1ceed0f26793e925b168e02a39..e0f78d0221e75b6dfc068552e3a390fcd2c0c462 100644 --- a/src/github.com/turt2live/matrix-media-repo/storage/ds_utils.go +++ b/src/github.com/turt2live/matrix-media-repo/storage/ds_utils.go @@ -16,6 +16,29 @@ func GetOrCreateDatastore(ctx context.Context, log *logrus.Entry, basePath strin return getOrCreateDatastoreWithMediaService(mediaService, basePath) } +func GetOrCreateDatastoreOfType(ctx context.Context, log *logrus.Entry, dsType string, dsUri string) (*types.Datastore, error) { + mediaService := GetDatabase().GetMediaStore(ctx, log) + datastore, err := mediaService.GetDatastoreByUri(dsUri) + if err != nil && err == sql.ErrNoRows { + id, err2 := util.GenerateRandomString(32) + if err2 != nil { + logrus.Error("Error generating datastore ID for URI ", dsUri, ": ", err) + return nil, err2 + } + datastore = &types.Datastore{ + DatastoreId: id, + Type: dsType, + Uri: dsUri, + } + err2 = mediaService.InsertDatastore(datastore) + if err2 != nil { + logrus.Error("Error creating datastore for URI ", dsUri, ": ", err) + return nil, err2 + } + } + return datastore, nil +} + func getOrCreateDatastoreWithMediaService(mediaService *stores.MediaStore, basePath string) (*types.Datastore, error) { datastore, err := mediaService.GetDatastoreByUri(basePath) if err != nil && err == sql.ErrNoRows { diff --git a/vendor/manifest b/vendor/manifest index 0fb7d376742b08725729091f97e5adcb180c10b2..7730ad31b1f6e64a55bc343ba50c6ec2c333ac26 100644 --- a/vendor/manifest +++ b/vendor/manifest @@ -163,6 +163,18 @@ "branch": "master", "path": "/pbutil" }, + { + "importpath": "github.com/minio/minio-go", + "repository": "https://github.com/minio/minio-go", + "revision": "c8a261de75c1a9a9ece4dcc0c81ff6db525bcf27", + "branch": "master" + }, + { + "importpath": "github.com/mitchellh/go-homedir", + "repository": "https://github.com/mitchellh/go-homedir", + "revision": "af06845cf3004701891bf4fdb884bfe4920b3727", + "branch": "master" + }, { "importpath": "github.com/olebedev/emitter", "repository": "https://github.com/olebedev/emitter", @@ -257,6 +269,20 @@ "revision": "89742aefa4b206dcf400792f3bd35b542998eb3b", "branch": "master" }, + { + "importpath": "golang.org/x/crypto/argon2", + "repository": "https://go.googlesource.com/crypto", + "revision": "b8fe1690c61389d7d2a8074a507d1d40c5d30448", + "branch": "master", + "path": "/argon2" + }, + { + "importpath": "golang.org/x/crypto/blake2b", + "repository": "https://go.googlesource.com/crypto", + "revision": "b8fe1690c61389d7d2a8074a507d1d40c5d30448", + "branch": "master", + "path": "/blake2b" + }, { "importpath": "golang.org/x/crypto/ed25519", "repository": "https://go.googlesource.com/crypto", @@ -327,6 +353,34 @@ "branch": "master", "path": "/html" }, + { + "importpath": "golang.org/x/net/http/httpguts", + "repository": "https://go.googlesource.com/net", + "revision": "d26f9f9a57f3fab6a695bec0d84433c2c50f8bbf", + "branch": "master", + "path": "/http/httpguts" + }, + { + "importpath": "golang.org/x/net/idna", + "repository": "https://go.googlesource.com/net", + "revision": "d26f9f9a57f3fab6a695bec0d84433c2c50f8bbf", + "branch": "master", + "path": "/idna" + }, + { + "importpath": "golang.org/x/net/publicsuffix", + "repository": "https://go.googlesource.com/net", + "revision": "d26f9f9a57f3fab6a695bec0d84433c2c50f8bbf", + "branch": "master", + "path": "/publicsuffix" + }, + { + "importpath": "golang.org/x/sys/cpu", + "repository": "https://go.googlesource.com/sys", + "revision": "7ae0202eb74c2b534255c71b5a15fa4115aabbcc", + "branch": "master", + "path": "/cpu" + }, { "importpath": "golang.org/x/sys/unix", "repository": "https://go.googlesource.com/sys", @@ -341,6 +395,34 @@ "branch": "master", "path": "/windows" }, + { + "importpath": "golang.org/x/text/secure/bidirule", + "repository": "https://go.googlesource.com/text", + "revision": "e6919f6577db79269a6443b9dc46d18f2238fb5d", + "branch": "master", + "path": "/secure/bidirule" + }, + { + "importpath": "golang.org/x/text/transform", + "repository": "https://go.googlesource.com/text", + "revision": "e6919f6577db79269a6443b9dc46d18f2238fb5d", + "branch": "master", + "path": "/transform" + }, + { + "importpath": "golang.org/x/text/unicode/bidi", + "repository": "https://go.googlesource.com/text", + "revision": "e6919f6577db79269a6443b9dc46d18f2238fb5d", + "branch": "master", + "path": "/unicode/bidi" + }, + { + "importpath": "golang.org/x/text/unicode/norm", + "repository": "https://go.googlesource.com/text", + "revision": "e6919f6577db79269a6443b9dc46d18f2238fb5d", + "branch": "master", + "path": "/unicode/norm" + }, { "importpath": "golang.org/x/time/rate", "repository": "https://go.googlesource.com/time", @@ -362,6 +444,12 @@ "branch": "master", "path": "/types" }, + { + "importpath": "gopkg.in/ini.v1", + "repository": "https://gopkg.in/ini.v1", + "revision": "6ed8d5f64cd79a498d1f3fab5880cc376ce41bbe", + "branch": "master" + }, { "importpath": "gopkg.in/yaml.v2", "repository": "https://gopkg.in/yaml.v2",