This commit is contained in:
huangzhenpc
2025-05-23 23:08:02 +08:00
parent 9444bf4802
commit a8d25054fc
14 changed files with 2277 additions and 0 deletions

530
cmd/web_server/main.go Normal file
View File

@@ -0,0 +1,530 @@
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)
}
}