Add in-memory user cache

This commit is contained in:
mikiher 2024-11-10 08:34:47 +02:00
parent 2e970cbb39
commit a382482173
2 changed files with 117 additions and 25 deletions

View File

@ -990,28 +990,18 @@ class Auth {
})
}
}
Database.userModel
.update(
{
pash: pw
},
{
where: { id: matchingUser.id }
}
)
.then(() => {
try {
await matchingUser.update({ pash: pw })
Logger.info(`[Auth] User "${matchingUser.username}" changed password`)
res.json({
success: true
})
})
.catch((error) => {
} catch (error) {
Logger.error(`[Auth] User "${matchingUser.username}" failed to change password`, error)
res.json({
error: 'Unknown error'
})
})
}
}
}

View File

@ -3,6 +3,53 @@ const sequelize = require('sequelize')
const Logger = require('../Logger')
const SocketAuthority = require('../SocketAuthority')
const { isNullOrNaN } = require('../utils')
const { LRUCache } = require('lru-cache')
class UserCache {
constructor() {
this.cache = new LRUCache({ max: 100 })
}
getById(id) {
const user = this.cache.get(id)
return user
}
getByEmail(email) {
const user = this.cache.find((u) => u.email === email)
return user
}
getByUsername(username) {
const user = this.cache.find((u) => u.username === username)
return user
}
getByOldId(oldUserId) {
const user = this.cache.find((u) => u.extraData?.oldUserId === oldUserId)
return user
}
getByOpenIDSub(sub) {
const user = this.cache.find((u) => u.extraData?.authOpenIDSub === sub)
return user
}
set(user) {
user.fromCache = true
this.cache.set(user.id, user)
}
delete(userId) {
this.cache.delete(userId)
}
maybeInvalidate(user) {
if (!user.fromCache) this.delete(user.id)
}
}
const userCache = new UserCache()
const { DataTypes, Model } = sequelize
@ -206,7 +253,11 @@ class User extends Model {
*/
static async getUserByUsername(username) {
if (!username) return null
return this.findOne({
const cachedUser = userCache.getByUsername(username)
if (cachedUser) return cachedUser
const user = await this.findOne({
where: {
username: {
[sequelize.Op.like]: username
@ -214,6 +265,10 @@ class User extends Model {
},
include: this.sequelize.models.mediaProgress
})
if (user) userCache.set(user)
return user
}
/**
@ -223,7 +278,11 @@ class User extends Model {
*/
static async getUserByEmail(email) {
if (!email) return null
return this.findOne({
const cachedUser = userCache.getByEmail(email)
if (cachedUser) return cachedUser
const user = await this.findOne({
where: {
email: {
[sequelize.Op.like]: email
@ -231,6 +290,10 @@ class User extends Model {
},
include: this.sequelize.models.mediaProgress
})
if (user) userCache.set(user)
return user
}
/**
@ -240,9 +303,17 @@ class User extends Model {
*/
static async getUserById(userId) {
if (!userId) return null
return this.findByPk(userId, {
const cachedUser = userCache.getById(userId)
if (cachedUser) return cachedUser
const user = await this.findByPk(userId, {
include: this.sequelize.models.mediaProgress
})
if (user) userCache.set(user)
return user
}
/**
@ -254,12 +325,19 @@ class User extends Model {
*/
static async getUserByIdOrOldId(userId) {
if (!userId) return null
return this.findOne({
const cachedUser = userCache.getById(userId) || userCache.getByOldId(userId)
if (cachedUser) return cachedUser
const user = await this.findOne({
where: {
[sequelize.Op.or]: [{ id: userId }, { 'extraData.oldUserId': userId }]
},
include: this.sequelize.models.mediaProgress
})
if (user) userCache.set(user)
return user
}
/**
@ -269,10 +347,18 @@ class User extends Model {
*/
static async getUserByOpenIDSub(sub) {
if (!sub) return null
return this.findOne({
const cachedUser = userCache.getByOpenIDSub(sub)
if (cachedUser) return cachedUser
const user = await this.findOne({
where: sequelize.where(sequelize.literal(`extraData->>"authOpenIDSub"`), sub),
include: this.sequelize.models.mediaProgress
})
if (user) userCache.set(user)
return user
}
/**
@ -623,6 +709,7 @@ class User extends Model {
mediaProgress = await this.sequelize.models.mediaProgress.create(newMediaProgressPayload)
this.mediaProgresses.push(mediaProgress)
}
userCache.maybeInvalidate(this)
return {
mediaProgress
}
@ -804,6 +891,21 @@ class User extends Model {
return hasUpdates
}
async update(values, options) {
userCache.maybeInvalidate(this)
return await super.update(values, options)
}
async save(options) {
userCache.maybeInvalidate(this)
return await super.save(options)
}
async destroy(options) {
userCache.delete(this.id)
await super.destroy(options)
}
}
module.exports = User