tangled
alpha
login
or
join now
zzstoatzz.io
/
zat
1
fork
atom
atproto tools in zig
zat.dev
sdk
atproto
zig
1
fork
atom
overview
issues
pulls
pipelines
fix: use zig 0.15 apis (ArrayList, http.Client.fetch)
zzstoatzz.io
2 months ago
01b5723e
1573973a
+61
-89
3 changed files
expand all
collapse all
unified
split
src
internal
did_document.zig
did_resolver.zig
xrpc.zig
+12
-12
src/internal/did_document.zig
···
85
85
errdefer allocator.free(id);
86
86
87
87
// parse alsoKnownAs -> handles
88
88
-
var handles = std.ArrayList([]const u8).init(allocator);
88
88
+
var handles: std.ArrayList([]const u8) = .empty;
89
89
errdefer {
90
90
for (handles.items) |h| allocator.free(h);
91
91
-
handles.deinit();
91
91
+
handles.deinit(allocator);
92
92
}
93
93
94
94
if (obj.get("alsoKnownAs")) |aka| {
···
101
101
s[5..]
102
102
else
103
103
s;
104
104
-
try handles.append(try allocator.dupe(u8, h));
104
104
+
try handles.append(allocator, try allocator.dupe(u8, h));
105
105
}
106
106
}
107
107
}
108
108
}
109
109
110
110
// parse verificationMethod
111
111
-
var vms = std.ArrayList(VerificationMethod).init(allocator);
111
111
+
var vms: std.ArrayList(VerificationMethod) = .empty;
112
112
errdefer {
113
113
for (vms.items) |vm| {
114
114
allocator.free(vm.id);
···
116
116
allocator.free(vm.controller);
117
117
allocator.free(vm.public_key_multibase);
118
118
}
119
119
-
vms.deinit();
119
119
+
vms.deinit(allocator);
120
120
}
121
121
122
122
if (obj.get("verificationMethod")) |vm_arr| {
···
130
130
.controller = try allocator.dupe(u8, getStr(vm_obj, "controller") orelse ""),
131
131
.public_key_multibase = try allocator.dupe(u8, getStr(vm_obj, "publicKeyMultibase") orelse ""),
132
132
};
133
133
-
try vms.append(vm);
133
133
+
try vms.append(allocator, vm);
134
134
}
135
135
}
136
136
}
137
137
}
138
138
139
139
// parse service
140
140
-
var svcs = std.ArrayList(Service).init(allocator);
140
140
+
var svcs: std.ArrayList(Service) = .empty;
141
141
errdefer {
142
142
for (svcs.items) |svc| {
143
143
allocator.free(svc.id);
144
144
allocator.free(svc.type);
145
145
allocator.free(svc.service_endpoint);
146
146
}
147
147
-
svcs.deinit();
147
147
+
svcs.deinit(allocator);
148
148
}
149
149
150
150
if (obj.get("service")) |svc_arr| {
···
157
157
.type = try allocator.dupe(u8, getStr(svc_obj, "type") orelse ""),
158
158
.service_endpoint = try allocator.dupe(u8, getStr(svc_obj, "serviceEndpoint") orelse ""),
159
159
};
160
160
-
try svcs.append(svc);
160
160
+
try svcs.append(allocator, svc);
161
161
}
162
162
}
163
163
}
···
166
166
return .{
167
167
.allocator = allocator,
168
168
.id = id,
169
169
-
.handles = try handles.toOwnedSlice(),
170
170
-
.verification_methods = try vms.toOwnedSlice(),
171
171
-
.services = try svcs.toOwnedSlice(),
169
169
+
.handles = try handles.toOwnedSlice(allocator),
170
170
+
.verification_methods = try vms.toOwnedSlice(allocator),
171
171
+
.services = try svcs.toOwnedSlice(allocator),
172
172
};
173
173
}
174
174
+17
-31
src/internal/did_resolver.zig
···
18
18
pub fn init(allocator: std.mem.Allocator) DidResolver {
19
19
return .{
20
20
.allocator = allocator,
21
21
-
.http_client = std.http.Client{ .allocator = allocator },
21
21
+
.http_client = .{ .allocator = allocator },
22
22
};
23
23
}
24
24
···
51
51
const domain_and_path = did.raw["did:web:".len..];
52
52
53
53
// decode percent-encoded colons in path
54
54
-
var url_buf = std.ArrayList(u8).init(self.allocator);
55
55
-
defer url_buf.deinit();
54
54
+
var url_buf: std.ArrayList(u8) = .empty;
55
55
+
defer url_buf.deinit(self.allocator);
56
56
57
57
-
try url_buf.appendSlice("https://");
57
57
+
try url_buf.appendSlice(self.allocator, "https://");
58
58
59
59
var first_segment = true;
60
60
var it = std.mem.splitScalar(u8, domain_and_path, ':');
61
61
while (it.next()) |segment| {
62
62
if (first_segment) {
63
63
// first segment is the domain
64
64
-
try url_buf.appendSlice(segment);
64
64
+
try url_buf.appendSlice(self.allocator, segment);
65
65
first_segment = false;
66
66
} else {
67
67
// subsequent segments are path components
68
68
-
try url_buf.append('/');
69
69
-
try url_buf.appendSlice(segment);
68
68
+
try url_buf.append(self.allocator, '/');
69
69
+
try url_buf.appendSlice(self.allocator, segment);
70
70
}
71
71
}
72
72
73
73
// add .well-known/did.json or /did.json
74
74
if (std.mem.indexOf(u8, domain_and_path, ":") == null) {
75
75
// no path, use .well-known
76
76
-
try url_buf.appendSlice("/.well-known/did.json");
76
76
+
try url_buf.appendSlice(self.allocator, "/.well-known/did.json");
77
77
} else {
78
78
// has path, append did.json
79
79
-
try url_buf.appendSlice("/did.json");
79
79
+
try url_buf.appendSlice(self.allocator, "/did.json");
80
80
}
81
81
82
82
return try self.fetchDidDocument(url_buf.items);
···
84
84
85
85
/// fetch and parse a did document from url
86
86
fn fetchDidDocument(self: *DidResolver, url: []const u8) !DidDocument {
87
87
-
const uri = try std.Uri.parse(url);
88
88
-
89
89
-
var header_buf: [4096]u8 = undefined;
90
90
-
var req = try self.http_client.open(.GET, uri, .{
91
91
-
.server_header_buffer = &header_buf,
92
92
-
});
93
93
-
defer req.deinit();
87
87
+
var aw: std.Io.Writer.Allocating = .init(self.allocator);
88
88
+
defer aw.deinit();
94
89
95
95
-
try req.send();
96
96
-
try req.wait();
90
90
+
const result = self.http_client.fetch(.{
91
91
+
.location = .{ .url = url },
92
92
+
.response_writer = &aw.writer,
93
93
+
}) catch return error.DidResolutionFailed;
97
94
98
98
-
if (req.status != .ok) {
95
95
+
if (result.status != .ok) {
99
96
return error.DidResolutionFailed;
100
97
}
101
98
102
102
-
// read response body
103
103
-
var body = std.ArrayList(u8).init(self.allocator);
104
104
-
defer body.deinit();
105
105
-
106
106
-
var buf: [4096]u8 = undefined;
107
107
-
while (true) {
108
108
-
const n = try req.reader().read(&buf);
109
109
-
if (n == 0) break;
110
110
-
try body.appendSlice(buf[0..n]);
111
111
-
}
112
112
-
113
113
-
return try DidDocument.parse(self.allocator, body.items);
99
99
+
return try DidDocument.parse(self.allocator, aw.toArrayList().items);
114
100
}
115
101
};
116
102
+32
-46
src/internal/xrpc.zig
···
21
21
pub fn init(allocator: std.mem.Allocator, host: []const u8) XrpcClient {
22
22
return .{
23
23
.allocator = allocator,
24
24
-
.http_client = std.http.Client{ .allocator = allocator },
24
24
+
.http_client = .{ .allocator = allocator },
25
25
.host = host,
26
26
};
27
27
}
···
40
40
const url = try self.buildUrl(nsid, params);
41
41
defer self.allocator.free(url);
42
42
43
43
-
return try self.doRequest(.GET, url, null);
43
43
+
return try self.doRequest(url, null);
44
44
}
45
45
46
46
/// call a procedure method (POST)
···
48
48
const url = try self.buildUrl(nsid, null);
49
49
defer self.allocator.free(url);
50
50
51
51
-
return try self.doRequest(.POST, url, body);
51
51
+
return try self.doRequest(url, body);
52
52
}
53
53
54
54
fn buildUrl(self: *XrpcClient, nsid: Nsid, params: ?std.StringHashMap([]const u8)) ![]u8 {
55
55
-
var url = std.ArrayList(u8).init(self.allocator);
56
56
-
errdefer url.deinit();
55
55
+
var url: std.ArrayList(u8) = .empty;
56
56
+
errdefer url.deinit(self.allocator);
57
57
58
58
-
try url.appendSlice(self.host);
59
59
-
try url.appendSlice("/xrpc/");
60
60
-
try url.appendSlice(nsid.raw);
58
58
+
try url.appendSlice(self.allocator, self.host);
59
59
+
try url.appendSlice(self.allocator, "/xrpc/");
60
60
+
try url.appendSlice(self.allocator, nsid.raw);
61
61
62
62
if (params) |p| {
63
63
var first = true;
64
64
var it = p.iterator();
65
65
while (it.next()) |entry| {
66
66
-
try url.append(if (first) '?' else '&');
66
66
+
try url.append(self.allocator, if (first) '?' else '&');
67
67
first = false;
68
68
-
try url.appendSlice(entry.key_ptr.*);
69
69
-
try url.append('=');
68
68
+
try url.appendSlice(self.allocator, entry.key_ptr.*);
69
69
+
try url.append(self.allocator, '=');
70
70
// url encode value
71
71
for (entry.value_ptr.*) |c| {
72
72
if (std.ascii.isAlphanumeric(c) or c == '-' or c == '_' or c == '.' or c == '~') {
73
73
-
try url.append(c);
73
73
+
try url.append(self.allocator, c);
74
74
} else {
75
75
-
try url.writer().print("%{X:0>2}", .{c});
75
75
+
try url.print(self.allocator, "%{X:0>2}", .{c});
76
76
}
77
77
}
78
78
}
79
79
}
80
80
81
81
-
return try url.toOwnedSlice();
81
81
+
return try url.toOwnedSlice(self.allocator);
82
82
}
83
83
84
84
-
fn doRequest(self: *XrpcClient, method: std.http.Method, url: []const u8, body: ?[]const u8) !Response {
85
85
-
const uri = try std.Uri.parse(url);
86
86
-
87
87
-
var header_buf: [8192]u8 = undefined;
88
88
-
var req = try self.http_client.open(method, uri, .{
89
89
-
.server_header_buffer = &header_buf,
90
90
-
.extra_headers = if (self.access_token) |token| &.{
91
91
-
.{ .name = "Authorization", .value = try std.fmt.allocPrint(self.allocator, "Bearer {s}", .{token}) },
92
92
-
} else &.{},
93
93
-
});
94
94
-
defer req.deinit();
95
95
-
96
96
-
req.transfer_encoding = if (body) |b| .{ .content_length = b.len } else .none;
97
97
-
98
98
-
try req.send();
84
84
+
fn doRequest(self: *XrpcClient, url: []const u8, body: ?[]const u8) !Response {
85
85
+
var aw: std.Io.Writer.Allocating = .init(self.allocator);
86
86
+
errdefer aw.deinit();
99
87
100
100
-
if (body) |b| {
101
101
-
try req.writer().writeAll(b);
102
102
-
try req.finish();
88
88
+
// build extra headers for auth
89
89
+
var extra_headers: std.http.Client.Request.Headers = .{};
90
90
+
var auth_header_buf: [256]u8 = undefined;
91
91
+
if (self.access_token) |token| {
92
92
+
const auth_value = try std.fmt.bufPrint(&auth_header_buf, "Bearer {s}", .{token});
93
93
+
extra_headers.authorization = .{ .override = auth_value };
103
94
}
104
95
105
105
-
try req.wait();
106
106
-
107
107
-
// read response body
108
108
-
var response_body = std.ArrayList(u8).init(self.allocator);
109
109
-
errdefer response_body.deinit();
110
110
-
111
111
-
var buf: [4096]u8 = undefined;
112
112
-
while (true) {
113
113
-
const n = try req.reader().read(&buf);
114
114
-
if (n == 0) break;
115
115
-
try response_body.appendSlice(buf[0..n]);
116
116
-
}
96
96
+
const result = self.http_client.fetch(.{
97
97
+
.location = .{ .url = url },
98
98
+
.response_writer = &aw.writer,
99
99
+
.method = if (body != null) .POST else .GET,
100
100
+
.payload = body,
101
101
+
.headers = extra_headers,
102
102
+
}) catch return error.RequestFailed;
117
103
118
104
return .{
119
105
.allocator = self.allocator,
120
120
-
.status = req.status,
121
121
-
.body = try response_body.toOwnedSlice(),
106
106
+
.status = result.status,
107
107
+
.body = try aw.toArrayList().toOwnedSlice(self.allocator),
122
108
};
123
109
}
124
110