package kutt import ( "bytes" "context" "encoding/json" "fmt" "io" "net/http" "strings" "time" ) // Client 是 Kutt API 客户端 // 用于创建和管理短链接 type Client struct { apiURL string // Kutt API 基础 URL apiKey string // API 认证密钥 httpClient *http.Client // HTTP 客户端 } // NewClient 创建一个新的 Kutt 客户端 // // 参数: // - apiURL: Kutt API 基础 URL (例如: https://kutt.it/api/v2) // - apiKey: Kutt API 密钥 // // 返回: // - *Client: Kutt 客户端实例 func NewClient(apiURL, apiKey string) *Client { return &Client{ apiURL: apiURL, apiKey: apiKey, httpClient: &http.Client{ Timeout: 10 * time.Second, }, } } // CreateLinkRequest 创建短链接的请求参数 type CreateLinkRequest struct { Target string `json:"target"` // 目标 URL (必填) Description string `json:"description,omitempty"` // 链接描述 (可选) ExpireIn string `json:"expire_in,omitempty"` // 过期时间,例如 "2 days" (可选) Password string `json:"password,omitempty"` // 访问密码 (可选) CustomURL string `json:"customurl,omitempty"` // 自定义短链后缀 (可选) Reuse bool `json:"reuse,omitempty"` // 如果目标 URL 已存在则复用 (可选) Domain string `json:"domain,omitempty"` // 自定义域名 (可选) } // Link 短链接响应结构 type Link struct { ID string `json:"id"` // 链接 UUID Address string `json:"address"` // 短链地址后缀 Banned bool `json:"banned"` // 是否被封禁 CreatedAt time.Time `json:"created_at"` // 创建时间 Link string `json:"link"` // 完整短链接 URL Password bool `json:"password"` // 是否有密码保护 Target string `json:"target"` // 目标 URL Description string `json:"description"` // 链接描述 UpdatedAt time.Time `json:"updated_at"` // 更新时间 VisitCount int `json:"visit_count"` // 访问次数 } // ErrorResponse Kutt API 错误响应 type ErrorResponse struct { Error string `json:"error"` Message string `json:"message"` } // CreateShortLink 创建短链接 // // 参数: // - ctx: 上下文 // - req: 创建请求参数 // // 返回: // - *Link: 创建的短链接信息 // - error: 错误信息 func (c *Client) CreateShortLink(ctx context.Context, req *CreateLinkRequest) (*Link, error) { // 序列化请求体 body, err := json.Marshal(req) if err != nil { return nil, fmt.Errorf("marshal request failed: %w", err) } // 创建 HTTP 请求 httpReq, err := http.NewRequestWithContext(ctx, http.MethodPost, c.apiURL+"/links", bytes.NewReader(body)) if err != nil { return nil, fmt.Errorf("create request failed: %w", err) } // 设置请求头 httpReq.Header.Set("Content-Type", "application/json") httpReq.Header.Set("X-API-KEY", c.apiKey) // 发送请求 resp, err := c.httpClient.Do(httpReq) if err != nil { return nil, fmt.Errorf("send request failed: %w", err) } defer resp.Body.Close() // 读取响应体 respBody, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("read response failed: %w", err) } // 检查响应状态 if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { var errResp ErrorResponse if err := json.Unmarshal(respBody, &errResp); err == nil && errResp.Error != "" { return nil, fmt.Errorf("kutt api error: %s - %s", errResp.Error, errResp.Message) } return nil, fmt.Errorf("kutt api error: status %d, body: %s", resp.StatusCode, string(respBody)) } // 解析响应 var link Link if err := json.Unmarshal(respBody, &link); err != nil { return nil, fmt.Errorf("unmarshal response failed: %w", err) } return &link, nil } // CreateInviteShortLink 为邀请码创建短链接 // 这是一个便捷方法,用于生成邀请链接 // // 参数: // - ctx: 上下文 // - baseURL: 注册页面基础 URL (例如: https://gethifast.net) // - inviteCode: 邀请码 // - domain: 短链接域名 (例如: getsapp.net),可为空 // // 返回: // - string: 短链接 URL // - error: 错误信息 func (c *Client) CreateInviteShortLink(ctx context.Context, baseURL, inviteCode, domain string) (string, error) { // 构建目标 URL - 落地页 // 格式:https://gethifast.net/?ic=邀请码 targetURL := fmt.Sprintf("%s?ic=%s", baseURL, inviteCode) req := &CreateLinkRequest{ Target: targetURL, Description: fmt.Sprintf("Invite link for code: %s", inviteCode), Reuse: true, // 如果已存在相同目标 URL 则复用 Domain: domain, } link, err := c.CreateShortLink(ctx, req) if err != nil { return "", err } // 强制使用 HTTPS if strings.HasPrefix(link.Link, "http://") { link.Link = strings.Replace(link.Link, "http://", "https://", 1) } return link.Link, nil }