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  }