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