Files
huangzhenpc a8d25054fc sdd
2025-05-23 23:08:02 +08:00

531 lines
13 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"encoding/json"
"flag"
"fmt"
"log"
"math/rand"
"net/http"
"os"
"stalwart_client/pkg/api"
"strconv"
"strings"
"time"
)
// 请求和响应结构
type CreateUserRequest struct {
Email string `json:"email"`
Password string `json:"password,omitempty"`
Description string `json:"description,omitempty"`
Quota int64 `json:"quota,omitempty"`
}
type UserResponse struct {
ID int `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
Password string `json:"password,omitempty"`
Success bool `json:"success"`
Message string `json:"message,omitempty"`
}
type ListUsersRequest struct {
Limit int `json:"limit,omitempty"`
Page int `json:"page,omitempty"`
}
type ListUsersResponse struct {
Users []api.User `json:"users"`
Total int `json:"total"`
Success bool `json:"success"`
Message string `json:"message,omitempty"`
}
type GetUserRequest struct {
ID int `json:"id,omitempty"`
Email string `json:"email,omitempty"`
}
type GetUserResponse struct {
User map[string]interface{} `json:"user"`
Success bool `json:"success"`
Message string `json:"message,omitempty"`
}
type GetEmailRequest struct {
Email string `json:"email"`
Password string `json:"password"`
Server string `json:"server,omitempty"`
Port int `json:"port,omitempty"`
Count int `json:"count,omitempty"`
}
type EmailResponse struct {
Emails []*api.EmailMessage `json:"emails"`
Success bool `json:"success"`
Message string `json:"message,omitempty"`
}
// 全局变量
var (
client *api.Client
)
// API处理函数
// 创建用户
func createUserHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
var req CreateUserRequest
// 尝试解析请求体,但即使失败也继续处理
_ = json.NewDecoder(r.Body).Decode(&req)
// 如果email为空自动生成一个随机用户名和域名
if req.Email == "" {
randomUsername := api.GenerateRandomPassword(8)
req.Email = fmt.Sprintf("%s@%s", randomUsername, client.Config.User.DefaultDomain)
}
// 如果密码为空,将由系统自动生成
// 如果配额为0使用默认配额
if req.Quota == 0 {
req.Quota = client.Config.User.DefaultQuota
}
// 如果描述为空,添加默认描述
if req.Description == "" {
req.Description = "系统自动创建的用户"
}
// 创建用户
userID, username, email, password, err := client.CreateEmailUser(
req.Email,
req.Password,
req.Description,
req.Quota,
api.APIKeyAuth, // 默认使用API Key认证
"",
"",
client.Config.Auth.APIKey,
)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{
"success": "false",
"message": fmt.Sprintf("创建用户失败: %v", err),
})
return
}
// 返回响应
response := UserResponse{
ID: userID,
Username: username,
Email: email,
Password: password,
Success: true,
Message: "用户创建成功",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// 创建简单用户 - 无需任何参数,直接返回创建的用户信息
func createSimpleUserHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet && r.Method != http.MethodPost {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
// 生成随机用户名 - 确保不包含特殊字符
randomUsername := api.GenerateRandomUsername(8)
// 确保用户名只包含字母和数字
for i := 0; i < len(randomUsername); i++ {
if !((randomUsername[i] >= 'a' && randomUsername[i] <= 'z') ||
(randomUsername[i] >= '0' && randomUsername[i] <= '9')) {
// 替换为字母
randomUsername = randomUsername[:i] + "x" + randomUsername[i+1:]
}
}
email := fmt.Sprintf("%s@%s", randomUsername, client.Config.User.DefaultDomain)
description := "自动创建的临时用户"
quota := client.Config.User.DefaultQuota
// 创建用户
userID, username, email, password, err := client.CreateEmailUser(
email,
"", // 空密码,系统会自动生成
description,
quota,
api.APIKeyAuth,
"",
"",
client.Config.Auth.APIKey,
)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{
"success": "false",
"message": fmt.Sprintf("创建用户失败: %v", err),
})
return
}
// 返回简单格式的响应
response := map[string]interface{}{
"id": userID,
"username": username,
"email": email,
"password": password,
"server": fmt.Sprintf("mail.%s", strings.Split(email, "@")[1]),
"success": true,
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// 创建模拟用户 - 不实际调用API只生成模拟数据
func createMockUserHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet && r.Method != http.MethodPost {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
// 生成随机用户名 - 确保不包含特殊字符
randomUsername := api.GenerateRandomUsername(8)
// 确保用户名只包含字母和数字
for i := 0; i < len(randomUsername); i++ {
if !((randomUsername[i] >= 'a' && randomUsername[i] <= 'z') ||
(randomUsername[i] >= '0' && randomUsername[i] <= '9')) {
// 替换为字母
randomUsername = randomUsername[:i] + "x" + randomUsername[i+1:]
}
}
domain := client.Config.User.DefaultDomain
email := fmt.Sprintf("%s@%s", randomUsername, domain)
password := api.GenerateRandomPassword(12)
// 返回模拟响应
userID := rand.Intn(1000) + 1000 // 随机生成ID
response := map[string]interface{}{
"id": userID,
"username": randomUsername,
"email": email,
"password": password,
"server": fmt.Sprintf("mail.%s", domain),
"imap_server": fmt.Sprintf("mail.%s", domain),
"imap_port": 993,
"smtp_server": fmt.Sprintf("mail.%s", domain),
"smtp_port": 465,
"description": "模拟生成的测试用户",
"quota": client.Config.User.DefaultQuota,
"created_time": time.Now().Format(time.RFC3339),
"success": true,
"message": "模拟用户创建成功仅本地数据未实际调用API",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// 列出用户
func listUsersHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
// 解析查询参数
limitStr := r.URL.Query().Get("limit")
pageStr := r.URL.Query().Get("page")
limit := 100
page := 1
if limitStr != "" {
if l, err := strconv.Atoi(limitStr); err == nil && l > 0 {
limit = l
}
}
if pageStr != "" {
if p, err := strconv.Atoi(pageStr); err == nil && p > 0 {
page = p
}
}
// 获取用户列表
userList, err := client.ListUsers(
api.APIKeyAuth, // 默认使用API Key认证
"",
"",
client.Config.Auth.APIKey,
limit,
page,
)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{
"success": "false",
"message": fmt.Sprintf("获取用户列表失败: %v", err),
})
return
}
// 返回响应
response := ListUsersResponse{
Users: userList.Data.Items,
Total: userList.Data.Total,
Success: true,
Message: "获取用户列表成功",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// 获取单个用户信息
func getUserHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
// 解析参数
idStr := r.URL.Query().Get("id")
email := r.URL.Query().Get("email")
// 如果两个参数都为空,尝试从路径中获取
if idStr == "" && email == "" {
pathParts := strings.Split(r.URL.Path, "/")
if len(pathParts) > 3 {
// 路径形式可能是 /api/get_user/123 或 /api/get_user/user@example.com
lastPart := pathParts[len(pathParts)-1]
if _, err := strconv.Atoi(lastPart); err == nil {
// 是数字当作ID处理
idStr = lastPart
} else if strings.Contains(lastPart, "@") {
// 包含@,当作邮箱处理
email = lastPart
}
}
}
if idStr == "" && email == "" {
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{
"success": "false",
"message": "必须提供用户ID或邮箱地址",
})
return
}
var userInfo map[string]interface{}
var err error
if idStr != "" {
// 通过ID查询
id, err := strconv.Atoi(idStr)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{
"success": "false",
"message": "无效的用户ID",
})
return
}
userInfo, err = client.GetUserDetails(
id,
api.APIKeyAuth, // 默认使用API Key认证
"",
"",
client.Config.Auth.APIKey,
)
} else {
// 通过邮箱查询
userInfo, err = client.GetUserByEmail(
email,
api.APIKeyAuth, // 默认使用API Key认证
"",
"",
client.Config.Auth.APIKey,
)
}
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{
"success": "false",
"message": fmt.Sprintf("获取用户信息失败: %v", err),
})
return
}
// 返回响应
response := GetUserResponse{
User: userInfo,
Success: true,
Message: "获取用户信息成功",
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// 获取邮件
func getEmailsHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}
var req GetEmailRequest
// 尝试解析请求体,但即使失败也继续处理
_ = json.NewDecoder(r.Body).Decode(&req)
// 检查是否提供了邮箱和密码参数
if req.Email == "" || req.Password == "" {
// 也可以从URL参数获取
req.Email = r.URL.Query().Get("email")
req.Password = r.URL.Query().Get("password")
// 如果仍然为空,则返回错误
if req.Email == "" || req.Password == "" {
w.WriteHeader(http.StatusBadRequest)
json.NewEncoder(w).Encode(map[string]string{
"success": "false",
"message": "邮箱地址和密码必须提供",
})
return
}
}
// 设置默认参数
server := req.Server
if server == "" {
// 尝试从邮箱地址提取域名
parts := strings.Split(req.Email, "@")
if len(parts) > 1 {
server = fmt.Sprintf("mail.%s", parts[1])
} else {
server = "mail.evnmail.com"
}
}
port := req.Port
if port == 0 {
port = 993
}
count := req.Count
if count == 0 {
count = 5 // 默认获取5封邮件
}
// 获取邮件
emails, err := api.GetLatestEmails(
req.Email,
req.Password,
server,
port,
true, // 使用SSL
count,
)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
json.NewEncoder(w).Encode(map[string]string{
"success": "false",
"message": fmt.Sprintf("获取邮件失败: %v", err),
})
return
}
// 返回响应
response := EmailResponse{
Emails: emails,
Success: true,
Message: fmt.Sprintf("成功获取 %d 封邮件", len(emails)),
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// 启动Web服务器
func main() {
// 初始化随机数生成器
rand.Seed(time.Now().UnixNano())
// 解析命令行参数
portPtr := flag.Int("p", 8080, "服务器端口")
configPtr := flag.String("c", "", "配置文件路径")
flag.Parse()
// 加载配置
config, err := api.LoadConfig(*configPtr)
if err != nil {
fmt.Printf("加载配置失败: %v\n", err)
os.Exit(1)
}
// 创建客户端
client = api.NewClient(config)
// 设置路由 - 不再使用authMiddleware
http.HandleFunc("/api/create_user", createUserHandler)
http.HandleFunc("/api/simple_user", createSimpleUserHandler)
http.HandleFunc("/api/mock_user", createMockUserHandler)
http.HandleFunc("/api/list_users", listUsersHandler)
http.HandleFunc("/api/get_user", getUserHandler)
http.HandleFunc("/api/get_emails", getEmailsHandler)
// 添加一个简单的健康检查端点
http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
})
// 添加一个简单的根路径处理
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
w.WriteHeader(http.StatusOK)
w.Write([]byte("Stalwart 邮件 API 服务运行中"))
})
// 启动服务器
port := *portPtr
addr := fmt.Sprintf(":%d", port)
fmt.Printf("启动Web服务器监听端口: %d\n", port)
fmt.Printf("API端点 (无需认证):\n")
fmt.Printf(" - POST /api/create_user (创建用户,可自定义参数)\n")
fmt.Printf(" - GET /api/simple_user (创建随机用户,无需任何参数)\n")
fmt.Printf(" - GET /api/mock_user (创建模拟用户,仅本地数据)\n")
fmt.Printf(" - GET /api/list_users (获取用户列表)\n")
fmt.Printf(" - GET /api/get_user (获取用户信息)\n")
fmt.Printf(" - POST /api/get_emails (获取用户邮件)\n")
if err := http.ListenAndServe(addr, nil); err != nil {
log.Fatalf("启动服务器失败: %v", err)
}
}