Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/seo-sidecar / seo_client.go |
| Date | Not specified in source |
| Repository | Janady13/seo-sidecar |
| Revision | c66ba23646cf638023e8803dc201dd69089107c9 |
| Branch | main |
| Path or archive member | seo_client.go |
| Original SHA-256 | 6c4710c7b723500b65dcb7d710b032544be366e6504fe074e81d75a920993096 |
| Git blob SHA | cc32861f1e16e96bf6b6bec74b5fc3a2f2f68a1b |
| Reading-copy SHA-256 | d78fcda89de36a63d2c5cd57b9602f5740fb17b67574697189968b26abda877e |
Recovered source transcript
Download complete source text ↓156 lines · 3.8 KB
Credential-bearing and unrelated personal details were removed from this reading copy. The source identity and original checksum remain recorded.
package seo
// Package seo provides the MEGAMIND SEO push client.
// Pushes generated JSON-LD schemas to BUBBLES sidecar over Tailscale.
//
// Usage from MEGAMIND Go code:
// client := seo.NewClient("http://<SIDECAR_HOST>:9090", "your-auth-token")
// err := client.Push("thatdeveloperguy", jsonldString)
// err := client.PushAll(schemaMap)
// status, err := client.Status()
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
type Client struct {
BaseURL string
AuthToken string
HTTPClient *http.Client
}
type SchemaUpdate struct {
Site string `json:"site"`
JSONLD string `json:"jsonld"`
PushedBy string `json:"pushed_by"`
}
type BulkUpdate struct {
Schemas []SchemaUpdate `json:"schemas"`
}
type PushResult struct {
Status string `json:"status"`
Site string `json:"site"`
Version int `json:"version"`
UpdatedAt string `json:"updated_at"`
}
type SiteStatus struct {
Site string `json:"site"`
UpdatedAt string `json:"updated_at"`
PushedBy string `json:"pushed_by"`
Version int `json:"version"`
SizeBytes int `json:"size_bytes"`
}
type StatusResponse struct {
Status string `json:"status"`
TotalSites int `json:"total_sites"`
Sites []SiteStatus `json:"sites"`
}
func NewClient(baseURL, authToken string) *Client {
return &Client{
BaseURL: baseURL,
AuthToken: [credential removed],
HTTPClient: &http.Client{
Timeout: 10 * time.Second,
},
}
}
// Push sends a single site schema to the sidecar.
func (c *Client) Push(site, jsonld string) (*PushResult, error) {
payload := SchemaUpdate{
Site: site,
JSONLD: jsonld,
PushedBy: "megamind",
}
body, err := json.Marshal(payload)
if err != nil {
return nil, fmt.Errorf("marshal: %w", err)
}
req, err := http.NewRequest("POST", fmt.Sprintf("%s/update/%s", c.BaseURL, site), bytes.NewReader(body))
if err != nil {
return nil, fmt.Errorf("request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+c.AuthToken)
req.Header.Set("Content-Type", "application/json")
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, fmt.Errorf("post: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
b, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("sidecar returned %d: %s", resp.StatusCode, string(b))
}
var result PushResult
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, fmt.Errorf("decode: %w", err)
}
return &result, nil
}
// PushAll sends all schemas in a single bulk request.
func (c *Client) PushAll(schemas map[string]string) error {
bulk := BulkUpdate{}
for site, jsonld := range schemas {
bulk.Schemas = append(bulk.Schemas, SchemaUpdate{
Site: site,
JSONLD: jsonld,
PushedBy: "megamind",
})
}
body, err := json.Marshal(bulk)
if err != nil {
return fmt.Errorf("marshal: %w", err)
}
req, err := http.NewRequest("POST", fmt.Sprintf("%s/update-bulk", c.BaseURL), bytes.NewReader(body))
if err != nil {
return fmt.Errorf("request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+c.AuthToken)
req.Header.Set("Content-Type", "application/json")
resp, err := c.HTTPClient.Do(req)
if err != nil {
return fmt.Errorf("post: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
b, _ := io.ReadAll(resp.Body)
return fmt.Errorf("sidecar returned %d: %s", resp.StatusCode, string(b))
}
return nil
}
// Status checks what schemas are live on the sidecar.
func (c *Client) Status() (*StatusResponse, error) {
resp, err := c.HTTPClient.Get(fmt.Sprintf("%s/status", c.BaseURL))
if err != nil {
return nil, fmt.Errorf("get: %w", err)
}
defer resp.Body.Close()
var status StatusResponse
if err := json.NewDecoder(resp.Body).Decode(&status); err != nil {
return nil, fmt.Errorf("decode: %w", err)
}
return &status, nil
}