init
This commit is contained in:
commit
ed1d845933
9 changed files with 280 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
.env
|
||||||
0
README.md
Normal file
0
README.md
Normal file
1
app/app.go
Normal file
1
app/app.go
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
package app
|
||||||
3
go.mod
Normal file
3
go.mod
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
module github.com/deeerain/togo-domain-manager
|
||||||
|
|
||||||
|
go 1.27.2
|
||||||
44
main.go
Normal file
44
main.go
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/deeerain/togo-domain-manager/playtogo"
|
||||||
|
)
|
||||||
|
|
||||||
|
const BASE_URL string = "https://play2go.cloud/"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
slog.SetLogLoggerLevel(slog.LevelDebug)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
token := os.Getenv("ACCESS_TOKEN")
|
||||||
|
|
||||||
|
client := playtogo.New(BASE_URL, token)
|
||||||
|
|
||||||
|
domains, err := client.GetDomains(ctx)
|
||||||
|
fmt.Printf("%v : %v", domains, err)
|
||||||
|
|
||||||
|
records, err := client.GetRecods(ctx, domains[0].ID)
|
||||||
|
fmt.Printf("%v : %v", records, err)
|
||||||
|
|
||||||
|
new_rec := playtogo.CreateRecord{
|
||||||
|
Name: "tg",
|
||||||
|
TTL: 300,
|
||||||
|
Type: playtogo.A.String(),
|
||||||
|
Records: []playtogo.CreateRecordAddress{
|
||||||
|
{
|
||||||
|
Address: "192.168.1.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cr, err := client.AddRecord(ctx, domains[0].ID, new_rec)
|
||||||
|
fmt.Errorf("%v : %v", cr, err)
|
||||||
|
}
|
||||||
82
playtogo/client.go
Normal file
82
playtogo/client.go
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
package playtogo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
baseURL string
|
||||||
|
token string
|
||||||
|
httpClient *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(baseURL, token string) *Client {
|
||||||
|
return &Client{
|
||||||
|
baseURL: strings.TrimRight(baseURL, "/"),
|
||||||
|
token: token,
|
||||||
|
httpClient: &http.Client{
|
||||||
|
Timeout: 10 * time.Second,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) do(ctx context.Context, method, path string, body, result any) error {
|
||||||
|
var reader io.Reader
|
||||||
|
|
||||||
|
if body != nil {
|
||||||
|
data, err := json.Marshal(body)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("encode request: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
reader = bytes.NewReader(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, method, c.baseURL+path, reader)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("create reqest: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
headers := map[string]string{
|
||||||
|
"Accept": "application/json",
|
||||||
|
"Authorization": "Bearer " + c.token,
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range headers {
|
||||||
|
req.Header.Set(k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if body != nil {
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("send reqest: %s", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
slog.Debug("response", "status code", resp.StatusCode)
|
||||||
|
|
||||||
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||||
|
return fmt.Errorf("API returned HTTP %d", resp.StatusCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result == nil {
|
||||||
|
return fmt.Errorf("decode response: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(result); err != nil {
|
||||||
|
return fmt.Errorf("decode response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
39
playtogo/domain.go
Normal file
39
playtogo/domain.go
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
package playtogo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NameServer struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
IP string `json:"ip"`
|
||||||
|
IPv6 string `json:"ip6"`
|
||||||
|
SeqNR int `json:"seq_nr"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Domain struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
FullName string `json:"full_name"`
|
||||||
|
DisplayName string `json:"display_name"`
|
||||||
|
DomainName string `json:"domain_name"`
|
||||||
|
DomainExtention string `json:"domain_extention"`
|
||||||
|
DomainServers []NameServer `json:"name_servers"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetDomains(ctx context.Context) ([]Domain, error) {
|
||||||
|
var response ApiResponse[[]Domain]
|
||||||
|
path := "/api/domains/my"
|
||||||
|
|
||||||
|
if err := c.do(ctx, http.MethodGet, path, nil, &response); err != nil {
|
||||||
|
return nil, fmt.Errorf("get subscription: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !response.Success {
|
||||||
|
return nil, fmt.Errorf("api error: %v", response.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.Data, nil
|
||||||
|
}
|
||||||
55
playtogo/dto.go
Normal file
55
playtogo/dto.go
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
package playtogo
|
||||||
|
|
||||||
|
type RecordType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
A RecordType = iota
|
||||||
|
AAAA
|
||||||
|
CNAME
|
||||||
|
MX
|
||||||
|
TXT
|
||||||
|
SPF
|
||||||
|
SRV
|
||||||
|
CAA
|
||||||
|
PTR
|
||||||
|
NS
|
||||||
|
)
|
||||||
|
|
||||||
|
var recordTypeNames = map[RecordType]string{
|
||||||
|
A: "A",
|
||||||
|
AAAA: "AAAA",
|
||||||
|
CNAME: "CNAME",
|
||||||
|
MX: "MX",
|
||||||
|
TXT: "TXT",
|
||||||
|
SPF: "SPF",
|
||||||
|
SRV: "SRV",
|
||||||
|
CAA: "CAA",
|
||||||
|
PTR: "PTR",
|
||||||
|
NS: "NS",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t RecordType) String() string {
|
||||||
|
return recordTypeNames[t]
|
||||||
|
}
|
||||||
|
|
||||||
|
type ApiResponse[T any] struct {
|
||||||
|
Success bool `json:"success"`
|
||||||
|
Data T `json:"data"`
|
||||||
|
Error any `json:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateRecordAddress struct {
|
||||||
|
Address string `json:"address"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateRecord struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Records []CreateRecordAddress `json:"records"`
|
||||||
|
TTL int `json:"ttl"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreateRecordResult struct {
|
||||||
|
DomainID int `json:"domain_id"`
|
||||||
|
Zone string `json:"zone"`
|
||||||
|
}
|
||||||
55
playtogo/records.go
Normal file
55
playtogo/records.go
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
package playtogo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Record struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
FullName string `json:"full_name"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
TTL int `json:"ttl"`
|
||||||
|
Disabled bool `json:"disabled"`
|
||||||
|
Content string `json:"content"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DomainRecord struct {
|
||||||
|
ID int `json:"domain_id"`
|
||||||
|
Zone string `json:"zone"`
|
||||||
|
AllowedRecordTypes []string `json:"allowed_record_types"`
|
||||||
|
Records []Record `json:"records"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetRecods(ctx context.Context, domain_id int) ([]Record, error) {
|
||||||
|
var response ApiResponse[DomainRecord]
|
||||||
|
path := fmt.Sprintf("/api/domains/%v/dns/records", domain_id)
|
||||||
|
|
||||||
|
if err := c.do(ctx, http.MethodGet, path, nil, &response); err != nil {
|
||||||
|
return nil, fmt.Errorf("get records: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !response.Success {
|
||||||
|
return nil, fmt.Errorf("api error: %v", response.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.Data.Records, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AddRecord(ctx context.Context, domain_id int, record CreateRecord) (*CreateRecordResult, error) {
|
||||||
|
var response ApiResponse[CreateRecordResult]
|
||||||
|
path := fmt.Sprintf("/api/domains/%v/dns/records", domain_id)
|
||||||
|
|
||||||
|
if err := c.do(ctx, http.MethodPost, path, record, &response); err != nil {
|
||||||
|
return nil, fmt.Errorf("add record: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !response.Success {
|
||||||
|
return nil, fmt.Errorf("api error: %v", response.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &response.Data, nil
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue