Skip to content

Commit 4db405c

Browse files
authored
Merge pull request #65 from BigBen-7/fix/horizon-fee-stats-field-mapping
fix: resolve issues with self parameter in FeeRepository methods and improve webhook delivery handling
2 parents 14cd046 + 51c4eff commit 4db405c

10 files changed

Lines changed: 1322 additions & 20 deletions

File tree

Cargo.lock

Lines changed: 339 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/core/.env.example

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,27 @@ POLL_INTERVAL_SECONDS=10
1010
# API server port (default: 8080)
1111
API_PORT=8080
1212

13-
# Comma-separated list of origins allowed to call the API.
14-
# Defaults to http://localhost:3000 when unset.
15-
# Example for production: ALLOWED_ORIGINS=https://your-app.vercel.app,https://www.your-domain.com
13+
# Allowed origins
1614
ALLOWED_ORIGINS=http://localhost:3000
15+
16+
# Cache TTL for /fees/current responses (seconds)
17+
CACHE_TTL_SECONDS=5
18+
19+
# Rate limiting (requests per minute per IP, default: 60)
20+
RATE_LIMIT_PER_MINUTE=60
21+
22+
# Retention window for fee data in SQLite (days, default: 7)
23+
STORAGE_RETENTION_DAYS=7
24+
25+
# Retry config
26+
RETRY_ATTEMPTS=3
27+
BASE_RETRY_DELAY_MS=1000
28+
29+
# API key for protected routes (leave unset to disable auth)
30+
# API_KEY=your-secret-key-here
31+
32+
# Webhook URL for fee spike alerts (leave unset to disable)
33+
# WEBHOOK_URL=https://hooks.slack.com/services/xxx
34+
35+
# Alert threshold: Minor | Moderate | Major | Critical (default: Major)
36+
ALERT_THRESHOLD=Major

packages/core/clippy-results.txt

