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
//! Convenience
//! It is a module that provides sugar-type and helper function.
use crate::prelude::*;

/// No size type, API compliant consistency.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct MyUnit;

impl DelayTaskHandler for MyUnit {
    fn quit(self: Box<Self>) -> AnyResult<()> {
        Ok(())
    }
}

/// The convenient functions to combine.
pub mod functions {

    use super::super::parse_and_run;
    use crate::prelude::*;
    use crate::timer::runtime_trace::task_handle::DelayTaskHandler;

    /// UnBlock execution of a command line task in delay-timer.
    ///
    /// This method mainly teaches how to encapsulate custom `async` logic in conjunction with `delay-timer`.
    ///
    /// The implementation could be tweaked at any time in the future,
    ///
    /// And it is recommended that you do your own encapsulation based on this reference.
    ///
    /// Note: now you can't get the output of the process through status-report.
    ///
    /// Please use this template to compose channels to achieve similar results.

    #[deprecated]
    #[instrument]
    pub async fn unblock_process_task_fn(shell_command: String, task_id: u64) {
        use smol::process::{Child, Command};
        debug!("Unblock-Process task start, Command {}", &shell_command);

        let shell_command_clone = shell_command.clone();
        let childs = parse_and_run::<Child, Command>(&shell_command_clone).await;

        if let Err(err) = childs {
            debug!("Unblock-Process task init fail for: {}", err.to_string());
            return;
        }

        if let Ok(mut childs) = childs.map_err(|e| error!("No process derived successfully: {}", e))
        {
            if let Ok(last_child) = childs.pop_back().ok_or_else(|| error!("Without child.")) {
                if let Ok(status) = last_child
                    .wait()
                    .await
                    .map_err(|e| error!("Unblock-Process task run fail for: {}", e))
                {
                    debug!("Unblock-Process task ExitStatus: {}", status);
                }
            }
        }
    }

    use tokio::process::{Child, Command};

    /// UnBlock execution of a command line task in delay-timer `Runtime` based on tokio.
    ///
    /// This method mainly teaches how to encapsulate custom `async` logic in conjunction with `delay-timer`.
    ///
    /// The implementation could be tweaked at any time in the future,
    ///
    /// And it is recommended that you do your own encapsulation based on this reference.
    ///
    /// Note: now you can't get the output of the process through status-report.
    ///
    /// Please use this template to compose channels to achieve similar results.
    #[deprecated]
    #[instrument]
    pub async fn tokio_unblock_process_task_fn(shell_command: String, task_id: u64) {
        let shell_command_clone = shell_command.clone();

        debug!("Unblock-Process task start, Command {}", &shell_command);

        let childs = parse_and_run::<Child, Command>(&shell_command_clone).await;

        if let Err(err) = childs {
            debug!("Unblock-Process task init fail for: {}", err.to_string());
            return;
        }

        if let Ok(mut childs) = childs.map_err(|e| error!("No process derived successfully {}", e))
        {
            if let Ok(last_child) = childs.pop_back().ok_or_else(|| error!("Without child.")) {
                if let Ok(status) = last_child
                    .wait()
                    .await
                    .map_err(|e| error!("Unblock-Process task run fail for: {}", e))
                {
                    debug!("Unblock-Process task ExitStatus: {}", status);
                }
            }
        }
    }

    #[inline(always)]
    ///convert task_handler of impl DelayTaskHandler to a `Box<dyn DelayTaskHander>`.
    pub fn create_delay_task_handler(
        task_handle: impl DelayTaskHandler + 'static + Send + Sync,
    ) -> Box<dyn DelayTaskHandler> {
        Box::new(task_handle) as Box<dyn DelayTaskHandler>
    }

    #[inline(always)]
    ///Create a Box<dyn DelayTaskHandler> illusion.
    pub fn create_default_delay_task_handler() -> Box<dyn DelayTaskHandler> {
        create_delay_task_handler(super::MyUnit)
    }
}

/// cron expression syntax sugar related.
pub mod cron_expression_grammatical_candy {
    use std::ops::Deref;

