bskyrb 0.4 → 0.5.1

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: 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