-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmain.cpp
More file actions
178 lines (154 loc) · 5.31 KB
/
Copy pathmain.cpp
File metadata and controls
178 lines (154 loc) · 5.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#include <spdlog/spdlog.h>
#include <CLI/CLI.hpp>
#include <iostream>
#include <memory>
#include <string>
#include <tl/expected.hpp>
#include "config.h"
#include "exceptions.h"
#include "weather_data.h"
#include "weather_service.h"
namespace weather {
/**
* @brief Application configuration structure
*/
struct AppConfig {
std::string city;
bool debug_mode = false;
bool fahrenheit = false;
bool json_output = false;
bool show_extended_info = false;
};
/**
* @brief Setup logging based on debug mode
*/
void SetupLogging(bool debug_mode) {
if (debug_mode) {
spdlog::set_level(spdlog::level::debug);
spdlog::set_pattern("[%Y-%m-%d %H:%M:%S] [%l] [%n] - %v");
} else {
spdlog::set_level(spdlog::level::info);
spdlog::set_pattern("[%H:%M:%S] %v");
}
}
/**
* @brief Print weather data in human-readable format
*/
void PrintWeatherData(const WeatherData& weather_data, bool fahrenheit,
bool extended_info) {
if (fahrenheit) {
std::cout << "Weather in " << weather_data.GetCity() << ": "
<< weather_data.GetTemperatureFahrenheit() << "°F"
<< " (feels like " << weather_data.GetFeelsLikeFahrenheit()
<< "°F)"
<< ", " << weather_data.GetDescription() << std::endl;
} else {
std::cout << "Weather in " << weather_data.GetCity() << ": "
<< weather_data.GetTemperatureCelsius() << "°C"
<< " (feels like " << weather_data.GetFeelsLikeCelsius() << "°C)"
<< ", " << weather_data.GetDescription() << std::endl;
}
if (extended_info) {
std::cout << "Humidity: " << weather_data.GetHumidity() << "%"
<< ", Pressure: " << weather_data.GetPressureHpa() << " hPa"
<< std::endl;
std::cout << "Wind: " << weather_data.GetWindSpeedMs() << " m/s"
<< " at " << weather_data.GetWindDirectionDeg() << " degrees"
<< std::endl;
}
}
/**
* @brief Main application logic
*/
tl::expected<int, WeatherError> RunWeatherCli(const AppConfig& config) {
try {
// Create weather service with default OpenMeteoClient
auto weather_service = std::make_unique<WeatherService>();
// Get weather data
auto weather_result = weather_service->GetWeather(config.city);
if (!weather_result) {
switch (weather_result.error()) {
case WeatherError::Network:
spdlog::error("Network connection failed");
break;
case WeatherError::ApiKey:
spdlog::error("API error");
break;
case WeatherError::NotFound:
spdlog::error("City '{}' not found. Please check the spelling.",
config.city);
break;
case WeatherError::Parse:
spdlog::error("Failed to parse weather data");
break;
case WeatherError::Timeout:
spdlog::error("Request timed out");
break;
default:
spdlog::error("Failed to get weather data");
break;
}
return tl::unexpected(weather_result.error());
}
const auto& weather_data = weather_result.value();
// Output weather data
if (config.json_output) {
std::cout << weather_data.ToJson() << std::endl;
} else {
PrintWeatherData(weather_data, config.fahrenheit,
config.show_extended_info);
}
return 0;
} catch (const ConfigException& e) {
spdlog::error("Configuration error: {}", e.what());
return tl::unexpected(WeatherError::InvalidInput);
} catch (const WeatherApiException& e) {
spdlog::error("Weather API error: {}", e.what());
return tl::unexpected(WeatherError::Network);
} catch (const WeatherException& e) {
spdlog::error("Weather error: {}", e.what());
return tl::unexpected(WeatherError::Network);
} catch (const std::exception& e) {
spdlog::error("Unexpected error: {}", e.what());
return tl::unexpected(WeatherError::Network);
}
}
} // namespace weather
/**
* @brief Main entry point
*/
int main(int argc, char* argv[]) {
weather::AppConfig config;
// Setup CLI11 command line parser
CLI::App app{"Weather CLI - Get current weather information for any city"};
app.set_version_flag("--version", "1.0.0");
// Add arguments
auto* city_option = app.add_option("city", config.city,
"Name of the city to get weather for");
city_option->required();
// Add flags
app.add_flag("-d,--debug", config.debug_mode, "Enable debug logging");
app.add_flag("-f,--fahrenheit", config.fahrenheit,
"Show temperature in Fahrenheit");
app.add_flag("-j,--json", config.json_output, "Output in JSON format");
app.add_flag("-e,--extended", config.show_extended_info,
"Show extended weather information");
// Parse command line
try {
app.parse(argc, argv);
} catch (const CLI::ParseError& e) {
return app.exit(e);
}
// Setup logging
weather::SetupLogging(config.debug_mode);
spdlog::debug("Starting Weather CLI application");
spdlog::debug("City: {}, Debug: {}, Fahrenheit: {}, JSON: {}", config.city,
config.debug_mode, config.fahrenheit, config.json_output);
// Run the weather CLI application
auto result = weather::RunWeatherCli(config);
if (!result) {
std::cerr << "Error occurred during execution" << std::endl;
return 1;
}
return result.value();
}