Skip to content

Commit cbf4db6

Browse files
ZGeomanticgeomantic
andauthored
feat: Add RPCs for statement (#500)
Introduce a new `statement` module in the Rust SDK providing: - `StatementContext` for querying account statement data - `GET /v1/statement/list` to retrieve statement data list (daily/monthly) - `GET /v1/statement/download` to get statement file download URLs - Comprehensive deserialization types for statement content (member info, asset, equity holdings, trades, fees, corporate actions, etc.) Also add `LONGBRIDGE_TEST_ENV` environment variable support in the OAuth client to route requests to the test environment (`longbridge.xyz`). --------- Co-authored-by: geomantic <lei.zhong@longbridge-inc.com>
1 parent ecb47ed commit cbf4db6

35 files changed

Lines changed: 1450 additions & 1 deletion

File tree

c/csrc/include/longbridge.h

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,11 @@ typedef enum lb_granularity_t {
12781278
GranularityMonthly,
12791279
} lb_granularity_t;
12801280

1281+
/**
1282+
* Asset context
1283+
*/
1284+
typedef struct CAssetContext CAssetContext;
1285+
12811286
/**
12821287
* Configuration options for Longbridge SDK
12831288
*/
@@ -4107,6 +4112,54 @@ typedef struct lb_news_item_t {
41074112
extern "C" {
41084113
#endif // __cplusplus
41094114

4115+
/**
4116+
* Create a new `AssetContext`
4117+
*
4118+
* @param config Config object
4119+
* @return A new asset context
4120+
*/
4121+
const struct CAssetContext *lb_asset_context_new(const struct lb_config_t *config);
4122+
4123+
/**
4124+
* Retain the asset context (increment reference count)
4125+
*/
4126+
void lb_asset_context_retain(const struct CAssetContext *ctx);
4127+
4128+
/**
4129+
* Release the asset context (decrement reference count)
4130+
*/
4131+
void lb_asset_context_release(const struct CAssetContext *ctx);
4132+
4133+
/**
4134+
* Get statement data list
4135+
*
4136+
* @param ctx Asset context
4137+
* @param statement_type 1 = daily, 2 = monthly
4138+
* @param start_date Start date for pagination (0 = default)
4139+
* @param limit Number of results (0 = default 20)
4140+
* @param callback Async callback
4141+
* @param userdata User data passed to the callback
4142+
*/
4143+
void lb_asset_context_statements(const struct CAssetContext *ctx,
4144+
int32_t statement_type,
4145+
int32_t start_date,
4146+
int32_t limit,
4147+
lb_async_callback_t callback,
4148+
void *userdata);
4149+
4150+
/**
4151+
* Get statement data download URL
4152+
*
4153+
* @param ctx Asset context
4154+
* @param file_key File key from the list response
4155+
* @param callback Async callback
4156+
* @param userdata User data passed to the callback
4157+
*/
4158+
void lb_asset_context_download_url(const struct CAssetContext *ctx,
4159+
const char *file_key,
4160+
lb_async_callback_t callback,
4161+
void *userdata);
4162+
41104163
/**
41114164
* Create a new `Config` using API Key authentication
41124165
*

c/src/asset_context/context.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
use std::{ffi::c_void, os::raw::c_char, sync::Arc};
2+
3+
use longbridge::asset::{
4+
AssetContext, GetStatementListOptions, GetStatementOptions, StatementType,
5+
};
6+
7+
use crate::{
8+
asset_context::types::CStatementItemOwned,
9+
async_call::{CAsyncCallback, execute_async},
10+
config::CConfig,
11+
types::{CString, CVec, cstr_to_rust},
12+
};
13+
14+
/// Asset context
15+
pub struct CAssetContext {
16+
ctx: AssetContext,
17+
}
18+
19+
/// Create a new `AssetContext`
20+
///
21+
/// @param config Config object
22+
/// @return A new asset context
23+
#[unsafe(no_mangle)]
24+
pub unsafe extern "C" fn lb_asset_context_new(config: *const CConfig) -> *const CAssetContext {
25+
let config = Arc::new((*config).0.clone());
26+
let ctx = AssetContext::new(config);
27+
Arc::into_raw(Arc::new(CAssetContext { ctx }))
28+
}
29+
30+
/// Retain the asset context (increment reference count)
31+
#[unsafe(no_mangle)]
32+
pub unsafe extern "C" fn lb_asset_context_retain(ctx: *const CAssetContext) {
33+
Arc::increment_strong_count(ctx);
34+
}
35+
36+
/// Release the asset context (decrement reference count)
37+
#[unsafe(no_mangle)]
38+
pub unsafe extern "C" fn lb_asset_context_release(ctx: *const CAssetContext) {
39+
let _ = Arc::from_raw(ctx);
40+
}
41+
42+
/// Get statement data list
43+
///
44+
/// @param ctx Asset context
45+
/// @param statement_type 1 = daily, 2 = monthly
46+
/// @param start_date Start date for pagination (0 = default)
47+
/// @param limit Number of results (0 = default 20)
48+
/// @param callback Async callback
49+
/// @param userdata User data passed to the callback
50+
#[unsafe(no_mangle)]
51+
pub unsafe extern "C" fn lb_asset_context_statements(
52+
ctx: *const CAssetContext,
53+
statement_type: i32,
54+
start_date: i32,
55+
limit: i32,
56+
callback: CAsyncCallback,
57+
userdata: *mut c_void,
58+
) {
59+
let ctx_inner = (*ctx).ctx.clone();
60+
let st = if statement_type == 2 {
61+
StatementType::Monthly
62+
} else {
63+
StatementType::Daily
64+
};
65+
let mut opts = GetStatementListOptions::new(st);
66+
if start_date > 0 {
67+
opts = opts.page(start_date);
68+
}
69+
if limit > 0 {
70+
opts = opts.page_size(limit);
71+
}
72+
execute_async(callback, ctx, userdata, async move {
73+
let rows: CVec<CStatementItemOwned> = ctx_inner.statements(opts).await?.list.into();
74+
Ok(rows)
75+
});
76+
}
77+
78+
/// Get statement data download URL
79+
///
80+
/// @param ctx Asset context
81+
/// @param file_key File key from the list response
82+
/// @param callback Async callback
83+
/// @param userdata User data passed to the callback
84+
#[unsafe(no_mangle)]
85+
pub unsafe extern "C" fn lb_asset_context_download_url(
86+
ctx: *const CAssetContext,
87+
file_key: *const c_char,
88+
callback: CAsyncCallback,
89+
userdata: *mut c_void,
90+
) {
91+
let ctx_inner = (*ctx).ctx.clone();
92+
let file_key = cstr_to_rust(file_key);
93+
let opts = GetStatementOptions::new(file_key);
94+
execute_async(callback, ctx, userdata, async move {
95+
let url: CString = ctx_inner.statement_download_url(opts).await?.url.into();
96+
Ok(url)
97+
});
98+
}

c/src/asset_context/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
mod context;
2+
mod types;

c/src/asset_context/types.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
use std::os::raw::c_char;
2+
3+
use longbridge::asset::StatementItem;
4+
5+
use crate::types::{CString, ToFFI};
6+
7+
/// Statement item
8+
#[repr(C)]
9+
pub struct CStatementItem {
10+
/// Statement date (integer, e.g. 20250301)
11+
pub dt: i32,
12+
/// File key
13+
pub file_key: *const c_char,
14+
}
15+
16+
#[derive(Debug)]
17+
pub(crate) struct CStatementItemOwned {
18+
dt: i32,
19+
file_key: CString,
20+
}
21+
22+
impl From<StatementItem> for CStatementItemOwned {
23+
fn from(item: StatementItem) -> Self {
24+
Self {
25+
dt: item.dt,
26+
file_key: item.file_key.into(),
27+
}
28+
}
29+
}
30+
31+
impl ToFFI for CStatementItemOwned {
32+
type FFIType = CStatementItem;
33+
fn to_ffi_type(&self) -> CStatementItem {
34+
CStatementItem {
35+
dt: self.dt,
36+
file_key: self.file_key.to_ffi_type(),
37+
}
38+
}
39+
}

c/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#![allow(unsafe_op_in_unsafe_fn)]
22

3+
mod asset_context;
34
mod async_call;
45
mod callback;
56
mod config;

cpp/include/asset_context.hpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#pragma once
2+
3+
#include "async_result.hpp"
4+
#include "callback.hpp"
5+
#include "config.hpp"
6+
#include "types.hpp"
7+
8+
typedef struct lb_asset_context_t lb_asset_context_t;
9+
10+
namespace longbridge {
11+
namespace asset {
12+
13+
/// Statement item
14+
struct StatementItem
15+
{
16+
/// Statement date (integer, e.g. 20250301)
17+
int32_t dt;
18+
/// File key
19+
std::string file_key;
20+
};
21+
22+
/// Statement download URL response
23+
struct StatementDownloadUrlResponse
24+
{
25+
/// Presigned download URL
26+
std::string url;
27+
};
28+
29+
/// Asset context
30+
class AssetContext
31+
{
32+
private:
33+
const lb_asset_context_t* ctx_;
34+
35+
public:
36+
AssetContext();
37+
AssetContext(const lb_asset_context_t* ctx);
38+
AssetContext(const AssetContext& ctx);
39+
AssetContext(AssetContext&& ctx);
40+
~AssetContext();
41+
42+
AssetContext& operator=(const AssetContext& ctx);
43+
44+
static AssetContext create(const Config& config);
45+
46+
/// Get statement data list
47+
void statements(
48+
int32_t statement_type,
49+
int32_t start_date,
50+
int32_t limit,
51+
AsyncCallback<AssetContext, std::vector<StatementItem>> callback) const;
52+
53+
/// Get statement data download URL
54+
void statement_download_url(
55+
const std::string& file_key,
56+
AsyncCallback<AssetContext, StatementDownloadUrlResponse> callback)
57+
const;
58+
};
59+
60+
} // namespace asset
61+
} // namespace longbridge

cpp/include/longbridge.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include "asset_context.hpp"
34
#include "config.hpp"
45
#include "decimal.hpp"
56
#include "http_client.hpp"

0 commit comments

Comments
 (0)