iyzipay-rust 0.1.2

iyzipay rust client
Documentation
extern crate chrono;
extern crate sha1;

use std::iter;

use chrono::prelude::*;
use log::debug;
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use reqwest::header::{HeaderMap, HeaderValue};
use uuid::Uuid;

use crate::hash::HashGenerator;
use crate::hash::IyziAuthV2Generator;
use crate::options::Options;

pub const CLIENT_VERSION: &str = env!("CARGO_PKG_VERSION");
pub const CLIENT_TITLE: &str = env!("CARGO_PKG_NAME");

const AUTHORIZATION: &str = "Authorization";
const RANDOM_HEADER_NAME: &str = "x-iyzi-rnd";
const CLIENT_VERSION_HEADER_NAME: &str = "x-iyzi-client-version";
const RANDOM_STRING_SIZE: usize = 8;

#[derive(Debug, Default, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct IyzipayResource {
    status: Option<String>,

    error_code: Option<String>,

    error_message: Option<String>,

    error_group: Option<String>,

    locale: Option<String>,

    system_time: Option<i64>,

    conversation_id: Option<String>,
}

impl IyzipayResource {
    pub fn new() -> IyzipayResource {
        IyzipayResource::default()
    }

    pub fn get_http_headers(request: String, options: &Options) -> HeaderMap {
        let mut headers = HeaderMap::new();
        let mut rng = thread_rng();
        let random_alpanumeric: String = iter::repeat(())
            .map(|()| rng.sample(Alphanumeric))
            .take(RANDOM_STRING_SIZE)
            .collect();
        let random_string = format!(
            "{}{}",
            IyzipayResource::get_unix_timestamp_ms(),
            random_alpanumeric
        );
        debug!("Request:{}", request);

        headers.insert(
            RANDOM_HEADER_NAME,
            HeaderValue::from_str(random_string.as_str()).unwrap(),
        );
        headers.insert(
            AUTHORIZATION,
            IyzipayResource::prepare_authorization_header(request, random_string, options),
        );

        IyzipayResource::put_client_version_header(&mut headers);

        debug!(
            "Header:{}:{:?}",
            RANDOM_HEADER_NAME,
            headers.get(RANDOM_HEADER_NAME).unwrap()
        );
        debug!(
            "Header:{}:{:?}",
            AUTHORIZATION,
            headers.get(AUTHORIZATION).unwrap()
        );
        debug!(
            "Header:{}:{:?}",
            CLIENT_VERSION_HEADER_NAME,
            headers.get(CLIENT_VERSION_HEADER_NAME).unwrap()
        );
        headers
    }

    pub fn prepare_authorization_header(
        request: String,
        random_string: String,
        options: &Options,
    ) -> HeaderValue {
        let auth_str = format!(
            "{} {}:{}",
            "IYZWS",
            options.api_key(),
            HashGenerator::generate_hash(
                options.api_key(),
                options.secret_key(),
                random_string.as_str(),
                request.as_str()
            )
        );
        HeaderValue::from_str(auth_str.as_str()).unwrap()
    }

    pub fn prepare_authorization_header_v2(
        uri: String,
        request: String,
        random_string: String,
        options: &Options,
    ) -> HeaderValue {
        let auth_str = format!(
            "{} {}",
            "IYZWSv2",
            IyziAuthV2Generator::generate_auth_content(
                uri.as_str(),
                options.api_key(),
                options.secret_key(),
                random_string.as_str(),
                request.as_str()
            )
        );
        HeaderValue::from_str(auth_str.as_str()).unwrap()
    }

    pub fn get_http_headers_v2(uri: String, request: String, options: &Options) -> HeaderMap {
        let mut headers = HeaderMap::new();
        let random_string = Uuid::new_v4().to_string();
        headers.insert(
            AUTHORIZATION,
            IyzipayResource::prepare_authorization_header_v2(uri, request, random_string, options),
        );
        IyzipayResource::put_client_version_header(&mut headers);

        debug!(
            "Header:{}:{:?}",
            AUTHORIZATION,
            headers.get(AUTHORIZATION).unwrap()
        );
        debug!(
            "Header:{}:{:?}",
            CLIENT_VERSION_HEADER_NAME,
            headers.get(CLIENT_VERSION_HEADER_NAME).unwrap()
        );

        headers
    }

    fn get_unix_timestamp_ms() -> i64 {
        let now = Utc::now();
        let seconds: i64 = now.timestamp();
        let nanoseconds: i64 = now.nanosecond() as i64;
        (seconds * 1000) + (nanoseconds / 1000 / 1000)
    }

    fn put_client_version_header(headers: &mut HeaderMap<HeaderValue>) {
        let client: String = format!("{}-{}", CLIENT_TITLE, CLIENT_VERSION);
        headers.insert(
            CLIENT_VERSION_HEADER_NAME,
            HeaderValue::from_str(client.as_str()).unwrap(),
        );
    }

    pub fn set_status<T: Into<String>>(&mut self, status: T) {
        self.status = Some(status.into());
    }

    pub fn set_error_code<T: Into<String>>(&mut self, error_code: T) {
        self.error_code = Some(error_code.into());
    }

    pub fn set_error_message<T: Into<String>>(&mut self, error_message: T) {
        self.error_message = Some(error_message.into());
    }

    pub fn set_error_group<T: Into<String>>(&mut self, error_group: T) {
        self.error_group = Some(error_group.into());
    }

    pub fn set_locale<T: Into<String>>(&mut self, locale: T) {
        self.locale = Some(locale.into());
    }

    pub fn set_system_time<T: Into<i64>>(&mut self, system_time: T) {
        self.system_time = Some(system_time.into());
    }

    pub fn set_conversation_id<T: Into<String>>(&mut self, conversation_id: T) {
        self.conversation_id = Some(conversation_id.into());
    }

    pub fn status(&self) -> Option<&String> {
        self.status.as_ref()
    }
    pub fn error_code(&self) -> Option<&String> {
        self.error_code.as_ref()
    }
    pub fn error_message(&self) -> Option<&String> {
        self.error_message.as_ref()
    }
    pub fn error_group(&self) -> Option<&String> {
        self.error_group.as_ref()
    }
    pub fn locale(&self) -> Option<&String> {
        self.locale.as_ref()
    }
    pub fn system_time(&self) -> Option<&i64> {
        self.system_time.as_ref()
    }
    pub fn conversation_id(&self) -> Option<&String> {
        self.conversation_id.as_ref()
    }
}