299 lines
6.2 KiB
Go
299 lines
6.2 KiB
Go
package model
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"time"
|
|
|
|
"spark-server/internal/module/user/entity"
|
|
"spark-server/internal/pkg/errs"
|
|
)
|
|
|
|
type MemoryRepo struct {
|
|
mu sync.Mutex
|
|
byID map[int64]*entity.User
|
|
byEmail map[string]int64
|
|
bySpark map[string]int64
|
|
devices map[deviceKey]*entity.UserDeviceLink
|
|
logs []*entity.LoginLog
|
|
deleted map[int64]*entity.Deleted
|
|
deviceSeq int64
|
|
logSeq int64
|
|
}
|
|
|
|
type deviceKey struct {
|
|
UserID int64
|
|
DeviceID uint64
|
|
}
|
|
|
|
func NewMemoryRepo() *MemoryRepo {
|
|
return &MemoryRepo{
|
|
byID: make(map[int64]*entity.User),
|
|
byEmail: make(map[string]int64),
|
|
bySpark: make(map[string]int64),
|
|
devices: make(map[deviceKey]*entity.UserDeviceLink),
|
|
logs: make([]*entity.LoginLog, 0),
|
|
deleted: make(map[int64]*entity.Deleted),
|
|
}
|
|
}
|
|
|
|
func (m *MemoryRepo) GetByID(_ context.Context, id int64) (*entity.User, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
u, ok := m.byID[id]
|
|
if !ok {
|
|
return nil, errs.ErrNotFound
|
|
}
|
|
cp := *u
|
|
return &cp, nil
|
|
}
|
|
|
|
func (m *MemoryRepo) GetByEmail(_ context.Context, email string) (*entity.User, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
id, ok := m.byEmail[email]
|
|
if !ok {
|
|
return nil, errs.ErrNotFound
|
|
}
|
|
cp := *m.byID[id]
|
|
return &cp, nil
|
|
}
|
|
|
|
func (m *MemoryRepo) GetBySparkID(_ context.Context, sparkID string) (*entity.User, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
id, ok := m.bySpark[sparkID]
|
|
if !ok {
|
|
return nil, errs.ErrNotFound
|
|
}
|
|
cp := *m.byID[id]
|
|
return &cp, nil
|
|
}
|
|
|
|
func (m *MemoryRepo) GetByQRCode(_ context.Context, qrcode string) (*entity.User, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
if qrcode == "" {
|
|
return nil, errs.ErrNotFound
|
|
}
|
|
for _, u := range m.byID {
|
|
if u.QRCode == qrcode {
|
|
cp := *u
|
|
return &cp, nil
|
|
}
|
|
}
|
|
return nil, errs.ErrNotFound
|
|
}
|
|
|
|
func (m *MemoryRepo) CreateWithEmail(_ context.Context, u *entity.User, email string) error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
if _, ok := m.byEmail[email]; ok {
|
|
return errs.ErrDuplicate
|
|
}
|
|
if _, ok := m.bySpark[u.SparkID]; ok {
|
|
return errs.ErrDuplicate
|
|
}
|
|
if _, ok := m.byID[u.ID]; ok {
|
|
return errs.ErrDuplicate
|
|
}
|
|
cp := *u
|
|
m.byID[u.ID] = &cp
|
|
m.byEmail[email] = u.ID
|
|
m.bySpark[u.SparkID] = u.ID
|
|
return nil
|
|
}
|
|
|
|
func (m *MemoryRepo) UpdateSparkID(_ context.Context, userID int64, sparkID string) error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
u, ok := m.byID[userID]
|
|
if !ok {
|
|
return errs.ErrNotFound
|
|
}
|
|
if other, ok := m.bySpark[sparkID]; ok && other != userID {
|
|
return errs.ErrDuplicate
|
|
}
|
|
delete(m.bySpark, u.SparkID)
|
|
u.SparkID = sparkID
|
|
u.UpdatedAt = time.Now()
|
|
m.bySpark[sparkID] = userID
|
|
return nil
|
|
}
|
|
|
|
func (m *MemoryRepo) TouchLogin(_ context.Context, userID int64, at time.Time) error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
u, ok := m.byID[userID]
|
|
if !ok {
|
|
return errs.ErrNotFound
|
|
}
|
|
u.LastLoginAt = at
|
|
u.LastActiveAt = at
|
|
return nil
|
|
}
|
|
|
|
func (m *MemoryRepo) UpsertDevice(_ context.Context, d *entity.UserDeviceLink) error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
key := deviceKey{UserID: d.UserID, DeviceID: d.DeviceID}
|
|
if old, ok := m.devices[key]; ok {
|
|
d.ID = old.ID
|
|
d.CreatedAt = old.CreatedAt
|
|
} else if d.ID == 0 {
|
|
m.deviceSeq++
|
|
d.ID = m.deviceSeq
|
|
}
|
|
cp := *d
|
|
m.devices[key] = &cp
|
|
return nil
|
|
}
|
|
|
|
func (m *MemoryRepo) GetDevice(_ context.Context, userID int64, deviceID uint64) (*entity.UserDeviceLink, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
d, ok := m.devices[deviceKey{UserID: userID, DeviceID: deviceID}]
|
|
if !ok {
|
|
return nil, errs.ErrNotFound
|
|
}
|
|
cp := *d
|
|
return &cp, nil
|
|
}
|
|
|
|
func (m *MemoryRepo) TouchDeviceActive(_ context.Context, userID int64, deviceID uint64, at time.Time) error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
d, ok := m.devices[deviceKey{UserID: userID, DeviceID: deviceID}]
|
|
if !ok {
|
|
return errs.ErrNotFound
|
|
}
|
|
t := at
|
|
d.LastActiveAt = &t
|
|
return nil
|
|
}
|
|
|
|
func (m *MemoryRepo) UpdateQRCode(_ context.Context, userID int64, qrcode string) error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
u, ok := m.byID[userID]
|
|
if !ok {
|
|
return errs.ErrNotFound
|
|
}
|
|
u.QRCode = qrcode
|
|
return nil
|
|
}
|
|
|
|
func (m *MemoryRepo) UpdateProfile(_ context.Context, u *entity.User) error {
|
|
if u == nil || u.ID <= 0 {
|
|
return errs.ErrInvalidArgument
|
|
}
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
cur, ok := m.byID[u.ID]
|
|
if !ok {
|
|
return errs.ErrNotFound
|
|
}
|
|
if other, ok := m.bySpark[u.SparkID]; ok && other != u.ID {
|
|
return errs.ErrDuplicate
|
|
}
|
|
delete(m.bySpark, cur.SparkID)
|
|
cur.SparkID = u.SparkID
|
|
cur.Nickname = u.Nickname
|
|
cur.Avatar = u.Avatar
|
|
cur.Gender = u.Gender
|
|
cur.Birthday = u.Birthday
|
|
cur.UpdatedAt = u.UpdatedAt
|
|
m.bySpark[cur.SparkID] = u.ID
|
|
return nil
|
|
}
|
|
|
|
func (m *MemoryRepo) InsertLoginLog(_ context.Context, log *entity.LoginLog) error {
|
|
if log == nil {
|
|
return nil
|
|
}
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
m.logSeq++
|
|
cp := *log
|
|
cp.ID = m.logSeq
|
|
log.ID = cp.ID
|
|
m.logs = append(m.logs, &cp)
|
|
return nil
|
|
}
|
|
|
|
func (m *MemoryRepo) GetEmail(_ context.Context, userID int64) (string, error) {
|
|
if userID <= 0 {
|
|
return "", errs.ErrInvalidArgument
|
|
}
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
for email, id := range m.byEmail {
|
|
if id == userID {
|
|
return email, nil
|
|
}
|
|
}
|
|
return "", errs.ErrNotFound
|
|
}
|
|
|
|
func (m *MemoryRepo) GetDeleted(_ context.Context, id int64) (*entity.Deleted, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
row, ok := m.deleted[id]
|
|
if !ok {
|
|
return nil, errs.ErrNotFound
|
|
}
|
|
cp := *row
|
|
return &cp, nil
|
|
}
|
|
|
|
func (m *MemoryRepo) ArchiveAndDelete(_ context.Context, d *entity.Deleted) error {
|
|
if d == nil || d.ID <= 0 {
|
|
return errs.ErrInvalidArgument
|
|
}
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
u, ok := m.byID[d.ID]
|
|
if !ok {
|
|
return errs.ErrNotFound
|
|
}
|
|
email := d.Email
|
|
for em, id := range m.byEmail {
|
|
if id == d.ID {
|
|
email = em
|
|
delete(m.byEmail, em)
|
|
break
|
|
}
|
|
}
|
|
if d.DeletedAt.IsZero() {
|
|
d.DeletedAt = time.Now()
|
|
}
|
|
snap := entity.SnapshotDeleted(u, email, d.DeletedAt)
|
|
m.deleted[d.ID] = snap
|
|
delete(m.byID, d.ID)
|
|
delete(m.bySpark, u.SparkID)
|
|
for key := range m.devices {
|
|
if key.UserID == d.ID {
|
|
delete(m.devices, key)
|
|
}
|
|
}
|
|
kept := m.logs[:0]
|
|
for _, log := range m.logs {
|
|
if log != nil && log.UserID != d.ID {
|
|
kept = append(kept, log)
|
|
}
|
|
}
|
|
m.logs = kept
|
|
return nil
|
|
}
|
|
|
|
func (m *MemoryRepo) LoginLogs() []*entity.LoginLog {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
out := make([]*entity.LoginLog, len(m.logs))
|
|
for i, row := range m.logs {
|
|
cp := *row
|
|
out[i] = &cp
|
|
}
|
|
return out
|
|
}
|