1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
use super::super::client;
use super::epp_proto;

impl From<client::balance::BalanceResponse> for epp_proto::BalanceReply {
    fn from(res: client::balance::BalanceResponse) -> Self {
        epp_proto::BalanceReply {
            balance: res.balance,
            currency: res.currency,
            available_credit: res.available_credit,
            credit_limit: res.credit_limit,
            credit_threshold: res.credit_threshold.map(|t| match t {
                client::balance::CreditThreshold::Fixed(f) => {
                    epp_proto::balance_reply::CreditThreshold::FixedCreditThreshold(f)
                }
                client::balance::CreditThreshold::Percentage(p) => {
                    epp_proto::balance_reply::CreditThreshold::PercentageCreditThreshold(p.into())
                }
            }),
            cmd_resp: None,
        }
    }
}

/// Helper function to convert chrono times to protobuf well-known type times
pub fn chrono_to_proto<T: chrono::TimeZone>(
    time: Option<chrono::DateTime<T>>,
) -> Option<prost_types::Timestamp> {
    time.map(|t| prost_types::Timestamp {
        seconds: t.timestamp(),
        nanos: t.timestamp_subsec_nanos() as i32,
    })
}

pub fn proto_to_chrono(
    time: Option<prost_types::Timestamp>,
) -> Option<chrono::DateTime<chrono::Utc>> {
    use chrono::offset::TimeZone;
    match time {
        Some(t) => chrono::Utc
            .timestamp_opt(t.seconds, t.nanos as u32)
            .single(),
        None => None,
    }
}

impl From<client::Error> for tonic::Status {
    fn from(err: client::Error) -> Self {
        match err {
            client::Error::Err(s) => tonic::Status::invalid_argument(s),
            client::Error::NotReady => tonic::Status::unavailable("not yet ready"),
            client::Error::Unsupported => {
                tonic::Status::unimplemented("unsupported operation for registrar")
            }
            client::Error::Timeout => {
                tonic::Status::deadline_exceeded("registrar didn't respond in time")
            }
            client::Error::ServerInternal => tonic::Status::internal("internal server error"),
        }
    }
}

pub fn i32_from_transfer_status(from: client::TransferStatus) -> i32 {
    match from {
        client::TransferStatus::ClientApproved => {
            epp_proto::common::TransferStatus::ClientApproved.into()
        }
        client::TransferStatus::ClientCancelled => {
            epp_proto::common::TransferStatus::ClientCancelled.into()
        }
        client::TransferStatus::ClientRejected => {
            epp_proto::common::TransferStatus::ClientRejected.into()
        }
        client::TransferStatus::Pending => epp_proto::common::TransferStatus::Pending.into(),
        client::TransferStatus::ServerApproved => {
            epp_proto::common::TransferStatus::ServerApproved.into()
        }
        client::TransferStatus::ServerCancelled => {
            epp_proto::common::TransferStatus::ServerCancelled.into()
        }
    }
}

impl From<client::verisign::LowBalanceData> for epp_proto::BalanceReply {
    fn from(res: client::verisign::LowBalanceData) -> Self {
        epp_proto::BalanceReply {
            balance: String::new(),
            currency: String::new(),
            available_credit: Some(res.available_credit),
            credit_limit: Some(res.credit_limit),
            credit_threshold: Some(match res.credit_threshold {
                client::verisign::CreditThreshold::Fixed(f) => {
                    epp_proto::balance_reply::CreditThreshold::FixedCreditThreshold(f)
                }
                client::verisign::CreditThreshold::Percentage(p) => {
                    epp_proto::balance_reply::CreditThreshold::PercentageCreditThreshold(p.into())
                }
            }),
            cmd_resp: None,
        }
    }
}

pub fn map_command_response<T>(
    from: client::CommandResponse<T>,
) -> (T, epp_proto::common::CommandResponse) {
    (
        from.response,
        epp_proto::common::CommandResponse {
            extra_values: from
                .extra_values
                .into_iter()
                .map(|e| epp_proto::common::CommandExtraValue {
                    reason: e.reason,
                    value: e.value,
                })
                .collect(),
            transaction_id: from
                .transaction_id
                .map(|t| epp_proto::common::CommandTransactionId {
                    client: t.client,
                    server: t.server,
                }),
        },
    )
}

pub fn period_unit_from_i32(from: i32) -> client::PeriodUnit {
    match epp_proto::common::period::Unit::from_i32(from) {
        Some(e) => match e {
            epp_proto::common::period::Unit::Months => client::PeriodUnit::Months,
            epp_proto::common::period::Unit::Years => client::PeriodUnit::Years,
        },
        None => client::PeriodUnit::Years,
    }
}

pub fn i32_from_period_unit(from: client::PeriodUnit) -> i32 {
    match from {
        client::PeriodUnit::Months => epp_proto::common::period::Unit::Months.into(),
        client::PeriodUnit::Years => epp_proto::common::period::Unit::Years.into(),
    }
}

impl From<epp_proto::common::Period> for client::Period {
    fn from(from: epp_proto::common::Period) -> Self {
        client::Period {
            unit: period_unit_from_i32(from.unit),
            value: from.value,
        }
    }
}

impl From<epp_proto::common::Phone> for client::Phone {
    fn from(from: epp_proto::common::Phone) -> Self {
        client::Phone {
            number: from.number,
            extension: from.extension,
        }
    }
}

impl From<client::Phone> for epp_proto::common::Phone {
    fn from(from: client::Phone) -> Self {
        epp_proto::common::Phone {
            number: from.number,
            extension: from.extension,
        }
    }
}