Skip to content
This repository has been archived by the owner on Sep 6, 2024. It is now read-only.

Commit

Permalink
[+] release v0.0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
heng30 committed Dec 31, 2023
1 parent e99d2c0 commit e860ee6
Show file tree
Hide file tree
Showing 27 changed files with 256 additions and 63 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash

build-evn=SLINT_STYLE=fluent
run-evn=RUST_LOG=error,warn,info,sqlx=off,reqwest=off
run-evn=RUST_LOG=error,warn,info,debug,sqlx=off,reqwest=off

all:
$(build-evn) cargo build --release
Expand Down
2 changes: 2 additions & 0 deletions bitbox/src/config/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ pub struct Account {
pub max_feerate: u32,
pub max_fee_amount: u32,
pub max_send_amount: f64,
pub skip_utxo_amount: u32,
}

impl Default for Account {
Expand All @@ -63,6 +64,7 @@ impl Default for Account {
max_feerate: 100_u32,
max_fee_amount: 10_000_u32,
max_send_amount: 1_f64,
skip_utxo_amount: 1_000_u32,
}
}
}
Expand Down
19 changes: 15 additions & 4 deletions bitbox/src/db/activity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@ use anyhow::Result;
#[derive(Serialize, Deserialize, Debug, Clone, sqlx::FromRow)]
pub struct Activity {
pub uuid: String,
pub network: String,
pub data: String,
}

pub async fn new() -> Result<()> {
sqlx::query(
"CREATE TABLE IF NOT EXISTS activity (
id INTEGER PRIMARY KEY,
uuid TEXT NOT NULL UNIQUE,
network TEXT NOT NULL,
data TEXT NOT NULL)",
id INTEGER PRIMARY KEY,
uuid TEXT NOT NULL UNIQUE,
network TEXT NOT NULL,
data TEXT NOT NULL)",
)
.execute(&pool())
.await?;
Expand All @@ -34,6 +35,16 @@ pub async fn delete_all() -> Result<()> {
Ok(())
}

pub async fn update(uuid: &str, data: &str) -> Result<()> {
sqlx::query("UPDATE activity SET data=? WHERE uuid=?")
.bind(data)
.bind(uuid)
.execute(&pool())
.await?;

Ok(())
}

pub async fn insert(uuid: &str, network: &str, data: &str) -> Result<()> {
sqlx::query("INSERT INTO activity (uuid, network, data) VALUES (?, ?, ?)")
.bind(uuid)
Expand Down
1 change: 1 addition & 0 deletions bitbox/src/db/address_book.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use anyhow::Result;
#[derive(Serialize, Deserialize, Debug, Clone, sqlx::FromRow)]
pub struct AddressBook {
pub uuid: String,
pub network: String,
pub data: String,
}

Expand Down
94 changes: 87 additions & 7 deletions bitbox/src/logic/activity.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
use crate::db;
use crate::message::{async_message_success, async_message_warn};
use crate::slint_generatedAppWindow::{ActivityItem, AppWindow, Logic, Store};
use crate::util;
use crate::util::translator::tr;
use crate::wallet::transaction::blockstream;
use crate::{db, util};
use serde_json::{json, Value};
use slint::{ComponentHandle, Model, VecModel, Weak};
use std::sync::atomic::{AtomicBool, Ordering};
use tokio::task::spawn;
use tokio::time::{sleep, Duration};
use uuid::Uuid;

static IS_FLUSH_NOW: AtomicBool = AtomicBool::new(false);

pub fn init(ui: &AppWindow) {
check_confirm_timer(ui.as_weak());

let ui_handle = ui.as_weak();
ui.global::<Logic>().on_activity_delete_item(move |uuid| {
let ui = ui_handle.unwrap();
Expand Down Expand Up @@ -36,6 +42,84 @@ pub fn init(ui: &AppWindow) {
}
}
});

ui.global::<Logic>().on_flush_activity(move || {
IS_FLUSH_NOW.store(true, Ordering::SeqCst);
});
}

