ohmu
·
2026-10-15
1#include "weather.h"
2#include "common/networking.h"
3
4#define FF_UNITIALIZED ((const char*) (uintptr_t) -1)
5static FFNetworkingState state;
6static const char* status = FF_UNITIALIZED;
7
8void ffPrepareWeather(FFWeatherOptions* options) {
9 if (status != FF_UNITIALIZED) {
10 fputs("Error: Weather module can only be used once due to internal limitations\n", stderr);
11 exit(1);
12 }
13
14 state.timeout = options->timeout;
15
16 FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateS("/");
17 if (options->location.length) {
18 ffStrbufAppend(&path, &options->location);
19 }
20 ffStrbufAppendS(&path, "?format=");
21 ffStrbufAppend(&path, &options->outputFormat);
22 switch (instance.config.display.tempUnit) {
23 case FF_TEMPERATURE_UNIT_CELSIUS:
24 ffStrbufAppendS(&path, "&m");
25 break;
26 case FF_TEMPERATURE_UNIT_FAHRENHEIT:
27 ffStrbufAppendS(&path, "&u");
28 break;
29 default:
30 break;
31 }
32 status = ffNetworkingSendHttpRequest(&state, "wttr.in", 80, path.chars, "User-Agent: curl/0.0.0\r\n");
33}
34
35const char* ffDetectWeather(FFWeatherOptions* options, FFstrbuf* result) {
36 if (status == FF_UNITIALIZED) {
37 ffPrepareWeather(options);
38 }
39
40 if (status != nullptr) {
41 const char* error = status;
42 ffNetworkingResetState(&state);
43 status = FF_UNITIALIZED;
44 return error;
45 }
46
47 ffStrbufEnsureFree(result, 4095);
48 const char* error = ffNetworkingRecvHttpResponse(&state, result);
49
50 ffNetworkingResetState(&state);
51 status = FF_UNITIALIZED;
52
53 if (error == nullptr) {
54 ffStrbufSubstrAfterFirstS(result, "\r\n\r\n");
55 ffStrbufTrimRightSpace(result);
56 } else {
57 return error;
58 }
59
60 if (result->length == 0) {
61 return "Empty server response received";
62 }
63
64 return nullptr;
65}