Bugfix/Rate limit updating (#3311)

fix rate limit updating
This commit is contained in:
Henry Heng 2024-10-05 13:33:53 +01:00 committed by GitHub
parent f5cedb2460
commit 10bfba78dd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 57 additions and 22 deletions

View File

@ -2,7 +2,7 @@ import { NextFunction, Request, Response } from 'express'
import { StatusCodes } from 'http-status-codes' import { StatusCodes } from 'http-status-codes'
import apiKeyService from '../../services/apikey' import apiKeyService from '../../services/apikey'
import { ChatFlow } from '../../database/entities/ChatFlow' import { ChatFlow } from '../../database/entities/ChatFlow'
import { createRateLimiter } from '../../utils/rateLimit' import { updateRateLimiter } from '../../utils/rateLimit'
import { InternalFlowiseError } from '../../errors/internalFlowiseError' import { InternalFlowiseError } from '../../errors/internalFlowiseError'
import { ChatflowType } from '../../Interface' import { ChatflowType } from '../../Interface'
import chatflowsService from '../../services/chatflows' import chatflowsService from '../../services/chatflows'
@ -130,7 +130,7 @@ const updateChatflow = async (req: Request, res: Response, next: NextFunction) =
Object.assign(updateChatFlow, body) Object.assign(updateChatFlow, body)
updateChatFlow.id = chatflow.id updateChatFlow.id = chatflow.id
createRateLimiter(updateChatFlow) updateRateLimiter(updateChatFlow)
const apiResponse = await chatflowsService.updateChatflow(chatflow, updateChatFlow) const apiResponse = await chatflowsService.updateChatflow(chatflow, updateChatFlow)
return res.json(apiResponse) return res.json(apiResponse)

View File

@ -21,6 +21,12 @@ async function addRateLimiter(id: string, duration: number, limit: number, messa
} }
} }
function removeRateLimit(id: string) {
if (rateLimiters[id]) {
delete rateLimiters[id]
}
}
export function getRateLimiter(req: Request, res: Response, next: NextFunction) { export function getRateLimiter(req: Request, res: Response, next: NextFunction) {
const id = req.params.id const id = req.params.id
if (!rateLimiters[id]) return next() if (!rateLimiters[id]) return next()
@ -28,21 +34,22 @@ export function getRateLimiter(req: Request, res: Response, next: NextFunction)
return idRateLimiter(req, res, next) return idRateLimiter(req, res, next)
} }
export async function createRateLimiter(chatFlow: IChatFlow) { export async function updateRateLimiter(chatFlow: IChatFlow) {
if (!chatFlow.apiConfig) return if (!chatFlow.apiConfig) return
const apiConfig = JSON.parse(chatFlow.apiConfig) const apiConfig = JSON.parse(chatFlow.apiConfig)
const rateLimit: { limitDuration: number; limitMax: number; limitMsg: string } = apiConfig.rateLimit const rateLimit: { limitDuration: number; limitMax: number; limitMsg: string; status?: boolean } = apiConfig.rateLimit
if (!rateLimit) return if (!rateLimit) return
const { limitDuration, limitMax, limitMsg } = rateLimit const { limitDuration, limitMax, limitMsg, status } = rateLimit
if (limitMax && limitDuration && limitMsg) await addRateLimiter(chatFlow.id, limitDuration, limitMax, limitMsg) if (status === false) removeRateLimit(chatFlow.id)
else if (limitMax && limitDuration && limitMsg) await addRateLimiter(chatFlow.id, limitDuration, limitMax, limitMsg)
} }
export async function initializeRateLimiter(chatFlowPool: IChatFlow[]) { export async function initializeRateLimiter(chatFlowPool: IChatFlow[]) {
await Promise.all( await Promise.all(
chatFlowPool.map(async (chatFlow) => { chatFlowPool.map(async (chatFlow) => {
await createRateLimiter(chatFlow) await updateRateLimiter(chatFlow)
}) })
) )
} }

View File

