61 lines
1.9 KiB
Go
61 lines
1.9 KiB
Go
package clientnotify
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"math/rand"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// vkBaseURL — VK's public API, no self-hosting concept like Telegram's,
|
|
// same reasoning as MAX's own hardcoded maxBaseURL.
|
|
const vkBaseURL = "https://api.vk.com/method"
|
|
const vkAPIVersion = "5.199"
|
|
|
|
// buildVkSendRequest — unlike Telegram/MAX's JSON bodies, messages.send
|
|
// takes form-encoded params (verified against VK's current API docs) and
|
|
// always answers HTTP 200 even on failure, with the error nested in the
|
|
// body under "error" — see parseVkSendResponse.
|
|
func buildVkSendRequest(ctx context.Context, text, groupToken, chatID string) (*http.Request, error) {
|
|
form := url.Values{
|
|
"user_id": {chatID},
|
|
"message": {text},
|
|
// VK's random_id is a 32-bit signed int in practice — a nanosecond
|
|
// epoch value (~19 digits) overflows that and gets every send
|
|
// rejected with VK error 100 ("invalid parameter"). rand.Int31()
|
|
// stays within the accepted range.
|
|
"random_id": {strconv.FormatInt(int64(rand.Int31()), 10)},
|
|
"access_token": {groupToken},
|
|
"v": {vkAPIVersion},
|
|
}
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost, vkBaseURL+"/messages.send", strings.NewReader(form.Encode()))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
return req, nil
|
|
}
|
|
|
|
type vkSendError struct {
|
|
ErrorCode int `json:"error_code"`
|
|
ErrorMsg string `json:"error_msg"`
|
|
}
|
|
|
|
func parseVkSendResponse(body []byte) (string, error) {
|
|
var out struct {
|
|
Response json.Number `json:"response"`
|
|
Error *vkSendError `json:"error"`
|
|
}
|
|
if err := json.Unmarshal(body, &out); err != nil {
|
|
return "", fmt.Errorf("vk: malformed response: %w", err)
|
|
}
|
|
if out.Error != nil {
|
|
return "", fmt.Errorf("vk: %d: %s", out.Error.ErrorCode, out.Error.ErrorMsg)
|
|
}
|
|
return out.Response.String(), nil
|
|
}
|