Skip to content

Commit 59a1119

Browse files
committed
Release v1.0.0
1 parent 7c196e3 commit 59a1119

10 files changed

Lines changed: 12 additions & 134 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "bitmex-cli"
3-
version = "1.1.0"
3+
version = "1.0.0"
44
edition = "2024"
55
description = "BitMEX CLI — trade, query, and manage your BitMEX account from the terminal"
66
license = "MIT"

src/cli/commands/helpers.rs

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,5 @@
11
/// Shared helper functions used across multiple command modules.
2-
use serde_json::Value;
3-
42
use crate::errors::{BitmexError, Result};
5-
use crate::cli::output::CommandOutput;
6-
7-
/// Extract a string value from a JSON object by key, returning "-" on miss.
8-
pub(crate) fn jstr(val: &Value, key: &str) -> String {
9-
val.get(key)
10-
.map(|v| match v {
11-
Value::String(s) => s.clone(),
12-
other => other.to_string(),
13-
})
14-
.unwrap_or_else(|| "-".to_string())
15-
}
16-
17-
/// Parse a generic JSON value into key-value pairs for rendering.
18-
pub(crate) fn parse_generic(data: &Value) -> CommandOutput {
19-
let pairs: Vec<(String, String)> = if let Some(obj) = data.as_object() {
20-
obj.iter()
21-
.map(|(k, v)| {
22-
let val = match v {
23-
Value::String(s) => s.clone(),
24-
other => other.to_string(),
25-
};
26-
(k.clone(), val)
27-
})
28-
.collect()
29-
} else if let Some(arr) = data.as_array() {
30-
arr.iter()
31-
.enumerate()
32-
.map(|(i, v)| (format!("[{i}]"), v.to_string()))
33-
.collect()
34-
} else {
35-
vec![("Result".into(), data.to_string())]
36-
};
37-
CommandOutput::key_value(pairs, data.clone())
38-
}
393

404
/// Build a URL query string from (key, Option<value>) pairs, skipping None values.
415
///