    #[derive(Debug, Clone)]
    // Here, for the convenience of the user to create CandyCronStr,
    // it is the internal type of CandyCronStr that from &'static str is changed to String,
    // so that the user can construct CandyCronStr according to the indefinite conditions of the runtime.
    // For: https://github.com/BinChengZhao/delay-timer/issues/4
    /// Syntactic sugar enumeration of the corresponding structure instance.
    pub struct CandyCronStr(pub String);

    impl Deref for CandyCronStr {
        type Target = str;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    #[derive(Debug, Copy, Clone)]
    /// Syntactic sugar for cron expressions.
    pub enum CandyCron {
        /// This variant for Secondly.
        Secondly,
        /// This variant for Minutely.
        Minutely,
        /// This variant for Hourly.
        Hourly,
        /// This variant for Daily.
        Daily,
        /// This variant for Weekly.
        Weekly,
        /// This variant for Monthly.
        Monthly,
        /// This variant for Yearly.
        Yearly,
    }
    use CandyCron::*;

    impl From<CandyCron> for CandyCronStr {
        fn from(value: CandyCron) -> CandyCronStr {
            match value {
                Secondly => CandyCronStr(String::from("@secondly")),
                Minutely => CandyCronStr(String::from("@minutely")),
                Hourly => CandyCronStr(String::from("@hourly")),
                Daily => CandyCronStr(String::from("@daily")),
                Weekly => CandyCronStr(String::from("@weekly")),
                Monthly => CandyCronStr(String::from("@monthly")),
                Yearly => CandyCronStr(String::from("@yearly")),
            }
        }
    }

    #[derive(Debug, Copy, Clone)]
    ///Enumerated values of repeating types.
    pub enum CandyFrequency<T: Into<CandyCronStr>> {
        ///Repeat once.
        Once(T),
        ///Repeat ad infinitum.
        Repeated(T),
        ///Type of countdown.
        CountDown(u32, T),
    }
}

/// Provide a template function that supports dynamic generation of closures.
pub fn generate_closure_template(
    a: i32,
    b: String,
) -> impl Fn() -> Box<dyn DelayTaskHandler> + 'static + Send + Sync {
    move || {
        self::functions::create_delay_task_handler(async_spawn_by_smol(async_template(
            a,
            b.clone(),
        )))
    }
}

/// This is a demo case to demonstrate a custom asynchronous task.
pub async fn async_template(_: i32, _: String) -> AnyResult<()> {
    Ok(())
}

mod tests {

    #[test]
    fn test_cron_candy() {
        use super::cron_expression_grammatical_candy::{CandyCron, CandyCronStr};

        let mut s: String;

        s = <CandyCron as Into<CandyCronStr>>::into(CandyCron::Daily).0;
        assert_eq!(s, "@daily");

        s = <CandyCron as Into<CandyCronStr>>::into(CandyCron::Yearly).0;
        assert_eq!(s, "@yearly");

        s = <CandyCron as Into<CandyCronStr>>::into(CandyCron::Secondly).0;

        assert_eq!(s, "@secondly");
    }

    #[test]
    fn test_customization_cron_candy() {
        use super::cron_expression_grammatical_candy::CandyCronStr;
        use std::convert::Into;
        use std::ops::Deref;

        struct CustomizationCandyCron(i32);

        impl From<CustomizationCandyCron> for CandyCronStr {
            fn from(val: CustomizationCandyCron) -> Self {
                let s = match val.0 {
                    0 => "1 1 1 1 1 1 1",
                    1 => "0 59 23 18 11 3 2100",
                    _ => "* * * * * * *",
                };
                CandyCronStr(s.to_owned())
            }
        }

        let mut candy_cron_str: CandyCronStr;

        candy_cron_str = CustomizationCandyCron(0).into();
        debug_assert_eq!(
            <CandyCronStr as Deref>::deref(&candy_cron_str),
            "1 1 1 1 1 1 1"
        );

        candy_cron_str = CustomizationCandyCron(1).into();
        debug_assert_eq!(candy_cron_str.deref(), "0 59 23 18 11 3 2100");

        candy_cron_str = CustomizationCandyCron(999).into();
        debug_assert_eq!(&*candy_cron_str, "* * * * * * *");
    }
}