use std::c_str::CString;
use std::mem;
use std::slice;
use libc;
use {raw, Error, Cred, CredentialType};
pub struct RemoteCallbacks<'a> {
progress: Option<TransferProgress<'a>>,
credentials: Option<Credentials<'a>>,
sideband_progress: Option<TransportMessage<'a>>,
}
#[deriving(Copy)]
pub struct Progress {
pub total_objects: uint,
pub indexed_objects: uint,
pub received_objects: uint,
pub local_objects: uint,
pub total_deltas: uint,
pub indexed_deltas: uint,
pub received_bytes: uint,
}
pub type Credentials<'a> = |url: &str,
username_from_url: Option<&str>,
allowed_types: CredentialType|: 'a
-> Result<Cred, Error>;
pub type TransferProgress<'a> = |progress: Progress|: 'a -> bool;
pub type TransportMessage<'a> = |message: &[u8]|: 'a -> bool;
impl<'a> RemoteCallbacks<'a> {
pub fn new() -> RemoteCallbacks<'a> {
RemoteCallbacks {
credentials: None,
progress: None,
sideband_progress: None,
}
}
pub fn credentials(mut self, cb: Credentials<'a>) -> RemoteCallbacks<'a> {
self.credentials = Some(cb);
self
}
pub fn transfer_progress(mut self, cb: TransferProgress<'a>)
-> RemoteCallbacks<'a> {
self.progress = Some(cb);
self
}
pub fn sideband_progress(mut self, cb: TransportMessage<'a>)
-> RemoteCallbacks<'a> {
self.sideband_progress = Some(cb);
self
}
pub unsafe fn raw(&mut self) -> raw::git_remote_callbacks {
let mut callbacks: raw::git_remote_callbacks = mem::zeroed();
assert_eq!(raw::git_remote_init_callbacks(&mut callbacks,
raw::GIT_REMOTE_CALLBACKS_VERSION), 0);
if self.progress.is_some() {
callbacks.transfer_progress = Some(transfer_progress_cb);
}
if self.credentials.is_some() {
callbacks.credentials = Some(credentials_cb);
}
if self.sideband_progress.is_some() {
callbacks.sideband_progress = Some(sideband_progress_cb);
}
callbacks.payload = self as *mut _ as *mut _;
return callbacks;
}
}
extern fn credentials_cb(ret: *mut *mut raw::git_cred,
url: *const libc::c_char,
username_from_url: *const libc::c_char,
allowed_types: libc::c_uint,
payload: *mut libc::c_void) -> libc::c_int {
unsafe {
let payload: &mut RemoteCallbacks = &mut *(payload as *mut RemoteCallbacks);
let callback = match payload.credentials {
Some(ref mut c) => c,
None => return raw::GIT_PASSTHROUGH as libc::c_int,
};
*ret = 0 as *mut raw::git_cred;
let url = CString::new(url, false);
let url = match url.as_str() {
Some(url) => url,
None => return raw::GIT_PASSTHROUGH as libc::c_int,
};
let username_from_url = if username_from_url.is_null() {
None
} else {
Some(CString::new(username_from_url, false))
};
let username_from_url = match username_from_url {
Some(ref username) => match username.as_str() {
Some(s) => Some(s),
None => return raw::GIT_PASSTHROUGH as libc::c_int,
},
None => None,
};
let cred_type = CredentialType::from_bits_truncate(allowed_types as uint);
match (*callback)(url, username_from_url, cred_type) {
Ok(cred) => {
if allowed_types & (cred.credtype() as libc::c_uint) != 0 {
*ret = cred.unwrap();
0
} else {
raw::GIT_PASSTHROUGH as libc::c_int
}
}
Err(e) => e.raw_code() as libc::c_int,
}
}
}
extern fn transfer_progress_cb(stats: *const raw::git_transfer_progress,
payload: *mut libc::c_void) -> libc::c_int {
unsafe {
let payload: &mut RemoteCallbacks = &mut *(payload as *mut RemoteCallbacks);
let callback = match payload.progress {
Some(ref mut c) => c,
None => return 0,
};
let progress = Progress {
total_objects: (*stats).total_objects as uint,
indexed_objects: (*stats).indexed_objects as uint,
received_objects: (*stats).received_objects as uint,
local_objects: (*stats).local_objects as uint,
total_deltas: (*stats).total_deltas as uint,
indexed_deltas: (*stats).indexed_deltas as uint,
received_bytes: (*stats).received_bytes as uint,
};
if (*callback)(progress) {0} else {-1}
}
}
extern fn sideband_progress_cb(str: *const libc::c_char,
len: libc::c_int,
payload: *mut libc::c_void) -> libc::c_int {
unsafe {
let payload: &mut RemoteCallbacks = &mut *(payload as *mut RemoteCallbacks);
let callback = match payload.sideband_progress {
Some(ref mut c) => c,
None => return 0,
};
let ptr = str as *const u8;
let buf = slice::from_raw_buf(&ptr, len as uint);
let r = (*callback)(buf);
if r {0} else {-1}
}
}