src/cli/output/json.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,3 @@ pub(crate) fn render_error(err: &BitmexError) {
2626
}
2727
}
2828
}
29-
30-
/// Render a single NDJSON line to stdout (for WebSocket streaming).
31-
pub(crate) fn render_ndjson(data: &serde_json::Value) {
32-
match serde_json::to_string(data) {
33-
Ok(s) => println!("{s}"),
34-
Err(e) => {
35-
eprintln!("JSON serialization failed: {e}");
36-
println!(r#"{{"error":"parse","message":"JSON serialization failed"}}"#);
37-
}
38-
}
39-
}

src/cli/output/mod.rs

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -37,38 +37,11 @@ impl CommandOutput {
3737
///
3838
/// // Explicit columns (replaces from_json_cols):
3939
/// CommandOutput::builder().data(val).columns(&["price", "size"]).build()
40-
///
41-
/// // Fixed message:
42-
/// CommandOutput::builder().message("Done").build()
4340
/// ```
4441
pub(crate) fn builder() -> CommandOutputBuilder {
4542
CommandOutputBuilder::default()
4643
}
4744

48-
/// Create output from a JSON value with explicit table structure.
49-
pub(crate) fn new(
50-
data: serde_json::Value,
51-
headers: Vec<String>,
52-
rows: Vec<Vec<String>>,
53-
) -> Self {
54-
Self {
55-
data,
56-
headers,
57-
rows,
58-
}
59-
}
60-
61-
/// Create a simple key-value output (rendered as two-column table).
62-
pub(crate) fn key_value(pairs: Vec<(String, String)>, json_data: serde_json::Value) -> Self {
63-
let headers = vec!["Field".to_string(), "Value".to_string()];
64-
let rows: Vec<Vec<String>> = pairs.into_iter().map(|(k, v)| vec![k, v]).collect();
65-
Self {
66-
data: json_data,
67-
headers,
68-
rows,
69-
}
70-
}
71-
7245
/// Create output from a raw JSON value, auto-populating table rows from the data.
7346
///
7447
/// - If the value is an array of objects, headers come from the first object's keys.
@@ -196,11 +169,10 @@ impl CommandOutput {
196169
pub(crate) struct CommandOutputBuilder {
197170
data: Option<serde_json::Value>,
198171
columns: Option<Vec<String>>,
199-
message: Option<String>,
200172
}
201173

202174
impl CommandOutputBuilder {
203-
/// Set the JSON payload. Required unless `.message()` is used.
175+
/// Set the JSON payload.
204176
pub(crate) fn data(mut self, data: serde_json::Value) -> Self {
205177
self.data = Some(data);
206178
self
@@ -212,17 +184,8 @@ impl CommandOutputBuilder {
212184
self
213185
}
214186

215-
/// Produce a single-message output (sets data to `{"message": msg}`).
216-
pub(crate) fn message(mut self, msg: impl Into<String>) -> Self {
217-
self.message = Some(msg.into());
218-
self
219-
}
220-
221187
/// Consume the builder and produce a `CommandOutput`.
222188
pub(crate) fn build(self) -> CommandOutput {
223-
if let Some(msg) = self.message {
224-
return CommandOutput::message(&msg);
225-
}
226189
match (self.data, self.columns) {
227190
(Some(data), Some(cols)) => {
228191
let col_refs: Vec<&str> = cols.iter().map(|s| s.as_str()).collect();

src/cli/output/table.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,3 @@ pub(crate) fn render(output: &CommandOutput) {
2222

2323
println!("{table}");
2424
}
25-
26-
/// Render a single append-only line for WebSocket streaming in table mode.
27-
pub(crate) fn render_stream_line(fields: &[(&str, &str)]) {
28-
let parts: Vec<String> = fields.iter().map(|(k, v)| format!("{k}: {v}")).collect();
29-
println!("{}", parts.join(" | "));
30-
}

src/cli/shell.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -120,26 +120,26 @@ pub(crate) async fn run(ctx: &AppContext) -> Result<()> {
120120
struct BitmexPrompt;
121121

122122
impl Prompt for BitmexPrompt {
123-
fn render_prompt_left(&self) -> Cow<str> {
123+
fn render_prompt_left(&self) -> Cow<'_, str> {
124124
"bitmex> ".into()
125125
}
126126

127-
fn render_prompt_right(&self) -> Cow<str> {
127+
fn render_prompt_right(&self) -> Cow<'_, str> {
128128
"".into()
129129
}
130130

131-
fn render_prompt_indicator(&self, _mode: PromptEditMode) -> Cow<str> {
131+
fn render_prompt_indicator(&self, _mode: PromptEditMode) -> Cow<'_, str> {
132132
"".into()
133133
}
134134

135-
fn render_prompt_multiline_indicator(&self) -> Cow<str> {
135+
fn render_prompt_multiline_indicator(&self) -> Cow<'_, str> {
136136
"... ".into()
137137
}
138138

139139
fn render_prompt_history_search_indicator(
140140
&self,
141141
_history_search: PromptHistorySearch,
142-
) -> Cow<str> {
142+
) -> Cow<'_, str> {
143143
"(history-search) ".into()
144144
}
145145
}
@@ -184,7 +184,7 @@ struct BitmexHighlighter;
184184

185185
impl Highlighter for BitmexHighlighter {
186186
fn highlight(&self, line: &str, _cursor: usize) -> StyledText {
187-
use nu_ansi_term::{Color, Style};
187+
use nu_ansi_term::Style;
188188

189189
let mut styled = StyledText::new();
190190
if line.is_empty() {

src/config/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ pub(crate) fn save(cfg: &BitmexConfig) -> Result<()> {
191191
// Auto-migration
192192
// ---------------------------------------------------------------------------
193193

194-
fn maybe_migrate_legacy_auth(cfg: &mut BitmexConfig, path: &Path) -> Result<()> {
194+
fn maybe_migrate_legacy_auth(cfg: &mut BitmexConfig, _path: &Path) -> Result<()> {
195195
let (Some(key), Some(secret)) = (
196196
cfg.auth.api_key.take(),
197197
cfg.auth.api_secret.take(),

src/exchange/client.rs

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,6 @@ pub trait ExchangeClient: Send + Sync {
5353
body: Option<&Value>,
5454
creds: &Credentials,
5555
) -> impl Future<Output = Result<Value>> + Send;
56-
fn base_url(&self) -> &str;
57-
fn is_testnet(&self) -> bool;
5856
}
5957

6058
use std::future::Future;
@@ -63,7 +61,6 @@ use std::future::Future;
6361
pub struct BitmexClient {
6462
http: reqwest::Client,
6563
pub(crate) base_url: String,
66-
pub(crate) testnet: bool,
6764
verbose: bool,
6865
/// When Some, timing phases are collected and printed for every request.
6966
timing: Option<super::timing::TimingHandle>,
@@ -114,19 +111,17 @@ impl BitmexClient {
114111
Ok(Self {
115112
http: build_http_client(timing_handle.as_ref())?,
116113
base_url,
117-
testnet,
118114
verbose,
119115
timing: timing_handle,
120116
})
121117
}
122118

123119
/// Create a new client with an explicit base URL override.
124-
pub fn new_with_url(base_url: String, testnet: bool, verbose: bool, timing: bool) -> Result<Self> {
120+
pub fn new_with_url(base_url: String, verbose: bool, timing: bool) -> Result<Self> {
125121
let timing_handle = timing.then(super::timing::new_handle);
126122
Ok(Self {
127123
http: build_http_client(timing_handle.as_ref())?,
128124
base_url,
129-
testnet,
130125
verbose,
131126
timing: timing_handle,
132127
})
@@ -202,25 +197,6 @@ impl BitmexClient {
202197
self.parse_response(resp, "PUT", &url).await
203198
}
204199

205-
/// Authenticated PATCH with JSON body.
206-
pub async fn patch(&self, path: &str, body: &Value, creds: &Credentials) -> Result<Value> {
207-
let full_path = format!("/api/v1{path}");
208-
let body_str = serde_json::to_string(body)?;
209-
let url = self.url(path, "");
210-
if self.verbose { crate::cli::output::verbose(&format!("PATCH {url}")); }
211-
self.begin_request();
212-
let resp = super::middleware::execute_with_retry(self.verbose, || async {
213-
let expires = auth::generate_expires()?;
214-
let sig = auth::sign("PATCH", &full_path, expires, &body_str, &creds.api_secret)?;
215-
let headers = self.auth_headers(&creds.api_key, expires, &sig)?;
216-
self.http.patch(&url).headers(headers)
217-
.header("Content-Type", "application/json")
218-
.body(body_str.clone()).send().await
219-
.map_err(|e| BitmexError::Network { message: e.to_string() })
220-
}).await?;
221-
self.parse_response(resp, "PATCH", &url).await
222-
}
223-
224200
/// Authenticated DELETE, optional JSON body.
225201
pub async fn delete(
226202
&self,
@@ -413,14 +389,6 @@ impl ExchangeClient for BitmexClient {
413389
) -> Result<Value> {
414390
BitmexClient::delete(self, path, query, body, creds).await
415391
}
416-
417-
fn base_url(&self) -> &str {
418-
&self.base_url
419-
}
420-
421-
fn is_testnet(&self) -> bool {
422-
self.testnet
423-
}
424392
}
425393

426394
/// Extract a human-readable error message from a BitMEX error response body.

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ pub enum Command {
241241

242242
fn build_client(ctx: &AppContext) -> Result<BitmexClient> {
243243
if let Some(ref url) = ctx.api_url {
244-
BitmexClient::new_with_url(url.clone(), ctx.testnet, ctx.verbose, ctx.timing)
244+
BitmexClient::new_with_url(url.clone(), ctx.verbose, ctx.timing)
245245
} else {
246246
BitmexClient::new(ctx.testnet, ctx.verbose, ctx.timing)
247247
}

0 commit comments

Comments
 (0)