package push import ( "context" "encoding/json" "fmt" "io" "net/http" "net/url" "strings" "time" ) const wpushAPIURL = "https://api.wpush.cn/api/v1/send" // WPushConfig 是 WPush 推送的配置。 type WPushConfig struct { APIKey string } // WPushProvider 实现了通过 WPush 发送推送。 // 支持微信公众号、飞书、钉钉、企业微信等多种渠道,取决于用户在 WPush 侧的配置。 type WPushProvider struct { apiKey string client *http.Client } // NewWPushProvider 创建 WPush 推送 Provider。 // APIKey 为空时返回 ErrProviderConfigInvalid。 func NewWPushProvider(cfg WPushConfig) (*WPushProvider, error) { if strings.TrimSpace(cfg.APIKey) == "" { return nil, ErrProviderConfigInvalid } return &WPushProvider{ apiKey: strings.TrimSpace(cfg.APIKey), client: &http.Client{Timeout: 10 * time.Second}, }, nil } func (p *WPushProvider) Name() string { return "wpush" } func (p *WPushProvider) Send(ctx context.Context, msg Message) error { form := url.Values{} form.Set("apikey", p.apiKey) form.Set("title", msg.Title) form.Set("content", msg.Content) req, err := http.NewRequestWithContext(ctx, http.MethodPost, wpushAPIURL, strings.NewReader(form.Encode())) if err != nil { return fmt.Errorf("wpush: create request: %w", err) } req.Header.Set("Content-Type", "application/x-www-form-urlencoded") resp, err := p.client.Do(req) if err != nil { return fmt.Errorf("wpush: send failed: %w", err) } defer resp.Body.Close() bodyBytes, _ := io.ReadAll(resp.Body) var result struct { Code int `json:"code"` Message string `json:"message"` } if err := json.Unmarshal(bodyBytes, &result); err != nil { return fmt.Errorf("wpush: parse response: %w (body: %s)", err, string(bodyBytes)) } if result.Code != 0 { return fmt.Errorf("wpush: api error code=%d: %s", result.Code, result.Message) } return nil }