زبان برنامهنویسی Go به دلیل کارایی بالا، کامپایل سریع به باینری مستقل و مدل همزمانی کمنظیر با Goroutines، انتخاب اول توسعه میکروسرویسها، صرافیهای مالی و سرویسهای پرمصرف است. در این مقاله یک پکیج آماده و کامل برای اتصال به وبسرویس RESTful فری اس ام اس میسازیم.
پیادهسازی پکیج کلاینت فری اس ام اس در Go
فایل freesms.go را در پکیج خود ایجاد کرده و ساختار کلاینت را به شکل زیر بنویسید:
package freesms
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"time"
)
type Client struct {
BaseURL string
APIKey string
HTTPClient *http.Client
}
func NewClient(apiKey string) *Client {
return &Client{
BaseURL: "https://api.free-sms.ir/v1",
APIKey: apiKey,
HTTPClient: &http.Client{
Timeout: 5 * time.Second,
Transport: &http.Transport{
MaxIdleConns: 100,
MaxIdleConnsPerHost: 20,
},
},
}
}
// ساختار درخواست ارسال OTP
type OTPRequest struct {
To string `json:"to"`
PatternCode string `json:"pattern_code"`
Params map[string]interface{} `json:"params"`
}
type APIResponse struct {
Status bool `json:"status"`
Code int `json:"code"`
Message string `json:"message"`
}
// متد ارسال کد تایید یکبار مصرف
func (c *Client) SendOTP(to, patternCode string, params map[string]interface{}) (*APIResponse, error) {
reqBody, err := json.Marshal(OTPRequest{
To: to,
PatternCode: patternCode,
Params: params,
})
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", c.BaseURL+"/otp", bytes.NewBuffer(reqBody))
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "Bearer "+c.APIKey)
req.Header.Set("Content-Type", "application/json")
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
var result APIResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, err
}
return &result, nil
}
ارسال همزمان هزاران پیامک با Worker Pool در Go
یکی از درخشانترین ویژگیهای Go استفاده از کانالها و Goroutineها برای ارسال پیامک بدون قفل کردن پردازنده است:
package main
import (
"fmt"
"sync"
"your-module/freesms"
)
func worker(id int, client *freesms.Client, jobs <-chan string, wg *sync.WaitGroup) {
defer wg.Done()
for mobile := range jobs {
resp, err := client.SendOTP(mobile, "login_otp", map[string]interface{}{"code": 58291})
if err != nil {
fmt.Printf("Worker %d error sending to %s: %v\n", id, mobile, err)
} else {
fmt.Printf("Worker %d sent to %s, response: %s\n", id, mobile, resp.Message)
}
}
}
func main() {
client := freesms.NewClient("YOUR_API_KEY")
recipients := []string{"09121234567", "09351234567", "09191234567"}
jobs := make(chan string, len(recipients))
var wg sync.WaitGroup
// اجرای ۵ ورکر همزمان
for w := 1; w <= 5; w++ {
wg.Add(1)
go worker(w, client, jobs, &wg)
}
for _, r := range recipients {
jobs <- r
}
close(jobs)
wg.Wait()
}
راندمان شبکه: با تنظیم MaxIdleConnsPerHost روی اعداد بالاتر (مثل ۲۰ تا ۵۰)، کلاینت Go ارتباطات TCP را با وبسرویس فری اس ام اس باز نگه میدارد (Keep-Alive) و زمان تاخیر برقراری اتصال SSL Handshake برای درخواستهای متوالی به صفر میرسد.
پیادهسازی هندلر وبهوک در فریمورک Gin
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
type WebhookPayload struct {
MessageID string `json:"message_id"`
Recipient string `json:"recipient"`
Status string `json:"status"`
DeliveredAt string `json:"delivered_at"`
}
func main() {
r := gin.Default()
r.POST("/api/sms/webhook", func(c *gin.Context) {
var payload WebhookPayload
if err := c.ShouldBindJSON(&payload); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// ذخیره در دیتابیس PostgreSQL یا MongoDB
c.JSON(http.StatusOK, gin.H{"status": "received"})
})
r.Run(":8080")
}
سوالات متداول
آیا کدهای بالا با کامپایلر Go 1.22+ سازگار است؟+
بله، کدهای فوق کاملاً با نسخههای Go 1.18 تا Go 1.23 سازگار هستند و از تمامی استانداردهای Idiomatic Go پیروی میکنند.
چگونه مانع از مصرف بیش از حد اعتبار در زمان حلقههای اشتباه شویم؟+
در پنل کاربری فری اس ام اس امکان تعیین سقف مصرف روزانه بر حسب ریال یا تعداد پیامک وجود دارد تا در صورت بروز باگ در کدهای تکرار شونده، اعتبار پنل حفظ شود.
چرا زبان Go برای سامانههای ارسال پیامک با ترافیک بالا (High Throughput) مناسب است؟+
زبان Go با برخورداری از گوروتینهای بسیار سبکوزن (حدود ۲ کیلوبایت حافظه به ازای هر گوروتین) و کانکشنپولینگ داخلی در http.Transport، امکان ارسال همزمان دهها هزار پیامک بدون مسدود شدن منابع سرور را فراهم میآورد.
آیا در Go نیاز به نصب پکیج جانبی برای ارسال HTTP وجود دارد؟+
خیر، کتابخانه استاندارد net/http زبان Go فوقالعاده قدرتمند است و کلاینت پیادهسازیشده در این راهنما به صورت کاملاً Zero-Dependency و بدون نیاز به پکیجهای ثالث کار میکند.