in progress
This commit is contained in:
5
.vscode/extensions.json
vendored
Normal file
5
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"gigacode.gigacode-vscode"
|
||||
]
|
||||
}
|
||||
112
README.md
112
README.md
@@ -1,3 +1,111 @@
|
||||
# smsc
|
||||
# SMSc - Отправка SMS через smsc.ru
|
||||
|
||||
Отправка смс при помощи сервиса smsc.ru
|
||||
Пакет `smsc` предоставляет простой способ отправки SMS через сервис [smsc.ru](https://smsc.ru) на языке Go.
|
||||
|
||||
## Установка
|
||||
|
||||
```bash
|
||||
go get git.gm6.ru/icewind/smsc
|
||||
```
|
||||
|
||||
## Использование
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"git.gm6.ru/icewind/smsc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Создание запроса на отправку SMS
|
||||
req := smsc.RequestSMS{
|
||||
ApiKey: "ваш_api_ключ", // Замените на ваш реальный API-ключ
|
||||
Phone: "+79991234567", // Номер получателя
|
||||
Message: "Привет от Go!", // Текст сообщения
|
||||
}
|
||||
|
||||
// Отправка SMS
|
||||
resp := smsc.SendSMS(req)
|
||||
|
||||
// Проверка результата
|
||||
if resp.Error != "" {
|
||||
// Обработка ошибки
|
||||
panic(resp.Error)
|
||||
}
|
||||
|
||||
// Успешная отправка
|
||||
fmt.Printf("SMS отправлена. ID: %d, Количество сообщений: %d\n", resp.ID, resp.Cnt)
|
||||
}
|
||||
```
|
||||
|
||||
## Функции
|
||||
|
||||
### `SendSMS(req RequestSMS) ResponseSMS`
|
||||
Отправляет SMS через сервис smsc.ru.
|
||||
|
||||
**Параметры:**
|
||||
- `req` — структура `RequestSMS` с данными для отправки.
|
||||
|
||||
**Возвращает:**
|
||||
- `ResponseSMS` — ответ от сервера, включая `ID` и `Cnt`, или ошибку.
|
||||
|
||||
## Структуры
|
||||
|
||||
### `RequestSMS`
|
||||
|
||||
| Поле | Тип | Описание | JSON-тег |
|
||||
|-----------|--------|------------------------------|--------------|
|
||||
| `ApiKey` | string | API-ключ от smsc.ru | `apikey` |
|
||||
| `Phone` | string | Номер телефона получателя | `phones` |
|
||||
| `Message` | string | Текст сообщения | `mes` |
|
||||
|
||||
### `ResponseSMS`
|
||||
|
||||
| Поле | Тип | Описание | JSON-тег |
|
||||
|-----------|-----|---------------------------------|----------|
|
||||
| `ID` | int | Уникальный идентификатор SMS | `id` |
|
||||
| `Cnt` | int | Количество отправленных SMS | `cnt` |
|
||||
| `Error` | string | Описание ошибки (если есть) | `error` |
|
||||
| `ErrorCode`| int | Код ошибки | `error_code` |
|
||||
|
||||
## Обработка ошибок
|
||||
|
||||
Если произошла ошибка при отправке, поле `Error` в `ResponseSMS` будет содержать описание ошибки.
|
||||
|
||||
```go
|
||||
resp := smsc.SendSMS(req)
|
||||
if resp.Error != "" {
|
||||
log.Printf("Ошибка: %s (код: %d)\n", resp.Error, resp.ErrorCode)
|
||||
}
|
||||
```
|
||||
|
||||
## Тестирование
|
||||
|
||||
Для тестирования функции `SendSMS` можно использовать реальные вызовы (интеграционные тесты). Пример теста:
|
||||
|
||||
```go
|
||||
func TestSendSMS(t *testing.T) {
|
||||
req := RequestSMS{
|
||||
ApiKey: "ваш_api_ключ",
|
||||
Phone: "+79991234567",
|
||||
Message: "Тестовое сообщение",
|
||||
}
|
||||
|
||||
resp := SendSMS(req)
|
||||
|
||||
if resp.Error != "" {
|
||||
t.Errorf("Ошибка при отправке SMS: %s", resp.Error)
|
||||
}
|
||||
|
||||
if resp.ID == 0 {
|
||||
t.Error("Ожидался ненулевой ID")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> **Внимание:** Не забудьте заменить `ваш_api_ключ` на реальный ключ и убедитесь, что номер телефона корректен.
|
||||
|
||||
## Лицензия
|
||||
|
||||
MIT
|
||||
|
||||
66
request.go
Normal file
66
request.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package smsc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func httpRequest(req *http.Request, resp any) error {
|
||||
client := &http.Client{}
|
||||
|
||||
httpResp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("http request error: %w", err)
|
||||
}
|
||||
defer httpResp.Body.Close()
|
||||
|
||||
body, err := io.ReadAll(httpResp.Body)
|
||||
if err != nil {
|
||||
return fmt.Errorf("http response read error: %w", err)
|
||||
}
|
||||
|
||||
//log.Println(string(body))
|
||||
|
||||
if err = json.Unmarshal(body, resp); err != nil {
|
||||
var rErr Response
|
||||
if err = json.Unmarshal(body, &rErr); err == nil && rErr.ErrorCode != 0 {
|
||||
return fmt.Errorf("error %d: %s", rErr.ErrorCode, rErr.Error)
|
||||
}
|
||||
err = fmt.Errorf("http response unmarshal error: %w", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func requestPost(url string, req, resp any) error {
|
||||
reqData, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("request marshal error: %w", err)
|
||||
}
|
||||
|
||||
httpReq, err := http.NewRequest("POST", url, bytes.NewReader(reqData))
|
||||
if err != nil {
|
||||
return fmt.Errorf("http request create error: %w", err)
|
||||
}
|
||||
|
||||
httpReq.Header.Set("Content-Type", "application/json")
|
||||
httpReq.Header.Set("Accept", "application/json")
|
||||
|
||||
err = httpRequest(httpReq, resp)
|
||||
return err
|
||||
}
|
||||
|
||||
func requestGet(url, apiKey string, params url.Values, resp any) error {
|
||||
httpReq, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("http request create error: %w", err)
|
||||
}
|
||||
httpReq.URL.RawQuery = params.Encode()
|
||||
httpReq.Header.Set("Accept", "application/json")
|
||||
|
||||
err = httpRequest(httpReq, resp)
|
||||
return err
|
||||
}
|
||||
10
response.go
Normal file
10
response.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package smsc
|
||||
|
||||
type Response struct {
|
||||
Error string `json:"error"`
|
||||
ErrorCode int `json:"error_code"`
|
||||
}
|
||||
|
||||
func (s *Response) IsError() bool {
|
||||
return s.Error == ""
|
||||
}
|
||||
24
sms.go
Normal file
24
sms.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package smsc
|
||||
|
||||
const (
|
||||
UrlSMS = "https://smsc.ru/rest/send/"
|
||||
)
|
||||
|
||||
type RequestSMS struct {
|
||||
ApiKey string `json:"apikey"`
|
||||
Phone string `json:"phones"`
|
||||
Message string `json:"mes"`
|
||||
}
|
||||
|
||||
type ResponseSMS struct {
|
||||
Response
|
||||
ID int `json:"id"`
|
||||
Cnt int `json:"cnt"`
|
||||
}
|
||||
|
||||
func SendSMS(req RequestSMS) (resp ResponseSMS) {
|
||||
if err := requestPost(UrlSMS, req, &resp); err != nil {
|
||||
resp.Error = err.Error()
|
||||
}
|
||||
return
|
||||
}
|
||||
49
sms_test.go
Normal file
49
sms_test.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package smsc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func generateCode() string {
|
||||
return fmt.Sprintf("%04d", rand.Intn(10000))
|
||||
}
|
||||
|
||||
func TestSendSMS(t *testing.T) {
|
||||
// Создаем тестовый запрос
|
||||
req := RequestSMS{
|
||||
ApiKey: "80g8w5-t4D5n2X5v2!8s1S3p5E2n2X68e", // Замените на реальный API-ключ для теста
|
||||
Phone: "79397804368", // Замените на реальный номер телефона
|
||||
Message: "Код подтверждения: " + generateCode(),
|
||||
}
|
||||
|
||||
// Вызываем тестируемую функцию
|
||||
resp := SendSMS(req)
|
||||
|
||||
// Проверяем, что нет ошибки
|
||||
if resp.Error != "" {
|
||||
t.Errorf("Ошибка при отправке SMS: %s", resp.Error)
|
||||
}
|
||||
|
||||
// Проверяем, что ID и Cnt имеют ожидаемые значения (если применимо)
|
||||
// Эти проверки могут быть опциональными, так как значения зависят от ответа сервера
|
||||
if resp.ID == 0 {
|
||||
t.Error("Ожидался ненулевой ID")
|
||||
}
|
||||
if resp.Cnt == 0 {
|
||||
t.Error("Ожидался ненулевой Cnt")
|
||||
}
|
||||
|
||||
printJSON(t, resp)
|
||||
}
|
||||
|
||||
func printJSON(t *testing.T, data any) {
|
||||
jsonData, err := json.MarshalIndent(data, "", " ")
|
||||
if err != nil {
|
||||
t.Errorf("Ошибка при преобразовании в JSON: %v", err)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(jsonData))
|
||||
}
|
||||
Reference in New Issue
Block a user