bskyrb 0.3 → 0.5

Sign up to get free protection for your applications and to get access to all the features.
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