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
// Copyright 2018-2019 Urs Schulz
//
// This file is part of inwx-rs.
//
// inwx-rs is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// inwx-rs is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with inwx-rs.  If not, see <http://www.gnu.org/licenses/>.


use std::sync::Arc;
use std::sync::Mutex;

use crate::request::Request;

use crate::connection::Connection;

use super::RequestError;
use super::Value;


#[derive(Debug)]
pub struct DomainInfo {
    pub ro_id: i32,
    pub domain: String,
    pub typ: String,
    pub slave_dns: Vec<(String, String)>,
    pub records: Vec<DomainRecord>,
}


#[derive(Debug, Clone)]
pub struct DomainRecord {
    pub id: i32,
    pub name: String,
    pub typ: String,
    pub content: String,
    pub ttl: i32,
    pub prio: i32,
}


pub struct Nameserver {
    pub(crate) conn: Arc<Mutex<Connection>>,
}


impl Nameserver {
    pub fn info(&mut self, domain: &str) -> Result<DomainInfo, RequestError> {
        const E: RequestError = RequestError::InvalidResponse;

        let mut req = Request::new("nameserver.info");
        req.param("domain", Value::from(domain));
        let res = self.conn.lock().unwrap().send(&req)?.ok_or(E)?;

        let domain = res.get("domain").ok_or(E)?.as_str().ok_or(E)?.to_owned();
        let ro_id = res.get("roId").ok_or(E)?.as_i32().ok_or(E)?;
        let typ = res.get("type").ok_or(E)?.as_str().ok_or(E)?.to_owned();

        let mut slave_dns = Vec::new();
        if let Some(arr) = res.get("slaveDns") {
            for entry in arr.as_array().ok_or(E)? {
                let entry = entry.as_struct().ok_or(E)?;
                let name = entry.get("name").ok_or(E)?.as_str().ok_or(E)?.to_owned();
                let ip = entry.get("ip").ok_or(E)?.as_str().ok_or(E)?.to_owned();
                slave_dns.push((name, ip));
            }
        }

        let mut records = Vec::new();
        if let Some(arr) = res.get("record") {
            for record in arr.as_array().ok_or(E)? {
                let record = record.as_struct().ok_or(E)?;
                let id = record.get("id").ok_or(E)?.as_i32().ok_or(E)?;
                let name = record.get("name").ok_or(E)?.as_str().ok_or(E)?.to_owned();
                let typ = record.get("type").ok_or(E)?.as_str().ok_or(E)?.to_owned();
                let content = record
                    .get("content")
                    .ok_or(E)?
                    .as_str()
                    .ok_or(E)?
                    .to_owned();
                let ttl = record.get("ttl").ok_or(E)?.as_i32().ok_or(E)?;
                let prio = record.get("prio").ok_or(E)?.as_i32().ok_or(E)?;
                records.push(DomainRecord {
                    id,
                    name,
                    typ,
                    content,
                    ttl,
                    prio,
                });
            }
        }

        Ok(DomainInfo {
            domain,
            ro_id,
            typ,
            slave_dns,
            records,
        })
    }

    pub fn update_record(&mut self, record: &DomainRecord) -> Result<(), RequestError> {
        let mut req = Request::new("nameserver.updateRecord");

        req.param("id", Value::from(record.id));
        req.param("name", Value::from(&*record.name));
        req.param("type", Value::from(&*record.typ));
        req.param("content", Value::from(&*record.content));
        req.param("prio", Value::from(record.prio));
        req.param("ttl", Value::from(record.ttl));

        self.conn.lock().unwrap().send(&req)?;
        Ok(())
    }
}