首次提交:初始化项目代码

This commit is contained in:
sunct
2026-07-31 15:24:14 +08:00
commit 8d3c97bd01
73 changed files with 11720 additions and 0 deletions
+53
View File
@@ -0,0 +1,53 @@
package crypto
import "golang.org/x/crypto/bcrypt"
// HashPassword hashes a plain text password using bcrypt.
// HashPassword 使用 bcrypt 对明文密码进行加密。
//
// Parameters:
// - password: The plain text password to hash.
//
// Returns:
// - string: The hashed password.
// - error: An error if hashing fails.
//
// Note:
// - Uses bcrypt.DefaultCost (10) for hashing.
// - The resulting hash is approximately 60 characters long.
//
// 参数:
// - password: 要加密的明文密码。
//
// 返回值:
// - string: 加密后的密码。
// - error: 如果加密失败则返回错误。
//
// 注意:
// - 使用 bcrypt.DefaultCost (10) 进行加密。
// - 生成的哈希值大约为 60 个字符。
func HashPassword(password string) (string, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
return string(bytes), err
}
// CheckPasswordHash compares a plain text password with a hashed password.
// CheckPasswordHash 比较明文密码和加密密码。
//
// Parameters:
// - password: The plain text password to check.
// - hash: The hashed password to compare against.
//
// Returns:
// - bool: true if the password matches the hash, false otherwise.
//
// 参数:
// - password: 要检查的明文密码。
// - hash: 要比较的加密密码。
//
// 返回值:
// - bool: 如果密码匹配哈希值则返回 true,否则返回 false。
func CheckPasswordHash(password, hash string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
return err == nil
}
+258
View File
@@ -0,0 +1,258 @@
package errors
import "net/http"
// AppError represents an application-specific error.
// AppError 表示应用程序特定的错误。
//
// This struct extends the standard error interface with additional fields
// for HTTP status codes and custom error codes.
//
// 此结构体扩展了标准的 error 接口,添加了 HTTP 状态码和自定义错误码字段。
type AppError struct {
StatusCode int
Code int
Message string
Err error
}
// Error implements the error interface.
// Error 实现了 error 接口。
//
// Returns:
// - string: The error message, including the wrapped error if present.
//
// 返回值:
// - string: 错误消息,如果存在包装的错误则包含该错误。
func (e *AppError) Error() string {
if e.Err != nil {
return e.Message + ": " + e.Err.Error()
}
return e.Message
}
// New creates a new AppError with the specified code and message.
// New 创建一个具有指定代码和消息的新 AppError。
//
// Parameters:
// - code: The custom error code.
// - message: The error message.
//
// Returns:
// - *AppError: A pointer to the new AppError instance.
//
// 参数:
// - code: 自定义错误代码。
// - message: 错误消息。
//
// 返回值:
// - *AppError: 新创建的 AppError 实例指针。
func New(code int, message string) *AppError {
return &AppError{
StatusCode: http.StatusOK,
Code: code,
Message: message,
}
}
// NewWithErr creates a new AppError with the specified code, message, and wrapped error.
// NewWithErr 创建一个具有指定代码、消息和包装错误的新 AppError。
//
// Parameters:
// - code: The custom error code.
// - message: The error message.
// - err: The wrapped error.
//
// Returns:
// - *AppError: A pointer to the new AppError instance.
//
// 参数:
// - code: 自定义错误代码。
// - message: 错误消息。
// - err: 包装的错误。
//
// 返回值:
// - *AppError: 新创建的 AppError 实例指针。
func NewWithErr(code int, message string, err error) *AppError {
return &AppError{
StatusCode: http.StatusOK,
Code: code,
Message: message,
Err: err,
}
}
// BadRequest creates an AppError for 400 Bad Request.
// BadRequest 创建一个 400 Bad Request 的 AppError。
//
// Parameters:
// - message: The error message.
//
// Returns:
// - *AppError: A pointer to the BadRequest AppError.
//
// 参数:
// - message: 错误消息。
//
// 返回值:
// - *AppError: BadRequest AppError 的指针。
func BadRequest(message string) *AppError {
return &AppError{
StatusCode: http.StatusBadRequest,
Code: 400,
Message: message,
}
}
// Unauthorized creates an AppError for 401 Unauthorized.
// Unauthorized 创建一个 401 Unauthorized 的 AppError。
//
// Parameters:
// - message: The error message.
//
// Returns:
// - *AppError: A pointer to the Unauthorized AppError.
//
// 参数:
// - message: 错误消息。
//
// 返回值:
// - *AppError: Unauthorized AppError 的指针。
func Unauthorized(message string) *AppError {
return &AppError{
StatusCode: http.StatusUnauthorized,
Code: 401,
Message: message,
}
}
// Forbidden creates an AppError for 403 Forbidden.
// Forbidden 创建一个 403 Forbidden 的 AppError。
//
// Parameters:
// - message: The error message.
//
// Returns:
// - *AppError: A pointer to the Forbidden AppError.
//
// 参数:
// - message: 错误消息。
//
// 返回值:
// - *AppError: Forbidden AppError 的指针。
func Forbidden(message string) *AppError {
return &AppError{
StatusCode: http.StatusForbidden,
Code: 403,
Message: message,
}
}
// Conflict creates an AppError for 409 Conflict.
// Conflict 创建一个 409 Conflict 的 AppError。
//
// Parameters:
// - message: The error message.
//
// Returns:
// - *AppError: A pointer to the Conflict AppError.
//
// 参数:
// - message: 错误消息。
//
// 返回值:
// - *AppError: Conflict AppError 的指针。
func Conflict(message string) *AppError {
return &AppError{
StatusCode: http.StatusConflict,
Code: 409,
Message: message,
}
}
// NotFound creates an AppError for 404 Not Found.
// NotFound 创建一个 404 Not Found 的 AppError。
//
// Parameters:
// - message: The error message.
//
// Returns:
// - *AppError: A pointer to the NotFound AppError.
//
// 参数:
// - message: 错误消息。
//
// 返回值:
// - *AppError: NotFound AppError 的指针。
func NotFound(message string) *AppError {
return &AppError{
StatusCode: http.StatusNotFound,
Code: 404,
Message: message,
}
}
// InternalError creates an AppError for 500 Internal Server Error.
// InternalError 创建一个 500 Internal Server Error 的 AppError。
//
// Parameters:
// - message: The error message.
// - err: The wrapped error (typically the underlying cause).
//
// Returns:
// - *AppError: A pointer to the InternalError AppError.
//
// 参数:
// - message: 错误消息。
// - err: 包装的错误(通常是根本原因)。
//
// 返回值:
// - *AppError: InternalError AppError 的指针。
func InternalError(message string, err error) *AppError {
return &AppError{
StatusCode: http.StatusInternalServerError,
Code: 500,
Message: message,
Err: err,
}
}
// IsAppError checks if an error is an AppError.
// IsAppError 检查错误是否是 AppError。
//
// Parameters:
// - err: The error to check.
//
// Returns:
// - bool: true if the error is an AppError, false otherwise.
//
// 参数:
// - err: 要检查的错误。
//
// 返回值:
// - bool: 如果错误是 AppError 则返回 true,否则返回 false。
func IsAppError(err error) bool {
_, ok := err.(*AppError)
return ok
}
// AsAppError attempts to convert an error to an AppError.
// AsAppError 尝试将错误转换为 AppError。
//
// Parameters:
// - err: The error to convert.
//
// Returns:
// - *AppError: The converted AppError if successful.
// - bool: true if the conversion was successful, false otherwise.
//
// 参数:
// - err: 要转换的错误。
//
// 返回值:
// - *AppError: 如果转换成功则返回转换后的 AppError。
// - bool: 如果转换成功则返回 true,否则返回 false。
func AsAppError(err error) (*AppError, bool) {
e, ok := err.(*AppError)
return e, ok
}
+41
View File
@@ -0,0 +1,41 @@
package jwt
import (
"time"
"cloudnest/internal/pkg/errors"
"github.com/golang-jwt/jwt/v5"
)
type Claims struct {
UserID uint `json:"user_id"`
Username string `json:"username"`
UserCode string `json:"user_code"`
jwt.RegisteredClaims
}
func GenerateToken(userID uint, username, userCode string, secret string, expiresIn time.Duration) (string, error) {
claims := Claims{
UserID: userID,
Username: username,
UserCode: userCode,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(expiresIn)),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString([]byte(secret))
}
func ParseToken(tokenString, secret string) (*Claims, error) {
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(secret), nil
})
if err != nil {
return nil, errors.Unauthorized("invalid token")
}
if claims, ok := token.Claims.(*Claims); ok && token.Valid {
return claims, nil
}
return nil, errors.Unauthorized("invalid token")
}
+131
View File
@@ -0,0 +1,131 @@
package logger
import (
"encoding/json"
"fmt"
"io"
"os"
"sync"
"sync/atomic"
"time"
)
// Level represents log level.
type Level int
const (
LevelDebug Level = iota
LevelInfo
LevelWarn
LevelError
)
func (l Level) String() string {
switch l {
case LevelDebug:
return "DEBUG"
case LevelInfo:
return "INFO"
case LevelWarn:
return "WARN"
case LevelError:
return "ERROR"
default:
return "INFO"
}
}
// Logger is a simple JSON logger compatible with Go 1.20.
type Logger struct {
level Level
writer io.Writer
mu sync.Mutex
}
// Default is the global default logger.
var Default atomic.Value
func init() {
Default.Store(&Logger{level: LevelInfo, writer: os.Stderr})
}
func getDefault() *Logger {
if l, ok := Default.Load().(*Logger); ok && l != nil {
return l
}
return &Logger{level: LevelInfo, writer: os.Stderr}
}
// Init initializes the logger with the specified log level.
func Init(level string) {
InitWithWriter(level, os.Stdout)
}
// InitWithWriter initializes the logger with the specified log level and writer.
func InitWithWriter(level string, writer io.Writer) {
var lvl Level
switch level {
case "debug":
lvl = LevelDebug
case "info":
lvl = LevelInfo
case "warn":
lvl = LevelWarn
case "error":
lvl = LevelError
default:
lvl = LevelInfo
}
if writer == nil {
writer = os.Stdout
}
Default.Store(&Logger{level: lvl, writer: writer})
}
func (l *Logger) log(level Level, msg string, args ...any) {
if level < l.level {
return
}
record := map[string]any{
"time": time.Now().Format(time.RFC3339Nano),
"level": level.String(),
"msg": msg,
}
for i := 0; i < len(args)-1; i += 2 {
key, ok := args[i].(string)
if !ok {
continue
}
record[key] = args[i+1]
}
l.mu.Lock()
defer l.mu.Unlock()
data, _ := json.Marshal(record)
fmt.Fprintln(l.writer, string(data))
}
// Debug logs a message at Debug level.
func Debug(msg string, args ...any) {
getDefault().log(LevelDebug, msg, args...)
}
// Info logs a message at Info level.
func Info(msg string, args ...any) {
getDefault().log(LevelInfo, msg, args...)
}
// Warn logs a message at Warn level.
func Warn(msg string, args ...any) {
getDefault().log(LevelWarn, msg, args...)
}
// Error logs a message at Error level.
func Error(msg string, args ...any) {
getDefault().log(LevelError, msg, args...)
}
// Fatal logs a message at Error level and exits.
func Fatal(msg string, args ...any) {
getDefault().log(LevelError, msg, args...)
os.Exit(1)
}
+182
View File
@@ -0,0 +1,182 @@
package response
import (
"net/http"
"github.com/gin-gonic/gin"
)
// Response represents the standard API response structure.
// Response 表示标准的 API 响应结构。
//
// This struct provides a consistent format for all API responses.
//
// 此结构体为所有 API 响应提供了一致的格式。
type Response struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
}
// Success sends a successful response with data.
// Success 发送包含数据的成功响应。
//
// Parameters:
// - c: The Gin context.
// - data: The data to include in the response.
//
// Note:
// - Sets HTTP status code to 200 OK.
// - Sets code to 0 (success).
//
// 参数:
// - c: Gin 上下文。
// - data: 要包含在响应中的数据。
//
// 注意:
// - 设置 HTTP 状态码为 200 OK。
// - 设置 code 为 0(成功)。
func Success(c *gin.Context, data interface{}) {
c.JSON(http.StatusOK, Response{
Code: 0,
Message: "success",
Data: data,
})
}
// SuccessMsg sends a successful response with only a message.
// SuccessMsg 发送仅包含消息的成功响应。
//
// Parameters:
// - c: The Gin context.
// - message: The success message.
//
// Note:
// - Sets HTTP status code to 200 OK.
// - Sets code to 0 (success).
//
// 参数:
// - c: Gin 上下文。
// - message: 成功消息。
//
// 注意:
// - 设置 HTTP 状态码为 200 OK。
// - 设置 code 为 0(成功)。
func SuccessMsg(c *gin.Context, message string) {
c.JSON(http.StatusOK, Response{
Code: 0,
Message: message,
})
}
// Error sends an error response with a custom code and message.
// Error 发送包含自定义代码和消息的错误响应。
//
// Parameters:
// - c: The Gin context.
// - code: The custom error code.
// - message: The error message.
//
// Note:
// - Sets HTTP status code to 200 OK.
// - The custom code indicates the specific error type.
//
// 参数:
// - c: Gin 上下文。
// - code: 自定义错误代码。
// - message: 错误消息。
//
// 注意:
// - 设置 HTTP 状态码为 200 OK。
// - 自定义代码表示特定的错误类型。
func Error(c *gin.Context, code int, message string) {
c.JSON(http.StatusOK, Response{
Code: code,
Message: message,
})
}
// BadRequest sends a 400 Bad Request response.
// BadRequest 发送 400 Bad Request 响应。
//
// Parameters:
// - c: The Gin context.
// - message: The error message.
//
// 参数:
// - c: Gin 上下文。
// - message: 错误消息。
func BadRequest(c *gin.Context, message string) {
c.JSON(http.StatusBadRequest, Response{
Code: 400,
Message: message,
})
}
// Unauthorized sends a 401 Unauthorized response.
// Unauthorized 发送 401 Unauthorized 响应。
//
// Parameters:
// - c: The Gin context.
// - message: The error message.
//
// 参数:
// - c: Gin 上下文。
// - message: 错误消息。
func Unauthorized(c *gin.Context, message string) {
c.JSON(http.StatusUnauthorized, Response{
Code: 401,
Message: message,
})
}
// Forbidden sends a 403 Forbidden response.
// Forbidden 发送 403 Forbidden 响应。
//
// Parameters:
// - c: The Gin context.
// - message: The error message.
//
// 参数:
// - c: Gin 上下文。
// - message: 错误消息。
func Forbidden(c *gin.Context, message string) {
c.JSON(http.StatusForbidden, Response{
Code: 403,
Message: message,
})
}
// NotFound sends a 404 Not Found response.
// NotFound 发送 404 Not Found 响应。
//
// Parameters:
// - c: The Gin context.
// - message: The error message.
//
// 参数:
// - c: Gin 上下文。
// - message: 错误消息。
func NotFound(c *gin.Context, message string) {
c.JSON(http.StatusNotFound, Response{
Code: 404,
Message: message,
})
}
// InternalError sends a 500 Internal Server Error response.
// InternalError 发送 500 Internal Server Error 响应。
//
// Parameters:
// - c: The Gin context.
// - message: The error message.
//
// 参数:
// - c: Gin 上下文。
// - message: 错误消息。
func InternalError(c *gin.Context, message string) {
c.JSON(http.StatusInternalServerError, Response{
Code: 500,
Message: message,
})
}
+25
View File
@@ -0,0 +1,25 @@
package validator
import (
"cloudnest/internal/pkg/logger"
"github.com/go-playground/validator/v10"
)
// Validator is the global validator instance.
// Validator 是全局验证器实例。
var Validator *validator.Validate
// Init initializes the validator.
// Init 初始化验证器。
//
// Note:
// - Should be called once during application startup.
// - Creates a new validator instance with default settings.
//
// 注意:
// - 应在应用程序启动时调用一次。
// - 使用默认设置创建新的验证器实例。
func Init() {
Validator = validator.New()
logger.Info("validator initialized")
}