Lines changed: 313 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,313 @@
1+
Checking cfg-if v1.0.4
2+
Checking smallvec v1.15.1
3+
Checking pin-project-lite v0.2.16
4+
Checking bytes v1.11.0
5+
Checking scopeguard v1.2.0
6+
Checking libc v0.2.180
7+
Checking futures-core v0.3.31
8+
Checking once_cell v1.21.3
9+
Checking itoa v1.0.17
10+
Compiling zerofrom v0.1.6
11+
Compiling stable_deref_trait v1.2.1
12+
Checking lock_api v0.4.14
13+
Compiling yoke v0.8.1
14+
Checking futures-sink v0.3.31
15+
Checking memchr v2.7.6
16+
Checking pin-utils v0.1.0
17+
Checking core-foundation-sys v0.8.7
18+
Checking tracing-core v0.1.36
19+
Checking log v0.4.29
20+
Checking futures-io v0.3.32
21+
Compiling zerovec v0.11.5
22+
Checking futures-task v0.3.31
23+
Compiling litemap v0.8.1
24+
Checking slab v0.4.11
25+
Compiling writeable v0.6.2
26+
Checking tracing v0.1.44
27+
Compiling zerotrie v0.2.3
28+
Checking serde_core v1.0.228
29+
Checking futures-util v0.3.31
30+
Checking parking_lot_core v0.9.12
31+
Checking errno v0.3.14
32+
Checking socket2 v0.6.2
33+
Checking mio v1.1.1
34+
Checking getrandom v0.3.4
35+
Checking signal-hook-registry v1.4.8
36+
Checking parking_lot v0.12.5
37+
Checking bitflags v2.10.0
38+
Checking tinystr v0.8.2
39+
Checking potential_utf v0.1.4
40+
Checking zerocopy v0.8.39
41+
Compiling typenum v1.19.0
42+
Checking icu_locale_core v2.1.1
43+
Compiling icu_collections v2.1.1
44+
Checking tokio v1.49.0
45+
Compiling generic-array v0.14.7
46+
Checking core-foundation v0.9.4
47+
Checking futures-channel v0.3.31
48+
Compiling icu_normalizer_data v2.1.1
49+
Checking icu_provider v2.1.1
50+
Compiling icu_properties_data v2.1.2
51+
Checking rustix v1.1.3
52+
Checking security-framework-sys v2.15.0
53+
Compiling icu_normalizer v2.1.1
54+
Compiling icu_properties v2.1.2
55+
Checking serde v1.0.228
56+
Checking percent-encoding v2.3.2
57+
Checking hashbrown v0.16.1
58+
Checking equivalent v1.0.2
59+
Checking fastrand v2.3.0
60+
Checking tower-service v0.3.3
61+
Checking form_urlencoded v1.2.2
62+
Checking tempfile v3.24.0
63+
Compiling block-buffer v0.10.4
64+
Compiling crypto-common v0.1.7
65+
Checking security-framework v2.11.1
66+
Checking indexmap v2.13.0
67+
Compiling idna_adapter v1.2.1
68+
Checking http v1.4.0
69+
Checking fnv v1.0.7
70+
Compiling utf8_iter v1.0.4
71+
Compiling minimal-lexical v0.2.1
72+
Compiling allocator-api2 v0.2.21
73+
Compiling nom v7.1.3
74+
Checking http-body v1.0.1
75+
Compiling idna v1.1.0
76+
Checking native-tls v0.2.14
77+
Checking ahash v0.8.12
78+
Compiling digest v0.10.7
79+
Checking httparse v1.10.1
80+
Compiling cpufeatures v0.2.17
81+
Compiling num-traits v0.2.19
82+
Compiling zmij v1.0.17
83+
Checking httpdate v1.0.3
84+
Compiling unicode_categories v0.1.1
85+
Compiling crc-catalog v2.4.0
86+
Compiling serde_json v1.0.149
87+
Checking hashbrown v0.14.5
88+
Compiling atoi v2.0.0
89+
Compiling sqlformat v0.2.6
90+
Compiling crc v3.4.0
91+
Compiling sha2 v0.10.9
92+
Compiling crossbeam-queue v0.3.12
93+
Compiling either v1.15.0
94+
Compiling url v2.5.8
95+
Compiling futures-intrusive v0.5.0
96+
Checking crossbeam-utils v0.8.21
97+
Checking http v0.2.12
98+
Compiling hashlink v0.8.4
99+
Compiling spin v0.9.8
100+
Compiling thiserror v1.0.69
101+
Compiling event-listener v2.5.3
102+
Compiling hex v0.4.3
103+
Compiling byteorder v1.5.0
104+
Compiling flume v0.11.1
105+
Checking tokio-util v0.7.18
106+
Compiling libsqlite3-sys v0.27.0
107+
Checking try-lock v0.2.5
108+
Compiling urlencoding v2.1.3
109+
Checking tower-layer v0.3.3
110+
Compiling futures-executor v0.3.31
111+
Checking utf8parse v0.2.2
112+
Checking anstyle-parse v0.2.7
113+
Checking want v0.3.1
114+
Checking http-body v0.4.6
115+
Checking tokio-stream v0.1.18
116+
Checking http-body-util v0.1.3
117+
Checking h2 v0.3.27
118+
Checking getrandom v0.2.17
119+
Checking socket2 v0.5.10
120+
Compiling dotenvy v0.15.7
121+
Checking atomic-waker v1.1.2
122+
Checking anstyle-query v1.1.5
123+
Checking mime v0.3.17
124+
Checking colorchoice v1.0.4
125+
Checking sync_wrapper v1.0.2
126+
Checking anstyle v1.0.13
127+
Checking lazy_static v1.5.0
128+
Checking is_terminal_polyfill v1.70.2
129+
Checking regex-syntax v0.8.8
130+
Checking ryu v1.0.22
131+
Checking hyper v1.8.1
132+
Checking anstream v0.6.21
133+
Checking serde_urlencoded v0.7.1
134+
Checking rand_core v0.6.4
135+
Checking system-configuration-sys v0.5.0
136+
Checking tokio-native-tls v0.3.1
137+
Checking ppv-lite86 v0.2.21
138+
Checking base64 v0.21.7
139+
Checking clap_lex v0.7.7
140+
Checking strsim v0.11.1
141+
Checking bitflags v1.3.2
142+
Checking rustls-pemfile v1.0.4
143+
Checking clap_builder v4.5.54
144+
Checking system-configuration v0.5.1
145+
Checking rand_chacha v0.3.1
146+
Checking hyper-util v0.1.19
147+
Checking axum-core v0.4.5
148+
Checking protobuf v2.28.0
149+
Checking sharded-slab v0.1.7
150+
Checking tower v0.5.3
151+
Checking regex-automata v0.4.13
152+
Compiling sqlx-core v0.7.4
153+
Checking serde_path_to_error v0.1.20
154+
Checking tracing-log v0.2.0
155+
Checking iana-time-zone v0.1.64
156+
Checking thread_local v1.1.9
157+
Checking encoding_rs v0.8.35
158+
Checking nu-ansi-term v0.50.3
159+
Checking ipnet v2.11.0
160+
Checking sync_wrapper v0.1.2
161+
Checking matchit v0.7.3
162+
Checking chrono v0.4.43
163+
Checking rand v0.8.5
164+
Checking clap v4.5.54
165+
Checking tower-http v0.5.2
166+
Checking dashmap v6.1.0
167+
Checking matchers v0.2.0
168+
Checking tracing-subscriber v0.3.22
169+
Checking axum v0.7.9
170+
Checking prometheus v0.13.4
171+
Checking hyper v0.14.32
172+
Compiling sqlx-sqlite v0.7.4
173+
Compiling sqlx-macros-core v0.7.4
174+
Checking hyper-tls v0.5.0
175+
Checking reqwest v0.11.27
176+
Compiling sqlx-macros v0.7.4
177+
Checking sqlx v0.7.4
178+
Checking stellar-fee-tracker v0.1.0 (/Users/bigben7/Documents/ME/stellar-fee-tracker/packages/core)
179+
error: `self` parameter is only allowed in associated functions
180+
--> packages/core/src/repository.rs:167:9
181+
|
182+
167 | &self,
183+
| ^^^^^ not semantically valid as function parameter
184+
|
185+
= note: associated functions are those in `impl` or `trait` definitions
186+
187+
error: `self` parameter is only allowed in associated functions
188+
--> packages/core/src/repository.rs:183:37
189+
|
190+
183 | pub async fn list_alert_configs(&self) -> Result<Vec<AlertConfig>, sqlx::Error> {
191+
| ^^^^^ not semantically valid as function parameter
192+
|
193+
= note: associated functions are those in `impl` or `trait` definitions
194+
195+
error: `self` parameter is only allowed in associated functions
196+
--> packages/core/src/repository.rs:216:9
197+
|
198+
216 | &self,
199+
| ^^^^^ not semantically valid as function parameter
200+
|
201+
= note: associated functions are those in `impl` or `trait` definitions
202+
203+
error: `self` parameter is only allowed in associated functions
204+
--> packages/core/src/repository.rs:237:38
205+
|
206+
237 | pub async fn delete_alert_config(&self, id: i64) -> Result<bool, sqlx::Error> {
207+
| ^^^^^ not semantically valid as function parameter
208+
|
209+
= note: associated functions are those in `impl` or `trait` definitions
210+
211+
error: `self` parameter is only allowed in associated functions
212+
--> packages/core/src/repository.rs:251:34
213+
|
214+
251 | pub async fn log_alert_event(&self, event: &AlertEvent) -> Result<(), sqlx::Error> {
215+
| ^^^^^ not semantically valid as function parameter
216+
|
217+
= note: associated functions are those in `impl` or `trait` definitions
218+
219+
error: `self` parameter is only allowed in associated functions
220+
--> packages/core/src/repository.rs:275:9
221+
|
222+
275 | &self,
223+
| ^^^^^ not semantically valid as function parameter
224+
|
225+
= note: associated functions are those in `impl` or `trait` definitions
226+
227+
error: `self` parameter is only allowed in associated functions
228+
--> packages/core/src/repository.rs:353:9
229+
|
230+
353 | &self,
231+
| ^^^^^ not semantically valid as function parameter
232+
|
233+
= note: associated functions are those in `impl` or `trait` definitions
234+
235+
error[E0382]: use of moved value: `delivery`
236+
--> packages/core/src/alerts/mod.rs:73:26
237+
|
238+
37 | let Some(delivery) = self.webhook_delivery.clone() else {
239+
| -------- move occurs because `delivery` has type `alerts::webhook::WebhookDelivery`, which does not implement the `Copy` trait
240+
...
241+
41 | for spike in &update.insights.congestion_trends.recent_spikes {
242+
| ------------------------------------------------------------- inside of this loop
243+
...
244+
73 | tokio::spawn(async move {
245+
| ^^^^^^^^^^ value moved here, in previous iteration of loop
246+
74 | if let Err(err) = delivery.send_with_retry(&payload).await {
247+
| -------- use occurs due to use in coroutine
248+
249+
error[E0599]: no method named `insert_alert_config` found for struct `std::sync::Arc<repository::FeeRepository>` in the current scope
250+
--> packages/core/src/api/alerts.rs:74:10
251+
|
252+
73 | let id = repo
253+
| ______________-
254+
74 | | .insert_alert_config(&body.webhook_url, threshold)
255+
| | -^^^^^^^^^^^^^^^^^^^ method not found in `std::sync::Arc<repository::FeeRepository>`
256+
| |_________|
257+
|
258+
259+
error[E0599]: no method named `list_alert_configs` found for struct `std::sync::Arc<repository::FeeRepository>` in the current scope
260+
--> packages/core/src/api/alerts.rs:90:24
261+
|
262+
90 | let configs = repo.list_alert_configs().await.map_err(|e| {
263+
| ^^^^^^^^^^^^^^^^^^ method not found in `std::sync::Arc<repository::FeeRepository>`
264+
265+
error[E0599]: no method named `list_alert_configs` found for struct `std::sync::Arc<repository::FeeRepository>` in the current scope
266+
--> packages/core/src/api/alerts.rs:107:24
267+
|
268+
107 | let configs = repo.list_alert_configs().await.map_err(|e| {
269+
| ^^^^^^^^^^^^^^^^^^ method not found in `std::sync::Arc<repository::FeeRepository>`
270+
271+
error[E0599]: no method named `update_alert_config` found for struct `std::sync::Arc<repository::FeeRepository>` in the current scope
272+
--> packages/core/src/api/alerts.rs:138:10
273+
|
274+
137 | let updated = repo
275+
| ___________________-
276+
138 | | .update_alert_config(id, threshold, enabled)
277+
| | -^^^^^^^^^^^^^^^^^^^ method not found in `std::sync::Arc<repository::FeeRepository>`
278+
| |_________|
279+
|
280+
281+
error[E0599]: no method named `delete_alert_config` found for struct `std::sync::Arc<repository::FeeRepository>` in the current scope
282+
--> packages/core/src/api/alerts.rs:162:24
283+
|
284+
162 | let deleted = repo.delete_alert_config(id).await.map_err(|e| {
285+
| ^^^^^^^^^^^^^^^^^^^ method not found in `std::sync::Arc<repository::FeeRepository>`
286+
287+
error[E0599]: no method named `query_alert_history` found for struct `std::sync::Arc<repository::FeeRepository>` in the current scope
288+
--> packages/core/src/api/alerts.rs:225:14
289+
|
290+
225 | repo.query_alert_history(limit, severity, delivered),
291+
| ^^^^^^^^^^^^^^^^^^^ method not found in `std::sync::Arc<repository::FeeRepository>`
292+
293+
error[E0599]: no method named `count_alert_events` found for struct `std::sync::Arc<repository::FeeRepository>` in the current scope
294+
--> packages/core/src/api/alerts.rs:226:14
295+
|
296+
226 | repo.count_alert_events(severity, delivered),
297+
| ^^^^^^^^^^^^^^^^^^ method not found in `std::sync::Arc<repository::FeeRepository>`
298+
299+
error[E0282]: type annotations needed
300+
--> packages/core/src/api/alerts.rs:224:26
301+
|
302+
224 | let (items, total) = tokio::try_join!(
303+
| __________________________^
304+
225 | | repo.query_alert_history(limit, severity, delivered),
305+
226 | | repo.count_alert_events(severity, delivered),
306+
227 | | )
307+
| |_____^ cannot infer type
308+
|
309+
= note: this error originates in the macro `$crate::try_join` which comes from the expansion of the macro `tokio::try_join` (in Nightly builds, run with -Z macro-backtrace for more info)
310+
311+
Some errors have detailed explanations: E0282, E0382, E0599.
312+
For more information about an error, try `rustc --explain E0282`.
313+
error: could not compile `stellar-fee-tracker` (lib) due to 19 previous errors

packages/core/src/alerts/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ impl AlertManager {
7070
timestamp: Utc::now(),
7171
};
7272

73+
let delivery = delivery.clone();
7374
tokio::spawn(async move {
7475
if let Err(err) = delivery.send_with_retry(&payload).await {
7576
tracing::error!("Webhook dispatch failed: {}", err);
@@ -245,4 +246,4 @@ mod tests {
245246
manager.check_and_dispatch(&update).await;
246247
tokio::time::sleep(std::time::Duration::from_millis(100)).await;
247248
}
248-
}
249+
}

packages/core/src/metrics.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ mod integration_tests {
247247
.unwrap();
248248
let resp = app.oneshot(req).await.unwrap();
249249
let bytes = resp.into_body().collect().await.unwrap().to_bytes();
250-
let body = String::from_utf8(bytes).unwrap();
250+
let body = String::from_utf8(bytes.to_vec()).unwrap();
251251

252252
assert!(body.contains("stellar_fee_tracker_polls_total"));
253253
assert!(body.contains("stellar_fee_tracker_poll_errors_total"));
@@ -270,9 +270,9 @@ mod integration_tests {
270270
.unwrap();
271271
let resp = app.oneshot(req).await.unwrap();
272272
let bytes = resp.into_body().collect().await.unwrap().to_bytes();
273-
let body = String::from_utf8(bytes).unwrap();
273+
let body = String::from_utf8(bytes.to_vec()).unwrap();
274274

275275
// Prometheus text format: metric_name value\n
276276
assert!(body.contains("stellar_fee_tracker_polls_total 5"));
277277
}
278-
}
278+
}

0 commit comments

Comments
 (0)