fn check_confirm_timer(ui: Weak<AppWindow>) {
spawn(async move {
const FLUSH_INTERVAL: u64 = 60_u64;
let mut inc_index = 0_u64;

loop {
if inc_index % FLUSH_INTERVAL == 0 || IS_FLUSH_NOW.load(Ordering::SeqCst) {
match db::activity::select_all().await {
Ok(items) => {
let mut update_items = vec![];

for item in items.into_iter() {
match serde_json::from_str::<Value>(&item.data) {
Err(e) => log::warn!("Error: {e:?}"),
Ok(mut value) => {
if value["status"].as_str().unwrap() == "unconfirmed" {
let txid = value["txid"].as_str().unwrap();
match blockstream::is_tx_confirmed(&item.network, &txid)
.await
{
Ok(true) => {
value["status"] =
Value::String("confirmed".to_string());
let _ = db::activity::update(
&item.uuid,
&value.to_string(),
)
.await;
update_items.push((item.uuid, item.network));
}
_ => (),
}
}
}
}
}

let ui = ui.clone();
let _ = slint::invoke_from_event_loop(move || {
let ui = ui.unwrap();
let current_network =
ui.global::<Store>().get_account().network.to_string();

for (uuid, network) in update_items.into_iter() {
if current_network != network {
continue;
}

for (index, mut item) in
ui.global::<Store>().get_activity_datas().iter().enumerate()
{
if uuid.as_str() != item.uuid.as_str() {
continue;
}

item.status = "confirmed".into();
ui.global::<Store>()
.get_activity_datas()
.set_row_data(index, item);
}
}
});
}
Err(e) => log::warn!("Error: {}", e),
};
}

inc_index += 1;
IS_FLUSH_NOW.store(false, Ordering::SeqCst);
sleep(Duration::from_secs(1)).await;
}
});
}

pub fn load_items(ui: Weak<AppWindow>, network: String) {
Expand Down Expand Up @@ -127,11 +211,7 @@ pub fn activity_add_item(
#[allow(unused)]
fn test_add(ui: &AppWindow) {
for i in 0..5 {
let network = if i % 2 == 0 {
"main"
} else {
"test"
};
let network = if i % 2 == 0 { "main" } else { "test" };

let i = format!("{}", i);
activity_add_item(&ui, network, &i, &i, &i, &i);
Expand Down
1 change: 1 addition & 0 deletions bitbox/src/logic/btcinfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ fn update_timer(ui: Weak<AppWindow>) {
}

inc_index += 1;
IS_FLUSH_NOW.store(false, Ordering::SeqCst);
sleep(Duration::from_secs(1)).await;
}
});
Expand Down
16 changes: 16 additions & 0 deletions bitbox/src/logic/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ macro_rules! message_success {
};
}

#[macro_export]
macro_rules! message_info {
($ui:expr, $msg:expr) => {
$ui.global::<Logic>()
.invoke_show_message(slint::format!("{}", $msg), "info".into());
};
}

