Created
February 22, 2018 13:43
-
-
Save olly/6ca5781ec6ad607bc549d74ae045dbba to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![allow(non_upper_case_globals)] | |
#![allow(non_camel_case_types)] | |
#![allow(non_snake_case)] | |
extern crate chrono; | |
#[macro_use] | |
extern crate serde_json; | |
extern crate uuid; | |
use chrono::TimeZone; | |
use std::ffi::CString; | |
use std::ffi::CStr; | |
use std::os::raw::c_void; | |
use std::path::Path; | |
use uuid::Uuid; | |
include!(concat!(env!("OUT_DIR"), "/bindings.rs")); | |
extern "C" fn transaction_callback( | |
data: OfxTransactionData, | |
_user_data: *mut std::os::raw::c_void, | |
) -> i32 { | |
let context: &mut Context = unsafe { &mut *(_user_data as *mut Context) }; | |
println!("callback: user_data {:p}", _user_data); | |
println!("callback: handler {:p}", context.handler); | |
// context.transaction_callback(Transaction::from(data)); | |
return 0; | |
} | |
#[derive(Debug)] | |
struct Transaction { | |
unique_id: Option<String>, | |
fi_id: Option<String>, | |
description: Option<String>, | |
amount: Option<f64>, | |
date: Option<chrono::DateTime<chrono::Utc>>, | |
} | |
impl From<OfxTransactionData> for Transaction { | |
fn from(data: OfxTransactionData) -> Self { | |
let unique_id = match data.unique_id_valid { | |
1 => Some(unsafe { CStr::from_ptr(data.unique_id.as_ptr()) }.to_str().unwrap().to_string()), | |
_ => None, | |
}; | |
let fi_id = match data.fi_id_valid { | |
1 => Some(unsafe { CStr::from_ptr(data.fi_id.as_ptr()) }.to_str().unwrap().to_string()), | |
_ => None, | |
}; | |
let name = match data.name_valid { | |
1 => Some(unsafe { CStr::from_ptr(data.name.as_ptr()) }.to_str().unwrap().to_string()), | |
_ => None, | |
}; | |
let amount = match data.amount_valid { | |
1 => Some(data.amount), | |
_ => None, | |
}; | |
let date = match data.date_initiated_valid { | |
1 => Some(chrono::Utc.timestamp(data.date_initiated, 0)), | |
_ => None, | |
}; | |
return Transaction { | |
unique_id: unique_id, | |
fi_id: fi_id, | |
description: name, | |
amount: amount, | |
date: date, | |
}; | |
} | |
} | |
trait Handler: std::fmt::Debug { | |
fn transaction_callback(&self) -> (Option<fn(transaction: Transaction) -> ()>); | |
} | |
struct Context<'a> { | |
context: LibofxContextPtr, | |
handler: &'a Handler, | |
} | |
impl<'a> std::fmt::Debug for Context<'a> { | |
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | |
// write!(f, "Context {:?}", self.context) | |
write!(f, "Context {:?} {:?}", self.context, self.handler) | |
} | |
} | |
impl<'a> Context<'a> { | |
fn new(handler: &'a Handler) -> Self { | |
let context_ptr = unsafe { libofx_get_new_context() }; | |
let mut context = Context { | |
context: context_ptr, | |
handler: handler, | |
}; | |
println!("Context::new &context: {:p}", &context); | |
println!("Context::new &mut context: {:p}", &mut context); | |
println!("Context::new &mut context: {:p}", &mut context as *mut _); | |
println!("Context::new &mut context: {:p}", &mut context as *mut _ as *mut c_void); | |
let user_data = &mut context as *mut _ as *mut c_void; | |
println!("Context::new user_data: {:p}", user_data); | |
println!("Context::new handler: {:p}", handler); | |
unsafe { ofx_set_transaction_cb(context.context, Some(transaction_callback), user_data) } | |
return context; | |
} | |
fn transaction_callback(&self, transaction: Transaction) { | |
// println!("{:?}", &self); | |
// if let Some(callback) = self.handler.transaction_callback() { | |
// println!("{:?}", transaction); | |
// callback(transaction); | |
// } | |
} | |
} | |
impl<'a> Drop for Context<'a> { | |
fn drop(&mut self) { | |
unsafe { libofx_free_context(self.context) }; | |
} | |
} | |
#[derive(Debug)] | |
struct HermesImporter { | |
transactions: Vec<Transaction> | |
} | |
impl HermesImporter { | |
fn new() -> Self { | |
return HermesImporter { | |
transactions: Vec::new() | |
} | |
} | |
} | |
impl Handler for HermesImporter { | |
fn transaction_callback(&self) -> (Option<fn(transaction: Transaction) -> ()>) { | |
let closure = |transaction: Transaction| -> () { | |
let namespace = Uuid::parse_str("724E48D0-17C0-11E8-ADD0-5BB725286909").unwrap(); | |
let identifier = Uuid::new_v5(&namespace, transaction.fi_id.unwrap().as_str()); | |
let json = json!({ | |
"transaction": { | |
"identifier": identifier.to_string(), | |
"amount": transaction.amount, | |
"date": transaction.date.map(|date| date.format("%Y-%m-%d").to_string()), | |
"description": transaction.description, | |
} | |
}); | |
println!("{}", json.to_string()); | |
}; | |
return Some(closure); | |
} | |
} | |
fn main() { | |
let importer = HermesImporter::new(); | |
println!("&importer: {:p}", &importer); | |
let context = Context::new(&importer); | |
let path = Path::new("/Users/Olly/Dropbox/Documents/Banking/AMEX/2018-01.ofx"); | |
let path_str = CString::new(path.to_str().unwrap()).unwrap(); | |
unsafe { libofx_proc_file(context.context, path_str.as_ptr(), LibofxFileFormat::OFX) }; | |
println!("context.handler: {:p}", context.handler); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
&importer: 0x7ffeef0a0238 | |
Context::new &context: 0x7ffeef09ff50 | |
Context::new &mut context: 0x7ffeef09ff50 | |
Context::new &mut context: 0x7ffeef09ff50 | |
Context::new &mut context: 0x7ffeef09ff50 | |
Context::new user_data: 0x7ffeef09ff50 | |
Context::new handler: 0x7ffeef0a0238 | |
callback: user_data 0x7ffeef09ff50 | |
callback: handler 0x0 | |
callback: user_data 0x7ffeef09ff50 | |
callback: handler 0x0 | |
... | |
context.handler: 0x7ffeef0a0238 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment