پرش به مطلب اصلی

Go SDK

SDK رسمی XLADA برای Go وجود ندارد. API XLADA با API Remnawave یکسان است، بنابراین کلاینت روی کتابخانهٔ استاندارد net/http و بدون هیچ وابستگی خارجی ساخته می‌شود — این‌گونه به چرخهٔ انتشار دیگران وابسته نیستید.

سازگاری

برای Remnawave انجمن یک Go-SDK را نگه‌داری می‌کند که از همان مشخصات OpenAPI تولید شده است. XLADA به همان مسیرها پاسخ می‌دهد، بنابراین آن SDK اینجا هم قابل استفاده است، اما ما آن را رسماً با XLADA آزمایش نکرده‌ایم. نمونهٔ زیر به هیچ ماژولی وابسته نیست.

نصب​

به Go 1.18+ نیاز است (any استفاده می‌شود) و ماژول پروژه:

mkdir xlada-bot && cd xlada-bot
go mod init example.com/xlada-bot

بسته‌های خارجی لازم نیست — فقط net/http، encoding/json و context.

کلاینت​

توکن یا JWT از POST /api/auth/login است، یا توکن API دیرزیست از POST /api/tokens. هر دو در هدر Authorization: Bearer فرستاده می‌شوند. در دسترسی مستقیم به پنل هدرهای X-Forwarded-For و X-Forwarded-Proto: https را اضافه کنید، وگرنه middleware پنل اتصال را قطع می‌کند.

package main

import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"time"
)

type Client struct {
baseURL string
token string
http *http.Client
}

func NewClient(baseURL, token string) *Client {
return &Client{
baseURL: baseURL,
token: token,
http: &http.Client{Timeout: 30 * time.Second},
}
}

func (c *Client) do(ctx context.Context, method, path string, body, out any) error {
var payload []byte
if body != nil {
var err error
if payload, err = json.Marshal(body); err != nil {
return err
}
}

req, err := http.NewRequestWithContext(ctx, method, c.baseURL+path, bytes.NewReader(payload))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+c.token)
req.Header.Set("X-Forwarded-For", "127.0.0.1")
req.Header.Set("X-Forwarded-Proto", "https")

res, err := c.http.Do(req)
if err != nil {
return err
}
defer res.Body.Close()

if res.StatusCode >= http.StatusBadRequest {
return fmt.Errorf("xlada: %s %s: %s", method, path, res.Status)
}

if out != nil {
return json.NewDecoder(res.Body).Decode(out)
}
return nil
}

فهرست کاربران​

خروجی صفحه‌بندی‌شده با پارامترهای query به نام‌های start (جابه‌جایی) و size (اندازهٔ صفحه، 1–1000) تعیین می‌شود.

type user struct {
ID int `json:"id"`
Username string `json:"username"`
Status string `json:"status"`
ShortUUID string `json:"shortUuid"`
ExpireAt string `json:"expireAt"`
}

type usersResponse struct {
Response struct {
Users []user `json:"users"`
Total int `json:"total"`
} `json:"response"`
}

func listUsers(ctx context.Context, c *Client) error {
var out usersResponse
if err := c.do(ctx, http.MethodGet, "/api/users?start=0&size=25", nil, &out); err != nil {
return err
}

for _, u := range out.Response.Users {
fmt.Printf("%s\t%s\t%s\n", u.Username, u.Status, u.ExpireAt)
}
fmt.Printf("مجموع: %d\n", out.Response.Total)
return nil
}

ایجاد کاربر​

POST /api/users پارامتر username را می‌پذیرد (3–36 نویسه، فقط a-z، A-Z، 0-9، _، -) و expireAt اجباری در قالب ISO 8601.

type createUserRequest struct {
Username string `json:"username"`
Status string `json:"status,omitempty"`
ExpireAt string `json:"expireAt"`
TrafficLimitBytes int64 `json:"trafficLimitBytes,omitempty"`
TrafficLimitStrategy string `json:"trafficLimitStrategy,omitempty"`
}

func createUser(ctx context.Context, c *Client) error {
var out struct {
Response struct {
ID int `json:"id"`
ShortUUID string `json:"shortUuid"`
} `json:"response"`
}

err := c.do(ctx, http.MethodPost, "/api/users", createUserRequest{
Username: "john_doe",
Status: "ACTIVE",
ExpireAt: "2026-01-17T15:38:45.065Z",
TrafficLimitStrategy: "NO_RESET",
}, &out)
if err != nil {
return err
}

fmt.Printf("ایجاد شد id=%d, shortUuid=%s\n", out.Response.ID, out.Response.ShortUUID)
return nil
}

دریافت نود​

یک نود مشخص با uuid درخواست می‌شود، فهرست نودها — با GET /api/nodes.

func getNode(ctx context.Context, c *Client, uuid string) error {
var out struct {
Response struct {
Name string `json:"name"`
Address string `json:"address"`
Port *int `json:"port"`
IsConnected bool `json:"isConnected"`
} `json:"response"`
}

if err := c.do(ctx, http.MethodGet, "/api/nodes/"+uuid, nil, &out); err != nil {
return err
}

fmt.Printf("%s (%s) connected=%v\n", out.Response.Name, out.Response.Address, out.Response.IsConnected)
return nil
}
نکته

همهٔ ساختارهای پاسخ در مشخصات صفحهٔ API Specification توصیف شده‌اند. تگ‌های json را مستقیماً از آنجا بردارید — فیلدهای پنل با camelCase نام‌گذاری شده‌اند.

گام بعدی​