pub fn async_message_warn(ui: Weak<AppWindow>, msg: String) {
let _ = slint::invoke_from_event_loop(move || {
ui.unwrap()
Expand All @@ -34,6 +42,14 @@ pub fn async_message_success(ui: Weak<AppWindow>, msg: String) {
});
}

pub fn async_message_info(ui: Weak<AppWindow>, msg: String) {

Check warning on line 45 in bitbox/src/logic/message.rs

View workflow job for this annotation

GitHub Actions / action-run

function `async_message_info` is never used
let _ = slint::invoke_from_event_loop(move || {
ui.unwrap()
.global::<Logic>()
.invoke_show_message(slint::format!("{}", msg), "info".into());
});
}

pub fn init(ui: &AppWindow) {
let timer = Timer::default();
let ui_handle = ui.as_weak();
Expand Down
35 changes: 22 additions & 13 deletions bitbox/src/logic/send_tx.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
use crate::message::{async_message_success, async_message_warn};
use crate::activity::activity_add_item;
use crate::message::async_message_warn;
use crate::password_dialog::is_password_verify;
use crate::slint_generatedAppWindow::{AppWindow, Logic, Store, TxDetail};
use crate::util::translator::tr;
use crate::wallet::{
account::{address, sendinfo, tx},
transaction::blockstream,
};
use crate::{config, db, message_warn};
use crate::{config, db, message_info, message_success, message_warn};
use serde_json::Value;
use slint::ComponentHandle;
use tokio::task::spawn;
use uuid::Uuid;

pub fn init(ui: &AppWindow) {
let ui_handle = ui.as_weak();
Expand Down Expand Up @@ -111,10 +111,8 @@ pub fn init(ui: &AppWindow) {
tx_detail.detail_hex = detail.tx_hex.into();

let _ = slint::invoke_from_event_loop(move || {
ui.clone()
.unwrap()
.global::<Store>()
.set_tx_detail_dialog(tx_detail);
let ui = ui.clone().unwrap();
ui.global::<Store>().set_tx_detail_dialog(tx_detail);
});
}
}
Expand All @@ -131,10 +129,13 @@ pub fn init(ui: &AppWindow) {

let ui_handle = ui.as_weak();
ui.global::<Logic>()
.on_broadcast_tx(move |network, tx_hex| {
.on_broadcast_tx(move |network, tx_hex, send_amount_btc| {
let ui = ui_handle.clone();
let network = network.to_string();
let tx_hex = tx_hex.to_string();
let amount = send_amount_btc.to_string();

message_info!(ui.clone().unwrap(), tr("正在发送交易..."));

spawn(async move {
match blockstream::broadcast_transaction(&network, tx_hex).await {
Expand All @@ -143,11 +144,19 @@ pub fn init(ui: &AppWindow) {
format!("{}. {}: {e:?}", tr("发送交易失败"), tr("原因")),
),
Ok(txid) => {
// TODO
async_message_success(
ui.clone(),
format!("{}. txid: {txid}", tr("发送交易成功")),
);
if !tx::is_valid_txid(&txid) {
async_message_warn(
ui.clone(),
format!("{}. txid: {txid}", tr("非法交易")),
);
return;
}

let _ = slint::invoke_from_event_loop(move || {
let ui = ui.clone().unwrap();
activity_add_item(&ui, &network, &txid, "send", &amount, "unconfirmed");
message_success!(ui, tr("发送交易成功"));
});
}
}
});
Expand Down
7 changes: 7 additions & 0 deletions bitbox/src/logic/setting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ pub fn init(ui: &AppWindow) {
.to_string()
.parse()
.unwrap_or(1_f64);
config.account.skip_utxo_amount = setting_config
.account
.skip_utxo_amount
.to_string()
.parse()
.unwrap_or(1_000);

config.socks5.enabled = setting_config.proxy.enabled;
config.socks5.url = setting_config.proxy.url.to_string();
Expand Down Expand Up @@ -113,6 +119,7 @@ fn init_setting_dialog(ui: Weak<AppWindow>) {
setting_dialog.account.max_feerate = slint::format!("{}", account_config.max_feerate);
setting_dialog.account.max_fee_amount = slint::format!("{}", account_config.max_fee_amount);
setting_dialog.account.max_send_amount = slint::format!("{}", account_config.max_send_amount);
setting_dialog.account.skip_utxo_amount = slint::format!("{}", account_config.skip_utxo_amount);

setting_dialog.proxy.enabled = socks5_config.enabled;
setting_dialog.proxy.url = socks5_config.url.into();
Expand Down
9 changes: 8 additions & 1 deletion bitbox/src/logic/util.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::message_warn;
use crate::slint_generatedAppWindow::{AppWindow, Logic, Util};
use crate::util::translator::tr;
use crate::util::{number, time};
use crate::util::{self, number, time};
use image::Rgb;
use qrcode::QrCode;
use slint::{ComponentHandle, Image, Rgb8Pixel, SharedPixelBuffer};
Expand Down Expand Up @@ -55,4 +55,11 @@ pub fn init(ui: &AppWindow) {

ui.global::<Util>()
.on_local_now(move |format| time::local_now(format.as_str()).into());

ui.global::<Util>()
.on_split_and_join_string(move |input, length, sep| {
util::str::split_string_to_fixed_length_parts(input.as_str(), length as usize)
.join(sep.as_str())
.into()
});
}
1 change: 1 addition & 0 deletions bitbox/src/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ pub mod http;
pub mod number;
pub mod translator;
pub mod time;
pub mod str;
8 changes: 8 additions & 0 deletions bitbox/src/util/str.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
pub fn split_string_to_fixed_length_parts(input: &str, length: usize) -> Vec<String> {
input
.chars()
.collect::<Vec<_>>()
.chunks(length)
.map(|chunk| chunk.iter().collect::<String>())
.collect()
}
1 change: 1 addition & 0 deletions bitbox/src/util/translator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub fn tr(text: &str) -> String {
items.insert("生成交易失败", "Generate transaction failed");
items.insert("发送交易成功", "Send transaction success");
items.insert("发送交易失败", "Send transaction failed");
items.insert("非法交易", "Invalid transaction");
items.insert("刷新...", "Flush...");
items.insert("在线", "Online");
items.insert("正忙", "Busy");
Expand Down
8 changes: 1 addition & 7 deletions bitbox/src/wallet/account/address.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
extern crate rand;

use crate::db;
use crate::util;
use anyhow::{anyhow, Result};
use bip32::{Language, Mnemonic, Seed};
Expand Down Expand Up @@ -49,7 +48,7 @@ impl Info {
..Default::default()
})
}

#[allow(dead_code)]
pub fn recover(password: &str, mnemonic: &str) -> Result<Self> {
Self::new("account_0", password, mnemonic)
}
Expand Down Expand Up @@ -93,11 +92,6 @@ impl Info {

Ok(())
}

pub async fn save(&self) -> Result<()> {
let text = serde_json::to_string(self)?;
db::account::insert(&self.uuid, &text).await
}
}

#[cfg(test)]
Expand Down
Loading

0 comments on commit e860ee6

Please sign in to comment.