-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: server connection configuration
- Loading branch information
Showing
5 changed files
with
115 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
const std = @import("std"); | ||
|
||
const FILENAME = "zcached.conf"; | ||
|
||
pub const Config = struct { | ||
address: []const u8 = @constCast("127.0.0.1"), | ||
port: u16 = 7556, | ||
|
||
_arena: std.heap.ArenaAllocator, | ||
|
||
pub fn deinit(config: *Config) void { | ||
config._arena.deinit(); | ||
} | ||
|
||
pub fn load(allocator: std.mem.Allocator) !Config { | ||
var config = Config{ ._arena = std.heap.ArenaAllocator.init(allocator) }; | ||
|
||
const file = std.fs.cwd().openFile(FILENAME, .{ .mode = .read_only }) catch |err| { | ||
// if the file doesn't exist, just return the default config | ||
if (err == error.FileNotFound) return config; | ||
return err; | ||
}; | ||
defer file.close(); | ||
|
||
const file_size = (try file.stat()).size; | ||
var buffer = try config._arena.allocator().alloc(u8, file_size); | ||
defer config._arena.allocator().free(buffer); | ||
|
||
const readed_size = try file.read(buffer); | ||
if (readed_size != file_size) return error.InvalidInput; | ||
|
||
var iter = std.mem.split(u8, buffer, "\n"); | ||
while (iter.next()) |line| { | ||
// # is comment, _ is for internal use, like _allocator | ||
if (line.len == 0 or line[0] == '#' or line[0] == '_') continue; | ||
|
||
const key_value = try process_line(config._arena.allocator(), line); | ||
defer key_value.deinit(); | ||
|
||
try assign_field_value(&config, key_value); | ||
} | ||
|
||
return config; | ||
} | ||
|
||
fn process_line(allocator: std.mem.Allocator, line: []const u8) !std.ArrayList([]const u8) { | ||
var result = std.ArrayList([]const u8).init(allocator); | ||
|
||
var iter = std.mem.split(u8, line, "="); | ||
const key = iter.next(); | ||
const value = iter.next(); | ||
if (key == null or value == null) return error.InvalidInput; | ||
|
||
try result.append(key.?); | ||
try result.append(value.?); | ||
|
||
return result; | ||
} | ||
|
||
fn assign_field_value(config: *Config, key_value: std.ArrayList([]const u8)) !void { | ||
// I don't like how many nested things are here, but there is no other way | ||
inline for (std.meta.fields(Config)) |field| { | ||
if (std.mem.eql(u8, field.name, key_value.items[0])) { | ||
var value = try config._arena.allocator().alloc(u8, key_value.items[1].len); | ||
std.mem.copy(u8, value, key_value.items[1]); | ||
|
||
switch (field.type) { | ||
u16 => { | ||
const parsed = try std.fmt.parseInt(u16, value, 10); | ||
@field(config, field.name) = parsed; | ||
}, | ||
[]const u8 => @field(config, field.name) = value, | ||
else => unreachable, | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
|
||
test "config default values" { | ||
var config = try Config.load(std.testing.allocator); | ||
defer config.deinit(); | ||
|
||
try std.testing.expectEqualStrings(config.address, "127.0.0.1"); | ||
try std.testing.expectEqual(config.port, 7556); | ||
} | ||
|
||
test "config load" { | ||
const file_content = "address=192.16.0.1\nport=1234\n"; | ||
// create file | ||
const file = try std.fs.cwd().createFile(FILENAME, .{}); | ||
try file.writeAll(file_content); | ||
defer file.close(); | ||
|
||
var config = try Config.load(std.testing.allocator); | ||
defer config.deinit(); | ||
|
||
try std.testing.expectEqualStrings(config.address, "192.16.0.1"); | ||
try std.testing.expectEqual(config.port, 1234); | ||
|
||
// delete file | ||
try std.fs.cwd().deleteFile(FILENAME); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
address=192.168.0.1 | ||
port=5555 |