| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- // Copyright (C) 2025 The Syncthing Authors.
- //
- // This Source Code Form is subject to the terms of the Mozilla Public
- // License, v. 2.0. If a copy of the MPL was not distributed with this file,
- // You can obtain one at https://mozilla.org/MPL/2.0/.
- package azureblob
- import (
- "context"
- "io"
- "time"
- stblob "github.com/syncthing/syncthing/internal/blob"
- "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
- "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob"
- "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blockblob"
- "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/container"
- )
- var _ stblob.Store = (*BlobStore)(nil)
- type BlobStore struct {
- client *azblob.Client
- container string
- }
- func NewBlobStore(accountName, accountKey, containerName string) (*BlobStore, error) {
- credential, err := azblob.NewSharedKeyCredential(accountName, accountKey)
- if err != nil {
- return nil, err
- }
- url := "https://" + accountName + ".blob.core.windows.net/"
- sc, err := azblob.NewClientWithSharedKeyCredential(url, credential, &azblob.ClientOptions{})
- if err != nil {
- return nil, err
- }
- // This errors when the container already exists, which we ignore.
- _, _ = sc.CreateContainer(context.Background(), containerName, &container.CreateOptions{})
- return &BlobStore{
- client: sc,
- container: containerName,
- }, nil
- }
- func (a *BlobStore) Upload(ctx context.Context, key string, data io.Reader) error {
- _, err := a.client.UploadStream(ctx, a.container, key, data, &blockblob.UploadStreamOptions{})
- return err
- }
- func (a *BlobStore) Download(ctx context.Context, key string, w stblob.Writer) error {
- resp, err := a.client.DownloadStream(ctx, a.container, key, &blob.DownloadStreamOptions{})
- if err != nil {
- return err
- }
- defer resp.Body.Close()
- _, err = io.Copy(w, resp.Body)
- return err
- }
- func (a *BlobStore) LatestKey(ctx context.Context) (string, error) {
- opts := &azblob.ListBlobsFlatOptions{}
- pager := a.client.NewListBlobsFlatPager(a.container, opts)
- var latest string
- var lastModified time.Time
- for pager.More() {
- page, err := pager.NextPage(ctx)
- if err != nil {
- return "", err
- }
- for _, blob := range page.Segment.BlobItems {
- if latest == "" || blob.Properties.LastModified.After(lastModified) {
- latest = *blob.Name
- lastModified = *blob.Properties.LastModified
- }
- }
- }
- return latest, nil
- }
|