bskyrb 0.3 → 0.5

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