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
extern crate aprs;
extern crate fap;

mod codec;

use std::error::Error;
use std::time::Duration;

use futures::sink::SinkExt;
use futures::StreamExt;

use log::{info, trace, warn};

use tokio::net::TcpStream;
use tokio::time;
use tokio_util::codec::{FramedRead, FramedWrite};

pub struct APRSPacket {
    pub raw: Vec<u8>,
}

impl APRSPacket {
    pub fn parsed(&self) -> Result<Box<dyn aprs::Packet>, Box<dyn Error>> {
        let raw_packet = self.raw.clone();
        let parsed = fap::Packet::new(raw_packet);
        match parsed {
            Ok(packet) => Ok(Box::new(packet)),
            Err(err) => Err(Box::new(err)),
        }
    }
}

pub struct ISSettings {
    pub host: String,
    pub port: u16,
    pub callsign: String,
    pub passcode: String,
    pub filter: String,
}

impl ISSettings {
    pub fn new(
        host: String,
        port: u16,
        callsign: String,
        passcode: String,
        filter: String,
    ) -> ISSettings {
        ISSettings {
            host,
            port,
            callsign,
            passcode,
            filter,
        }
    }
}

pub type PacketHandler = fn(APRSPacket);

pub struct IS {
    settings: ISSettings,
    packet_handler: PacketHandler,
}

impl IS {
    pub fn new(settings: ISSettings, packet_handler: PacketHandler) -> IS {
        IS {
            settings,
            packet_handler,
        }
    }

    #[tokio::main]
    pub async fn connect(&self) -> Result<(), Box<dyn Error>> {
        let address = format!("{}:{}", self.settings.host, self.settings.port);

        let stream = TcpStream::connect(address).await?;

        let (r, w) = stream.into_split();

        let mut writer = FramedWrite::new(w, codec::ByteLinesCodec::new());
        let mut reader = FramedRead::new(r, codec::ByteLinesCodec::new());

        let login_message = {
            let name = option_env!("CARGO_PKG_NAME").unwrap_or("unknown");
            let version = option_env!("CARGO_PKG_VERSION").unwrap_or("0.0.0");

            format!(
                "user {} pass {} vers {} {}{}",
                self.settings.callsign,
                self.settings.passcode,
                name,
                version,
                if self.settings.filter == "" {
                    "".to_string()
                } else {
                    format!(" filter {}", self.settings.filter)
                }
            )
        };

        info!("Logging on to APRS-IS server");
        trace!("Login message: {}", login_message);
        writer.send(login_message.as_bytes()).await?;

        tokio::spawn(async move {
            let mut interval = time::interval(Duration::from_secs(3600));
            loop {
                interval.tick().await;
                info!("Sending keep alive message to APRS-IS server");
                writer.send("# keep alive".as_bytes()).await.unwrap();
            }
        });

        while let Some(packet) = reader.next().await {
            match packet {
                Ok(packet) => {
                    if packet[0] == b'#' {
                        match String::from_utf8(packet.to_vec()) {
                            Ok(server_message) => {
                                trace!("Received server response: {}", server_message);
                                if server_message.contains("unverified") {
                                    info!("User not verified on APRS-IS server");
                                    continue;
                                }
                                if server_message.contains(" verified") {
                                    info!("User verified on APRS-IS server");
                                }
                            }
                            Err(err) => warn!("Error processing server response: {}", err),
                        }
                    } else {
                        trace!("{:?}", packet);
                        (self.packet_handler)(APRSPacket {
                            raw: packet.to_vec(),
                        });
                    }
                }
                Err(err) => {
                    warn!("Error processing packet from APRS-IS server: {}", err);
                }
            }
        }

        Ok(())
    }
}