github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/service/store/handler/blob.go (about)

     1  package handler
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"io"
     7  
     8  	pb "github.com/tickoalcantara12/micro/v3/proto/store"
     9  	"github.com/tickoalcantara12/micro/v3/service/errors"
    10  	"github.com/tickoalcantara12/micro/v3/service/store"
    11  	authns "github.com/tickoalcantara12/micro/v3/util/auth/namespace"
    12  	"github.com/tickoalcantara12/micro/v3/util/namespace"
    13  )
    14  
    15  const bufferSize = 1024
    16  
    17  type BlobStore struct{}
    18  
    19  func (b *BlobStore) Read(ctx context.Context, req *pb.BlobReadRequest, stream pb.BlobStore_ReadStream) error {
    20  	// parse the options
    21  	if ns := req.GetOptions().GetNamespace(); len(ns) == 0 {
    22  		req.Options = &pb.BlobOptions{
    23  			Namespace: namespace.FromContext(ctx),
    24  		}
    25  	}
    26  
    27  	// authorize the request
    28  	if err := authns.AuthorizeAdmin(ctx, req.Options.Namespace, "store.Blob.Read"); err != nil {
    29  		return err
    30  	}
    31  
    32  	// execute the request
    33  	blob, err := store.DefaultBlobStore.Read(req.Key, store.BlobNamespace(req.Options.Namespace))
    34  	if err == store.ErrNotFound {
    35  		return errors.NotFound("store.Blob.Read", "Blob not found")
    36  	} else if err == store.ErrMissingKey {
    37  		return errors.BadRequest("store.Blob.Read", "Missing key")
    38  	} else if err != nil {
    39  		return errors.InternalServerError("store.Blob.Read", err.Error())
    40  	}
    41  
    42  	// read from the blob and stream it to the client
    43  	buffer := make([]byte, bufferSize)
    44  	for {
    45  		num, err := blob.Read(buffer)
    46  		if err == io.EOF {
    47  			break
    48  		} else if err != nil {
    49  			return err
    50  		}
    51  
    52  		if err := stream.Send(&pb.BlobReadResponse{Blob: buffer[:num]}); err != nil {
    53  			return err
    54  		}
    55  	}
    56  
    57  	return stream.Close()
    58  }
    59  
    60  func (b *BlobStore) Write(ctx context.Context, stream pb.BlobStore_WriteStream) error {
    61  	// the key and options are passed on each message but we only need to extract them once
    62  	var buf *bytes.Buffer
    63  	var key string
    64  	var options *pb.BlobOptions
    65  
    66  	// recieve the blob from the client
    67  	for {
    68  		req, err := stream.Recv()
    69  		if err == io.EOF {
    70  			break
    71  		} else if err != nil {
    72  			return errors.InternalServerError("store.Blob.Write", err.Error())
    73  		}
    74  
    75  		if buf == nil {
    76  			// first message recieved from the stream
    77  			buf = bytes.NewBuffer(req.Blob)
    78  			key = req.Key
    79  			options = req.Options
    80  
    81  			// parse the options
    82  			if options == nil || len(options.Namespace) == 0 {
    83  				options.Namespace = namespace.FromContext(ctx)
    84  			}
    85  
    86  			// authorize the request. do this inside the loop so we fail fast
    87  			if err := authns.AuthorizeAdmin(ctx, options.Namespace, "store.Blob.Write"); err != nil {
    88  				return err
    89  			}
    90  
    91  		} else {
    92  			// subsequent message recieved from the stream
    93  			buf.Write(req.Blob)
    94  		}
    95  	}
    96  
    97  	// ensure the blob was sent over the stream
    98  	if buf == nil {
    99  		return errors.BadRequest("store.Blob.Write", "No blob was sent")
   100  	}
   101  
   102  	// execute the request
   103  	err := store.DefaultBlobStore.Write(key, buf, store.BlobNamespace(options.Namespace), store.BlobPublic(options.Public), store.BlobContentType(options.ContentType))
   104  	if err == store.ErrMissingKey {
   105  		return errors.BadRequest("store.Blob.Write", "Missing key")
   106  	} else if err != nil {
   107  		return errors.InternalServerError("store.Blob.Write", err.Error())
   108  	}
   109  
   110  	// close the stream
   111  	return stream.SendAndClose(&pb.BlobWriteResponse{})
   112  }
   113  
   114  func (b *BlobStore) Delete(ctx context.Context, req *pb.BlobDeleteRequest, rsp *pb.BlobDeleteResponse) error {
   115  	// parse the options
   116  	if ns := req.GetOptions().GetNamespace(); len(ns) == 0 {
   117  		req.Options = &pb.BlobOptions{
   118  			Namespace: namespace.FromContext(ctx),
   119  		}
   120  	}
   121  
   122  	// authorize the request
   123  	if err := authns.AuthorizeAdmin(ctx, req.Options.Namespace, "store.Blob.Delete"); err != nil {
   124  		return err
   125  	}
   126  
   127  	// execute the request
   128  	err := store.DefaultBlobStore.Delete(req.Key, store.BlobNamespace(req.Options.Namespace))
   129  	if err == store.ErrNotFound {
   130  		return errors.NotFound("store.Blob.Delete", "Blob not found")
   131  	} else if err == store.ErrMissingKey {
   132  		return errors.BadRequest("store.Blob.Delete", "Missing key")
   133  	} else if err != nil {
   134  		return errors.InternalServerError("store.Blob.Delete", err.Error())
   135  	}
   136  
   137  	return nil
   138  }
   139  
   140  func (b *BlobStore) List(ctx context.Context, req *pb.BlobListRequest, rsp *pb.BlobListResponse) error {
   141  	// parse the options
   142  	if ns := req.GetOptions().GetNamespace(); len(ns) == 0 {
   143  		req.Options = &pb.BlobListOptions{
   144  			Namespace: namespace.FromContext(ctx),
   145  			Prefix:    req.GetOptions().GetPrefix(),
   146  		}
   147  	}
   148  
   149  	// authorize the request
   150  	if err := authns.AuthorizeAdmin(ctx, req.Options.Namespace, "store.Blob.List"); err != nil {
   151  		return err
   152  	}
   153  
   154  	// execute the request
   155  	keys, err := store.DefaultBlobStore.List(
   156  		store.BlobListNamespace(req.GetOptions().GetNamespace()),
   157  		store.BlobListPrefix(req.GetOptions().GetPrefix()))
   158  	if err != nil {
   159  		return errors.InternalServerError("store.Blob.List", err.Error())
   160  	}
   161  	rsp.Keys = keys
   162  
   163  	return nil
   164  
   165  }