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 }