bskyrb 0.4 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d3ebcdf8ed7dabe9c22cf650ffecec5c8883d72b32c29baae4a44f40f94365bd
4
- data.tar.gz: d3ad042fa4d4a1b2e62e53ca2aae552078b7aa3f78f1c612b1a6fc568f3b0c61
3
+ metadata.gz: 3ae64c99f896f5ec3366f9c4e028d61c9006563351c34be989881ccb4fac52d9
4
+ data.tar.gz: 57903df97da314a87e257fad02d8536ad783ea88511c2f5b7efbf774ad36b4b4
5
5
  SHA512:
6
- metadata.gz: 8e6ab71de741b377398c4a651d3b34406b0f1c0fa3d5c1d9c3721976dacec12146ecf8900a9a33a38feaf75f2db45320723e5f1967587456d1200b16d2fe7130
7
- data.tar.gz: a022a0f04a37a4c4be4dab37fa9a9d2e348f3ff0c541ae02a8422ec3149d466d900465c90f834c0811163b12f43fde4789288607ce7d1a2faf0b4b2fc7efcaed
6
+ metadata.gz: 447074d457ecb73774ce6e355f3cd18820b13e508c58f144361105b8bb1bf6fe7547ac994d62c5a2fbdec49b3d56b96fd8fdcadfeb6d967cc521e983c7a84f26
7
+ data.tar.gz: f3440ccc3800260c21481da110ea68aa40e4d48ca70ab1e6292d80435820f389f0f59f3f02c31029812d2d9335d42cbddcefc3f40c1e667d0a21e139642e5d7c
@@ -0,0 +1,212 @@
1
+ # typed: false
2
+ require "json"
3
+ require "erb"
4
+
5
+ module Bskyrb
6
+ module LexiconParser
7
+ @@active_namespace = ""
8
+
9
+ def self.def_is_query(defn)
10
+ defn["defs"].has_key?("main") &&
11
+ defn["defs"]["main"].has_key?("type") &&
12
+ defn["defs"]["main"]["type"] == "query"
13
+ end
14
+
15
+ def self.def_is_subscription(defn)
16
+ defn["defs"].has_key?("main") &&
17
+ defn["defs"]["main"].has_key?("type") &&
18
+ defn["defs"]["main"]["type"] == "subscription"
19
+ end
20
+
21
+ def self.def_is_procedure(defn)
22
+ defn["defs"].has_key?("main") &&
23
+ defn["defs"]["main"].has_key?("type") &&
24
+ defn["defs"]["main"]["type"] == "procedure"
25
+ end
26
+
27
+ def self.build_classes_hash_from_lexicon_defs(lexicon_file)
28
+ parsed = File.open(lexicon_file) { |f| JSON.parse(f.read) }
29
+ output = {}
30
+ # return if def_is_query(parsed) || def_is_procedure(parsed) || def_is_subscription(parsed)
31
+ parsed["defs"].each do |k, v| # map {|v| build_class_hash_from_schema(v)}
32
+ next if v["type"] == "main" # skip queries, procedures, etc.
33
+ @@active_namespace = parsed["id"].split(".").map(&:capitalize).join("")
34
+ next if k == "main"
35
+ output[ref_to_class_str(k)] = if v["type"] == "record"
36
+ build_class_hash_from_schema(v["record"]["properties"])
37
+ else
38
+ build_class_hash_from_schema(v)
39
+ end
40
+ end
41
+ output
42
+ end
43
+
44
+ def self.build_queries_and_procedures_from_lexicon(lexicon_file)
45
+ parsed = File.open(lexicon_file) { |f| JSON.parse(f.read) }
46
+ output = {}
47
+ return unless def_is_query(parsed) || def_is_procedure(parsed)
48
+ parsed["defs"].each do |k, v| # map {|v| build_class_hash_from_schema(v)}
49
+ next if k != "main" || v["type"] == "record" # skip basic defs
50
+ next if v["type"] == "subscription" # some day
51
+ @@active_namespace = parsed["id"].split(".").map(&:capitalize).join("")
52
+ class_name = ref_to_class_str(parsed["id"].split(".").last)
53
+ built_def = {}
54
+ output[class_name] = {}
55
+ if v["type"] == "query"
56
+ built_def["input"] = build_class_hash_from_schema(v["parameters"])
57
+ if v["output"] && v["output"]["schema"]
58
+ built_def["output"] = build_class_hash_from_schema(v["output"]["schema"])
59
+ end
60
+ end
61
+ if v["type"] == "procedure"
62
+ if v["input"]
63
+ built_def["input"] = build_class_hash_from_schema(v["input"]["schema"])
64
+ end
65
+ if v["output"] && v["output"]["schema"]
66
+ built_def["output"] = build_class_hash_from_schema(v["output"]["schema"])
67
+ end
68
+ end
69
+ output[class_name] = built_def unless built_def.empty?
70
+ end
71
+ output
72
+ end
73
+
74
+ def self.build_class_hash_from_schema(json_schema, output = {})
75
+ return if json_schema.nil?
76
+ return if json_schema.has_key? "main"
77
+ to_process = json_schema["properties"] || json_schema
78
+ to_process.each_pair do |key, value|
79
+ if key == "type" || !value.is_a?(Hash) # || value["type"] == "query" || key == "main"
80
+ next
81
+ end
82
+
83
+ output[key] = if value["type"] == "object"
84
+ build_class_hash_from_schema(value, {})
85
+ elsif value["type"] == "array"
86
+ [build_class_hash_from_schema(value, {}).values.first]
87
+ elsif value["type"] == "ref"
88
+ ref_to_class_str(value["ref"])
89
+ else
90
+ -1
91
+ end
92
+ end
93
+ output
94
+ end
95
+
96
+ def self.ref_to_class_str(ref, ns = @@active_namespace)
97
+ klass_str_lower = ref.split("#")[-1]
98
+ klass_str = klass_str_lower[0].capitalize + klass_str_lower.slice(1..)
99
+ ns += "::" if ns
100
+ "#{ns}#{klass_str}"
101
+ end
102
+
103
+ def self.basic_template
104
+ %(
105
+ module <%= klass_str.split("::").first %>
106
+ class <%= klass_str.split("::").last %>
107
+ <% properties.each do |key, value| %>
108
+ attr_accessor :<%= key %>
109
+ <% end %>
110
+
111
+ def self.from_hash(hash)
112
+ # httparty-returned string-keyed hash
113
+ instance = new
114
+ <% properties.each do |key, value| %>
115
+ instance.send("<%= key %>=", hash["<%= key %>"])
116
+ <% end %>
117
+ instance
118
+ end
119
+ end
120
+ end
121
+ )
122
+ end
123
+
124
+ def self.basic_class_definitions(classes_hash)
125
+ classes_hash.map do |klass_str, properties|
126
+ ERB.new(basic_template).result_with_hash({klass_str: klass_str, properties: properties})
127
+ end
128
+ end
129
+
130
+ def self.input_output_template
131
+ %(
132
+ module <%= klass_str.split("::").first %>
133
+ module <%= klass_str.split("::").last %>
134
+ <% ["input", "output"].each do |top_level_key| %>
135
+ <% next unless properties.has_key?(top_level_key) && !properties[top_level_key].nil? %>
136
+ class <%= top_level_key.capitalize %>
137
+ <% properties[top_level_key].each do |key, value| %>
138
+ attr_accessor :<%= key %>
139
+ <% end %>
140
+
141
+ def self.from_hash(hash)
142
+ # httparty-returned string-keyed hash
143
+ instance = new
144
+ <% properties[top_level_key].each do |key, value| %>
145
+ instance.send("<%= key %>=", hash["<%= key %>"])
146
+ <% end %>
147
+ instance
148
+ end
149
+
150
+ def to_h
151
+ {
152
+ <% properties[top_level_key].each do |key, value| %>
153
+ "<%= key %>" => <%= key %>,
154
+ <% end %>
155
+ }
156
+ end
157
+ end
158
+ <% end %>
159
+ end
160
+ end
161
+ )
162
+ end
163
+
164
+ def self.input_output_class_definitions(classes_hash)
165
+ classes_hash.map do |klass_str, properties|
166
+ ERB.new(input_output_template).result_with_hash({klass_str: klass_str, properties: properties})
167
+ end
168
+ end
169
+ end
170
+
171
+ class DynamicClassFromHash
172
+ def self.from_hash(hash)
173
+ hash.each do |klass_sym, properties|
174
+ Object.const_set(klass_sym, Class.new do
175
+ attr_accessor(*properties.keys.map(&:to_sym))
176
+
177
+ def self.from_hash(properties)
178
+ # httparty-returned string-keyed hash body
179
+ instance = new
180
+ properties.each do |key, value|
181
+ instance.send("#{key}=", value)
182
+ end
183
+ instance
184
+ end
185
+ end)
186
+ end
187
+ end
188
+ end
189
+ end
190
+
191
+ if __FILE__ == $0
192
+ basic_defs = {}
193
+ Dir["atproto/lexicons/**/*.json"].each do |file|
194
+ hashes = Bskyrb::LexiconParser.build_classes_hash_from_lexicon_defs(file)
195
+ basic_defs = basic_defs.merge(hashes) unless hashes.empty?
196
+ end
197
+
198
+ input_output_defs = {}
199
+ Dir["atproto/lexicons/**/*.json"].each do |file|
200
+ hashes = Bskyrb::LexiconParser.build_queries_and_procedures_from_lexicon(file)
201
+ input_output_defs = input_output_defs.merge(hashes) unless hashes.nil? || hashes.empty?
202
+ end
203
+
204
+ File.open("lib/bskyrb/generated_classes.rb", "w") do |f|
205
+ f.puts "module Bskyrb"
206
+ f.puts Bskyrb::LexiconParser.basic_class_definitions(basic_defs)
207
+ f.puts Bskyrb::LexiconParser.input_output_class_definitions(input_output_defs)
208
+ f.puts "end"
209
+ end
210
+ `bin/format`
211
+ `bundle exec rbs prototype rb lib/bskyrb/generated_classes.rb > sig/generated_classes.rbs`
212
+ end
@@ -0,0 +1,10 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module Bskyrb
5
+ class Error < StandardError; end
6
+
7
+ class HTTPError < Error; end
8
+
9
+ class UnauthorizedError < HTTPError; end
10
+ end
@@ -0,0 +1,37 @@
1
+ # typed: false
2
+ require "faye/websocket"
3
+ require "eventmachine"
4
+ require "cbor"
5
+ require "json"
6
+
7
+ EM.run {
8
+ ws = Faye::WebSocket::Client.new("wss://bsky.social/xrpc/com.atproto.sync.subscribeRepos")
9
+
10
+ ws.on :open do |event|
11
+ p [:open]
12
+ ws.send("Hello, world!")
13
+ end
14
+
15
+ ws.on :message do |event|
16
+ msg_bytes = event.data
17
+ unpacker = CBOR::Unpacker.new(StringIO.new(msg_bytes.pack("C*")))
18
+ header, payload = unpacker.each.to_a
19
+
20
+ # decoder = CBOR::Decoding.new(StringIO.new(msg_bytes.pack('C*')))
21
+ # while item = decoder.read
22
+ # puts item
23
+ # end
24
+
25
+ if payload["ops"].first["path"].include? "app.bsky.feed.post"
26
+ # payload#["blocks"].length
27
+ decoded = CBOR.decode(payload)
28
+
29
+ # Convert the decoded object to JSON
30
+ json = decoded.to_json
31
+
32
+ # Print the JSON object
33
+ puts json
34
+ end
35
+ end
36
+ }
37
+ # end