Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 52 additions & 54 deletions c/csrc/include/longbridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -1665,6 +1665,48 @@ typedef struct lb_async_result_t {

typedef void (*lb_async_callback_t)(const struct lb_async_result_t*);

/**
* A single alert indicator configuration for a symbol.
*/
typedef struct lb_alert_item_t {
/**
* Unique alert identifier.
*/
const char *id;
/**
* Identifier of the indicator that triggers this alert.
*/
const char *indicator_id;
/**
* Whether this alert is currently enabled.
*/
bool enabled;
/**
* Alert notification frequency code.
*/
int32_t frequency;
/**
* Scope of the alert (e.g. per-symbol or global).
*/
int32_t scope;
/**
* Human-readable description text for the alert.
*/
const char *text;
/**
* Pointer to an array of state codes associated with this alert.
*/
const int32_t *state;
/**
* Number of elements in the `state` array.
*/
uintptr_t num_state;
/**
* JSON-serialized map of additional indicator parameter values.
*/
const char *value_map;
} lb_alert_item_t;

/**
* HTTP Header
*/
Expand Down Expand Up @@ -6700,48 +6742,6 @@ typedef struct lb_exchange_rates_t {
uintptr_t num_exchanges;
} lb_exchange_rates_t;

/**
* A single alert indicator configuration for a symbol.
*/
typedef struct lb_alert_item_t {
/**
* Unique alert identifier.
*/
const char *id;
/**
* Identifier of the indicator that triggers this alert.
*/
const char *indicator_id;
/**
* Whether this alert is currently enabled.
*/
bool enabled;
/**
* Alert notification frequency code.
*/
int32_t frequency;
/**
* Scope of the alert (e.g. per-symbol or global).
*/
int32_t scope;
/**
* Human-readable description text for the alert.
*/
const char *text;
/**
* Pointer to an array of state codes associated with this alert.
*/
const int32_t *state;
/**
* Number of elements in the `state` array.
*/
uintptr_t num_state;
/**
* JSON-serialized map of additional indicator parameter values.
*/
const char *value_map;
} lb_alert_item_t;

/**
* A symbol together with all of its associated alert indicators.
*/
Expand Down Expand Up @@ -7877,21 +7877,19 @@ void lb_alert_context_add(const struct lb_alert_context_t *ctx,
void *userdata);

/**
* Enable a price alert.
*/
void lb_alert_context_enable(const struct lb_alert_context_t *ctx,
const char *alert_id,
* Update (enable or disable) a price alert.
*
* `item` must point to a valid [`CAlertItem`] obtained from
* [`lb_alert_context_list`]. Set `enabled` to `true` to re-enable or
* `false` to disable. All fields of `item` are read before the function
* returns, so the pointer only needs to be valid for the duration of
* the call.
*/
void lb_alert_context_update(const struct lb_alert_context_t *ctx,
const struct lb_alert_item_t *item,
lb_async_callback_t callback,
void *userdata);

/**
* Disable a price alert.
*/
void lb_alert_context_disable(const struct lb_alert_context_t *ctx,
const char *alert_id,
lb_async_callback_t callback,
void *userdata);

/**
* Delete price alerts. alert_ids: array of alert ID strings, num_ids: count.
*/
Expand Down
32 changes: 11 additions & 21 deletions c/src/alert_context/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,34 +65,24 @@ pub unsafe extern "C" fn lb_alert_context_add(
});
}

/// Enable a price alert.
/// Update (enable or disable) a price alert.
///
/// `item` must point to a valid [`CAlertItem`] obtained from
/// [`lb_alert_context_list`]. Set `enabled` to `true` to re-enable or
/// `false` to disable. All fields of `item` are read before the function
/// returns, so the pointer only needs to be valid for the duration of
/// the call.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lb_alert_context_enable(
pub unsafe extern "C" fn lb_alert_context_update(
ctx: *const CAlertContext,
alert_id: *const c_char,
item: *const CAlertItem,
callback: CAsyncCallback,
userdata: *mut c_void,
) {
let ctx_inner = (*ctx).ctx.clone();
let id = cstr_to_rust(alert_id);
let alert_item = (*item).to_alert_item();
execute_async(callback, ctx, userdata, async move {
ctx_inner.enable(id).await?;
Ok(())
});
}

