Files
adcs_api
cbor_protocol
channel_protocol
clyde_3g_eps_api
clyde_3g_eps_service
comms_service
db_test
eps_api
example_rust_c_service
example_rust_service
extern_lib
file_protocol
file_service
iobc_supervisor_service
isis_ants
isis_ants_api
isis_ants_service
isis_imtq_api
isis_iobc_supervisor
kubos_app
kubos_app_service
kubos_build_helper
kubos_file_client
kubos_service
kubos_shell_client
kubos_system
kubos_telemetry_db
large_download
large_upload
local_comms_service
mai400
mai400_api
mai400_service
monitor_service
novatel_oem6_api
novatel_oem6_service
nsl_duplex_d2
nsl_duplex_d2_comms_service
obc_hs
radio_api
rust_i2c
rust_mission_app
rust_uart
scheduler_service
serial_comms_service
shell_protocol
shell_service
telemetry_service
uart_comms_client
udp_client
utils
  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
/*
 * Copyright (C) 2019 Kubos Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//!
//! Definitions and functions for dealing with scheduled app execution
//!

use crate::error::SchedulerError;
use crate::schema::GenericResponse;
use juniper::GraphQLObject;
use log::{error, info};
use reqwest::Client;
use serde::{Deserialize, Serialize};
use serde_json::from_str;
use std::collections::HashMap;
use std::time::Duration;

#[derive(Debug, Deserialize)]
pub struct StartAppResponse {
    #[serde(rename = "startApp")]
    pub start_app: GenericResponse,
}

#[derive(Debug, Deserialize)]
pub struct StartAppGraphQL {
    pub data: StartAppResponse,
}

// Helper function for sending query to app service
pub fn service_query(query: &str, hosturl: &str) -> Result<StartAppGraphQL, SchedulerError> {
    // The app service will wait 300ms to see if an app completes before returning its response to us
    let client = Client::builder()
        .timeout(Duration::from_millis(350))
        .build()
        .map_err(|e| SchedulerError::QueryError { err: e.to_string() })?;
    let mut map = HashMap::new();
    map.insert("query", query);
    let url = format!("http://{}", hosturl);

    let mut res = client
        .post(&url)
        .json(&map)
        .send()
        .map_err(|e| SchedulerError::QueryError { err: e.to_string() })?;

    Ok(from_str(
        &res.text()
            .map_err(|e| SchedulerError::QueryError { err: e.to_string() })?,
    )
    .map_err(|e| SchedulerError::QueryError { err: e.to_string() })?)
}

// Configuration used for execution of an app
#[derive(Clone, Debug, GraphQLObject, Serialize, Deserialize)]
pub struct App {
    pub name: String,
    pub args: Option<Vec<String>>,
    pub config: Option<String>,
}

impl App {
    pub fn execute(&self, service_url: &str) {
        info!("Start app {}", self.name);
        let mut query_args = format!("name: \"{}\"", self.name);
        if let Some(config) = &self.config {
            query_args.push_str(&format!(", config: \"{}\"", config));
        }
        if let Some(args) = &self.args {
            let app_args: Vec<String> = args.iter().map(|x| format!("\"{}\"", x)).collect();

            let app_args = app_args.join(",");
            query_args.push_str(&format!(", args: [{}]", app_args));
        }
        let query = format!(
            r#"mutation {{ startApp({}) {{ success, errors }} }}"#,
            query_args
        );
        match service_query(&query, &service_url) {
            Err(e) => {
                error!("Failed to send start app query: {}", e);
            }
            Ok(resp) => {
                if !resp.data.start_app.success {
                    error!(
                        "Failed to start scheduled app: {}",
                        resp.data.start_app.errors
                    );
                }
            }
        }
    }
}