This commit introduces a major architectural refactoring to improve quota management, centralize logging, and streamline the relay handling logic. Key changes: - **Pre-consume Quota:** Implements a new mechanism to check and reserve user quota *before* making the request to the upstream provider. This ensures more accurate quota deduction and prevents users from exceeding their limits due to concurrent requests. - **Unified Relay Handlers:** Refactors the relay logic to use generic handlers (e.g., `ChatHandler`, `ImageHandler`) instead of provider-specific implementations. This significantly reduces code duplication and simplifies adding new channels. - **Centralized Logger:** A new dedicated `logger` package is introduced, and all system logging calls are migrated to use it, moving this responsibility out of the `common` package. - **Code Reorganization:** DTOs are generalized (e.g., `dalle.go` -> `openai_image.go`) and utility code is moved to more appropriate packages (e.g., `common/http.go` -> `service/http.go`) for better code structure.
68 lines
1.9 KiB
Go
68 lines
1.9 KiB
Go
package service
|
|
|
|
import (
|
|
"fmt"
|
|
"one-api/common"
|
|
"one-api/dto"
|
|
"one-api/logger"
|
|
"one-api/model"
|
|
"strings"
|
|
)
|
|
|
|
func NotifyRootUser(t string, subject string, content string) {
|
|
user := model.GetRootUser().ToBaseUser()
|
|
err := NotifyUser(user.Id, user.Email, user.GetSetting(), dto.NewNotify(t, subject, content, nil))
|
|
if err != nil {
|
|
logger.SysError(fmt.Sprintf("failed to notify root user: %s", err.Error()))
|
|
}
|
|
}
|
|
|
|
func NotifyUser(userId int, userEmail string, userSetting dto.UserSetting, data dto.Notify) error {
|
|
notifyType := userSetting.NotifyType
|
|
if notifyType == "" {
|
|
notifyType = dto.NotifyTypeEmail
|
|
}
|
|
|
|
// Check notification limit
|
|
canSend, err := CheckNotificationLimit(userId, data.Type)
|
|
if err != nil {
|
|
logger.SysError(fmt.Sprintf("failed to check notification limit: %s", err.Error()))
|
|
return err
|
|
}
|
|
if !canSend {
|
|
return fmt.Errorf("notification limit exceeded for user %d with type %s", userId, notifyType)
|
|
}
|
|
|
|
switch notifyType {
|
|
case dto.NotifyTypeEmail:
|
|
// check setting email
|
|
userEmail = userSetting.NotificationEmail
|
|
if userEmail == "" {
|
|
logger.SysLog(fmt.Sprintf("user %d has no email, skip sending email", userId))
|
|
return nil
|
|
}
|
|
return sendEmailNotify(userEmail, data)
|
|
case dto.NotifyTypeWebhook:
|
|
webhookURLStr := userSetting.WebhookUrl
|
|
if webhookURLStr == "" {
|
|
logger.SysError(fmt.Sprintf("user %d has no webhook url, skip sending webhook", userId))
|
|
return nil
|
|
}
|
|
|
|
// 获取 webhook secret
|
|
webhookSecret := userSetting.WebhookSecret
|
|
return SendWebhookNotify(webhookURLStr, webhookSecret, data)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func sendEmailNotify(userEmail string, data dto.Notify) error {
|
|
// make email content
|
|
content := data.Content
|
|
// 处理占位符
|
|
for _, value := range data.Values {
|
|
content = strings.Replace(content, dto.ContentValueParam, fmt.Sprintf("%v", value), 1)
|
|
}
|
|
return common.SendEmail(data.Title, userEmail, content)
|
|
}
|