@ -8,6 +8,7 @@ import { Box, Typography, Button, OutlinedInput } from '@mui/material'
// Project import // Project import
import { StyledButton } from '@/ui-component/button/StyledButton' import { StyledButton } from '@/ui-component/button/StyledButton'
import { TooltipWithParser } from '@/ui-component/tooltip/TooltipWithParser' import { TooltipWithParser } from '@/ui-component/tooltip/TooltipWithParser'
import { SwitchInput } from '@/ui-component/switch/Switch'
// Icons // Icons
import { IconX } from '@tabler/icons-react' import { IconX } from '@tabler/icons-react'
@ -29,29 +30,47 @@ const RateLimit = () => {
const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args)) const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args))
const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args)) const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args))
const [rateLimitStatus, setRateLimitStatus] = useState(false)
const [limitMax, setLimitMax] = useState(apiConfig?.rateLimit?.limitMax ?? '') const [limitMax, setLimitMax] = useState(apiConfig?.rateLimit?.limitMax ?? '')
const [limitDuration, setLimitDuration] = useState(apiConfig?.rateLimit?.limitDuration ?? '') const [limitDuration, setLimitDuration] = useState(apiConfig?.rateLimit?.limitDuration ?? '')
const [limitMsg, setLimitMsg] = useState(apiConfig?.rateLimit?.limitMsg ?? '') const [limitMsg, setLimitMsg] = useState(apiConfig?.rateLimit?.limitMsg ?? '')
const formatObj = () => { const formatObj = () => {
const obj = { const obj = {
rateLimit: {} rateLimit: { status: rateLimitStatus }
} }
if (rateLimitStatus) {
const rateLimitValuesBoolean = [!limitMax, !limitDuration, !limitMsg] const rateLimitValuesBoolean = [!limitMax, !limitDuration, !limitMsg]
const rateLimitFilledValues = rateLimitValuesBoolean.filter((value) => value === false) const rateLimitFilledValues = rateLimitValuesBoolean.filter((value) => value === false)
if (rateLimitFilledValues.length >= 1 && rateLimitFilledValues.length <= 2) { if (rateLimitFilledValues.length >= 1 && rateLimitFilledValues.length <= 2) {
throw new Error('Need to fill all rate limit input fields') throw new Error('Need to fill all rate limit input fields')
} else if (rateLimitFilledValues.length === 3) { } else if (rateLimitFilledValues.length === 3) {
obj.rateLimit = { obj.rateLimit = {
...obj.rateLimit,
limitMax, limitMax,
limitDuration, limitDuration,
limitMsg limitMsg
} }
} }
}
return obj return obj
} }
const handleChange = (value) => {
setRateLimitStatus(value)
}
const checkDisabled = () => {
if (rateLimitStatus) {
if (limitMax === '' || limitDuration === '' || limitMsg === '') {
return true
}
}
return false
}
const onSave = async () => { const onSave = async () => {
try { try {
const saveResp = await chatflowsApi.updateChatflow(chatflowid, { const saveResp = await chatflowsApi.updateChatflow(chatflowid, {
@ -139,11 +158,20 @@ const RateLimit = () => {
} }
/> />
</Typography> </Typography>
<SwitchInput label='Enable Rate Limit' onChange={handleChange} value={rateLimitStatus} />
{rateLimitStatus && (
<>
{textField(limitMax, 'limitMax', 'Message Limit per Duration', 'number', '5')} {textField(limitMax, 'limitMax', 'Message Limit per Duration', 'number', '5')}
{textField(limitDuration, 'limitDuration', 'Duration in Second', 'number', '60')} {textField(limitDuration, 'limitDuration', 'Duration in Second', 'number', '60')}
{textField(limitMsg, 'limitMsg', 'Limit Message', 'string', 'You have reached the quota')} {textField(limitMsg, 'limitMsg', 'Limit Message', 'string', 'You have reached the quota')}
</>
<StyledButton style={{ marginBottom: 10, marginTop: 10 }} variant='contained' onClick={() => onSave()}> )}
<StyledButton
disabled={checkDisabled()}
style={{ marginBottom: 10, marginTop: 10 }}
variant='contained'
onClick={() => onSave()}
>
Save Changes Save Changes
</StyledButton> </StyledButton>
</> </>