gitee.com/woood2/luca@v1.0.4/internal/service/app.go (about)

     1  package service
     2  
     3  import (
     4  	"context"
     5  	"gitee.com/woood2/luca/internal/cache"
     6  	"gitee.com/woood2/luca/internal/errcode"
     7  	"gitee.com/woood2/luca/internal/layer"
     8  	"gitee.com/woood2/luca/internal/repository"
     9  	"go.uber.org/zap"
    10  	"gorm.io/gorm"
    11  	"time"
    12  )
    13  
    14  type App struct {
    15  	ID         int
    16  	Appkey     string
    17  	Secret     string
    18  	Name       string
    19  	Url        string
    20  	Logo       string
    21  	Contacts   string
    22  	Disabled   int
    23  	Createtime time.Time
    24  	Updatetime time.Time
    25  	Remark     string
    26  }
    27  
    28  type AppService interface {
    29  	//errcode.AppKeyAlreadyExists
    30  	//errcode.AppNameAlreadyExists
    31  	Create(ctx context.Context, dto *App) (id int, err error)
    32  
    33  	Twins(ctx context.Context) error
    34  
    35  	//errcode.AppNotExists
    36  	//errcode.AppNotAllowedToDelete
    37  	DeleteByKey(ctx context.Context, appkey string) error
    38  
    39  	//errcode.AppNotExists
    40  	//errcode.AppNotAllowedToChangeDisabled
    41  	Enable(ctx context.Context, appkey string) error
    42  
    43  	//errcode.AppNotExists
    44  	//errcode.AppNotAllowedToChangeDisabled
    45  	Disable(ctx context.Context, appkey string) error
    46  
    47  	//errcode.AppNotExists
    48  	//errcode.AppNameAlreadyExists
    49  	EditByKey(ctx context.Context, appkey string, dto *App) error
    50  
    51  	//errcode.AppNotExists
    52  	GetByKey(ctx context.Context, appkey string) (*App, error)
    53  
    54  	//errcode.AppNotExists
    55  	GetByKeyFromCache(ctx context.Context, c cache.Cache, appkey string) (*App, error)
    56  
    57  	//errcode.AppNotExists
    58  	GetByKeyFromCacheSafely(ctx context.Context, c cache.Cache, appkey string) (*App, error)
    59  
    60  	List(ctx context.Context, appkey string, name string) ([]*App, error)
    61  }
    62  
    63  func NewAppServiceImpl(logger *zap.Logger, db *gorm.DB,
    64  	repoFactory repository.AppRepoFactory) *AppServiceImpl {
    65  	return &AppServiceImpl{
    66  		Service:     layer.Service{Logger: logger},
    67  		repo:        repoFactory.Produce(logger, db),
    68  		repoFactory: repoFactory,
    69  		db:          db,
    70  	}
    71  }
    72  
    73  type AppServiceImpl struct {
    74  	layer.Service
    75  	repo        repository.AppRepo
    76  	repoFactory repository.AppRepoFactory
    77  	db          *gorm.DB
    78  }
    79  
    80  func (svc *AppServiceImpl) Create(ctx context.Context, dto *App) (id int, err error) {
    81  	if ok, err := svc.repo.ExistByKey(ctx, dto.Appkey); err != nil {
    82  		return 0, err
    83  	} else if ok {
    84  		return 0, errcode.AppKeyAlreadyExists
    85  	}
    86  	if ok, err := svc.repo.ExistByName(ctx, dto.Name); err != nil {
    87  		return 0, err
    88  	} else if ok {
    89  		return 0, errcode.AppNameAlreadyExists
    90  	}
    91  	app := &repository.App{
    92  		Appkey:   dto.Appkey,
    93  		Secret:   dto.Secret,
    94  		Name:     dto.Name,
    95  		Url:      dto.Url,
    96  		Logo:     dto.Logo,
    97  		Contacts: dto.Contacts,
    98  		Disabled: dto.Disabled,
    99  		Remark:   dto.Remark,
   100  	}
   101  	id, err = svc.repo.Create(ctx, app)
   102  	return
   103  }
   104  
   105  func (svc *AppServiceImpl) Twins(ctx context.Context) error {
   106  	saga := &repository.App{
   107  		Appkey: "saga",
   108  		Secret: "13",
   109  		Name:   "撒加",
   110  	}
   111  	kanon := &repository.App{
   112  		Appkey: "kanon",
   113  		Secret: "North Atlantic",
   114  		Name:   "加隆",
   115  	}
   116  	err := svc.db.Transaction(func(tx *gorm.DB) error {
   117  		repo := svc.repoFactory.Produce(svc.Logger, tx)
   118  		if _, err := repo.Create(ctx, saga); err != nil {
   119  			return err
   120  		}
   121  		if _, err := repo.Create(ctx, kanon); err != nil {
   122  			return err
   123  		}
   124  		return nil
   125  	})
   126  	return err
   127  }
   128  
   129  func (svc *AppServiceImpl) DeleteByKey(ctx context.Context, appkey string) error {
   130  	app, err := svc.repo.GetByKey(ctx, appkey)
   131  	if err != nil {
   132  		return err
   133  	}
   134  	if time.Now().After(app.Createtime.Add(2 * time.Hour)) {
   135  		return errcode.AppNotAllowedToDelete
   136  	}
   137  	return svc.repo.Delete(ctx, app)
   138  }
   139  
   140  func (svc *AppServiceImpl) Enable(ctx context.Context, appkey string) error {
   141  	user, err := svc.repo.GetByKey(ctx, appkey)
   142  	if err != nil {
   143  		return err
   144  	}
   145  	if user.Disabled == 0 {
   146  		return errcode.AppNotAllowedToChangeDisabled
   147  	}
   148  	return svc.repo.SetDisabled(ctx, appkey, 0)
   149  }
   150  
   151  func (svc *AppServiceImpl) Disable(ctx context.Context, appkey string) error {
   152  	user, err := svc.repo.GetByKey(ctx, appkey)
   153  	if err != nil {
   154  		return err
   155  	}
   156  	if user.Disabled == 1 {
   157  		return errcode.AppNotAllowedToChangeDisabled
   158  	}
   159  	return svc.repo.SetDisabled(ctx, appkey, 1)
   160  }
   161  
   162  func (svc *AppServiceImpl) EditByKey(ctx context.Context, appkey string, dto *App) error {
   163  	app, err := svc.repo.GetByKey(ctx, appkey)
   164  	if err != nil {
   165  		return err
   166  	}
   167  	if dto.Name != app.Name {
   168  		if ok, err := svc.repo.ExistByName(ctx, dto.Name); err != nil {
   169  			return err
   170  		} else if ok {
   171  			return errcode.AppNameAlreadyExists
   172  		}
   173  	}
   174  	now := time.Now()
   175  	app.Updatetime = now
   176  
   177  	app.Secret = dto.Secret
   178  	app.Name = dto.Name
   179  	app.Url = dto.Url
   180  	app.Logo = dto.Logo
   181  	app.Contacts = dto.Contacts
   182  	app.Remark = dto.Remark
   183  
   184  	return svc.repo.Edit(ctx, app)
   185  }
   186  
   187  func (svc *AppServiceImpl) GetByKey(ctx context.Context, appkey string) (*App, error) {
   188  	app, err := svc.repo.GetByKey(ctx, appkey)
   189  	if err != nil {
   190  		return nil, err
   191  	}
   192  
   193  	return &App{
   194  		ID:         app.ID,
   195  		Appkey:     app.Appkey,
   196  		Secret:     app.Secret,
   197  		Name:       app.Name,
   198  		Url:        app.Url,
   199  		Logo:       app.Logo,
   200  		Contacts:   app.Contacts,
   201  		Disabled:   app.Disabled,
   202  		Createtime: app.Createtime,
   203  		Updatetime: app.Updatetime,
   204  		Remark:     app.Remark,
   205  	}, nil
   206  }
   207  
   208  /**
   209  Mainly used in auth scene
   210  [error]
   211  errcode.AppNotExists not exist in DB
   212  ...other errors
   213  */
   214  func (svc *AppServiceImpl) GetByKeyFromCache(ctx context.Context, c cache.Cache, appkey string) (*App, error) {
   215  	k := cache.App.BuildKey(appkey)
   216  	var v *App
   217  	if e := c.Get(k, &v); e != nil {
   218  		//miss
   219  		if e == c.Miss() {
   220  			//exist
   221  			app, err := svc.GetByKey(ctx, appkey)
   222  			if err == nil {
   223  				if err := c.Set(k, app, cache.App.Duration); err != nil {
   224  					return nil, err
   225  				} else {
   226  					return app, nil
   227  				}
   228  			}
   229  			//not exist
   230  			if err == errcode.AppNotExists {
   231  				if err := c.Set(k, nil, cache.App.Duration); err != nil {
   232  					return nil, err
   233  				} else {
   234  					return nil, errcode.AppNotExists
   235  				}
   236  			}
   237  			//other errors
   238  			return nil, err
   239  		}
   240  		//other errors
   241  		return nil, e
   242  	}
   243  	//hit
   244  	if v == nil {
   245  		return nil, errcode.AppNotExists
   246  	}
   247  	return v, nil
   248  }
   249  
   250  /**
   251  Mainly used in auth scene
   252  Safe mode to prevent avalanches
   253  [error]
   254  errcode.AppNotExists not exist in DB
   255  ...other errors
   256  */
   257  func (svc *AppServiceImpl) GetByKeyFromCacheSafely(ctx context.Context, c cache.Cache, appkey string) (*App, error) {
   258  	k := cache.App.BuildKey(appkey)
   259  	var v *App
   260  	if e := c.Get(k, &v); e != nil {
   261  		//miss
   262  		if e == c.Miss() {
   263  			ok, ch, er := c.ApplyToSet(k)
   264  			if er != nil {
   265  				return nil, er
   266  			}
   267  			if ok {
   268  				defer func() {
   269  					close(ch)
   270  					c.Release(k)
   271  				}()
   272  				app, err := svc.GetByKey(ctx, appkey)
   273  				//exist
   274  				if err == nil {
   275  					if err := c.Set(k, app, cache.App.Duration); err != nil {
   276  						return nil, err
   277  					}
   278  					return app, nil
   279  				}
   280  				//not exist
   281  				if err == errcode.AppNotExists {
   282  					if err := c.Set(k, nil, cache.App.Duration); err != nil {
   283  						return nil, err
   284  					}
   285  					return nil, errcode.AppNotExists
   286  				}
   287  				//other errors
   288  				return nil, err
   289  			}
   290  			<-ch
   291  			var v *App
   292  			if e := c.Get(k, &v); e != nil {
   293  				return nil, e
   294  			}
   295  			if v == nil {
   296  				return nil, errcode.AppNotExists
   297  			}
   298  			return v, nil
   299  		}
   300  		//other errors
   301  		return nil, e
   302  	}
   303  	//hit
   304  	if v == nil {
   305  		return nil, errcode.AppNotExists
   306  	}
   307  	return v, nil
   308  }
   309  
   310  func (svc *AppServiceImpl) List(ctx context.Context, appkey string, name string) ([]*App, error) {
   311  	apps, err := svc.repo.List(ctx, appkey, name)
   312  	if err != nil {
   313  		return nil, err
   314  	}
   315  
   316  	var dtos []*App
   317  	for _, app := range apps {
   318  		dtos = append(dtos, &App{
   319  			ID:         app.ID,
   320  			Appkey:     app.Appkey,
   321  			Secret:     app.Secret,
   322  			Name:       app.Name,
   323  			Url:        app.Url,
   324  			Logo:       app.Logo,
   325  			Contacts:   app.Contacts,
   326  			Disabled:   app.Disabled,
   327  			Createtime: app.Createtime,
   328  			Updatetime: app.Updatetime,
   329  			Remark:     app.Remark,
   330  		})
   331  	}
   332  	return dtos, nil
   333  }