mirror of
https://github.com/mikkelam/fast-cli.git
synced 2025-12-18 21:04:05 +00:00
better handling of internet issues on initial requests
also improve json output
This commit is contained in:
parent
39d2cbd9d7
commit
08643d487c
2 changed files with 64 additions and 23 deletions
|
|
@ -13,16 +13,6 @@ const progress = @import("../lib/progress.zig");
|
||||||
const HttpLatencyTester = @import("../lib/http_latency_tester.zig").HttpLatencyTester;
|
const HttpLatencyTester = @import("../lib/http_latency_tester.zig").HttpLatencyTester;
|
||||||
const log = std.log.scoped(.cli);
|
const log = std.log.scoped(.cli);
|
||||||
|
|
||||||
/// Update spinner text with current speed measurement
|
|
||||||
fn updateSpinnerText(spinner: anytype, measurement: SpeedMeasurement) void {
|
|
||||||
spinner.updateText("⬇️ {d:.1} {s}", .{ measurement.value, measurement.unit.toString() }) catch {};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Update spinner text with current upload speed measurement
|
|
||||||
fn updateUploadSpinnerText(spinner: anytype, measurement: SpeedMeasurement) void {
|
|
||||||
spinner.updateText("⬆️ {d:.1} {s}", .{ measurement.value, measurement.unit.toString() }) catch {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const https_flag = zli.Flag{
|
const https_flag = zli.Flag{
|
||||||
.name = "https",
|
.name = "https",
|
||||||
.description = "Use https when connecting to fast.com",
|
.description = "Use https when connecting to fast.com",
|
||||||
|
|
@ -86,7 +76,11 @@ fn run(ctx: zli.CommandContext) !void {
|
||||||
if (!json_output) {
|
if (!json_output) {
|
||||||
try ctx.spinner.fail("Failed to get URLs: {}", .{err});
|
try ctx.spinner.fail("Failed to get URLs: {}", .{err});
|
||||||
} else {
|
} else {
|
||||||
std.debug.print("{{\"error\": \"{}\"}}\n", .{err});
|
const error_msg = switch (err) {
|
||||||
|
error.ConnectionTimeout => "Failed to contact fast.com servers",
|
||||||
|
else => "Failed to get URLs",
|
||||||
|
};
|
||||||
|
try outputJson(null, null, null, error_msg);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
@ -133,7 +127,7 @@ fn run(ctx: zli.CommandContext) !void {
|
||||||
// JSON mode: clean output only
|
// JSON mode: clean output only
|
||||||
break :blk speed_tester.measure_download_speed_stability(urls, criteria) catch |err| {
|
break :blk speed_tester.measure_download_speed_stability(urls, criteria) catch |err| {
|
||||||
log.err("Download test failed: {}", .{err});
|
log.err("Download test failed: {}", .{err});
|
||||||
std.debug.print("{{\"error\": \"{}\"}}\n", .{err});
|
try outputJson(null, null, null, "Download test failed");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
} else blk: {
|
} else blk: {
|
||||||
|
|
@ -155,7 +149,7 @@ fn run(ctx: zli.CommandContext) !void {
|
||||||
// JSON mode: clean output only
|
// JSON mode: clean output only
|
||||||
break :blk speed_tester.measure_upload_speed_stability(urls, criteria) catch |err| {
|
break :blk speed_tester.measure_upload_speed_stability(urls, criteria) catch |err| {
|
||||||
log.err("Upload test failed: {}", .{err});
|
log.err("Upload test failed: {}", .{err});
|
||||||
std.debug.print("{{\"error\": \"{}\"}}\n", .{err});
|
try outputJson(download_result.speed.value, latency_ms, null, "Upload test failed");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
} else blk: {
|
} else blk: {
|
||||||
|
|
@ -184,13 +178,33 @@ fn run(ctx: zli.CommandContext) !void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
std.debug.print("{{\"download_mbps\": {d:.1}", .{download_result.speed.value});
|
const upload_speed = if (upload_result) |up| up.speed.value else null;
|
||||||
if (latency_ms) |ping| {
|
try outputJson(download_result.speed.value, latency_ms, upload_speed, null);
|
||||||
std.debug.print(", \"ping_ms\": {d:.1}", .{ping});
|
|
||||||
}
|
|
||||||
if (upload_result) |up| {
|
|
||||||
std.debug.print(", \"upload_mbps\": {d:.1}", .{up.speed.value});
|
|
||||||
}
|
|
||||||
std.debug.print("}}\n", .{});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update spinner text with current speed measurement
|
||||||
|
fn updateSpinnerText(spinner: anytype, measurement: SpeedMeasurement) void {
|
||||||
|
spinner.updateText("⬇️ {d:.1} {s}", .{ measurement.value, measurement.unit.toString() }) catch {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update spinner text with current upload speed measurement
|
||||||
|
fn updateUploadSpinnerText(spinner: anytype, measurement: SpeedMeasurement) void {
|
||||||
|
spinner.updateText("⬆️ {d:.1} {s}", .{ measurement.value, measurement.unit.toString() }) catch {};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn outputJson(download_mbps: ?f64, ping_ms: ?f64, upload_mbps: ?f64, error_message: ?[]const u8) !void {
|
||||||
|
const stdout = std.io.getStdOut().writer();
|
||||||
|
|
||||||
|
var download_buf: [32]u8 = undefined;
|
||||||
|
var ping_buf: [32]u8 = undefined;
|
||||||
|
var upload_buf: [32]u8 = undefined;
|
||||||
|
var error_buf: [256]u8 = undefined;
|
||||||
|
|
||||||
|
const download_str = if (download_mbps) |d| try std.fmt.bufPrint(&download_buf, "{d:.1}", .{d}) else "null";
|
||||||
|
const ping_str = if (ping_ms) |p| try std.fmt.bufPrint(&ping_buf, "{d:.1}", .{p}) else "null";
|
||||||
|
const upload_str = if (upload_mbps) |u| try std.fmt.bufPrint(&upload_buf, "{d:.1}", .{u}) else "null";
|
||||||
|
const error_str = if (error_message) |e| try std.fmt.bufPrint(&error_buf, "\"{s}\"", .{e}) else "null";
|
||||||
|
|
||||||
|
try stdout.print("{{\"download_mbps\": {s}, \"ping_ms\": {s}, \"upload_mbps\": {s}, \"error\": {s}}}\n", .{ download_str, ping_str, upload_str, error_str });
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,13 @@ const testing = std.testing;
|
||||||
const log = std.log.scoped(.fast_api);
|
const log = std.log.scoped(.fast_api);
|
||||||
|
|
||||||
const mvzr = @import("mvzr");
|
const mvzr = @import("mvzr");
|
||||||
|
|
||||||
const FastError = error{
|
const FastError = error{
|
||||||
HttpRequestFailed,
|
HttpRequestFailed,
|
||||||
ScriptNotFound,
|
ScriptNotFound,
|
||||||
TokenNotFound,
|
TokenNotFound,
|
||||||
JsonParseError,
|
JsonParseError,
|
||||||
|
ConnectionTimeout,
|
||||||
};
|
};
|
||||||
|
|
||||||
const Location = struct {
|
const Location = struct {
|
||||||
|
|
@ -159,11 +161,36 @@ pub const Fast = struct {
|
||||||
_ = allocator;
|
_ = allocator;
|
||||||
var response_body = std.ArrayList(u8).init(self.arena.allocator());
|
var response_body = std.ArrayList(u8).init(self.arena.allocator());
|
||||||
|
|
||||||
const response: http.Client.FetchResult = try self.client.fetch(.{
|
const response: http.Client.FetchResult = self.client.fetch(.{
|
||||||
.method = .GET,
|
.method = .GET,
|
||||||
.location = .{ .url = url },
|
.location = .{ .url = url },
|
||||||
.response_storage = .{ .dynamic = &response_body },
|
.response_storage = .{ .dynamic = &response_body },
|
||||||
});
|
}) catch |err| switch (err) {
|
||||||
|
error.NetworkUnreachable, error.ConnectionRefused => {
|
||||||
|
log.err("Failed to reach fast.com servers (network/connection error) for URL: {s}", .{url});
|
||||||
|
return error.ConnectionTimeout;
|
||||||
|
},
|
||||||
|
error.UnknownHostName, error.NameServerFailure, error.TemporaryNameServerFailure, error.HostLacksNetworkAddresses => {
|
||||||
|
log.err("Failed to resolve fast.com hostname (DNS/internet connection issue) for URL: {s}", .{url});
|
||||||
|
return error.ConnectionTimeout;
|
||||||
|
},
|
||||||
|
error.ConnectionTimedOut, error.ConnectionResetByPeer => {
|
||||||
|
log.err("Connection to fast.com servers timed out or was reset for URL: {s}", .{url});
|
||||||
|
return error.ConnectionTimeout;
|
||||||
|
},
|
||||||
|
error.TlsInitializationFailed => {
|
||||||
|
log.err("Failed to establish secure connection to fast.com servers for URL: {s}", .{url});
|
||||||
|
return error.ConnectionTimeout;
|
||||||
|
},
|
||||||
|
error.UnexpectedConnectFailure => {
|
||||||
|
log.err("Unexpected connection failure to fast.com servers for URL: {s}", .{url});
|
||||||
|
return error.ConnectionTimeout;
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
log.err("Network error: {} for URL: {s}", .{ err, url });
|
||||||
|
return error.ConnectionTimeout;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
log.debug("HTTP response status: {} for URL: {s}", .{ response.status, url });
|
log.debug("HTTP response status: {} for URL: {s}", .{ response.status, url });
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue