this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add initial selector structure

Paul Frazee 1d49d154 eebba3d9

+180
+111
cmd/butterfly/README.md
··· 1 + # Butterfly 2 + 3 + A sync engine for atproto with an optional baked-in database. 4 + 5 + ## Example selectors 6 + 7 + My data: 8 + 9 + ```json 10 + { 11 + "select": [ 12 + { 13 + "where": {"repo": "at://pfrazee.com"}, 14 + "tag": "user" 15 + } 16 + ], 17 + "retain": { 18 + "user": {"*": "*"}, 19 + } 20 + } 21 + ``` 22 + 23 + A list of repos: 24 + 25 + ```json 26 + { 27 + "select": [ 28 + {"where": {"repo": "at://pfrazee.com"}, "tag": "user"}, 29 + {"where": {"repo": "at://atproto.com"}, "tag": "user"}, 30 + {"where": {"repo": "at://bsky.app"}, "tag": "user"} 31 + ], 32 + "retain": { 33 + "user": {"*": "*"}, 34 + } 35 + } 36 + ``` 37 + 38 + My personal network: 39 + 40 + ```json 41 + { 42 + "select": [ 43 + { 44 + "where": {"repo": "at://pfrazee.com"}, 45 + "tag": "me" 46 + }, 47 + { 48 + "where": {"repo": "me", "collection": "app.bsky.graph.follow", "attr": "subject"}, 49 + "tag": "followed" 50 + }, 51 + { 52 + "where": {"repo": "followed", "collection": "app.bsky.graph.follow", "attr": "subject"}, 53 + "tag": "k2-followed" 54 + } 55 + ], 56 + "retain": { 57 + "me": {"*": "*"}, 58 + "followed": : {"*": "*"}, 59 + "k2-followed": { 60 + "app.bsky.actor.profile": "self", 61 + "app.bsky.graph.follow": "latest:3000", 62 + "app.bsky.feed.post": "latest:10", 63 + "app.bsky.feed.repost": "latest:10", 64 + "app.bsky.feed.like": "latest:100", 65 + "app.bsky.*": "latest:1000" 66 + } 67 + } 68 + } 69 + ``` 70 + 71 + Recursive crawl from me: 72 + 73 + ```json 74 + { 75 + "select": [ 76 + { 77 + "where": {"repo": "at://pfrazee.com"}, 78 + "tag": "user" 79 + }, 80 + { 81 + "where": {"repo": "user", "collection": "app.bsky.graph.follow", "attr": "subject"}, 82 + "tag": "user" 83 + } 84 + ], 85 + "retain": { 86 + "user": {"*": "*"}, 87 + } 88 + } 89 + ``` 90 + 91 + All users tracked by bluesky's collection index: 92 + 93 + ```json 94 + { 95 + "select": [ 96 + { 97 + "where": { 98 + "service": "bsky.network", 99 + "method": "com.atproto.sync.listReposByCollection", 100 + "params": {"collection": "app.bsky.actor.profile"}, 101 + "attr": "repos.*.did", 102 + "pagination": {"param": "cursor", "attr": "cursor"} 103 + }, 104 + "tag": "bluesky-user" 105 + } 106 + ], 107 + "retain": { 108 + "bluesky-user": {"app.bsky.*": "*"} 109 + } 110 + } 111 + ```
+16
cmd/butterfly/main.go
··· 1 + package main 2 + 3 + import ( 4 + "encoding/json" 5 + "fmt" 6 + ) 7 + 8 + func main() { 9 + fmt.Println(WhereClause{}) 10 + fmt.Println(WhereClause{Repo: "pfrazee.com", Collection: "app.bsky.graph.follow", Attr: "subject"}) 11 + 12 + docJson := `{"select": [{"where": {"repo": "pfrazee.com"},"tag": "user"}],"retain": {"user": {"*": "*"}}}` 13 + var doc SelectorDoc 14 + json.Unmarshal([]byte(docJson), &doc) 15 + fmt.Println((doc)) 16 + }
+53
cmd/butterfly/selectors.go
··· 1 + /* 2 + Query patterns for selecting content to sync and retain 3 + */ 4 + 5 + package main 6 + 7 + import "fmt" 8 + 9 + type SelectorDoc struct { 10 + Selectors []Selector `json:"select"` 11 + Retainers Retainer `json:"retain"` 12 + } 13 + 14 + type Selector struct { 15 + Where WhereClause `json:"where"` 16 + Tag string `json:"tag"` 17 + } 18 + 19 + type WhereClause struct { 20 + Repo string `json:"repo"` 21 + Collection string `json:"collection"` 22 + Attr string `json:"attr"` 23 + Service string `json:"service"` 24 + Method string `json:"method"` 25 + Params map[string]string `json:"params"` 26 + Pagination map[string]string `json:"pagination"` 27 + } 28 + 29 + type Retainer map[string]map[string]string 30 + 31 + func (self SelectorDoc) String() string { 32 + return fmt.Sprintf("%s retain=%s", self.Selectors, self.Retainers) 33 + } 34 + 35 + func (self Selector) String() string { 36 + if self.Tag == "" { 37 + return "(Invalid selector)" 38 + } 39 + return fmt.Sprintf("%s,tag=%s", self.Where, self.Tag) 40 + } 41 + 42 + func (self WhereClause) String() string { 43 + if self.Repo != "" && self.Collection != "" && self.Attr != "" { 44 + return fmt.Sprintf("where=at://%s/%s/*#%s", self.Repo, self.Collection, self.Attr) 45 + } 46 + if self.Repo != "" { 47 + return fmt.Sprintf("where=at://%s", self.Repo) 48 + } 49 + if self.Service != "" && self.Method != "" && self.Attr != "" { 50 + return fmt.Sprintf("where=https://%s/_xrpc/%s/*#%s", self.Service, self.Method, self.Attr) 51 + } 52 + return "where=(Invalid clause)" 53 + }