Skip to content

Instantly share code, notes, and snippets.

@olly
Created February 22, 2018 13:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save olly/6ca5781ec6ad607bc549d74ae045dbba to your computer and use it in GitHub Desktop.
Save olly/6ca5781ec6ad607bc549d74ae045dbba to your computer and use it in GitHub Desktop.
#![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);
}
&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