summaryrefslogtreecommitdiff
path: root/src/rvi/parameters.rs
blob: 1fa1a875cc775a8f28d64d43962a0145eaee75e2 (plain)
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
use std::str;
use std::sync::Mutex;

use datatype::{ChunkReceived, Event, DownloadComplete, UpdateRequestId, UpdateAvailable};
use super::services::{BackendServices, RemoteServices};
use super::transfers::Transfers;


/// Each `Parameter` implementation handles a specific kind of RVI client request,
/// optionally responding with an `Event` on completion.
pub trait Parameter {
    fn handle(&self, remote: &Mutex<RemoteServices>, transfers: &Mutex<Transfers>)
              -> Result<Option<Event>, String>;
}


#[derive(RustcDecodable, RustcEncodable)]
pub struct Notify {
    update_available: UpdateAvailable,
    services:         BackendServices
}

impl Parameter for Notify {
    fn handle(&self, remote: &Mutex<RemoteServices>, _: &Mutex<Transfers>) -> Result<Option<Event>, String> {
        remote.lock().unwrap().backend = Some(self.services.clone());
        Ok(Some(Event::NewUpdateAvailable(self.update_available.clone())))
    }
}


#[derive(RustcDecodable, RustcEncodable)]
pub struct Start {
    update_id:   UpdateRequestId,
    chunkscount: u64,
    checksum:    String
}

impl Parameter for Start {
    fn handle(&self, remote: &Mutex<RemoteServices>, transfers: &Mutex<Transfers>) -> Result<Option<Event>, String> {
        info!("Starting transfer for update_id {}", self.update_id);
        let mut transfers = transfers.lock().unwrap();
        transfers.push(self.update_id.clone(), self.checksum.clone());

        let remote = remote.lock().unwrap();
        let chunk  = ChunkReceived {
            device:    remote.device_id.clone(),
            update_id: self.update_id.clone(),
            chunks:    Vec::new()
        };
        remote.send_chunk_received(chunk)
            .map(|_| None)
            .map_err(|err| format!("error sending start ack: {}", err))
    }
}


#[derive(RustcDecodable, RustcEncodable)]
pub struct Chunk {
    update_id: UpdateRequestId,
    bytes:     String,
    index:     u64
}

impl Parameter for Chunk {
    fn handle(&self, remote: &Mutex<RemoteServices>, transfers: &Mutex<Transfers>) -> Result<Option<Event>, String> {
        let remote = remote.lock().unwrap();

        let mut transfers = transfers.lock().unwrap();
        let transfer      = try!(transfers.get_mut(self.update_id.clone())
                                 .ok_or(format!("couldn't find transfer for update_id {}", self.update_id)));
        transfer.write_chunk(&self.bytes, self.index)
            .map_err(|err| format!("couldn't write chunk: {}", err))
            .and_then(|_| {
                trace!("wrote chunk {} for package {}", self.index, self.update_id);
                let chunk = ChunkReceived {
                    device:    remote.device_id.clone(),
                    update_id: self.update_id.clone(),
                    chunks:    transfer.transferred_chunks.clone(),
                };
                remote.send_chunk_received(chunk)
                    .map(|_| None)
                    .map_err(|err| format!("error sending ChunkReceived: {}", err))
            })
    }
}


#[derive(RustcDecodable, RustcEncodable)]
pub struct Finish {
    update_id: UpdateRequestId,
    signature: String
}

impl Parameter for Finish {
    fn handle(&self, _: &Mutex<RemoteServices>, transfers: &Mutex<Transfers>) -> Result<Option<Event>, String> {
        let mut transfers = transfers.lock().unwrap();
        let image = {
            let transfer = try!(transfers.get(self.update_id.clone())
                                .ok_or(format!("unknown package: {}", self.update_id)));
            let package  = try!(transfer.assemble_package()
                                .map_err(|err| format!("couldn't assemble package: {}", err)));
            try!(package.into_os_string().into_string()
                 .map_err(|err| format!("couldn't get image: {:?}", err)))
        };
        transfers.remove(self.update_id.clone());
        info!("Finished transfer of {}", self.update_id);

        let complete = DownloadComplete {
            update_id:    self.update_id.clone(),
            update_image: image,
            signature:    self.signature.clone()
        };
        Ok(Some(Event::DownloadComplete(complete)))
    }
}


#[derive(RustcDecodable, RustcEncodable)]
pub struct Report;

impl Parameter for Report {
    fn handle(&self, _: &Mutex<RemoteServices>, _: &Mutex<Transfers>) -> Result<Option<Event>, String> {
        Ok(Some(Event::InstalledSoftwareNeeded))
    }
}


#[derive(RustcDecodable, RustcEncodable)]
pub struct Abort;

impl Parameter for Abort {
    fn handle(&self, _: &Mutex<RemoteServices>, transfers: &Mutex<Transfers>) -> Result<Option<Event>, String> {
        transfers.lock().unwrap().clear();
        Ok(None)
    }
}