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