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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
use paste::paste;

pub use super::super::{router, Error, Response};

pub type HandleReqReturn<T> = Result<(super::proto::DACRequest, DACEnv), Response<T>>;

#[derive(Debug, Eq, PartialEq, Hash)]
pub enum DACEnv {
    RealTime,
    TimeDelay,
    Both,
}

impl From<super::super::dac::DACEnv> for DACEnv {
    fn from(from: super::super::dac::DACEnv) -> Self {
        match from {
            super::super::dac::DACEnv::RealTime => DACEnv::RealTime,
            super::super::dac::DACEnv::TimeDelay => DACEnv::TimeDelay,
        }
    }
}

#[derive(Hash, Eq, PartialEq, Debug)]
pub(super) struct DACKey {
    pub env: DACEnv,
    pub cmd: String,
}

macro_rules! router {
    ($($n:ident);*) => {
        #[derive(Default, Debug)]
        pub struct Router {
            pub(super) command_map: std::collections::HashMap<DACKey, uuid::Uuid>
        }

        impl router::InnerRouter<()> for Router {
            type Request = (super::proto::DACRequest, DACEnv);
            type Response = super::proto::DACResponse;

            fn Logout_request(&mut self, _client: &(), _req: &router::LogoutRequest, command_id: uuid::Uuid) -> HandleReqReturn<router::LogoutResponse> {
                self.command_map.insert(DACKey {
                    env: DACEnv::Both,
                    cmd: "#exit".to_string(),
                }, command_id);
                Ok((super::proto::DACRequest::Exit, DACEnv::Both))
            }

            fn Logout_response(&mut self, return_path: router::Sender<router::LogoutResponse>, _response: Self::Response) {
                let _ = return_path.send(Ok(router::CommandResponse {
                    response: (),
                    extra_values: vec![],
                    transaction_id: None,
                }));
            }

            fn DomainCheck_request(&mut self, _client: &(), req: &router::DomainCheckRequest, command_id: uuid::Uuid) -> HandleReqReturn<router::DomainCheckResponse> {
                if req.fee_check.is_some() {
                    return Err(Err(Error::Unsupported));
                }
                if req.launch_check.is_some() {
                    return Err(Err(Error::Unsupported));
                }

                self.command_map.insert(DACKey {
                    env: DACEnv::RealTime,
                    cmd: req.name.clone(),
                }, command_id);
                Ok((super::proto::DACRequest::Domain(req.name.clone()), DACEnv::RealTime))
            }

            fn DomainCheck_response(&mut self, return_path: router::Sender<router::DomainCheckResponse>, response: Self::Response) {
                match response {
                    super::proto::DACResponse::DomainRT(d) => {
                        let _ = return_path.send(Ok(router::CommandResponse {
                            response: router::DomainCheckResponse {
                                avail: !d.registered,
                                reason: None,
                                fee_check: None,
                                donuts_fee_check: None,
                                eurid_check: None,
                                eurid_idn: None,
                            },
                            extra_values: vec![],
                            transaction_id: None,
                        }));
                    },
                    super::proto::DACResponse::DomainTD(d) => {
                        let _ = return_path.send(Ok(router::CommandResponse {
                            response: router::DomainCheckResponse {
                                avail: match d.registered {
                                    super::proto::DomainRegistered::Registered => false,
                                    super::proto::DomainRegistered::Available => true,
                                    super::proto::DomainRegistered::NotWithinRegistry => false,
                                    super::proto::DomainRegistered::RulesPrevent => false,
                                },
                                reason: match d.registered {
                                    super::proto::DomainRegistered::Registered => Some("already registered".to_string()),
                                    super::proto::DomainRegistered::Available => None,
                                    super::proto::DomainRegistered::NotWithinRegistry => Some("not within this registry".to_string()),
                                    super::proto::DomainRegistered::RulesPrevent => Some("rules prevent registration".to_string()),
                                },
                                fee_check: None,
                                donuts_fee_check: None,
                                eurid_check: None,
                                eurid_idn: None,
                            },
                            extra_values: vec![],
                            transaction_id: None,
                        }));
                    },
                    super::proto::DACResponse::Aub(b) => {
                        let _ = return_path.send(Err(Error::Err(format!("Acceptable usage block, please try again in {} seconds", b.delay))));
                    },
                    _ => {
                        let _ = return_path.send(Err(Error::ServerInternal));
                    },
                }
            }

            fn DACDomain_request(&mut self, _client: &(), req: &router::DACDomainRequest, command_id: uuid::Uuid) -> HandleReqReturn<router::DACDomainResponse> {
                self.command_map.insert(DACKey {
                    env: req.env.into(),
                    cmd: req.domain.clone()
                }, command_id);
                Ok((super::proto::DACRequest::Domain(req.domain.clone()), req.env.into()))
            }

            fn DACDomain_response(&mut self, return_path: router::Sender<router::DACDomainResponse>, response: Self::Response) {
                match response {
                    super::proto::DACResponse::DomainRT(d) => {
                        let _ = return_path.send(Ok(router::CommandResponse {
                            response: router::DACDomainResponse {
                                registration_state: if d.registered {
                                    super::super::dac::DomainState::Registered
                                } else {
                                    super::super::dac::DomainState::Available
                                },
                                detagged: d.detagged,
                                created: d.created,
                                expiry: d.expiry,
                                status: super::super::dac::DomainStatus::Unknown,
                                suspended: None,
                                tag: d.tag,
                            },
                            extra_values: vec![],
                            transaction_id: None,
                        }));
                    },
                    super::proto::DACResponse::DomainTD(d) => {
                        let _ = return_path.send(Ok(router::CommandResponse {
                            response: router::DACDomainResponse {
                                registration_state: match d.registered {
                                    super::proto::DomainRegistered::Registered => super::super::dac::DomainState::Registered,
                                    super::proto::DomainRegistered::Available => super::super::dac::DomainState::Available,
                                    super::proto::DomainRegistered::NotWithinRegistry => super::super::dac::DomainState::NotWithinRegistry,
                                    super::proto::DomainRegistered::RulesPrevent => super::super::dac::DomainState::RulesPrevent,
                                },
                                detagged: d.detagged,
                                created: d.created,
                                expiry: d.expiry,
                                status: match d.status {
                                    super::proto::DomainStatus::Unknown => super::super::dac::DomainStatus::Unknown,
                                    super::proto::DomainStatus::RegisteredUntilExpiry => super::super::dac::DomainStatus::RegisteredUntilExpiry,
                                    super::proto::DomainStatus::RenewalRequired => super::super::dac::DomainStatus::RenewalRequired,
                                    super::proto::DomainStatus::NoLongerRequired => super::super::dac::DomainStatus::NoLongerRequired,
                                },
                                suspended: Some(d.suspended),
                                tag: d.tag,
                            },
                            extra_values: vec![],
                            transaction_id: None,
                        }));
                    },
                    super::proto::DACResponse::Aub(b) => {
                        let _ = return_path.send(Err(Error::Err(format!("Acceptable usage block, please try again in {} seconds", b.delay))));
                    },
                    _ => {
                        let _ = return_path.send(Err(Error::ServerInternal));
                    },
                }
            }

            fn DACUsage_request(&mut self, _client: &(), req: &router::DACUsageRequest, command_id: uuid::Uuid) -> HandleReqReturn<router::DACUsageResponse> {
                self.command_map.insert(DACKey {
                    env: req.env.into(),
                    cmd: "#usage".to_string()
                }, command_id);
                Ok((super::proto::DACRequest::Usage, req.env.into()))
            }

            fn DACUsage_response(&mut self, return_path: router::Sender<router::DACUsageResponse>, response: Self::Response) {
                match response {
                    super::proto::DACResponse::Usage(u) => {
                        let _ = return_path.send(Ok(router::CommandResponse {
                            response: router::DACUsageResponse {
                                usage_60: u.usage_60,
                                usage_24: u.usage_24,
                            },
                            extra_values: vec![],
                            transaction_id: None,
                        }));
                    },
                    super::proto::DACResponse::Aub(b) => {
                        let _ = return_path.send(Err(Error::Err(format!("Acceptable usage block, please try again in {} seconds", b.delay))));
                    },
                    _ => {
                        let _ = return_path.send(Err(Error::ServerInternal));
                    },
                }
            }

            fn DACLimits_request(&mut self, _client: &(), req: &router::DACLimitsRequest, command_id: uuid::Uuid) -> HandleReqReturn<router::DACLimitsResponse> {
                self.command_map.insert(DACKey {
                    env: req.env.into(),
                    cmd: "#limits".to_string()
                }, command_id);
                Ok((super::proto::DACRequest::Limits, req.env.into()))
            }

            fn DACLimits_response(&mut self, return_path: router::Sender<router::DACLimitsResponse>, response: Self::Response) {
                match response {
                    super::proto::DACResponse::Limits(u) => {
                        let _ = return_path.send(Ok(router::CommandResponse {
                            response: router::DACLimitsResponse {
                                usage_60: u.usage_60,
                                usage_24: u.usage_24,
                            },
                            extra_values: vec![],
                            transaction_id: None,
                        }));
                    },
                    super::proto::DACResponse::Aub(b) => {
                        let _ = return_path.send(Err(Error::Err(format!("Acceptable usage block, please try again in {} seconds", b.delay))));
                    },
                    _ => {
                        let _ = return_path.send(Err(Error::ServerInternal));
                    },
                }
            }

            paste! {
                $(fn [<$n _request>](&mut self, _client: &(), _req: &router::[<$n Request>], _command_id: uuid::Uuid) -> HandleReqReturn<router::[<$n Response>]> {
                    Err(Response::Err(Error::Unsupported))
                })*

                $(fn [<$n _response>](&mut self, return_path: router::Sender<router::[<$n Response>]>, _response: Self::Response) {
                    let _ = return_path.send(Err(Error::Unsupported));
                })*
            }
        }
    }
}

