@@ -292,16 +292,45 @@ class Launcher : public PluginHost::IPlugin {
292292 Core::JSON::String Value;
293293 };
294294
295+ public:
296+ class Schedule : public Core ::JSON::Container {
297+ private:
298+ Schedule& operator =(const Schedule&) = delete ;
299+
300+ public:
301+ Schedule ()
302+ : Core::JSON::Container()
303+ , RelativeTime()
304+ , Interval() {
305+ Add (_T (" relativetime" ), &RelativeTime);
306+ Add (_T (" interval" ), &Interval);
307+ }
308+ Schedule (const Schedule& copy)
309+ : Core::JSON::Container()
310+ , RelativeTime(copy.RelativeTime)
311+ , Interval(copy.Interval) {
312+ Add (_T (" relativetime" ), &RelativeTime);
313+ Add (_T (" interval" ), &Interval);
314+ }
315+ ~Schedule () {
316+ }
317+ public:
318+ Core::JSON::String RelativeTime;
319+ Core::JSON::String Interval;
320+ };
321+
295322 public:
296323 Config ()
297324 : Core::JSON::Container()
298325 , Command()
299326 , Parameters()
300327 , CloseTime(3 )
328+ , ScheduleTime()
301329 {
302330 Add (_T (" command" ), &Command);
303331 Add (_T (" parameters" ), &Parameters);
304332 Add (_T (" closetime" ), &CloseTime);
333+ Add (_T (" schedule" ), &ScheduleTime);
305334 }
306335 ~Config ()
307336 {
@@ -311,6 +340,193 @@ class Launcher : public PluginHost::IPlugin {
311340 Core::JSON::String Command;
312341 Core::JSON::ArrayType<Parameter> Parameters;
313342 Core::JSON::DecUInt8 CloseTime;
343+ Schedule ScheduleTime;
344+ };
345+
346+ class Time {
347+ public:
348+ Time ()
349+ : _hour(~0 )
350+ , _minute(~0 )
351+ , _second(~0 )
352+ {
353+ }
354+ Time (const string& time)
355+ : _hour(~0 )
356+ , _minute(~0 )
357+ , _second(~0 )
358+ {
359+ Parse (time);
360+ }
361+ Time (const Time& copy)
362+ : _hour(copy._hour)
363+ , _minute(copy._minute)
364+ , _second(copy._second)
365+ {
366+ }
367+ ~Time ()
368+ {
369+ }
370+
371+ public:
372+ bool IsValid () const { return (HasSeconds () || HasMinutes () || HasHours ()); }
373+ bool HasHours () const { return (_hour < 24 ); }
374+ bool HasMinutes () const { return (_minute < 60 ); }
375+ bool HasSeconds () const { return (_second < 60 ); }
376+ uint8_t Hour () const { return _hour; }
377+ uint8_t Minute () const { return _minute; }
378+ uint8_t Second () const { return _second; }
379+
380+ private:
381+ bool Parse (const string& time) {
382+ bool status = true ;
383+ string t = time;
384+
385+ // Get hours
386+ uint8_t hour;
387+ string hValue = Split (t, " :" );
388+ status = IsValidTime (hValue, hour, 24 );
389+ if (status == true ) {
390+
391+ // Get minutes
392+ uint8_t minute;
393+ string mValue = Split (t, " ." );
394+ status = IsValidTime (mValue , minute, 60 );
395+ if (status == true ) {
396+
397+ // Store seconds
398+ uint8_t second;
399+ string sValue = t;
400+ status = IsValidTime (sValue , second, 60 );
401+ if (status == true ) {
402+
403+ // Check all the time components are still valid
404+ if ((hour > 0 && second > 0 ) && (minute == 0 )) {
405+ status = false ;
406+ TRACE (Trace::Information, (_T (" Invalid time format" )));
407+ }
408+ else { // Update time components
409+ _hour = hour;
410+ _minute = minute;
411+ _second = second;
412+ }
413+ }
414+ }
415+ }
416+ return status;
417+ }
418+
419+ private:
420+ inline bool IsDigit (const string& str) {
421+ return (str.find_first_not_of ( " 0123456789" ) == std::string::npos);
422+ }
423+
424+ inline bool IsValidTime (const string& str, uint8_t & time, const uint8_t limit) {
425+ bool status = true ;
426+ if (IsDigit (str)) {
427+ int t = atoi (str.c_str ());
428+ if (t >= limit || t < 0 ) {
429+ status = false ;
430+ TRACE (Trace::Information, (_T (" Invalid time %s" ), str.c_str ()));
431+ }
432+ else {
433+ time = t;
434+ }
435+ }
436+ else {
437+ status = false ;
438+ TRACE (Trace::Information, (_T (" Invalid time %s" ), str.c_str ()));
439+ }
440+ return status;
441+ }
442+
443+ inline string Split (string& str, const string delimiter) {
444+ string word;
445+ size_t position = str.find (delimiter, 0 );
446+ if (position != string::npos) {
447+ word = str.substr (0 , position);
448+ str = str.substr (word.size () + 1 , str.size ());
449+ }
450+ return word;
451+ }
452+
453+ private:
454+ uint8_t _hour;
455+ uint8_t _minute;
456+ uint8_t _second;
457+ };
458+
459+ public:
460+ class Job : public Core ::IDispatchType<void > {
461+ private:
462+ Job () = delete ;
463+ Job (const Job&) = delete ;
464+ Job& operator =(const Job&) = delete ;
465+
466+ public:
467+ Job (Config* config, const Time& interval)
468+ : _hasRun(false )
469+ , _pid(0 )
470+ , _options(config->Command.Value().c_str())
471+ , _process(false )
472+ , _interval(interval)
473+ {
474+ auto iter = config->Parameters .Elements ();
475+
476+ while (iter.Next () == true ) {
477+ const Config::Parameter& element (iter.Current ());
478+
479+ if ((element.Option .IsSet () == true ) && (element.Option .Value ().empty () == false )) {
480+ if ((element.Value .IsSet () == true ) && (element.Value .Value ().empty () == false )) {
481+ _options.Set (element.Option .Value (), element.Value .Value ());
482+ }
483+ else {
484+ _options.Set (element.Option .Value ());
485+ }
486+ }
487+ }
488+ }
489+ ~Job ()
490+ {
491+ }
492+
493+ public:
494+ bool IsOperational () const {
495+
496+ return ((_hasRun == true ) && (_interval.IsValid () == true ));
497+ }
498+ Core::Process& Process () {
499+ return (_process);
500+ }
501+ uint32_t Pid () {
502+ return _pid;
503+ }
504+ virtual void Dispatch () override
505+ {
506+ _hasRun = true ;
507+ // Check if the process is not active, no need to reschedule the same job again.
508+ if (_process.IsActive () == false ) {
509+ _process.Launch (_options, &_pid);
510+ }
511+
512+ if (_interval.IsValid () == true && ((_interval.Hour () != 0 ) || (_interval.Minute () != 0 ) || (_interval.Second () != 0 ))) {
513+ // Reschedule our next launch point...
514+ Core::Time scheduledTime (Core::Time::Now ());
515+ uint64_t intervalTime = ((_interval.Hour () * 60 + _interval.Minute ()) * 60 + _interval.Second ()) * 1000 ;
516+ scheduledTime.Add (intervalTime);
517+ PluginHost::WorkerPool::Instance ().Schedule (scheduledTime,Core::ProxyType<Core::IDispatch>(*this ));
518+ }
519+ else {
520+ _hasRun = false ;
521+ }
522+ }
523+
524+ private:
525+ bool _hasRun;
526+ uint32_t _pid;
527+ Core::Process::Options _options;
528+ Core::Process _process;
529+ Time _interval;
314530 };
315531
316532public:
@@ -319,11 +535,10 @@ class Launcher : public PluginHost::IPlugin {
319535#endif
320536 Launcher ()
321537 : _service(nullptr )
322- , _process(false )
323- , _pid(0 )
324538 , _closeTime(0 )
325539 , _notification(this )
326540 , _memory(nullptr )
541+ , _activity()
327542 {
328543 }
329544#ifdef __WIN32__
@@ -362,16 +577,16 @@ class Launcher : public PluginHost::IPlugin {
362577
363578private:
364579 void Update (const ProcessObserver::Info& info);
580+ bool Execute ();
365581
366582private:
367583 PluginHost::IShell* _service;
368- Core::Process _process;
369- uint32_t _pid;
370584 uint8_t _closeTime;
371585 Core::Sink<Notification> _notification;
372586 Exchange::IMemory* _memory;
373587
374588 static ProcessObserver _observer;
589+ Core::ProxyType<Job> _activity;
375590};
376591
377592} // namespace Plugin
0 commit comments