add files
This commit is contained in:
commit
86a1a1c006
5 changed files with 864 additions and 0 deletions
181
bluesky.go
Normal file
181
bluesky.go
Normal file
|
@ -0,0 +1,181 @@
|
|||
package blueskyclient
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/charmbracelet/log"
|
||||
"github.com/dghubble/sling"
|
||||
)
|
||||
|
||||
type BlueskyConfig struct {
|
||||
PDSURL string `json:"pds-url"`
|
||||
Repo string `json:"repo"`
|
||||
Handle string `json:"handle"`
|
||||
DID string `json:"did"`
|
||||
AppPassword string `json:"app-password"`
|
||||
AccessJWT string `json:"access-jwt"`
|
||||
RefreshJWT string `json:"refresh-jwt"`
|
||||
Cursor int64 `json:"cursor"`
|
||||
}
|
||||
|
||||
type DIDResponse struct {
|
||||
Context []string `json:"@context"`
|
||||
ID string `json:"id"`
|
||||
AlsoKnownAs []string `json:"alsoKnownAs"`
|
||||
VerificationMethod []struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Controller string `json:"controller"`
|
||||
PublicKeyMultibase string `json:"publicKeyMultibase"`
|
||||
} `json:"verificationMethod"`
|
||||
Service []struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
ServiceEndpoint string `json:"serviceEndpoint"`
|
||||
} `json:"service"`
|
||||
}
|
||||
|
||||
type BSkySessionResponse struct {
|
||||
AccessJWT string `json:"accessJwt,omitempty"`
|
||||
RefreshJWT string `json:"refreshJwt,omitempty"`
|
||||
Handle string `json:"handle"`
|
||||
DID string `json:"did"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
type CommitResponse struct {
|
||||
URI string `json:"uri"`
|
||||
Cid string `json:"cid"`
|
||||
Commit struct {
|
||||
Cid string `json:"cid"`
|
||||
Rev string `json:"rev"`
|
||||
} `json:"commit"`
|
||||
Error string `json:"error"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
func (c *CommitResponse) GetRKey() string {
|
||||
s := strings.SplitN(c.URI, "/", 5)
|
||||
if len(s) == 5 {
|
||||
return s[4]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Link struct {
|
||||
Cid string `json:"cid"`
|
||||
URI string `json:"uri"`
|
||||
}
|
||||
|
||||
type Bluesky struct {
|
||||
Cfg *BlueskyConfig
|
||||
HttpClient *http.Client
|
||||
Logger *log.Logger
|
||||
sling *sling.Sling
|
||||
}
|
||||
|
||||
func (bluesky *Bluesky) CreateSession(cfg *BlueskyConfig) error {
|
||||
body := struct {
|
||||
Identifier string `json:"identifier"`
|
||||
Password string `json:"password"`
|
||||
}{
|
||||
Identifier: cfg.Handle,
|
||||
Password: cfg.AppPassword,
|
||||
}
|
||||
resp := new(BSkySessionResponse)
|
||||
|
||||
bluesky.sling.New().Post("/xrpc/com.atproto.server.createSession").BodyJSON(body).ReceiveSuccess(resp)
|
||||
if resp.AccessJWT != "" {
|
||||
cfg.AccessJWT = resp.AccessJWT
|
||||
cfg.RefreshJWT = resp.RefreshJWT
|
||||
return nil
|
||||
}
|
||||
|
||||
bluesky.sling.New().Set("Authorization", fmt.Sprintf("Bearer %s", bluesky.Cfg.AccessJWT))
|
||||
return errors.New("unable to authenticate, check handle/password")
|
||||
}
|
||||
|
||||
func (bluesky *Bluesky) RefreshSession() error {
|
||||
resp := new(BSkySessionResponse)
|
||||
|
||||
bluesky.sling.New().Set("Authorization", fmt.Sprintf("Bearer %s", bluesky.Cfg.RefreshJWT)).
|
||||
Post("/xrpc/com.atproto.server.refreshSession").Receive(resp, resp)
|
||||
if resp.AccessJWT != "" {
|
||||
bluesky.Cfg.AccessJWT = resp.AccessJWT
|
||||
bluesky.Cfg.RefreshJWT = resp.RefreshJWT
|
||||
PersistAuthSession(bluesky.Cfg)
|
||||
bluesky.sling.Set("Authorization", fmt.Sprintf("Bearer %s", bluesky.Cfg.AccessJWT))
|
||||
return nil
|
||||
}
|
||||
|
||||
return bluesky.CreateSession(bluesky.Cfg)
|
||||
}
|
||||
|
||||
func (bluesky *Bluesky) CheckSessionValid() {
|
||||
resp := new(BSkySessionResponse)
|
||||
|
||||
bluesky.sling.New().Set("Authorization", fmt.Sprintf("Bearer %s", bluesky.Cfg.AccessJWT)).
|
||||
Get("/xrpc/app.bsky.actor.getProfile").Receive(resp, resp)
|
||||
if resp.Error == "ExpiredToken" {
|
||||
bluesky.RefreshSession()
|
||||
}
|
||||
}
|
||||
|
||||
func (bluesky *Bluesky) GetPost(uri string) *Post {
|
||||
bluesky.CheckSessionValid()
|
||||
var post = struct {
|
||||
URI string `json:"uri"`
|
||||
CID string `json:"cid"`
|
||||
Value *Post `json:"value"`
|
||||
}{}
|
||||
|
||||
args := strings.SplitN(uri, "/", 5)
|
||||
params := struct {
|
||||
RKey string `url:"rkey"`
|
||||
Repo string `url:"repo"`
|
||||
Collection string `url:"collection"`
|
||||
}{
|
||||
RKey: args[4],
|
||||
Repo: args[2],
|
||||
Collection: args[3],
|
||||
}
|
||||
bluesky.sling.New().Get("/xrpc/com.atproto.repo.getRecord").QueryStruct(params).ReceiveSuccess(&post)
|
||||
|
||||
return post.Value
|
||||
}
|
||||
|
||||
func (bluesky *Bluesky) DeleteRecord(args []string) *CommitResponse {
|
||||
bluesky.CheckSessionValid()
|
||||
|
||||
resp := new(CommitResponse)
|
||||
params := struct {
|
||||
RKey string `json:"rkey"`
|
||||
Repo string `json:"repo"`
|
||||
Collection string `json:"collection"`
|
||||
}{
|
||||
RKey: args[0],
|
||||
Repo: args[1],
|
||||
Collection: args[2],
|
||||
}
|
||||
bluesky.sling.New().Set("Authorization", fmt.Sprintf("Bearer %s", bluesky.Cfg.AccessJWT)).
|
||||
Post("/xrpc/com.atproto.repo.deleteRecord").BodyJSON(params).Receive(resp, resp)
|
||||
return resp
|
||||
}
|
||||
|
||||
func (bluesky *Bluesky) FetchPost(did string, rkey string) Post {
|
||||
resp := &struct {
|
||||
Posts []Post `json:"posts"`
|
||||
}{}
|
||||
params := struct {
|
||||
URIs string `url:"uris"`
|
||||
}{
|
||||
URIs: fmt.Sprintf("at://%s/app.bsky.feed.post/%s", did, rkey),
|
||||
}
|
||||
bluesky.sling.New().Base("https://public.api.bsky.app").
|
||||
Get("/xrpc/app.bsky.feed.getPosts").QueryStruct(¶ms).Receive(resp, resp)
|
||||
return resp.Posts[0]
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue