feat: add im kafka admin integration
This commit is contained in:
@@ -10,10 +10,13 @@ import (
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
BaseUrl string `json:"baseUrl"`
|
||||
ServiceId string `json:"serviceId"`
|
||||
ServiceSecret string `json:"serviceSecret"`
|
||||
Timeout time.Duration `json:"timeout"`
|
||||
BaseUrl string `json:"baseUrl"`
|
||||
ServiceId string `json:"serviceId"`
|
||||
ServiceSecret string `json:"serviceSecret"`
|
||||
Timeout time.Duration `json:"timeout"`
|
||||
InternalBaseUrl string `json:"internalBaseUrl"`
|
||||
InternalServiceName string `json:"internalServiceName"`
|
||||
InternalServiceSecret string `json:"internalServiceSecret"`
|
||||
}
|
||||
|
||||
func LoadConfig(ctx context.Context) Config {
|
||||
@@ -28,10 +31,25 @@ func LoadConfig(ctx context.Context) Config {
|
||||
if serviceSecret == "" {
|
||||
serviceSecret = os.Getenv("IM_ADMIN_API_SECRET")
|
||||
}
|
||||
internalSecret := g.Cfg().MustGet(ctx, "imInternalApi.serviceSecret").String()
|
||||
if strings.HasPrefix(internalSecret, "${") && strings.HasSuffix(internalSecret, "}") {
|
||||
internalSecret = os.Getenv(strings.TrimSuffix(strings.TrimPrefix(internalSecret, "${"), "}"))
|
||||
}
|
||||
if internalSecret == "" {
|
||||
internalSecret = os.Getenv("IM_INTERNAL_API_SECRET")
|
||||
}
|
||||
if internalSecret == "" {
|
||||
internalSecret = serviceSecret
|
||||
}
|
||||
baseUrl := g.Cfg().MustGet(ctx, "imAdminApi.baseUrl").String()
|
||||
serviceId := g.Cfg().MustGet(ctx, "imAdminApi.serviceId", "hotgo-admin").String()
|
||||
return Config{
|
||||
BaseUrl: g.Cfg().MustGet(ctx, "imAdminApi.baseUrl").String(),
|
||||
ServiceId: g.Cfg().MustGet(ctx, "imAdminApi.serviceId", "hotgo-admin").String(),
|
||||
ServiceSecret: serviceSecret,
|
||||
Timeout: timeout,
|
||||
BaseUrl: baseUrl,
|
||||
ServiceId: serviceId,
|
||||
ServiceSecret: serviceSecret,
|
||||
Timeout: timeout,
|
||||
InternalBaseUrl: g.Cfg().MustGet(ctx, "imInternalApi.baseUrl", baseUrl).String(),
|
||||
InternalServiceName: g.Cfg().MustGet(ctx, "imInternalApi.serviceName", serviceId).String(),
|
||||
InternalServiceSecret: internalSecret,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
package imadmin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
func (c *Client) InternalGet(ctx context.Context, path string, out any) error {
|
||||
req, err := c.newInternalRequest(ctx, http.MethodGet, path, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp, err := c.http.Do(req)
|
||||
if err != nil {
|
||||
return gerror.New("IM内部查询服务暂不可用")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||
return c.parseError(resp)
|
||||
}
|
||||
if out == nil {
|
||||
return nil
|
||||
}
|
||||
body, err := io.ReadAll(io.LimitReader(resp.Body, maxResponseBody))
|
||||
if err != nil {
|
||||
return gerror.Wrap(err, "读取IM内部查询响应失败")
|
||||
}
|
||||
var envelope struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
Reason string `json:"reason"`
|
||||
Data json.RawMessage `json:"data"`
|
||||
}
|
||||
if err = json.Unmarshal(body, &envelope); err == nil && len(envelope.Data) > 0 {
|
||||
if envelope.Code != 0 {
|
||||
return stableError(envelope.Message, envelope.Reason)
|
||||
}
|
||||
return json.Unmarshal(envelope.Data, out)
|
||||
}
|
||||
return json.Unmarshal(body, out)
|
||||
}
|
||||
|
||||
func (c *Client) newInternalRequest(ctx context.Context, method string, path string, bodyBytes []byte) (*http.Request, error) {
|
||||
baseUrl := strings.TrimRight(c.conf.InternalBaseUrl, "/")
|
||||
if baseUrl == "" {
|
||||
baseUrl = strings.TrimRight(c.conf.BaseUrl, "/")
|
||||
}
|
||||
if baseUrl == "" {
|
||||
return nil, gerror.New("IM内部查询API未配置")
|
||||
}
|
||||
serviceName := strings.TrimSpace(c.conf.InternalServiceName)
|
||||
if serviceName == "" {
|
||||
serviceName = strings.TrimSpace(c.conf.ServiceId)
|
||||
}
|
||||
if serviceName == "" {
|
||||
return nil, gerror.New("IM内部查询服务名未配置")
|
||||
}
|
||||
secret := c.conf.InternalServiceSecret
|
||||
if secret == "" {
|
||||
secret = c.conf.ServiceSecret
|
||||
}
|
||||
if secret == "" {
|
||||
return nil, gerror.New("IM内部查询API密钥未配置")
|
||||
}
|
||||
req, err := http.NewRequestWithContext(ctx, method, baseUrl+path, bytes.NewReader(bodyBytes))
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "创建IM内部查询请求失败")
|
||||
}
|
||||
timestamp := strconv.FormatInt(time.Now().UTC().Unix(), 10)
|
||||
nonce, err := randomNonce()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bodyHash := sha256.Sum256(bodyBytes)
|
||||
signingText := strings.Join([]string{
|
||||
method,
|
||||
requestTarget(req),
|
||||
hex.EncodeToString(bodyHash[:]),
|
||||
timestamp,
|
||||
nonce,
|
||||
}, "\n")
|
||||
mac := hmac.New(sha256.New, []byte(secret))
|
||||
_, _ = mac.Write([]byte(signingText))
|
||||
req.Header.Set("Accept", "application/json")
|
||||
req.Header.Set("X-Service-Name", serviceName)
|
||||
req.Header.Set("X-Timestamp", timestamp)
|
||||
req.Header.Set("X-Nonce", nonce)
|
||||
req.Header.Set("X-Signature", hex.EncodeToString(mac.Sum(nil)))
|
||||
return req, nil
|
||||
}
|
||||
Reference in New Issue
Block a user