An atproto PDS written in Go

better http client usage

+26 -61
identity/identity.go
···
"strings"
"github.com/bluesky-social/indigo/atproto/syntax"
+
"github.com/bluesky-social/indigo/util"
)
-
func ResolveHandle(ctx context.Context, handle string) (string, error) {
+
func ResolveHandle(ctx context.Context, cli *http.Client, handle string) (string, error) {
+
if cli == nil {
+
cli = util.RobustHTTPClient()
+
}
+
var did string
_, err := syntax.ParseHandle(handle)
···
return did, nil
}
-
type DidDoc struct {
-
Context []string `json:"@context"`
-
Id string `json:"id"`
-
AlsoKnownAs []string `json:"alsoKnownAs"`
-
VerificationMethods []DidDocVerificationMethod `json:"verificationMethods"`
-
Service []DidDocService `json:"service"`
-
}
-
-
type DidDocVerificationMethod struct {
-
Id string `json:"id"`
-
Type string `json:"type"`
-
Controller string `json:"controller"`
-
PublicKeyMultibase string `json:"publicKeyMultibase"`
-
}
-
-
type DidDocService struct {
-
Id string `json:"id"`
-
Type string `json:"type"`
-
ServiceEndpoint string `json:"serviceEndpoint"`
-
}
-
-
type DidData struct {
-
Did string `json:"did"`
-
VerificationMethods map[string]string `json:"verificationMethods"`
-
RotationKeys []string `json:"rotationKeys"`
-
AlsoKnownAs []string `json:"alsoKnownAs"`
-
Services map[string]OperationService `json:"services"`
-
}
-
-
type OperationService struct {
-
Type string `json:"type"`
-
Endpoint string `json:"endpoint"`
-
}
+
func FetchDidDoc(ctx context.Context, cli *http.Client, did string) (*DidDoc, error) {
+
if cli == nil {
+
cli = util.RobustHTTPClient()
+
}
-
type DidLog []DidLogEntry
-
-
type DidLogEntry struct {
-
Sig string `json:"sig"`
-
Prev *string `json:"prev"`
-
Type string `json:"string"`
-
Services map[string]OperationService `json:"services"`
-
AlsoKnownAs []string `json:"alsoKnownAs"`
-
RotationKeys []string `json:"rotationKeys"`
-
VerificationMethods map[string]string `json:"verificationMethods"`
-
}
-
-
type DidAuditEntry struct {
-
Did string `json:"did"`
-
Operation DidLogEntry `json:"operation"`
-
Cid string `json:"cid"`
-
Nullified bool `json:"nullified"`
-
CreatedAt string `json:"createdAt"`
-
}
-
-
type DidAuditLog []DidAuditEntry
-
-
func FetchDidDoc(ctx context.Context, did string) (*DidDoc, error) {
var ustr string
if strings.HasPrefix(did, "did:plc:") {
ustr = fmt.Sprintf("https://plc.directory/%s", did)
···
return &diddoc, nil
}
-
func FetchDidData(ctx context.Context, did string) (*DidData, error) {
+
func FetchDidData(ctx context.Context, cli *http.Client, did string) (*DidData, error) {
+
if cli == nil {
+
cli = util.RobustHTTPClient()
+
}
+
var ustr string
ustr = fmt.Sprintf("https://plc.directory/%s/data", did)
···
return &diddata, nil
}
-
func FetchDidAuditLog(ctx context.Context, did string) (DidAuditLog, error) {
+
func FetchDidAuditLog(ctx context.Context, cli *http.Client, did string) (DidAuditLog, error) {
+
if cli == nil {
+
cli = util.RobustHTTPClient()
+
}
+
var ustr string
ustr = fmt.Sprintf("https://plc.directory/%s/log/audit", did)
···
return didlog, nil
}
-
func ResolveService(ctx context.Context, did string) (string, error) {
-
diddoc, err := FetchDidDoc(ctx, did)
+
func ResolveService(ctx context.Context, cli *http.Client, did string) (string, error) {
+
if cli == nil {
+
cli = util.RobustHTTPClient()
+
}
+
+
diddoc, err := FetchDidDoc(ctx, cli, did)
if err != nil {
return "", err
}
+10 -3
identity/passport.go
···
import (
"context"
+
"net/http"
"sync"
)
···
}
type Passport struct {
+
h *http.Client
bc BackingCache
lk sync.Mutex
}
-
func NewPassport(bc BackingCache) *Passport {
+
func NewPassport(h *http.Client, bc BackingCache) *Passport {
+
if h == nil {
+
h = http.DefaultClient
+
}
+
return &Passport{
+
h: h,
bc: bc,
lk: sync.Mutex{},
}
···
p.lk.Lock() // this is pretty pathetic, and i should rethink this. but for now, fuck it
defer p.lk.Unlock()
-
doc, err := FetchDidDoc(ctx, did)
+
doc, err := FetchDidDoc(ctx, p.h, did)
if err != nil {
return nil, err
}
···
}
}
-
did, err := ResolveHandle(ctx, handle)
+
did, err := ResolveHandle(ctx, p.h, handle)
if err != nil {
return "", err
}
+57
identity/types.go
···
+
package identity
+
+
type DidDoc struct {
+
Context []string `json:"@context"`
+
Id string `json:"id"`
+
AlsoKnownAs []string `json:"alsoKnownAs"`
+
VerificationMethods []DidDocVerificationMethod `json:"verificationMethods"`
+
Service []DidDocService `json:"service"`
+
}
+
+
type DidDocVerificationMethod struct {
+
Id string `json:"id"`
+
Type string `json:"type"`
+
Controller string `json:"controller"`
+
PublicKeyMultibase string `json:"publicKeyMultibase"`
+
}
+
+
type DidDocService struct {
+
Id string `json:"id"`
+
Type string `json:"type"`
+
ServiceEndpoint string `json:"serviceEndpoint"`
+
}
+
+
type DidData struct {
+
Did string `json:"did"`
+
VerificationMethods map[string]string `json:"verificationMethods"`
+
RotationKeys []string `json:"rotationKeys"`
+
AlsoKnownAs []string `json:"alsoKnownAs"`
+
Services map[string]OperationService `json:"services"`
+
}
+
+
type OperationService struct {
+
Type string `json:"type"`
+
Endpoint string `json:"endpoint"`
+
}
+
+
type DidLog []DidLogEntry
+
+
type DidLogEntry struct {
+
Sig string `json:"sig"`
+
Prev *string `json:"prev"`
+
Type string `json:"string"`
+
Services map[string]OperationService `json:"services"`
+
AlsoKnownAs []string `json:"alsoKnownAs"`
+
RotationKeys []string `json:"rotationKeys"`
+
VerificationMethods map[string]string `json:"verificationMethods"`
+
}
+
+
type DidAuditEntry struct {
+
Did string `json:"did"`
+
Operation DidLogEntry `json:"operation"`
+
Cid string `json:"cid"`
+
Nullified bool `json:"nullified"`
+
CreatedAt string `json:"createdAt"`
+
}
+
+
type DidAuditLog []DidAuditEntry
+8 -2
plc/client.go
···
"github.com/bluesky-social/indigo/atproto/crypto"
"github.com/bluesky-social/indigo/util"
+
"github.com/haileyok/cocoon/identity"
)
type Client struct {
···
}
type ClientArgs struct {
+
H *http.Client
Service string
RotationKey []byte
PdsHostname string
···
args.Service = "https://plc.directory"
}
+
if args.H == nil {
+
args.H = util.RobustHTTPClient()
+
}
+
rk, err := crypto.ParsePrivateBytesK256([]byte(args.RotationKey))
if err != nil {
return nil, err
}
return &Client{
-
h: util.RobustHTTPClient(),
+
h: args.H,
service: args.Service,
rotationKey: rk,
pdsHostname: args.PdsHostname,
···
AlsoKnownAs: []string{
"at://" + handle,
},
-
Services: map[string]OperationService{
+
Services: map[string]identity.OperationService{
"atproto_pds": {
Type: "AtprotoPersonalDataServer",
Endpoint: "https://" + c.pdsHostname,
+1 -1
server/handle_identity_update_handle.go
···
ctx := context.WithValue(e.Request().Context(), "skip-cache", true)
if strings.HasPrefix(repo.Repo.Did, "did:plc:") {
-
log, err := identity.FetchDidAuditLog(ctx, repo.Repo.Did)
+
log, err := identity.FetchDidAuditLog(ctx, nil, repo.Repo.Did)
if err != nil {
s.logger.Error("error fetching doc", "error", err)
return helpers.ServerError(e, nil)
+1 -1
server/handle_server_create_account.go
···
return helpers.ServerError(e, nil)
}
-
did, op, err := s.plcClient.CreateDID(e.Request().Context(), k, "", request.Handle)
+
did, op, err := s.plcClient.CreateDID(k, "", request.Handle)
if err != nil {
s.logger.Error("error creating operation", "endpoint", "com.atproto.server.createAccount", "error", err)
return helpers.ServerError(e, nil)
+7 -1
server/server.go
···
"github.com/bluesky-social/indigo/api/atproto"
"github.com/bluesky-social/indigo/atproto/syntax"
"github.com/bluesky-social/indigo/events"
+
"github.com/bluesky-social/indigo/util"
"github.com/bluesky-social/indigo/xrpc"
"github.com/go-playground/validator"
"github.com/golang-jwt/jwt/v4"
···
)
type Server struct {
+
http *http.Client
httpd *http.Server
echo *echo.Echo
db *gorm.DB
···
return nil, err
}
+
h := util.RobustHTTPClient()
+
plcClient, err := plc.NewClient(&plc.ClientArgs{
+
H: h,
Service: "https://plc.directory",
PdsHostname: args.Hostname,
RotationKey: rkbytes,
···
}
s := &Server{
+
http: h,
httpd: httpd,
echo: e,
logger: args.Logger,
···
Relays: args.Relays,
},
evtman: events.NewEventManager(events.NewMemPersister()),
-
passport: identity.NewPassport(identity.NewMemCache(10_000)),
+
passport: identity.NewPassport(h, identity.NewMemCache(10_000)),
}
s.repoman = NewRepoMan(s) // TODO: this is way too lazy, stop it