103 lines
2.2 KiB
Go
103 lines
2.2 KiB
Go
|
|
package centrifugo
|
||
|
|
|
||
|
|
import (
|
||
|
|
"bytes"
|
||
|
|
"encoding/json"
|
||
|
|
"fmt"
|
||
|
|
"io"
|
||
|
|
"net/http"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
// Client Centrifugo 客戶端
|
||
|
|
type Client struct {
|
||
|
|
apiURL string
|
||
|
|
apiKey string
|
||
|
|
client *http.Client
|
||
|
|
}
|
||
|
|
|
||
|
|
// NewClient 創建新的 Centrifugo 客戶端
|
||
|
|
func NewClient(apiURL, apiKey string) *Client {
|
||
|
|
return &Client{
|
||
|
|
apiURL: apiURL,
|
||
|
|
apiKey: apiKey,
|
||
|
|
client: &http.Client{
|
||
|
|
Timeout: 5 * time.Second,
|
||
|
|
},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// PublishRequest Centrifugo 發布請求
|
||
|
|
type PublishRequest struct {
|
||
|
|
Channel string `json:"channel"`
|
||
|
|
Data interface{} `json:"data"`
|
||
|
|
}
|
||
|
|
|
||
|
|
// PublishResponse Centrifugo 發布響應
|
||
|
|
type PublishResponse struct {
|
||
|
|
Error string `json:"error,omitempty"`
|
||
|
|
Result interface{} `json:"result,omitempty"`
|
||
|
|
}
|
||
|
|
|
||
|
|
// Publish 發布訊息到指定頻道
|
||
|
|
func (c *Client) Publish(channel string, data []byte) error {
|
||
|
|
req := PublishRequest{
|
||
|
|
Channel: channel,
|
||
|
|
Data: json.RawMessage(data),
|
||
|
|
}
|
||
|
|
return c.publishJSON(req)
|
||
|
|
}
|
||
|
|
|
||
|
|
// PublishJSON 發布 JSON 訊息到指定頻道
|
||
|
|
func (c *Client) PublishJSON(channel string, data interface{}) error {
|
||
|
|
req := PublishRequest{
|
||
|
|
Channel: channel,
|
||
|
|
Data: data,
|
||
|
|
}
|
||
|
|
return c.publishJSON(req)
|
||
|
|
}
|
||
|
|
|
||
|
|
func (c *Client) publishJSON(req PublishRequest) error {
|
||
|
|
body, err := json.Marshal(req)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("failed to marshal request: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
httpReq, err := http.NewRequest("POST", c.apiURL+"/publish", bytes.NewReader(body))
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("failed to create request: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
httpReq.Header.Set("Content-Type", "application/json")
|
||
|
|
if c.apiKey != "" {
|
||
|
|
httpReq.Header.Set("Authorization", "apikey "+c.apiKey)
|
||
|
|
}
|
||
|
|
|
||
|
|
resp, err := c.client.Do(httpReq)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("failed to send request: %w", err)
|
||
|
|
}
|
||
|
|
defer resp.Body.Close()
|
||
|
|
|
||
|
|
respBody, err := io.ReadAll(resp.Body)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("failed to read response: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
if resp.StatusCode != http.StatusOK {
|
||
|
|
return fmt.Errorf("centrifugo returned status %d: %s", resp.StatusCode, string(respBody))
|
||
|
|
}
|
||
|
|
|
||
|
|
var publishResp PublishResponse
|
||
|
|
if err := json.Unmarshal(respBody, &publishResp); err != nil {
|
||
|
|
return fmt.Errorf("failed to unmarshal response: %w", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
if publishResp.Error != "" {
|
||
|
|
return fmt.Errorf("centrifugo error: %s", publishResp.Error)
|
||
|
|
}
|
||
|
|
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|