diff options
author | Martin Ashby <martin@ashbysoft.com> | 2023-09-23 21:26:06 +0100 |
---|---|---|
committer | Martin Ashby <martin@ashbysoft.com> | 2023-09-23 21:26:06 +0100 |
commit | ddc6bee3757d3e68a14fafdc47eb5d0a0ba923bb (patch) | |
tree | 309ffbc89c42a3adf41a655025fe20e4014878c9 /src/main.zig | |
parent | 5a91b37ee7dd36db52dfde1727b780ec3fa4c67d (diff) | |
download | pgz-ddc6bee3757d3e68a14fafdc47eb5d0a0ba923bb.tar.gz pgz-ddc6bee3757d3e68a14fafdc47eb5d0a0ba923bb.tar.bz2 pgz-ddc6bee3757d3e68a14fafdc47eb5d0a0ba923bb.tar.xz pgz-ddc6bee3757d3e68a14fafdc47eb5d0a0ba923bb.zip |
Got a working test connecting to postgres server and reading data.
Added a couple more message types to facilitate this.
Diffstat (limited to 'src/main.zig')
-rw-r--r-- | src/main.zig | 85 |
1 files changed, 78 insertions, 7 deletions
diff --git a/src/main.zig b/src/main.zig index e540256..e539f2f 100644 --- a/src/main.zig +++ b/src/main.zig @@ -1,10 +1,13 @@ const std = @import("std"); const testing = std.testing; const StartupMessage = @import("startup_message.zig"); -const AuthenticationOk = @import("authentication_ok.zig"); -const AuthenticationCleartextPassword = @import("authentication_cleartext_password.zig"); +const AuthenticationRequest = @import("authentication_request.zig"); const PasswordMessage = @import("password_message.zig"); const ErrorResponse = @import("error_response.zig"); +const ReadyForQuery = @import("ready_for_query.zig"); +const ParameterStatus = @import("parameter_status.zig"); +const BackendKeyData = @import("backend_key_data.zig"); +const Conn = @import("conn.zig"); pub const ProtocolError = error{ InvalidProtocolVersion, @@ -12,15 +15,16 @@ pub const ProtocolError = error{ InvalidMessageLength, InvalidAuthType, MissingField, + WrongMessageType, + InvalidTransactionStatus, }; pub const ClientError = error{ UnsupportedAuthType, }; -pub const AuthType = enum(u32) { - AuthTypeOk = 0, - AuthTypeCleartextPassword = 3, +pub const ServerError = error{ + ErrorResponse, }; // Fallible version of enumFromInt @@ -38,10 +42,77 @@ pub fn enum_from_int(comptime e: type, i: anytype) ?e { } } +// Tag should already have been read in order to determine msg_type! +pub fn read_message(comptime msg_type: type, allocator: std.mem.Allocator, stream_reader: anytype) !msg_type { + if (!@hasDecl(msg_type, "Tag")) @compileError("msg_type must have a Tag declaration!"); + if (!@hasDecl(msg_type, "read")) @compileError("msg_type must have a read() function!"); + const len = try stream_reader.readIntBig(u32); + const buf = try allocator.alloc(u8, @as(u32, @intCast(len-4))); + defer allocator.free(buf); + try stream_reader.readNoEof(buf); + return try msg_type.read(allocator, buf); +} + + +pub fn diagnosticReader(comptime n: usize, base_reader: anytype) DiagnosticReader(n, @TypeOf(base_reader)) { + return .{.child_reader = base_reader}; +} + +// keeps a buffer of the last n bytes read +pub fn DiagnosticReader(comptime n: usize, comptime ReaderType: anytype) type { + return struct { + child_reader: ReaderType, + ring: [n]u8 = [_]u8{0}**n, + pos: usize = 0, + + pub const Error = ReaderType.Error; + pub const Reader = std.io.Reader(*@This(), Error, read); + + pub fn read(self: *@This(), buf: []u8) Error!usize { + const amt = try self.child_reader.read(buf); + for (0..amt) |i| { + self.ring[self.pos] = buf[i]; + self.pos += 1; + self.pos %= n; + } + return amt; + } + + pub fn reader(self: *@This()) Reader { + return .{ .context = self }; + } + + // Caller frees + pub fn get(self: @This(), allocator: std.mem.Allocator) ![]const u8 { + var buf = try allocator.alloc(u8, n); + errdefer allocator.free(buf); + @memcpy(buf[0..(n-self.pos)], self.ring[self.pos..n]); + @memcpy(buf[(n-self.pos)..n], self.ring[0..self.pos]); + return buf; + } + }; +} + +test "diagnostc reader" { + const a = std.testing.allocator; + const string = "The quick brown fox jumped over the lazy dog"; + var fbs = std.io.fixedBufferStream(string); + var dr = diagnosticReader(15, fbs.reader()); + var reader = dr.reader(); + var buf = [_]u8{0}**20; + try reader.readNoEof(&buf); + const diag = try dr.get(a); + defer a.free(diag); + try std.testing.expectEqualStrings("uick brown fox ", diag); +} + test { _ = StartupMessage; - _ = AuthenticationOk; - _ = AuthenticationCleartextPassword; + _ = AuthenticationRequest; _ = PasswordMessage; _ = ErrorResponse; + _ = Conn; + _ = ReadyForQuery; + _ = ParameterStatus; + _ = BackendKeyData; } |