at_protocol 0.0.4.1 → 0.0.4.3

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: b9079f38f8b754c7aab1c556dd3b79e98a5f95ffa5091ce0a36f3f3da483b69d
4
- data.tar.gz: b3423fa8c0a4595f7afb81cbb823c38a58a6d5e609dff38ebe297b85dfd4c84b
3
+ metadata.gz: e0dd450b9e79e59d5df52330a9e0fd00135db4e2a8eddce654780133835ca69f
4
+ data.tar.gz: bda2354c8c63d85eee0075c5fda834e1018e31e9c8b5daba221695644998e338
5
5
  SHA512:
6
- metadata.gz: 066a7e0ba5ea613209e4b180be05c25c82251968fad5e7b611fa3200ae820ceb41268c1759d0ec77eb733aa410c8878cbd6890c61e7bf47ebd1171c364ca84ed
7
- data.tar.gz: b106124acf97f5d6443aae45adcf65eac04319d923f92e08e3404bb87c8912ab59ff7feb739ef9b0a377c9b23e83fa0789bed8ba8128dd5e8ad9be4d4a7c0dad
6
+ metadata.gz: 19eec8bd3383a55ae752ed3561bcced63c5a438fe1060dcd1a08fe46249e56d469b7ded6a026c73d82a84a78ef4fd2af35572ccd610fa854287b1babf43e3e8f
7
+ data.tar.gz: e8d0dc32c9e1a4101fb8dc30b0ca16a49955f3d096fbc75d36ce20486590cefb67df66c83268dabde43716495247706b6f8a7599a6b530a67b75d1b096c621db
@@ -0,0 +1,3 @@
1
+ require "mkmf"
2
+
3
+ create_makefile("at_protocol/tid")
@@ -0,0 +1,130 @@
1
+ #include <ruby.h>
2
+ #include <time.h>
3
+ #include <stdio.h>
4
+ #include <stdint.h>
5
+ #include <math.h>
6
+
7
+ static VALUE atproto_module;
8
+ static VALUE tid_class;
9
+ const char b32_chars[32] = "234567abcdefghijklmnopqrstuvwxyz";
10
+
11
+ typedef struct {
12
+ uint64_t timestamp;
13
+ uint64_t clock_identifier;
14
+ } TID;
15
+
16
+ static VALUE tid_alloc(VALUE klass) {
17
+ TID *tid = ALLOC(TID);
18
+ return Data_Wrap_Struct(klass, 0, xfree, tid);
19
+ }
20
+
21
+ static VALUE tid_initialize(int argc, VALUE *argv, VALUE self) {
22
+ VALUE time_arg = Qnil;
23
+ rb_scan_args(argc, argv, "01", &time_arg);
24
+
25
+ TID *tid;
26
+ Data_Get_Struct(self, TID, tid);
27
+
28
+ if (NIL_P(time_arg)) {
29
+ struct timeval tv;
30
+ gettimeofday(&tv, NULL);
31
+ tid->timestamp = (uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec;
32
+ } else {
33
+ if (!rb_obj_is_kind_of(time_arg, rb_cTime)) {
34
+ rb_raise(rb_eTypeError, "Argument must be a Time object or nil");
35
+ return Qnil;
36
+ }
37
+
38
+ struct timeval tv;
39
+ tv.tv_sec = NUM2LONG(rb_funcall(time_arg, rb_intern("tv_sec"), 0));
40
+ tv.tv_usec = NUM2LONG(rb_funcall(time_arg, rb_intern("tv_usec"), 0));
41
+ tid->timestamp = (uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec;
42
+ }
43
+
44
+ tid->clock_identifier = rand() & 0x3FF;
45
+
46
+ return self;
47
+ }
48
+
49
+ static VALUE tid_to_time(VALUE self) {
50
+ TID *tid;
51
+ Data_Get_Struct(self, TID, tid);
52
+
53
+ VALUE sec = LL2NUM(tid->timestamp / 1000000);
54
+ VALUE usec = LL2NUM(tid->timestamp % 1000000);
55
+
56
+ return rb_funcall(rb_cTime, rb_intern("at"), 2, sec, usec);
57
+ }
58
+
59
+ static VALUE tid_to_s(VALUE self) {
60
+ TID *tid;
61
+ Data_Get_Struct(self, TID, tid);
62
+
63
+ char tid_str[14];
64
+ for (int i = 0; i < 11; i++) {
65
+ int index = (int)((tid->timestamp >> (50 - i * 5)) & 0x1F);
66
+ tid_str[i] = b32_chars[index];
67
+ }
68
+ tid_str[11] = b32_chars[(int)(tid->clock_identifier >> 6) & 0x1F];
69
+ tid_str[12] = b32_chars[(int)tid->clock_identifier & 0x1F];
70
+ tid_str[13] = '\0';
71
+
72
+ return rb_str_new_cstr(tid_str);
73
+ }
74
+
75
+ static VALUE tid_from_string(VALUE klass, VALUE str) {
76
+ Check_Type(str, T_STRING);
77
+
78
+ TID *tid;
79
+ VALUE tid_obj = Data_Make_Struct(klass, TID, NULL, xfree, tid);
80
+
81
+ if (RSTRING_LEN(str) != 13) {
82
+ rb_raise(rb_eArgError, "TID string must be 13 characters long");
83
+ return Qnil;
84
+ }
85
+
86
+ char tid_str[14];
87
+ strncpy(tid_str, StringValueCStr(str), sizeof(tid_str));
88
+ tid_str[13] = '\0';
89
+
90
+ // Convert the TID string back to a TID object
91
+ uint64_t timestamp = 0;
92
+ for (int i = 0; i < 11; i++) {
93
+ char c = tid_str[i];
94
+ const char *pos = strchr(b32_chars, c);
95
+ if (pos == NULL) {
96
+ rb_raise(rb_eArgError, "Invalid character in TID string");
97
+ return Qnil;
98
+ }
99
+ int index = (int)(pos - b32_chars);
100
+ timestamp = (timestamp << 5) | (index & 0x1F);
101
+ }
102
+
103
+ uint64_t clock_identifier = 0;
104
+ for (int i = 11; i < 13; i++) {
105
+ char c = tid_str[i];
106
+ const char *pos = strchr(b32_chars, c);
107
+ if (pos == NULL) {
108
+ rb_raise(rb_eArgError, "Invalid character in TID string");
109
+ return Qnil;
110
+ }
111
+ int index = (int)(pos - b32_chars);
112
+ clock_identifier = (clock_identifier << 5) | (index & 0x1F);
113
+ }
114
+
115
+ tid->timestamp = timestamp;
116
+ tid->clock_identifier = clock_identifier;
117
+
118
+ return tid_obj;
119
+ }
120
+
121
+ void Init_tid(void) {
122
+ atproto_module = rb_define_module("ATProto");
123
+
124
+ tid_class = rb_define_class_under(atproto_module, "TID", rb_cObject);
125
+ rb_define_alloc_func(tid_class, tid_alloc);
126
+ rb_define_method(tid_class, "initialize", tid_initialize, -1);
127
+ rb_define_method(tid_class, "to_time", tid_to_time, 0);
128
+ rb_define_method(tid_class, "to_s", tid_to_s, 0);
129
+ rb_define_singleton_method(tid_class, "from_string", tid_from_string, 1);
130
+ }
@@ -13,6 +13,10 @@ module ATProto
13
13
 
14
14
  module_function :at_uri
15
15
  end
16
+
17
+ def self.AtUri(str)
18
+ RequestUtils.at_uri(str)
19
+ end
16
20
  end
17
21
 
18
22
  module ATProto
@@ -9,22 +9,10 @@ module ATProto
9
9
  const(:repo, ATProto::Repo)
10
10
  const(:collection, String)
11
11
 
12
- sig { params(limit: Integer).returns(T::Array[ATProto::Record]) }
13
-
14
- def list(limit = 10)
15
- self.repo.xrpc
16
- .get.com_atproto_repo_listRecords(
17
- repo: self.repo.did,
18
- collection: self.collection,
19
- limit: limit,
20
- )["records"]
21
- .map { |record|
22
- ATProto::Record.from_hash(record)
23
- }
24
- end
12
+ sig { params(count: T.nilable(Integer)).returns(T::Array[ATProto::Record]) }
25
13
 
26
- def list_all()
27
- T.must(get_paginated_data(self.repo, :com_atproto_repo_listRecords.to_s, key: "records", params: { repo: self.repo.to_s, collection: self.to_s }, cursor: nil) do |record|
14
+ def list(count = nil)
15
+ T.must(get_paginated_data(self.repo, :com_atproto_repo_listRecords.to_s, key: "records", params: { repo: self.repo.to_s, collection: self.to_s }, count: count, cursor: nil) do |record|
28
16
  ATProto::Record.from_hash(record)
29
17
  end)
30
18
  end
@@ -78,6 +78,9 @@ module ATProto
78
78
  cursor: T.nilable(
79
79
  String
80
80
  ),
81
+ count: T.nilable(
82
+ Integer
83
+ ),
81
84
  map_block: T.nilable(Proc),
82
85
  )
83
86
  .returns(T
@@ -86,7 +89,7 @@ module ATProto
86
89
  ))
87
90
  }
