github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/modules/resource/resource.go (about) 1 package resource 2 3 import ( 4 "context" 5 "mime/multipart" 6 "time" 7 8 "github.com/machinefi/w3bstream/pkg/depends/conf/filesystem/amazonS3" 9 "github.com/machinefi/w3bstream/pkg/depends/conf/filesystem/local" 10 s3db "github.com/machinefi/w3bstream/pkg/depends/conf/filesystem/s3" 11 confid "github.com/machinefi/w3bstream/pkg/depends/conf/id" 12 "github.com/machinefi/w3bstream/pkg/depends/kit/logr" 13 "github.com/machinefi/w3bstream/pkg/depends/kit/sqlx" 14 "github.com/machinefi/w3bstream/pkg/depends/kit/sqlx/builder" 15 "github.com/machinefi/w3bstream/pkg/errors/status" 16 "github.com/machinefi/w3bstream/pkg/models" 17 "github.com/machinefi/w3bstream/pkg/types" 18 ) 19 20 func Create(ctx context.Context, acc types.SFID, fh *multipart.FileHeader, filename, md5 string) (*models.Resource, []byte, error) { 21 data, sum, err := CheckFileMd5SumAndGetData(ctx, fh, md5) 22 if err != nil { 23 return nil, nil, err 24 } 25 26 id := confid.MustNewSFIDGenerator().MustGenSFID() 27 res := &models.Resource{} 28 found := false 29 30 err = sqlx.NewTasks(types.MustMgrDBExecutorFromContext(ctx)).With( 31 func(d sqlx.DBExecutor) error { 32 res.Md5 = sum 33 if err = res.FetchByMd5(d); err != nil { 34 if sqlx.DBErr(err).IsNotFound() { 35 found = false 36 return nil 37 } 38 return status.DatabaseError.StatusErr().WithDesc(err.Error()) 39 } 40 found = true 41 return nil 42 }, 43 func(d sqlx.DBExecutor) error { 44 if found { 45 if !CheckExist(ctx, res.ResourceID) { 46 _, err := UploadFile(ctx, data, res.ResourceID) 47 if err != nil { 48 return err 49 } 50 } 51 return nil 52 } 53 54 path, err := UploadFile(ctx, data, id) 55 if err != nil { 56 return err 57 } 58 res = &models.Resource{ 59 RelResource: models.RelResource{ResourceID: id}, 60 ResourceInfo: models.ResourceInfo{Path: path, Md5: sum}, 61 } 62 if err = res.Create(d); err != nil { 63 if sqlx.DBErr(err).IsConflict() { 64 return status.ResourceConflict 65 } 66 return status.DatabaseError.StatusErr().WithDesc(err.Error()) 67 } 68 return nil 69 }, 70 func(d sqlx.DBExecutor) error { 71 own := &models.ResourceOwnership{ 72 RelResource: models.RelResource{ResourceID: res.ResourceID}, 73 RelAccount: models.RelAccount{AccountID: acc}, 74 } 75 err = own.FetchByResourceIDAndAccountID(d) 76 if err != nil { 77 if sqlx.DBErr(err).IsNotFound() { 78 own.UploadedAt = types.Timestamp{Time: time.Now()} 79 own.Filename = filename 80 if err := own.Create(d); err != nil { 81 return status.DatabaseError.StatusErr().WithDesc(err.Error()) 82 } 83 return nil 84 } 85 return status.DatabaseError.StatusErr().WithDesc(err.Error()) 86 } else { 87 own.Filename = filename 88 if err = own.UpdateByResourceIDAndAccountID(d); err != nil { 89 return status.DatabaseError.StatusErr().WithDesc(err.Error()) 90 } 91 return nil 92 } 93 }, 94 ).Do() 95 96 if err != nil { 97 return nil, nil, err 98 } 99 return res, data, nil 100 } 101 102 func GetBySFID(ctx context.Context, id types.SFID) (*models.Resource, error) { 103 ctx, l := logr.Start(ctx, "resource.GetBySFID") 104 defer l.End() 105 106 res := &models.Resource{} 107 res.ResourceID = id 108 if err := res.FetchByResourceID(types.MustMgrDBExecutorFromContext(ctx)); err != nil { 109 if sqlx.DBErr(err).IsNotFound() { 110 return nil, status.ResourceNotFound 111 } 112 return nil, status.DatabaseError.StatusErr().WithDesc(err.Error()) 113 } 114 return res, nil 115 } 116 117 func GetByMd5(ctx context.Context, md5 string) (*models.Resource, error) { 118 res := &models.Resource{} 119 res.Md5 = md5 120 if err := res.FetchByMd5(types.MustMgrDBExecutorFromContext(ctx)); err != nil { 121 if sqlx.DBErr(err).IsNotFound() { 122 return nil, status.ResourceNotFound 123 } 124 return nil, status.DatabaseError.StatusErr().WithDesc(err.Error()) 125 } 126 return res, nil 127 } 128 129 func GetContentBySFID(ctx context.Context, id types.SFID) (*models.Resource, []byte, error) { 130 ctx, l := logr.Start(ctx, "resource.GetContentBySFID") 131 defer l.End() 132 133 res, err := GetBySFID(ctx, id) 134 if err != nil { 135 return nil, nil, err 136 } 137 data, err := ReadContent(ctx, res) 138 if err != nil { 139 return nil, nil, err 140 } 141 return res, data, nil 142 } 143 144 func GetContentByMd5(ctx context.Context, md5 string) (*models.Resource, []byte, error) { 145 res, err := GetByMd5(ctx, md5) 146 if err != nil { 147 return nil, nil, err 148 } 149 data, err := ReadContent(ctx, res) 150 if err != nil { 151 return nil, nil, err 152 } 153 return res, data, nil 154 } 155 156 func GetDownloadUrlBySFID(ctx context.Context, id types.SFID) (*DownLoadResourceRsp, error) { 157 var ( 158 fs = types.MustFileSystemOpFromContext(ctx) 159 ship = types.MustResourceOwnershipFromContext(ctx) 160 161 res *models.Resource 162 url string 163 err error 164 ) 165 166 res, err = GetBySFID(ctx, id) 167 if err != nil { 168 return nil, err 169 } 170 171 switch v := fs.(type) { 172 case *local.LocalFileSystem: 173 err = status.UnsupportedFSOperator 174 case *amazonS3.AmazonS3: 175 url, err = v.DownloadUrl(res.Path) 176 case *s3db.ObjectDB: 177 url, err = v.DownloadUrl(res.Path) 178 } 179 180 if err != nil { 181 return nil, err 182 } 183 184 return &DownLoadResourceRsp{ 185 FileName: ship.Filename, 186 Url: url, 187 }, nil 188 } 189 190 func ReadContent(ctx context.Context, m *models.Resource) ([]byte, error) { 191 ctx, l := logr.Start(ctx, "resource.ReadContent") 192 defer l.End() 193 194 fs := types.MustFileSystemOpFromContext(ctx) 195 data, err := fs.Read(m.Path) 196 if err != nil { 197 return nil, status.FetchResourceFailed.StatusErr().WithDesc(err.Error()) 198 } 199 return data, nil 200 } 201 202 func GetOwnerByAccountAndSFID(ctx context.Context, acc, res types.SFID) (*models.ResourceOwnership, error) { 203 d := types.MustMgrDBExecutorFromContext(ctx) 204 m := &models.ResourceOwnership{ 205 RelAccount: models.RelAccount{AccountID: acc}, 206 RelResource: models.RelResource{ResourceID: res}, 207 } 208 209 if err := m.FetchByResourceIDAndAccountID(d); err != nil { 210 if sqlx.DBErr(err).IsNotFound() { 211 return nil, status.ResourcePermNotFound 212 } 213 return nil, status.DatabaseError.StatusErr().WithDesc(err.Error()) 214 } 215 return m, nil 216 } 217 218 func List(ctx context.Context, r *ListReq) (*ListRsp, error) { 219 d := types.MustMgrDBExecutorFromContext(ctx) 220 res := &models.Resource{} 221 own := &models.ResourceOwnership{} 222 rsp := &ListRsp{} 223 224 err := d.QueryAndScan( 225 builder.Select( 226 builder.MultiWith(",", 227 builder.Alias(res.ColResourceID(), "f_resource_id"), 228 builder.Alias(res.ColMd5(), "f_md5"), 229 builder.Alias(own.ColUploadedAt(), "f_uploaded_at"), 230 builder.Alias(own.ColExpireAt(), "f_expire_at"), 231 builder.Alias(own.ColFilename(), "f_filename"), 232 builder.Alias(own.ColComment(), "f_comment"), 233 builder.Alias(own.ColCreatedAt(), "f_created_at"), 234 builder.Alias(own.ColUpdatedAt(), "f_updated_at"), 235 ), 236 ).From( 237 d.T(res), 238 builder.LeftJoin(d.T(own)).On(res.ColResourceID().Eq(own.ColResourceID())), 239 builder.Where(r.Condition()), 240 ), &rsp.Data) 241 if err != nil { 242 return nil, status.DatabaseError.StatusErr().WithDesc(err.Error()) 243 } 244 245 err = d.QueryAndScan(builder.Select(builder.Count()).From( 246 d.T(res), 247 builder.LeftJoin(d.T(own)).On(res.ColResourceID().Eq(own.ResourceID)), 248 builder.Where(r.Condition()), 249 ), &rsp.Total) 250 if err != nil { 251 return nil, status.DatabaseError.StatusErr().WithDesc(err.Error()) 252 } 253 return rsp, nil 254 } 255 256 func RemoveOwnershipBySFID(ctx context.Context, id types.SFID) error { 257 d := types.MustMgrDBExecutorFromContext(ctx) 258 acc := types.MustAccountFromContext(ctx) 259 260 m := &models.ResourceOwnership{ 261 RelResource: models.RelResource{ResourceID: id}, 262 RelAccount: acc.RelAccount, 263 } 264 if err := m.DeleteByResourceIDAndAccountID(d); err != nil { 265 return status.DatabaseError.StatusErr().WithDesc(err.Error()) 266 } 267 return nil 268 }