/// Disable a price alert.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn lb_alert_context_disable(
ctx: *const CAlertContext,
alert_id: *const c_char,
callback: CAsyncCallback,
userdata: *mut c_void,
) {
let ctx_inner = (*ctx).ctx.clone();
let id = cstr_to_rust(alert_id);
execute_async(callback, ctx, userdata, async move {
ctx_inner.disable(id).await?;
ctx_inner.update(&alert_item).await?;
Ok(())
});
}
Expand Down
24 changes: 24 additions & 0 deletions c/src/alert_context/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,30 @@ impl From<AlertItem> for CAlertItemOwned {
}
}

impl CAlertItem {
/// Reconstruct a [`longbridge::alert::AlertItem`] from this C struct.
///
/// # Safety
/// All pointer fields must be valid null-terminated C strings and the
/// `state` pointer must point to at least `num_state` valid `i32` values.
pub unsafe fn to_alert_item(&self) -> longbridge::alert::AlertItem {
use crate::types::cstr_to_rust;
let state = std::slice::from_raw_parts(self.state, self.num_state).to_vec();
let value_map_str = cstr_to_rust(self.value_map);
let value_map = serde_json::from_str(&value_map_str).unwrap_or(serde_json::Value::Null);
longbridge::alert::AlertItem {
id: cstr_to_rust(self.id),
indicator_id: cstr_to_rust(self.indicator_id),
enabled: self.enabled,
frequency: self.frequency,
scope: self.scope,
text: cstr_to_rust(self.text),
state,
value_map,
}
}
}

impl ToFFI for CAlertItemOwned {
type FFIType = CAlertItem;
fn to_ffi_type(&self) -> Self::FFIType {
Expand Down
8 changes: 3 additions & 5 deletions cpp/include/alert_context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,10 @@ class AlertContext {
void add(const std::string& symbol, AlertCondition condition,
const std::string& trigger_value, AlertFrequency frequency,
AsyncCallback<AlertContext, void> callback) const;
/// Enable a price alert by alert_id.
void enable(const std::string& alert_id,
/// Update (enable or disable) a price alert.
/// Set item.enabled before calling to choose the new state.
void update(const AlertItem& item,
AsyncCallback<AlertContext, void> callback) const;
/// Disable a price alert by alert_id.
void disable(const std::string& alert_id,
AsyncCallback<AlertContext, void> callback) const;
};

} // namespace alert
Expand Down
30 changes: 15 additions & 15 deletions cpp/src/alert_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ void lb_alert_context_retain(const lb_alert_context_t*);
void lb_alert_context_release(const lb_alert_context_t*);
void lb_alert_context_list(const lb_alert_context_t*, lb_async_callback_t, void*);
void lb_alert_context_add(const lb_alert_context_t*, const char*, lb_alert_condition_t, const char*, lb_alert_frequency_t, lb_async_callback_t, void*);
void lb_alert_context_enable(const lb_alert_context_t*, const char*, lb_async_callback_t, void*);
void lb_alert_context_disable(const lb_alert_context_t*, const char*, lb_async_callback_t, void*);
void lb_alert_context_update(const lb_alert_context_t*, const lb_alert_item_t*, lb_async_callback_t, void*);
}

namespace longbridge {
Expand Down Expand Up @@ -50,20 +49,21 @@ void AlertContext::add(const std::string& symbol, AlertCondition condition,
}, new AsyncCallback<AlertContext, void>(callback));
}

void AlertContext::enable(const std::string& alert_id,
void AlertContext::update(const AlertItem& item,
AsyncCallback<AlertContext, void> callback) const {
lb_alert_context_enable(ctx_, alert_id.c_str(),
[](auto res) {
auto cb = callback::get_async_callback<AlertContext, void>(res->userdata);
AlertContext fctx((const lb_alert_context_t*)res->ctx);
Status status(res->error);
(*cb)(AsyncResult<AlertContext, void>(fctx, std::move(status), nullptr));
}, new AsyncCallback<AlertContext, void>(callback));
}

void AlertContext::disable(const std::string& alert_id,
AsyncCallback<AlertContext, void> callback) const {
lb_alert_context_disable(ctx_, alert_id.c_str(),
// Build a lb_alert_item_t from the C++ AlertItem to pass to the C layer.
std::vector<int32_t> state_copy = item.state;
lb_alert_item_t c_item{};
c_item.id = item.id.c_str();
c_item.indicator_id = item.indicator_id.c_str();
c_item.enabled = item.enabled;
c_item.frequency = item.frequency;
c_item.scope = item.scope;
c_item.text = item.text.c_str();
c_item.state = state_copy.data();
c_item.num_state = state_copy.size();
c_item.value_map = item.value_map.c_str();
lb_alert_context_update(ctx_, &c_item,
[](auto res) {
auto cb = callback::get_async_callback<AlertContext, void>(res->userdata);
AlertContext fctx((const lb_alert_context_t*)res->ctx);
Expand Down
67 changes: 43 additions & 24 deletions java/src/alert_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,47 @@ use longbridge::{AlertContext, Config, alert::types::*};
use crate::{
async_util,
error::jni_result,
types::{FromJValue, ObjectArray, get_field},
types::{ObjectArray, get_field},
};

/// Read a Java `AlertItem` object into a Rust [`longbridge::alert::AlertItem`].
fn read_alert_item(
env: &mut JNIEnv,
item: &JObject,
) -> jni::errors::Result<longbridge::alert::AlertItem> {
let id: String = get_field(env, item, "id")?;
let indicator_id: String = get_field(env, item, "indicatorId")?;
let enabled: bool = get_field(env, item, "enabled")?;
let frequency: i32 = get_field(env, item, "frequency")?;
let scope: i32 = get_field(env, item, "scope")?;
let text: String = get_field(env, item, "text")?;
// state: int[] — read as a Java int array
let state = unsafe {
let state_obj = env.get_field(item, "state", "[I")?.l()?;
if state_obj.is_null() {
Vec::new()
} else {
let arr = jni::objects::JIntArray::from(state_obj);
let elements = env
.get_array_elements::<jni::sys::jint>(&arr, jni::objects::ReleaseMode::CopyBack)?;
std::slice::from_raw_parts(elements.as_ptr(), elements.len()).to_vec()
}
};
// valueMap: JSON string
let value_map_str: String = get_field(env, item, "valueMap")?;
let value_map = serde_json::from_str(&value_map_str).unwrap_or(serde_json::Value::Null);
Ok(longbridge::alert::AlertItem {
id,
indicator_id,
enabled,
frequency,
scope,
text,
state,
value_map,
})
}

struct ContextObj {
ctx: AlertContext,
}
Expand Down Expand Up @@ -80,37 +118,18 @@ pub unsafe extern "system" fn Java_com_longbridge_SdkNative_alertContextAdd(
}

#[unsafe(no_mangle)]
pub unsafe extern "system" fn Java_com_longbridge_SdkNative_alertContextEnable(
mut env: JNIEnv,
_class: JClass,
context: i64,
alert_id: JObject,
callback: JObject,
) {
jni_result(&mut env, (), |env| {
let context = &*(context as *const ContextObj);
let id: String = FromJValue::from_jvalue(env, alert_id.into())?;
async_util::execute(env, callback, async move {
context.ctx.enable(id).await?;
Ok(())
})?;
Ok(())
})
}

#[unsafe(no_mangle)]
pub unsafe extern "system" fn Java_com_longbridge_SdkNative_alertContextDisable(
pub unsafe extern "system" fn Java_com_longbridge_SdkNative_alertContextUpdate(
mut env: JNIEnv,
_class: JClass,
context: i64,
alert_id: JObject,
item: JObject,
callback: JObject,
) {
jni_result(&mut env, (), |env| {
let context = &*(context as *const ContextObj);
let id: String = FromJValue::from_jvalue(env, alert_id.into())?;
let alert_item = read_alert_item(env, &item)?;
async_util::execute(env, callback, async move {
context.ctx.disable(id).await?;
context.ctx.update(&alert_item).await?;
Ok(())
})?;
Ok(())
Expand Down
17 changes: 7 additions & 10 deletions nodejs/src/alert/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,14 @@ impl AlertContext {
Ok(())
}

/// Enable a previously disabled price alert.
#[napi]
pub async fn enable(&self, alert_id: String) -> Result<()> {
self.ctx.enable(alert_id).await.map_err(ErrorNewType)?;
Ok(())
}

/// Disable a price alert without deleting it.
/// Update a price alert.
///
/// Pass the [`AlertItem`] obtained from [`list`](Self::list). Set
/// `item.enabled` to `true` to re-enable or `false` to disable before
/// calling this method.
#[napi]
pub async fn disable(&self, alert_id: String) -> Result<()> {
self.ctx.disable(alert_id).await.map_err(ErrorNewType)?;
pub async fn update(&self, item: AlertItem) -> Result<()> {
self.ctx.update(&item.into()).await.map_err(ErrorNewType)?;
Ok(())
}

Expand Down
Loading
Loading