88
91
 
89
- def get_paginated_data(session, method, key:, params:, cursor: nil, &map_block)
92
+ def get_paginated_data(session, method, key:, params:, cursor: nil, count: nil, &map_block)
90
93
  params.merge({ limit: 100, cursor: cursor }).then do |send_data|
91
94
  session.xrpc.get.public_send(method, **send_data).then do |response|
92
95
  response.dig(key).then do |data|
@@ -94,26 +97,19 @@ module ATProto
94
97
  return []
95
98
  end
96
99
 
97
- if block_given?
98
- data.map(&map_block).then do |results|
99
- response.dig("cursor").then do |next_cursor|
100
- if next_cursor.nil?
101
- return results
102
- else
103
- get_paginated_data(session, method, key: key, params: params, cursor: next_cursor, &map_block).then do |next_results|
104
- return results + next_results
105
- end
106
- end
107
- end
100
+ results = if block_given?
101
+ data.map(&map_block)
102
+ else
103
+ data
108
104
  end
109
- else
110
- response.dig("cursor").then do |next_cursor|
111
- if next_cursor.nil?
112
- return data
113
- else
114
- get_paginated_data(session, method, key: key, params: params, cursor: next_cursor, &map_block).then do |next_results|
115
- return data + next_results
116
- end
105
+
106
+ response.dig("cursor").then do |next_cursor|
107
+ if next_cursor.nil? || (count && results.length >= count)
108
+ return results[0..count]
109
+ else
110
+ remaining_count = count ? count - results.length : nil
111
+ get_paginated_data(session, method, key: key, params: params, cursor: next_cursor, count: remaining_count, &map_block).then do |next_results|
112
+ return (results + next_results)
117
113
  end
118
114
  end
119
115
  end
@@ -123,3 +119,26 @@ module ATProto
123
119
  end
124
120
  end
125
121
  end
122
+
123
+ module ATProto
124
+ module RequestUtils
125
+ class XRPCResponseCode < T::Enum
126
+ enums do
127
+ Unknown = new(1)
128
+ InvalidResponse = new(2)
129
+ Success = new(200)
130
+ InvalidRequest = new(400)
131
+ AuthRequired = new(401)
132
+ Forbidden = new(403)
133
+ XRPCNotSupported = new(404)
134
+ PayloadTooLarge = new(413)
135
+ RateLimitExceeded = new(429)
136
+ InternalServerError = new(500)
137
+ MethodNotImplemented = new(501)
138
+ UpstreamFailure = new(502)
139
+ NotEnoughResouces = new(503)
140
+ UpstreamTimeout = new(504)
141
+ end
142
+ end
143
+ end
144
+ end
@@ -66,6 +66,10 @@ module ATProto
66
66
  raise UnauthorizedError
67
67
  end
68
68
  end
69
+
70
+ def inspect
71
+ "#<ATProto::Session(did: #{did}, access_token: #{access_token})>"
72
+ end
69
73
  end
70
74
  end
71
75
 
@@ -0,0 +1,19 @@
1
+ require "at_protocol/tid"
2
+
3
+ class Time
4
+ def to_tid
5
+ ATProto::TID.new(self)
6
+ end
7
+ end
8
+
9
+ class String
10
+ def to_tid
11
+ ATProto::TID.from_string(self)
12
+ end
13
+ end
14
+
15
+ class ATProto::TID
16
+ def inspect
17
+ "#<ATProto::TID(#{self.to_s})>"
18
+ end
19
+ end
@@ -1,4 +1,4 @@
1
1
  # typed: strict
2
2
  module ATProto
3
- VERSION = "0.0.4.1"
3
+ VERSION = "0.0.4.3"
4
4
  end
@@ -1,5 +1,7 @@
1
1
  # typed: true
2
2
  module ATProto
3
+ extend T::Sig
4
+
3
5
  class Writes < T::Struct
4
6
  class Write < T::Struct
5
7
  class Action < T::Enum
@@ -101,14 +103,13 @@ module ATProto
101
103
 
102
104
  class << self
103
105
  extend T::Sig
104
- sig { params(block: Proc).returns(T::Array[Write]) }
105
-
106
- def generate(&block)
107
- Collector.new.instance_eval(&block)
108
- end
109
106
  end
110
107
  end
111
108
 
109
+ def self.Writes(session, &block)
110
+ Writes.new(writes: Writes::Collector.new.instance_eval(&block), session: session, repo: Repo.new(session.did))
111
+ end
112
+
112
113
  class Writes
113
114
  class Collector
114
115
  include RequestUtils
data/lib/at_protocol.rb CHANGED
@@ -15,9 +15,21 @@ class Class
15
15
  end
16
16
  end
17
17
 
18
+ module ATProto
19
+ class << self
20
+ def method_missing(method_name, *args, &block)
21
+ if const_defined?(method_name)
22
+ Object.const_get(method_name).new(*args, &block)
23
+ else
24
+ super
25
+ end
26
+ end
27
+ end
28
+ end
29
+
18
30
  require "skyfall/cid"
19
31
  require "xrpc"
20
32
 
21
- %w(requests session repo collection at_uri writes record record/strongref).each do |name|
33
+ %w(requests session repo collection at_uri writes record record/strongref tid_ext).each do |name|
22
34
  require "at_protocol/#{name}"
23
35
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: at_protocol
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4.1
4
+ version: 0.0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shreyan Jain
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-09-01 00:00:00.000000000 Z
12
+ date: 2023-10-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: xrpc
@@ -25,13 +25,30 @@ dependencies:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: 0.1.5
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake-compiler
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
28
42
  description: A Ruby gem for interacting with AT Protocol
29
43
  email:
30
44
  - shreyan.jain.9@outlook.com
31
45
  executables: []
32
- extensions: []
46
+ extensions:
47
+ - ext/at_protocol/extconf.rb
33
48
  extra_rdoc_files: []
34
49
  files:
50
+ - "./ext/at_protocol/extconf.rb"
51
+ - "./ext/at_protocol/tid.c"
35
52
  - "./lib/at_protocol.rb"
36
53
  - "./lib/at_protocol/at_uri.rb"
37
54
  - "./lib/at_protocol/collection.rb"
@@ -40,8 +57,10 @@ files:
40
57
  - "./lib/at_protocol/repo.rb"
41
58
  - "./lib/at_protocol/requests.rb"
42
59
  - "./lib/at_protocol/session.rb"
60
+ - "./lib/at_protocol/tid_ext.rb"
43
61
  - "./lib/at_protocol/version.rb"
44
62
  - "./lib/at_protocol/writes.rb"
63
+ - ext/at_protocol/extconf.rb
45
64
  homepage: https://github.com/ShreyanJain9/at_protocol
46
65
  licenses:
47
66
  - MIT
@@ -50,6 +69,7 @@ post_install_message:
50
69
  rdoc_options: []
51
70
  require_paths:
52
71
  - lib
72
+ - ext
53
73
  required_ruby_version: !ruby/object:Gem::Requirement
54
74
  requirements:
55
75
  - - ">="