router!(
    Poll;
    PollAck;
    DomainClaimsCheck;
    DomainTrademarkCheck;
    DomainInfo;
    DomainCreate;
    DomainDelete;
    DomainUpdate;
    DomainRenew;
    DomainTransferQuery;
    DomainTransferRequest;
    DomainTransferCancel;
    DomainTransferAccept;
    DomainTransferReject;
    VerisignSync;
    EmailForwardCheck;
    EmailForwardInfo;
    EmailForwardCreate;
    EmailForwardDelete;
    EmailForwardUpdate;
    EmailForwardRenew;
    EmailForwardTransferQuery;
    EmailForwardTransferRequest;
    EmailForwardTransferCancel;
    EmailForwardTransferAccept;
    EmailForwardTransferReject;
    RestoreRequest;
    HostCheck;
    HostInfo;
    HostCreate;
    HostDelete;
    HostUpdate;
    ContactCheck;
    ContactInfo;
    ContactCreate;
    ContactDelete;
    ContactUpdate;
    ContactTransferQuery;
    ContactTransferRequest;
    ContactTransferAccept;
    ContactTransferReject;
    NominetTagList;
    NominetAccept;
    NominetReject;
    NominetRelease;
    NominetContactValidate;
    NominetLock;
    NominetUnlock;
    Balance;
    MaintenanceList;
    MaintenanceInfo;
    EURIDHitPoints;
    EURIDRegistrationLimit;
    EURIDDNSSECEligibility;
    EURIDDNSQuality;
    TMCHCheck;
    TMCHCreate;
    TMCHMarkInfo;
    TMCHMarkSMDInfo;
    TMCHMarkEncodedSMDInfo;
    TMCHMarkFileInfo;
    TMCHUpdate;
    TMCHRenew;
    TMCHTransferInitiate;
    TMCHTransfer;
    TMCHTrexActivate;
    TMCHTrexRenew;
    Hello
);