diff --git a/pkg/errs/system.go b/pkg/errs/system.go index 25acf8b5..0ad33fda 100644 --- a/pkg/errs/system.go +++ b/pkg/errs/system.go @@ -8,4 +8,5 @@ var ( ErrApiNotFound = NewSystemError(SystemSubcategoryDefault, 1, http.StatusNotFound, "api not found") ErrMethodNotAllowed = NewSystemError(SystemSubcategoryDefault, 2, http.StatusMethodNotAllowed, "method not allowed") ErrNotImplemented = NewSystemError(SystemSubcategoryDefault, 3, http.StatusNotImplemented, "not implemented") + ErrSystemIsBusy = NewSystemError(SystemSubcategoryDefault, 4, http.StatusNotImplemented, "system is busy") ) diff --git a/pkg/services/accounts.go b/pkg/services/accounts.go index fadb1942..3a59dc23 100644 --- a/pkg/services/accounts.go +++ b/pkg/services/accounts.go @@ -163,12 +163,22 @@ func (s *AccountService) CreateAccounts(c *core.Context, mainAccount *models.Acc var allInitTransactions []*models.Transaction mainAccount.AccountId = s.GenerateUuid(uuid.UUID_TYPE_ACCOUNT) + + if mainAccount.AccountId < 1 { + return errs.ErrSystemIsBusy + } + allAccounts[0] = mainAccount if mainAccount.Type == models.ACCOUNT_TYPE_MULTI_SUB_ACCOUNTS { for i := 0; i < len(childrenAccounts); i++ { childAccount := childrenAccounts[i] childAccount.AccountId = s.GenerateUuid(uuid.UUID_TYPE_ACCOUNT) + + if childAccount.AccountId < 1 { + return errs.ErrSystemIsBusy + } + childAccount.ParentAccountId = mainAccount.AccountId childAccount.Uid = mainAccount.Uid childAccount.Type = models.ACCOUNT_TYPE_SINGLE_ACCOUNT @@ -185,8 +195,14 @@ func (s *AccountService) CreateAccounts(c *core.Context, mainAccount *models.Acc allAccounts[i].UpdatedUnixTime = now if allAccounts[i].Balance != 0 { + transactionId := s.GenerateUuid(uuid.UUID_TYPE_TRANSACTION) + + if transactionId < 1 { + return errs.ErrSystemIsBusy + } + newTransaction := &models.Transaction{ - TransactionId: s.GenerateUuid(uuid.UUID_TYPE_TRANSACTION), + TransactionId: transactionId, Uid: allAccounts[i].Uid, Deleted: false, Type: models.TRANSACTION_DB_TYPE_MODIFY_BALANCE, diff --git a/pkg/services/transaction_categories.go b/pkg/services/transaction_categories.go index 692a67d8..ac6b273b 100644 --- a/pkg/services/transaction_categories.go +++ b/pkg/services/transaction_categories.go @@ -163,6 +163,10 @@ func (s *TransactionCategoryService) CreateCategory(c *core.Context, category *m category.CategoryId = s.GenerateUuid(uuid.UUID_TYPE_CATEGORY) + if category.CategoryId < 1 { + return errs.ErrSystemIsBusy + } + category.Deleted = false category.CreatedUnixTime = time.Now().Unix() category.UpdatedUnixTime = time.Now().Unix() @@ -186,6 +190,10 @@ func (s *TransactionCategoryService) CreateCategories(c *core.Context, uid int64 primaryCategory := primaryCategories[i] primaryCategory.CategoryId = s.GenerateUuid(uuid.UUID_TYPE_CATEGORY) + if primaryCategory.CategoryId < 1 { + return nil, errs.ErrSystemIsBusy + } + primaryCategory.Deleted = false primaryCategory.CreatedUnixTime = time.Now().Unix() primaryCategory.UpdatedUnixTime = time.Now().Unix() @@ -197,6 +205,11 @@ func (s *TransactionCategoryService) CreateCategories(c *core.Context, uid int64 for j := 0; j < len(secondaryCategories); j++ { secondaryCategory := secondaryCategories[j] secondaryCategory.CategoryId = s.GenerateUuid(uuid.UUID_TYPE_CATEGORY) + + if secondaryCategory.CategoryId < 1 { + return nil, errs.ErrSystemIsBusy + } + secondaryCategory.ParentCategoryId = primaryCategory.CategoryId secondaryCategory.Deleted = false diff --git a/pkg/services/transaction_tags.go b/pkg/services/transaction_tags.go index e74747fc..64a65378 100644 --- a/pkg/services/transaction_tags.go +++ b/pkg/services/transaction_tags.go @@ -160,6 +160,10 @@ func (s *TransactionTagService) CreateTag(c *core.Context, tag *models.Transacti tag.TagId = s.GenerateUuid(uuid.UUID_TYPE_TAG) + if tag.TagId < 1 { + return errs.ErrSystemIsBusy + } + tag.Deleted = false tag.CreatedUnixTime = time.Now().Unix() tag.UpdatedUnixTime = time.Now().Unix() diff --git a/pkg/services/transactions.go b/pkg/services/transactions.go index e3b366f0..e3f5d03e 100644 --- a/pkg/services/transactions.go +++ b/pkg/services/transactions.go @@ -222,6 +222,11 @@ func (s *TransactionService) CreateTransaction(c *core.Context, transaction *mod } uuids := s.GenerateUuids(uuid.UUID_TYPE_TRANSACTION, uint8(needUuidCount)) + + if len(uuids) < needUuidCount { + return errs.ErrSystemIsBusy + } + transaction.TransactionId = uuids[0] if transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_OUT || transaction.Type == models.TRANSACTION_DB_TYPE_TRANSFER_IN { @@ -237,8 +242,14 @@ func (s *TransactionService) CreateTransaction(c *core.Context, transaction *mod transactionTagIndexs := make([]*models.TransactionTagIndex, len(tagIds)) for i := 0; i < len(tagIds); i++ { + tagIndexId := s.GenerateUuid(uuid.UUID_TYPE_TAG_INDEX) + + if tagIndexId < 1 { + return errs.ErrSystemIsBusy + } + transactionTagIndexs[i] = &models.TransactionTagIndex{ - TagIndexId: s.GenerateUuid(uuid.UUID_TYPE_TAG_INDEX), + TagIndexId: tagIndexId, Uid: transaction.Uid, Deleted: false, TagId: tagIds[i], @@ -431,8 +442,14 @@ func (s *TransactionService) ModifyTransaction(c *core.Context, transaction *mod transactionTagIndexs := make([]*models.TransactionTagIndex, len(addTagIds)) for i := 0; i < len(addTagIds); i++ { + tagIndexId := s.GenerateUuid(uuid.UUID_TYPE_TAG_INDEX) + + if tagIndexId < 1 { + return errs.ErrSystemIsBusy + } + transactionTagIndexs[i] = &models.TransactionTagIndex{ - TagIndexId: s.GenerateUuid(uuid.UUID_TYPE_TAG_INDEX), + TagIndexId: tagIndexId, Uid: transaction.Uid, Deleted: false, TagId: addTagIds[i], diff --git a/pkg/services/users.go b/pkg/services/users.go index 91a0bb8e..0354b76d 100644 --- a/pkg/services/users.go +++ b/pkg/services/users.go @@ -153,6 +153,11 @@ func (s *UserService) CreateUser(c *core.Context, user *models.User) error { } user.Uid = s.GenerateUuid(uuid.UUID_TYPE_USER) + + if user.Uid < 1 { + return errs.ErrSystemIsBusy + } + user.Password = utils.EncodePassword(user.Password, user.Salt) user.Deleted = false diff --git a/pkg/uuid/internal_generator.go b/pkg/uuid/internal_generator.go index d0e9aa4a..4eb1f39b 100644 --- a/pkg/uuid/internal_generator.go +++ b/pkg/uuid/internal_generator.go @@ -51,6 +51,11 @@ func NewInternalUuidGenerator(config *settings.Config) (*InternalUuidGenerator, // GenerateUuid generates a new uuid func (u *InternalUuidGenerator) GenerateUuid(idType UuidType) int64 { uuids := u.GenerateUuids(idType, 1) + + if len(uuids) < 1 { + return 0 + } + return uuids[0] } @@ -89,6 +94,12 @@ func (u *InternalUuidGenerator) GenerateUuids(idType UuidType, count uint8) []in for i := 0; i < int(count); i++ { seqId := (newFirstSeqId + uint64(i)) & seqNumberIdMask + + // the internal uuid generator can only generate 524,287 ids per second for specified type + if seqId > internalUuidSeqIdMask { + return nil + } + uuids[i] = u.assembleUuid(unixTime, uuidType, seqId) } diff --git a/pkg/uuid/internal_generator_test.go b/pkg/uuid/internal_generator_test.go index 5b86b5e0..95f4be90 100644 --- a/pkg/uuid/internal_generator_test.go +++ b/pkg/uuid/internal_generator_test.go @@ -374,3 +374,25 @@ func TestGenerateUuids_1000000TimesConcurrent(t *testing.T) { waitGroup.Wait() } + +func TestGenerateUuid_Over524287Times(t *testing.T) { + generator, _ := NewInternalUuidGenerator(&settings.Config{UuidServerId: 1}) + onceGenerateCount := uint8(255) + generationStartUnixTime := time.Now().Unix() + + for i := 0; i < 2057; i++ { // 2056*255=524280, 2057*255=524,535 (only can generates 524,287 uuids per second) + uuids := generator.GenerateUuids(UUID_TYPE_USER, onceGenerateCount) + + if i < 2056 { + if len(uuids) < int(onceGenerateCount) { + assert.Fail(t, fmt.Sprintf("%d uuids should be generated", onceGenerateCount)) + } + } else { + generationEndUnixTime := time.Now().Unix() + + if generationStartUnixTime == generationEndUnixTime && len(uuids) > 0 { + assert.Fail(t, fmt.Sprintf("uuids should not be generated because there are too many uuids in one second")) + } + } + } +} diff --git a/src/locales/en.js b/src/locales/en.js index 5bac1e69..b5362ed4 100644 --- a/src/locales/en.js +++ b/src/locales/en.js @@ -557,6 +557,7 @@ export default { 'system error': 'System Error', 'api not found': 'Failed to request api', 'not implemented': 'Not implemented', + 'system is busy': 'System is busy', 'database operation failed': 'Database operation failed', 'SMTP server is not enabled': 'SMTP server is not enabled', 'incomplete or incorrect submission': 'Incomplete or incorrect submission', diff --git a/src/locales/zh_Hans.js b/src/locales/zh_Hans.js index 45d38915..2b2ee630 100644 --- a/src/locales/zh_Hans.js +++ b/src/locales/zh_Hans.js @@ -557,6 +557,7 @@ export default { 'system error': '系统错误', 'api not found': '接口调用失败', 'not implemented': '未实现', + 'system is busy': '系统繁忙', 'database operation failed': '数据库操作失败', 'SMTP server is not enabled': 'SMTP 服务器没有启用', 'incomplete or incorrect submission': '提交不完整或不正确',