+61
-10
main.go
+61
-10
main.go
···
2
2
3
3
import (
4
4
"context"
5
+
"encoding/json"
6
+
"flag"
5
7
"fmt"
6
8
"log"
7
9
"net/http"
8
-
"os"
9
10
"time"
10
11
11
12
"tangled.org/whey.party/red-dwarf-server/microcosm/constellation"
12
13
"tangled.org/whey.party/red-dwarf-server/microcosm/slingshot"
14
+
appbskyactordefs "tangled.org/whey.party/red-dwarf-server/shims/lex/app/bsky/actor"
15
+
"tangled.org/whey.party/red-dwarf-server/shims/utils"
13
16
"tangled.org/whey.party/red-dwarf-server/sticket"
14
17
15
18
// "github.com/bluesky-social/indigo/atproto/atclient"
···
22
25
// "github.com/bluesky-social/jetstream/pkg/models"
23
26
)
24
27
28
+
var (
29
+
JETSTREAM_URL string
30
+
SPACEDUST_URL string
31
+
SLINGSHOT_URL string
32
+
CONSTELLATION_URL string
33
+
)
34
+
35
+
func initURLs(prod bool) {
36
+
if !prod {
37
+
JETSTREAM_URL = "wss://jetstream.whey.party/subscribe"
38
+
SPACEDUST_URL = "wss://spacedust.whey.party/subscribe"
39
+
SLINGSHOT_URL = "https://slingshot.whey.party"
40
+
CONSTELLATION_URL = "https://constellation.whey.party"
41
+
} else {
42
+
JETSTREAM_URL = "ws://localhost:6008/subscribe"
43
+
SPACEDUST_URL = "ws://localhost:9998/subscribe"
44
+
SLINGSHOT_URL = "http://localhost:7729"
45
+
CONSTELLATION_URL = "http://localhost:7728"
46
+
}
47
+
}
48
+
25
49
const (
26
-
JETSTREAM_URL = "ws://localhost:6008/subscribe"
27
-
SPACEDUST_URL = "ws://localhost:9998/subscribe"
28
-
SLINGSHOT_URL = "http://localhost:7729"
29
-
CONSTELLATION_URL = "http://localhost:7728"
50
+
BSKYIMAGECDN_URL = "https://cdn.bsky.app"
51
+
BSKYVIDEOCDN_URL = "https://video.bsky.app"
30
52
)
31
53
32
54
func main() {
33
-
fmt.Fprintf(os.Stdout, "red-dwarf-server started")
55
+
log.Println("red-dwarf-server started")
56
+
prod := flag.Bool("prod", false, "use production URLs instead of localhost")
57
+
flag.Parse()
58
+
59
+
initURLs(*prod)
34
60
35
61
ctx := context.Background()
36
62
mailbox := sticket.New()
···
39
65
// spacedust is type definitions only
40
66
// jetstream types is probably available from jetstream/pkg/models
41
67
42
-
responsewow, _ := agnostic.RepoGetRecord(ctx, sl, "", "app.bsky.feed.profile", "did:plc:44ybard66vv44zksje25o7dz", "self")
68
+
responsewow, err := agnostic.RepoGetRecord(ctx, sl, "", "app.bsky.actor.profile", "did:web:did12.whey.party", "self")
69
+
if err != nil {
70
+
log.Println(err)
71
+
}
72
+
73
+
log.Println(responsewow.Uri)
74
+
75
+
var didtest *utils.DID
76
+
didval, errdid := utils.NewDID("did:web:did12.whey.party")
77
+
if errdid != nil {
78
+
didtest = nil
79
+
} else {
80
+
didtest = &didval
81
+
}
82
+
profiletest, _, _ := appbskyactordefs.ProfileViewBasic(ctx, *didtest, sl, BSKYIMAGECDN_URL)
43
83
44
-
fmt.Fprintf(os.Stdout, responsewow.Uri)
84
+
log.Println(*profiletest.DisplayName)
85
+
log.Println(*profiletest.Avatar)
45
86
46
87
http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
47
88
mailbox.HandleWS(&w, r)
48
89
})
49
90
91
+
bskyappdid, _ := utils.NewDID("did:plc:z72i7hdynmk6r22z27h6tvur")
92
+
93
+
profiletest2, _, _ := appbskyactordefs.ProfileViewDetailed(ctx, bskyappdid, sl, cs, BSKYIMAGECDN_URL)
94
+
95
+
data, err := json.MarshalIndent(profiletest2, "", " ")
96
+
if err != nil {
97
+
panic(err)
98
+
}
99
+
fmt.Println(string(data))
100
+
50
101
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
51
-
fmt.Fprintf(w, "hello worldio !")
102
+
log.Println("hello worldio !")
52
103
clientUUID := sticket.GetUUIDFromRequest(r)
53
104
hasSticket := clientUUID != ""
54
105
if hasSticket {
···
77
128
}
78
129
79
130
func getPostThreadV2(w http.ResponseWriter, r *http.Request) {
80
-
fmt.Fprintf(w, "hello worldio !")
131
+
log.Println("hello worldio !")
81
132
}
+124
shims/lex/app/bsky/actor/defs.go
+124
shims/lex/app/bsky/actor/defs.go
···
1
+
package appbskyactordefs
2
+
3
+
import (
4
+
"context"
5
+
"encoding/json"
6
+
7
+
"github.com/bluesky-social/indigo/api/agnostic"
8
+
appbsky "github.com/bluesky-social/indigo/api/bsky"
9
+
"tangled.org/whey.party/red-dwarf-server/microcosm"
10
+
"tangled.org/whey.party/red-dwarf-server/microcosm/constellation"
11
+
"tangled.org/whey.party/red-dwarf-server/microcosm/slingshot"
12
+
"tangled.org/whey.party/red-dwarf-server/shims/utils"
13
+
)
14
+
15
+
func ProfileViewBasic(ctx context.Context, did utils.DID, sl *microcosm.MicrocosmClient, imgcdn string) (*appbsky.ActorDefs_ProfileViewBasic, *appbsky.ActorProfile, error) {
16
+
profileview, profile, err := ProfileView(ctx, did, sl, imgcdn)
17
+
18
+
return &appbsky.ActorDefs_ProfileViewBasic{
19
+
Associated: profileview.Associated,
20
+
Avatar: profileview.Avatar,
21
+
CreatedAt: profileview.CreatedAt,
22
+
Debug: profileview.Debug,
23
+
Did: profileview.Did,
24
+
DisplayName: profileview.DisplayName,
25
+
Handle: profileview.Handle,
26
+
Labels: profileview.Labels,
27
+
Pronouns: profileview.Pronouns,
28
+
Status: profileview.Status,
29
+
Verification: profileview.Verification,
30
+
Viewer: profileview.Viewer,
31
+
}, profile, err
32
+
}
33
+
34
+
func ProfileView(ctx context.Context, did utils.DID, sl *microcosm.MicrocosmClient, imgcdn string) (*appbsky.ActorDefs_ProfileView, *appbsky.ActorProfile, error) {
35
+
identity, err_i := slingshot.ResolveMiniDoc(ctx, sl, string(did))
36
+
if err_i != nil {
37
+
identity = nil
38
+
}
39
+
profilerecord, err_r := agnostic.RepoGetRecord(ctx, sl, "", "app.bsky.actor.profile", string(did), "self")
40
+
if err_r != nil {
41
+
return nil, nil, err_r
42
+
}
43
+
44
+
var profile appbsky.ActorProfile
45
+
if err := json.Unmarshal(*profilerecord.Value, &profile); err != nil {
46
+
return nil, nil, err
47
+
}
48
+
49
+
var handle string
50
+
if identity != nil {
51
+
handle = identity.Handle
52
+
} else {
53
+
handle = string(did)
54
+
}
55
+
56
+
var displayName string
57
+
if profile.DisplayName != nil {
58
+
displayName = *profile.DisplayName
59
+
} else {
60
+
if handle != "" {
61
+
displayName = handle
62
+
} else {
63
+
displayName = string(did)
64
+
}
65
+
}
66
+
avatar := utils.MakeImageCDN(did, imgcdn, "avatar", profile.Avatar.Ref.String())
67
+
68
+
return &appbsky.ActorDefs_ProfileView{
69
+
Associated: nil,
70
+
Avatar: &avatar,
71
+
CreatedAt: profile.CreatedAt,
72
+
Debug: nil,
73
+
Description: profile.Description,
74
+
Did: string(did),
75
+
DisplayName: &displayName,
76
+
Handle: handle,
77
+
IndexedAt: profile.CreatedAt,
78
+
Labels: nil,
79
+
Pronouns: nil,
80
+
Status: nil,
81
+
Verification: nil,
82
+
Viewer: nil,
83
+
}, &profile, nil
84
+
}
85
+
86
+
func ProfileViewDetailed(ctx context.Context, did utils.DID, sl *microcosm.MicrocosmClient, cs *microcosm.MicrocosmClient, imgcdn string) (*appbsky.ActorDefs_ProfileViewDetailed, *appbsky.ActorProfile, error) {
87
+
profileview, profile, err := ProfileView(ctx, did, sl, imgcdn)
88
+
if err != nil {
89
+
return nil, nil, err
90
+
}
91
+
followerCount_Out, err_i := constellation.LegacyLinksCountDistinctDids(ctx, cs, string(did), "app.bsky.graph.follow", ".subject", nil)
92
+
if err_i != nil {
93
+
followerCount_Out = nil
94
+
}
95
+
followerCount := int64(followerCount_Out.Total)
96
+
97
+
banner := utils.MakeImageCDN(did, imgcdn, "banner", profile.Avatar.Ref.String())
98
+
99
+
nilCount := int64(-1)
100
+
101
+
return &appbsky.ActorDefs_ProfileViewDetailed{
102
+
Associated: profileview.Associated,
103
+
Avatar: profileview.Avatar,
104
+
Banner: &banner,
105
+
CreatedAt: profileview.CreatedAt,
106
+
Debug: profileview.Debug,
107
+
Description: profileview.Description,
108
+
Did: profileview.Did,
109
+
DisplayName: profileview.DisplayName,
110
+
FollowersCount: &followerCount,
111
+
FollowsCount: &nilCount, // hardcoded placeholder
112
+
Handle: profileview.Handle,
113
+
IndexedAt: profileview.IndexedAt,
114
+
JoinedViaStarterPack: nil, // hardcoded placeholder
115
+
Labels: profileview.Labels,
116
+
PinnedPost: profile.PinnedPost,
117
+
PostsCount: &nilCount, // hardcoded placeholder
118
+
Pronouns: profileview.Pronouns,
119
+
Status: profileview.Status,
120
+
Verification: profileview.Verification,
121
+
Viewer: profileview.Viewer,
122
+
Website: profile.Website,
123
+
}, profile, nil
124
+
}
+41
shims/utils/utils.go
+41
shims/utils/utils.go
···
1
+
package utils
2
+
3
+
import (
4
+
"fmt"
5
+
"regexp"
6
+
)
7
+
8
+
type DID string
9
+
10
+
var didPattern = regexp.MustCompile(`^did:(plc|web):.+$`)
11
+
12
+
func NewDID(s string) (DID, error) {
13
+
if !didPattern.MatchString(s) {
14
+
return "", fmt.Errorf("invalid DID: %s", s)
15
+
}
16
+
return DID(s), nil
17
+
}
18
+
19
+
type AtURI string
20
+
21
+
var atUriPattern = regexp.MustCompile(`^at://did:(plc|web):.+/.+/.+$`)
22
+
23
+
func NewAtURI(s string) (AtURI, error) {
24
+
if !atUriPattern.MatchString(s) {
25
+
return "", fmt.Errorf("invalid AtURI: %s", s)
26
+
}
27
+
return AtURI(s), nil
28
+
}
29
+
30
+
func SafeStringPtr(s *string) *string {
31
+
if s != nil {
32
+
return s
33
+
}
34
+
return nil
35
+
}
36
+
37
+
func PtrString(s string) *string { return &s }
38
+
39
+
func MakeImageCDN(did DID, imgcdn string, kind string, cid string) string {
40
+
return imgcdn + "/img/" + kind + "/plain/" + string(did) + "/" + cid + "@jpeg"
41
+
}