summaryrefslogtreecommitdiff
path: root/src/transmission.zig
diff options
context:
space:
mode:
authorChristian Segundo2023-06-11 22:09:15 +0200
committerChristian Segundo2023-06-11 22:09:15 +0200
commit3bd3f432a95da405634cdbd2a662d79a3a5ba7af (patch)
treeed7ac24e3309d8c6b4f43d1051d95b18a7165a2c /src/transmission.zig
downloadzmission-3bd3f432a95da405634cdbd2a662d79a3a5ba7af.tar.gz
wip
Diffstat (limited to 'src/transmission.zig')
-rw-r--r--src/transmission.zig106
1 files changed, 106 insertions, 0 deletions
diff --git a/src/transmission.zig b/src/transmission.zig
new file mode 100644
index 0000000..fec1b12
--- /dev/null
+++ b/src/transmission.zig
@@ -0,0 +1,106 @@
+const std = @import("std");
+
+const Request = @import("request.zig").Request;
+const SessionGetFields = @import("request.zig").SessionGetFields;
+
+pub const ClientOptions = extern struct {
+ host: [*:0]const u8,
+ port: u16,
+ https: bool,
+ user: ?[*:0]const u8 = null,
+ password: ?[*:0]const u8 = null,
+};
+
+pub const Client = struct {
+ uri: std.Uri,
+ allocator: std.mem.Allocator,
+ http_client: std.http.Client,
+ http_headers: std.http.Headers,
+ current_session_id: []u8 = "",
+
+ pub fn init(allocator: std.mem.Allocator, opts: ClientOptions) Client {
+ const base_url = std.Uri{
+ .path = "/transmission/rpc",
+ .scheme = blk: {
+ if (opts.https) {
+ break :blk "https";
+ } else {
+ break :blk "http";
+ }
+ },
+ .host = std.mem.span(opts.host),
+ .port = opts.port,
+ .user = null,
+ .password = null,
+ .query = null,
+ .fragment = null,
+ };
+
+ return Client{
+ .uri = base_url,
+ .allocator = allocator,
+ .http_client = std.http.Client{ .allocator = allocator },
+ .http_headers = std.http.Headers{ .allocator = allocator },
+ };
+ }
+
+ pub fn deinit(self: *Client) void {
+ self.http_headers.deinit();
+ self.http_client.deinit();
+ self.allocator.free(self.current_session_id);
+ }
+
+ fn setSessionId(self: *Client, r: std.http.Client.Response) !void {
+ self.allocator.free(self.current_session_id);
+ const session_id = r.headers.getFirstValue("X-Transmission-Session-Id") orelse return error.NoSessionId;
+ self.current_session_id = try std.fmt.allocPrint(self.allocator, "{s}", .{session_id});
+ }
+
+ fn newRequest(self: *Client) !std.http.Client.Request {
+ try self.http_headers.append("X-Transmission-Session-Id", self.current_session_id);
+ return try self.http_client.request(.POST, self.uri, self.http_headers, .{});
+ }
+
+ pub fn do(self: *Client, req: Request) ![]u8 {
+ var real_req = try self.newRequest();
+ defer real_req.deinit();
+
+ var payload = std.ArrayList(u8).init(self.allocator);
+ defer payload.deinit();
+
+ try std.json.stringify(req, .{}, payload.writer());
+
+ real_req.transfer_encoding = std.http.Client.RequestTransfer{
+ .content_length = payload.items.len,
+ };
+
+ try real_req.start();
+ if (try real_req.write(payload.items) != payload.items.len) {
+ return error.InvalidSize;
+ }
+
+ try real_req.finish();
+ try real_req.wait();
+
+ if (real_req.response.status == std.http.Status.conflict) {
+ try self.setSessionId(real_req.response);
+ return self.do(req);
+ }
+
+ const body = try real_req.reader().readAllAlloc(self.allocator, 9000);
+ return body;
+ }
+};
+
+pub fn sessionGet(client: *Client) ![]u8 {
+ const r = Request{
+ .method = .session_get,
+ .arguments = .{
+ .session_get = .{
+ .fields = &[_]SessionGetFields{ .version, .utp_enabled },
+ },
+ },
+ };
+ const body = try client.do(r);
+ return body;
+}