Commit 711a7e34 by Calcium-Ion Committed by GitHub

Merge pull request #1498 from QuantumNous/multi-key-manage

feat: add multi-key management
parents bb08de0b 808c8c5b
...@@ -41,6 +41,7 @@ type Channel struct { ...@@ -41,6 +41,7 @@ type Channel struct {
Priority *int64 `json:"priority" gorm:"bigint;default:0"` Priority *int64 `json:"priority" gorm:"bigint;default:0"`
AutoBan *int `json:"auto_ban" gorm:"default:1"` AutoBan *int `json:"auto_ban" gorm:"default:1"`
OtherInfo string `json:"other_info"` OtherInfo string `json:"other_info"`
Settings string `json:"settings"`
Tag *string `json:"tag" gorm:"index"` Tag *string `json:"tag" gorm:"index"`
Setting *string `json:"setting" gorm:"type:text"` // 渠道额外设置 Setting *string `json:"setting" gorm:"type:text"` // 渠道额外设置
ParamOverride *string `json:"param_override" gorm:"type:text"` ParamOverride *string `json:"param_override" gorm:"type:text"`
...@@ -52,11 +53,13 @@ type Channel struct { ...@@ -52,11 +53,13 @@ type Channel struct {
} }
type ChannelInfo struct { type ChannelInfo struct {
IsMultiKey bool `json:"is_multi_key"` // 是否多Key模式 IsMultiKey bool `json:"is_multi_key"` // 是否多Key模式
MultiKeySize int `json:"multi_key_size"` // 多Key模式下的Key数量 MultiKeySize int `json:"multi_key_size"` // 多Key模式下的Key数量
MultiKeyStatusList map[int]int `json:"multi_key_status_list"` // key状态列表,key index -> status MultiKeyStatusList map[int]int `json:"multi_key_status_list"` // key状态列表,key index -> status
MultiKeyPollingIndex int `json:"multi_key_polling_index"` // 多Key模式下轮询的key索引 MultiKeyDisabledReason map[int]string `json:"multi_key_disabled_reason,omitempty"` // key禁用原因列表,key index -> reason
MultiKeyMode constant.MultiKeyMode `json:"multi_key_mode"` MultiKeyDisabledTime map[int]int64 `json:"multi_key_disabled_time,omitempty"` // key禁用时间列表,key index -> time
MultiKeyPollingIndex int `json:"multi_key_polling_index"` // 多Key模式下轮询的key索引
MultiKeyMode constant.MultiKeyMode `json:"multi_key_mode"`
} }
// Value implements driver.Valuer interface // Value implements driver.Valuer interface
...@@ -70,7 +73,7 @@ func (c *ChannelInfo) Scan(value interface{}) error { ...@@ -70,7 +73,7 @@ func (c *ChannelInfo) Scan(value interface{}) error {
return common.Unmarshal(bytesValue, c) return common.Unmarshal(bytesValue, c)
} }
func (channel *Channel) getKeys() []string { func (channel *Channel) GetKeys() []string {
if channel.Key == "" { if channel.Key == "" {
return []string{} return []string{}
} }
...@@ -101,7 +104,7 @@ func (channel *Channel) GetNextEnabledKey() (string, int, *types.NewAPIError) { ...@@ -101,7 +104,7 @@ func (channel *Channel) GetNextEnabledKey() (string, int, *types.NewAPIError) {
} }
// Obtain all keys (split by \n) // Obtain all keys (split by \n)
keys := channel.getKeys() keys := channel.GetKeys()
if len(keys) == 0 { if len(keys) == 0 {
// No keys available, return error, should disable the channel // No keys available, return error, should disable the channel
return "", 0, types.NewError(errors.New("no keys available"), types.ErrorCodeChannelNoAvailableKey) return "", 0, types.NewError(errors.New("no keys available"), types.ErrorCodeChannelNoAvailableKey)
...@@ -528,8 +531,8 @@ func CleanupChannelPollingLocks() { ...@@ -528,8 +531,8 @@ func CleanupChannelPollingLocks() {
}) })
} }
func handlerMultiKeyUpdate(channel *Channel, usingKey string, status int) { func handlerMultiKeyUpdate(channel *Channel, usingKey string, status int, reason string) {
keys := channel.getKeys() keys := channel.GetKeys()
if len(keys) == 0 { if len(keys) == 0 {
channel.Status = status channel.Status = status
} else { } else {
...@@ -547,6 +550,14 @@ func handlerMultiKeyUpdate(channel *Channel, usingKey string, status int) { ...@@ -547,6 +550,14 @@ func handlerMultiKeyUpdate(channel *Channel, usingKey string, status int) {
delete(channel.ChannelInfo.MultiKeyStatusList, keyIndex) delete(channel.ChannelInfo.MultiKeyStatusList, keyIndex)
} else { } else {
channel.ChannelInfo.MultiKeyStatusList[keyIndex] = status channel.ChannelInfo.MultiKeyStatusList[keyIndex] = status
if channel.ChannelInfo.MultiKeyDisabledReason == nil {
channel.ChannelInfo.MultiKeyDisabledReason = make(map[int]string)
}
if channel.ChannelInfo.MultiKeyDisabledTime == nil {
channel.ChannelInfo.MultiKeyDisabledTime = make(map[int]int64)
}
channel.ChannelInfo.MultiKeyDisabledReason[keyIndex] = reason
channel.ChannelInfo.MultiKeyDisabledTime[keyIndex] = common.GetTimestamp()
} }
if len(channel.ChannelInfo.MultiKeyStatusList) >= channel.ChannelInfo.MultiKeySize { if len(channel.ChannelInfo.MultiKeyStatusList) >= channel.ChannelInfo.MultiKeySize {
channel.Status = common.ChannelStatusAutoDisabled channel.Status = common.ChannelStatusAutoDisabled
...@@ -569,7 +580,7 @@ func UpdateChannelStatus(channelId int, usingKey string, status int, reason stri ...@@ -569,7 +580,7 @@ func UpdateChannelStatus(channelId int, usingKey string, status int, reason stri
} }
if channelCache.ChannelInfo.IsMultiKey { if channelCache.ChannelInfo.IsMultiKey {
// 如果是多Key模式,更新缓存中的状态 // 如果是多Key模式,更新缓存中的状态
handlerMultiKeyUpdate(channelCache, usingKey, status) handlerMultiKeyUpdate(channelCache, usingKey, status, reason)
//CacheUpdateChannel(channelCache) //CacheUpdateChannel(channelCache)
//return true //return true
} else { } else {
...@@ -600,7 +611,7 @@ func UpdateChannelStatus(channelId int, usingKey string, status int, reason stri ...@@ -600,7 +611,7 @@ func UpdateChannelStatus(channelId int, usingKey string, status int, reason stri
if channel.ChannelInfo.IsMultiKey { if channel.ChannelInfo.IsMultiKey {
beforeStatus := channel.Status beforeStatus := channel.Status
handlerMultiKeyUpdate(channel, usingKey, status) handlerMultiKeyUpdate(channel, usingKey, status, reason)
if beforeStatus != channel.Status { if beforeStatus != channel.Status {
shouldUpdateAbilities = true shouldUpdateAbilities = true
} }
......
...@@ -70,7 +70,7 @@ func InitChannelCache() { ...@@ -70,7 +70,7 @@ func InitChannelCache() {
//channelsIDM = newChannelId2channel //channelsIDM = newChannelId2channel
for i, channel := range newChannelId2channel { for i, channel := range newChannelId2channel {
if channel.ChannelInfo.IsMultiKey { if channel.ChannelInfo.IsMultiKey {
channel.Keys = channel.getKeys() channel.Keys = channel.GetKeys()
if channel.ChannelInfo.MultiKeyMode == constant.MultiKeyModePolling { if channel.ChannelInfo.MultiKeyMode == constant.MultiKeyModePolling {
if oldChannel, ok := channelsIDM[i]; ok { if oldChannel, ok := channelsIDM[i]; ok {
// 存在旧的渠道,如果是多key且轮询,保留轮询索引信息 // 存在旧的渠道,如果是多key且轮询,保留轮询索引信息
......
...@@ -120,6 +120,7 @@ func SetApiRouter(router *gin.Engine) { ...@@ -120,6 +120,7 @@ func SetApiRouter(router *gin.Engine) {
channelRoute.POST("/batch/tag", controller.BatchSetChannelTag) channelRoute.POST("/batch/tag", controller.BatchSetChannelTag)
channelRoute.GET("/tag/models", controller.GetTagModels) channelRoute.GET("/tag/models", controller.GetTagModels)
channelRoute.POST("/copy/:id", controller.CopyChannel) channelRoute.POST("/copy/:id", controller.CopyChannel)
channelRoute.POST("/multi_key/manage", controller.ManageMultiKeys)
} }
tokenRoute := apiRouter.Group("/token") tokenRoute := apiRouter.Group("/token")
tokenRoute.Use(middleware.UserAuth()) tokenRoute.Use(middleware.UserAuth())
......
...@@ -210,7 +210,9 @@ export const getChannelsColumns = ({ ...@@ -210,7 +210,9 @@ export const getChannelsColumns = ({
copySelectedChannel, copySelectedChannel,
refresh, refresh,
activePage, activePage,
channels channels,
setShowMultiKeyManageModal,
setCurrentMultiKeyChannel
}) => { }) => {
return [ return [
{ {
...@@ -503,36 +505,50 @@ export const getChannelsColumns = ({ ...@@ -503,36 +505,50 @@ export const getChannelsColumns = ({
/> />
</SplitButtonGroup> </SplitButtonGroup>
{
record.status === 1 ? (
<Button
type='danger'
size="small"
onClick={() => manageChannel(record.id, 'disable', record)}
>
{t('禁用')}
</Button>
) : (
<Button
size="small"
onClick={() => manageChannel(record.id, 'enable', record)}
>
{t('启用')}
</Button>
)
}
{record.channel_info?.is_multi_key ? ( {record.channel_info?.is_multi_key ? (
<SplitButtonGroup <SplitButtonGroup
aria-label={t('多密钥渠道操作项目组')} aria-label={t('多密钥渠道操作项目组')}
> >
{ <Button
record.status === 1 ? ( type='tertiary'
<Button size="small"
type='danger' onClick={() => {
size="small" setEditingChannel(record);
onClick={() => manageChannel(record.id, 'disable', record)} setShowEdit(true);
> }}
{t('禁用')} >
</Button> {t('编辑')}
) : ( </Button>
<Button
size="small"
onClick={() => manageChannel(record.id, 'enable', record)}
>
{t('启用')}
</Button>
)
}
<Dropdown <Dropdown
trigger='click' trigger='click'
position='bottomRight' position='bottomRight'
menu={[ menu={[
{ {
node: 'item', node: 'item',
name: t('启用全部密钥'), name: t('多key管理'),
onClick: () => manageChannel(record.id, 'enable_all', record), onClick: () => {
setCurrentMultiKeyChannel(record);
setShowMultiKeyManageModal(true);
},
} }
]} ]}
> >
...@@ -544,35 +560,18 @@ export const getChannelsColumns = ({ ...@@ -544,35 +560,18 @@ export const getChannelsColumns = ({
</Dropdown> </Dropdown>
</SplitButtonGroup> </SplitButtonGroup>
) : ( ) : (
record.status === 1 ? ( <Button
<Button type='tertiary'
type='danger' size="small"
size="small" onClick={() => {
onClick={() => manageChannel(record.id, 'disable', record)} setEditingChannel(record);
> setShowEdit(true);
{t('禁用')} }}
</Button> >
) : ( {t('编辑')}
<Button </Button>
size="small"
onClick={() => manageChannel(record.id, 'enable', record)}
>
{t('启用')}
</Button>
)
)} )}
<Button
type='tertiary'
size="small"
onClick={() => {
setEditingChannel(record);
setShowEdit(true);
}}
>
{t('编辑')}
</Button>
<Dropdown <Dropdown
trigger='click' trigger='click'
position='bottomRight' position='bottomRight'
......
...@@ -57,6 +57,9 @@ const ChannelsTable = (channelsData) => { ...@@ -57,6 +57,9 @@ const ChannelsTable = (channelsData) => {
setEditingTag, setEditingTag,
copySelectedChannel, copySelectedChannel,
refresh, refresh,
// Multi-key management
setShowMultiKeyManageModal,
setCurrentMultiKeyChannel,
} = channelsData; } = channelsData;
// Get all columns // Get all columns
...@@ -79,6 +82,8 @@ const ChannelsTable = (channelsData) => { ...@@ -79,6 +82,8 @@ const ChannelsTable = (channelsData) => {
refresh, refresh,
activePage, activePage,
channels, channels,
setShowMultiKeyManageModal,
setCurrentMultiKeyChannel,
}); });
}, [ }, [
t, t,
...@@ -98,6 +103,8 @@ const ChannelsTable = (channelsData) => { ...@@ -98,6 +103,8 @@ const ChannelsTable = (channelsData) => {
refresh, refresh,
activePage, activePage,
channels, channels,
setShowMultiKeyManageModal,
setCurrentMultiKeyChannel,
]); ]);
// Filter columns based on visibility settings // Filter columns based on visibility settings
......
...@@ -30,6 +30,7 @@ import ModelTestModal from './modals/ModelTestModal.jsx'; ...@@ -30,6 +30,7 @@ import ModelTestModal from './modals/ModelTestModal.jsx';
import ColumnSelectorModal from './modals/ColumnSelectorModal.jsx'; import ColumnSelectorModal from './modals/ColumnSelectorModal.jsx';
import EditChannelModal from './modals/EditChannelModal.jsx'; import EditChannelModal from './modals/EditChannelModal.jsx';
import EditTagModal from './modals/EditTagModal.jsx'; import EditTagModal from './modals/EditTagModal.jsx';
import MultiKeyManageModal from './modals/MultiKeyManageModal.jsx';
import { createCardProPagination } from '../../../helpers/utils'; import { createCardProPagination } from '../../../helpers/utils';
const ChannelsPage = () => { const ChannelsPage = () => {
...@@ -54,6 +55,12 @@ const ChannelsPage = () => { ...@@ -54,6 +55,12 @@ const ChannelsPage = () => {
/> />
<BatchTagModal {...channelsData} /> <BatchTagModal {...channelsData} />
<ModelTestModal {...channelsData} /> <ModelTestModal {...channelsData} />
<MultiKeyManageModal
visible={channelsData.showMultiKeyManageModal}
onCancel={() => channelsData.setShowMultiKeyManageModal(false)}
channel={channelsData.currentMultiKeyChannel}
onRefresh={channelsData.refresh}
/>
{/* Main Content */} {/* Main Content */}
<CardPro <CardPro
......
...@@ -83,6 +83,10 @@ export const useChannelsData = () => { ...@@ -83,6 +83,10 @@ export const useChannelsData = () => {
const [isProcessingQueue, setIsProcessingQueue] = useState(false); const [isProcessingQueue, setIsProcessingQueue] = useState(false);
const [modelTablePage, setModelTablePage] = useState(1); const [modelTablePage, setModelTablePage] = useState(1);
// Multi-key management states
const [showMultiKeyManageModal, setShowMultiKeyManageModal] = useState(false);
const [currentMultiKeyChannel, setCurrentMultiKeyChannel] = useState(null);
// Refs // Refs
const requestCounter = useRef(0); const requestCounter = useRef(0);
const allSelectingRef = useRef(false); const allSelectingRef = useRef(false);
...@@ -885,6 +889,12 @@ export const useChannelsData = () => { ...@@ -885,6 +889,12 @@ export const useChannelsData = () => {
setModelTablePage, setModelTablePage,
allSelectingRef, allSelectingRef,
// Multi-key management states
showMultiKeyManageModal,
setShowMultiKeyManageModal,
currentMultiKeyChannel,
setCurrentMultiKeyChannel,
// Form // Form
formApi, formApi,
setFormApi, setFormApi,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment