tangled
alpha
login
or
join now
mackuba.eu
/
didkit
1
fork
atom
A library for handling DID identifiers used in Bluesky AT Protocol
1
fork
atom
overview
issues
pulls
pipelines
added PLCImporter
mackuba.eu
2 years ago
617c1166
f59f08af
+131
3 changed files
expand all
collapse all
unified
split
lib
didkit
plc_importer.rb
plc_operation.rb
didkit.rb
+2
lib/didkit.rb
···
2
2
3
3
require_relative "didkit/did"
4
4
require_relative "didkit/document"
5
5
+
require_relative "didkit/plc_importer"
6
6
+
require_relative "didkit/plc_operation"
5
7
require_relative "didkit/resolver"
6
8
require_relative "didkit/version"
7
9
+73
lib/didkit/plc_importer.rb
···
1
1
+
require 'json'
2
2
+
require 'open-uri'
3
3
+
require 'time'
4
4
+
5
5
+
require_relative 'plc_operation'
6
6
+
7
7
+
module DIDKit
8
8
+
class PLCImporter
9
9
+
PLC_SERVICE = 'plc.directory'
10
10
+
MAX_PAGE = 1000
11
11
+
12
12
+
attr_accessor :ignore_errors, :last_date
13
13
+
14
14
+
def initialize(since: nil)
15
15
+
if since.to_s == 'beginning'
16
16
+
@last_date = nil
17
17
+
elsif since.is_a?(String)
18
18
+
@last_date = Time.parse(since)
19
19
+
elsif since
20
20
+
@last_date = since
21
21
+
else
22
22
+
@last_date = Time.now
23
23
+
@eof = true
24
24
+
end
25
25
+
26
26
+
@ignore_errors = false
27
27
+
end
28
28
+
29
29
+
def plc_service
30
30
+
PLC_SERVICE
31
31
+
end
32
32
+
33
33
+
def get_export(args = {})
34
34
+
url = URI("https://#{plc_service}/export")
35
35
+
url.query = URI.encode_www_form(args)
36
36
+
37
37
+
data = URI.open(url).read
38
38
+
data.lines.map(&:strip).reject(&:empty?).map { |x| JSON.parse(x) }
39
39
+
end
40
40
+
41
41
+
def fetch_page
42
42
+
request_time = Time.now
43
43
+
44
44
+
query = @last_date ? { :after => @last_date.utc.iso8601(6) } : {}
45
45
+
rows = get_export(query)
46
46
+
47
47
+
operations = rows.filter_map do |json|
48
48
+
begin
49
49
+
PLCOperation.new(json)
50
50
+
rescue PLCOperation::FormatError => e
51
51
+
ignore_errors ? nil : raise
52
52
+
end
53
53
+
end
54
54
+
55
55
+
@last_date = operations.last&.created_at || request_time
56
56
+
@eof = (rows.length < MAX_PAGE)
57
57
+
58
58
+
operations
59
59
+
end
60
60
+
61
61
+
def fetch(&block)
62
62
+
loop do
63
63
+
operations = fetch_page
64
64
+
block.call(operations)
65
65
+
break if eof?
66
66
+
end
67
67
+
end
68
68
+
69
69
+
def eof?
70
70
+
!!@eof
71
71
+
end
72
72
+
end
73
73
+
end
+56
lib/didkit/plc_operation.rb
···
1
1
+
require 'time'
2
2
+
3
3
+
module DIDKit
4
4
+
class PLCOperation
5
5
+
class FormatError < StandardError
6
6
+
end
7
7
+
8
8
+
attr_reader :did, :created_at, :type, :pds_endpoint, :handles
9
9
+
10
10
+
def initialize(json)
11
11
+
@did = json['did']
12
12
+
raise FormatError, "Missing DID" if @did.nil?
13
13
+
raise FormatError, "Invalid DID" unless @did.is_a?(String) && @did.start_with?('did:')
14
14
+
15
15
+
timestamp = json['createdAt']
16
16
+
raise FormatError, "Missing createdAt" if timestamp.nil?
17
17
+
raise FormatError, "Invalid createdAt" unless timestamp.is_a?(String)
18
18
+
19
19
+
@created_at = Time.parse(timestamp)
20
20
+
21
21
+
operation = json['operation']
22
22
+
raise FormatError, "Missing operation key" if operation.nil?
23
23
+
raise FormatError, "Invalid operation data" unless operation.is_a?(Hash)
24
24
+
25
25
+
type = operation['type']
26
26
+
raise FormatError, "Missing type" if type.nil?
27
27
+
28
28
+
@type = type.to_sym
29
29
+
return unless @type == :plc_operation
30
30
+
31
31
+
services = operation['services']
32
32
+
raise FormatError, "Missing services key" if services.nil?
33
33
+
raise FormatError, "Invalid services data" unless services.is_a?(Hash)
34
34
+
35
35
+
if pds = services['atproto_pds']
36
36
+
raise FormatError, "Invalid PDS data" unless pds.is_a?(Hash)
37
37
+
raise FormatError, "Missing PDS type" unless pds['type']
38
38
+
raise FormatError, "Invalid PDS type" unless pds['type'] == 'AtprotoPersonalDataServer'
39
39
+
raise FormatError, "Missing PDS endpoint" unless pds['endpoint']
40
40
+
raise FormatError, "Invalid PDS endpoint" unless pds['endpoint'].is_a?(String) && pds['endpoint'] =~ %r(://)
41
41
+
42
42
+
@pds_endpoint = pds['endpoint']
43
43
+
end
44
44
+
45
45
+
if aka = operation['alsoKnownAs']
46
46
+
raise FormatError, "Invalid alsoKnownAs" unless aka.is_a?(Array)
47
47
+
raise FormatError, "Invalid alsoKnownAs" unless aka.all? { |x| x.is_a?(String) }
48
48
+
raise FormatError, "Invalid alsoKnownAs" unless aka.all? { |x| x =~ %r(\Aat://[^/]+\z) }
49
49
+
50
50
+
@handles = aka.map { |x| x.gsub('at://', '') }
51
51
+
else
52
52
+
@handles = []
53
53
+
end
54
54
+
end
55
55
+
end
56
56
+
end