Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 67 additions & 4 deletions Launcher.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
#include "Launcher.h"
#include <inttypes.h>

namespace WPEFramework {

ENUM_CONVERSION_BEGIN(Plugin::Launcher::mode)

{ Plugin::Launcher::mode::RELATIVE, _TXT("relative") },
{ Plugin::Launcher::mode::ABSOLUTE, _TXT("absolute") },
{ Plugin::Launcher::mode::ABSOLUTE_WITH_INTERVAL, _TXT("interval") },

ENUM_CONVERSION_END(Plugin::Launcher::mode)
;
namespace Plugin {

SERVICE_REGISTRATION(Launcher, 1, 0);
Expand Down Expand Up @@ -70,6 +79,7 @@ SERVICE_REGISTRATION(Launcher, 1, 0);
{
Time time;
Time interval;
mode timeMode = RELATIVE;
string message;
Config config;

Expand All @@ -83,6 +93,8 @@ SERVICE_REGISTRATION(Launcher, 1, 0);

if (config.ScheduleTime.IsSet() == true) {

timeMode = config.ScheduleTime.Mode.Value();

time = Time(config.ScheduleTime.Time.Value());
if (time.IsValid() != true) {
SYSLOG(Trace::Warning, (_T("Time format is wrong")));
Expand All @@ -99,12 +111,25 @@ SERVICE_REGISTRATION(Launcher, 1, 0);
if (_activity->IsOperational() == false) {
// Well if we where able to parse the parameters (if needed) we are ready to start it..
_observer.Register(&_notification);

Core::Time scheduledTime;
if (time.IsValid() == true) {
Core::Time scheduledTime(Core::Time::Now());
uint64_t timeValueToTrigger = ((time.Hour() * 60 + time.Minute()) * 60 + time.Second()) * 1000;
scheduledTime.Add(timeValueToTrigger);
if (timeMode == RELATIVE) { //Schedule Job at relative timing
scheduledTime = Core::Time::Now();

uint64_t timeValueToTrigger = ((((time.Hours() != (uint8_t)(~0)) ? time.Hours(): 0) * MinutesPerHour +
((time.Minutes() != (uint8_t)(~0)) ? time.Minutes(): 0)) * SecondsPerMinute + time.Seconds()) * MilliSecondsPerSecond;
scheduledTime.Add(timeValueToTrigger);

}
else {
//Schedule Job at absolute timing
if (timeMode == ABSOLUTE_WITH_INTERVAL) {
scheduledTime = FindAbsoluteTimeForSchedule(time, interval);
}
else {
scheduledTime = FindAbsoluteTimeForSchedule(time, Time());
}
}
PluginHost::WorkerPool::Instance().Schedule(scheduledTime, _activity);
}
else {
Expand Down Expand Up @@ -179,6 +204,44 @@ void Launcher::Update(const ProcessObserver::Info& info)
}
}

Core::Time Launcher::FindAbsoluteTimeForSchedule(const Time& absoluteTime, const Time& interval) {
Core::Time startTime = Core::Time::Now();
// Go to a first viable start time (compared to the current time, in seconds)
Core::Time slotTime = Core::Time(startTime.Year(), startTime.Month(), startTime.Day(),
(absoluteTime.HasHours() ? absoluteTime.Hours() : startTime.Hours()),
(absoluteTime.HasMinutes() ? absoluteTime.Minutes() : startTime.Minutes()),
absoluteTime.Seconds(), 0, false);

if (interval.IsValid() == false) {
if (slotTime < startTime) {
uint32_t jump (absoluteTime.HasHours() ? HoursPerDay * MinutesPerHour * SecondsPerMinute : (absoluteTime.HasMinutes() ? MinutesPerHour * SecondsPerMinute : SecondsPerMinute));
slotTime.Add(jump * 100);
}
}
else {
uint32_t intervalJump = ( (interval.HasHours() ? interval.Hours() * MinutesPerHour * SecondsPerMinute : 0) +
(interval.HasMinutes() ? interval.Minutes() * SecondsPerMinute : 0) +
interval.Seconds() ) * 100;

ASSERT (intervalJump != 0);
if (slotTime >= startTime) {
Core::Time workTime (slotTime);

while (workTime.Sub(intervalJump) > startTime) {
slotTime.Sub(intervalJump);
}
}
else {
// Now increment with the intervall till we reach a valid point
while (slotTime < startTime) {
slotTime.Add(intervalJump);
}
}
}

return slotTime;
}

} //namespace Plugin

} // namespace WPEFramework
65 changes: 46 additions & 19 deletions Launcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ class Launcher : public PluginHost::IPlugin {
Launcher(const Launcher&) = delete;
Launcher& operator=(const Launcher&) = delete;

public:
enum mode {
RELATIVE,
ABSOLUTE,
ABSOLUTE_WITH_INTERVAL
};

class ProcessObserver {
private:
ProcessObserver(const ProcessObserver&) = delete;
Expand Down Expand Up @@ -300,21 +307,26 @@ class Launcher : public PluginHost::IPlugin {
public:
Schedule()
: Core::JSON::Container()
, Mode(RELATIVE)
, Time()
, Interval() {
Add(_T("mode"), &Mode);
Add(_T("time"), &Time);
Add(_T("interval"), &Interval);
}
Schedule(const Schedule& copy)
: Core::JSON::Container()
, Mode(copy.Mode)
, Time(copy.Time)
, Interval(copy.Interval) {
Add(_T("mode"), &Mode);
Add(_T("time"), &Time);
Add(_T("interval"), &Interval);
}
~Schedule() {
}
public:
Core::JSON::EnumType<mode> Mode;
Core::JSON::String Time;
Core::JSON::String Interval;
};
Expand Down Expand Up @@ -343,6 +355,12 @@ class Launcher : public PluginHost::IPlugin {
Schedule ScheduleTime;
};

private:
static constexpr uint32_t MilliSecondsPerSecond = 1000;
static constexpr uint32_t SecondsPerMinute = 60;
static constexpr uint32_t MinutesPerHour = 60;
static constexpr uint32_t HoursPerDay = 24;

class Time {
public:
Time()
Expand Down Expand Up @@ -370,38 +388,43 @@ class Launcher : public PluginHost::IPlugin {

public:
bool IsValid () const { return (HasSeconds() || HasMinutes() || HasHours()); }
bool HasHours() const { return (_hour < 24); }
bool HasMinutes() const { return (_minute < 60); }
bool HasSeconds() const { return (_second < 60); }
uint8_t Hour() const { return _hour; }
uint8_t Minute() const { return _minute; }
uint8_t Second() const { return _second; }
bool HasHours() const { return (_hour < HoursPerDay); }
bool HasMinutes() const { return (_minute < MinutesPerHour); }
bool HasSeconds() const { return (_second < SecondsPerMinute); }
uint8_t Hours() const { return _hour; }
uint8_t Minutes() const { return _minute; }
uint8_t Seconds() const { return _second; }

private:
bool Parse(const string& time) {
bool status = true;
string t = time;

//Get hours
uint8_t hour;
uint8_t hour = (~0);
string hValue = Split(t, ":");
status = IsValidTime(hValue, hour, 24);
if (hValue.empty() != true) {
status = IsValidTime(hValue, hour, HoursPerDay);
}
if (status == true) {

//Get minutes
uint8_t minute;
//Get minutes
uint8_t minute = (~0);
string mValue = Split(t, ".");
status = IsValidTime(mValue, minute, 60);
if (mValue.empty() != true) {
status = IsValidTime(mValue, minute, MinutesPerHour);
}
if (status == true) {

//Store seconds
uint8_t second;
uint8_t second = (~0);
string sValue = t;
status = IsValidTime(sValue, second, 60);
if (sValue.empty() != true) {
status = IsValidTime(sValue, second, SecondsPerMinute);
}
if (status == true) {

//Check all the time components are still valid
if ((hour > 0 && second > 0) && (minute == 0)) {
if ((hour != (~0) && second != (~0)) && (minute == (~0))) {
status = false;
TRACE(Trace::Information, (_T("Invalid time format")));
}
Expand All @@ -416,7 +439,7 @@ class Launcher : public PluginHost::IPlugin {
return status;
}

private:
private:
inline bool IsDigit(const string& str) {
return (str.find_first_not_of( "0123456789" ) == std::string::npos);
}
Expand Down Expand Up @@ -450,7 +473,7 @@ class Launcher : public PluginHost::IPlugin {
return word;
}

private:
private:
uint8_t _hour;
uint8_t _minute;
uint8_t _second;
Expand Down Expand Up @@ -506,13 +529,16 @@ class Launcher : public PluginHost::IPlugin {
_hasRun = true;
// Check if the process is not active, no need to reschedule the same job again.
if (_process.IsActive() == false) {

Core::Time currentTime(Core::Time::Now());
_process.Launch(_options, &_pid);
}

if (_interval.IsValid() == true && ((_interval.Hour() != 0) || (_interval.Minute() != 0) || (_interval.Second() != 0))) {
if (_interval.IsValid() == true) {
// Reschedule our next launch point...
Core::Time scheduledTime(Core::Time::Now());
uint64_t intervalTime = ((_interval.Hour() * 60 + _interval.Minute()) * 60 + _interval.Second()) * 1000;
uint64_t intervalTime = ((((_interval.Hours() != (uint8_t)(~0)) ? _interval.Hours(): 0) * MinutesPerHour +
((_interval.Minutes() != (uint8_t)(~0)) ? _interval.Minutes():0)) * SecondsPerMinute + _interval.Seconds()) * MilliSecondsPerSecond;
scheduledTime.Add(intervalTime);
PluginHost::WorkerPool::Instance().Schedule(scheduledTime,Core::ProxyType<Core::IDispatch>(*this));
}
Expand Down Expand Up @@ -578,6 +604,7 @@ class Launcher : public PluginHost::IPlugin {
private:
void Update(const ProcessObserver::Info& info);
bool Execute();
Core::Time FindAbsoluteTimeForSchedule(const Time& absoluteTime, const Time& interval);

private:
PluginHost::IShell* _service;
Expand Down
47 changes: 41 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ Plugin to "Launch" linux applications and scripts
}
```

### How to schedule an application/script
### How to schedule an application/script with relative time

1. Add schedule relative time information to the Launcher.json in the HH:MM.SS format (Hour:Minute.Second)
1. Add 'relative' time information to the Launcher.json in the HH:MM.SS format (Hour:Minute.Second)
```
"configuration": {
"command":"du",
Expand All @@ -69,15 +69,46 @@ Plugin to "Launch" linux applications and scripts
{ "option": "-h"}
],
"schedule": {
"absolute": false,
"mode": "relative",
"time": "06:04.10"
}
}
```

Note:
1. If field "absolute" is false or not set, it will treat the time as relative
1. If field "mode" is empty or not set, it will treat the time as relative
2. If relative time value is "00:00.00"/invalid format/not set, the launcher will ignore the given time and launch the application at the launcher activation time itself.
3. If time format given is
a. "XX", treat it as SS
b. "XX.XX" treat it as MM.SS

### How to schedule an application/script with absolute time

1. Add 'absolute' time information to the Launcher.json in the HH:MM.SS format (Hour:Minute.Second)
```
"configuration": {
"command":"du",
"parameters": [
{ "option": "-a", "value": "/etc" },
{ "option": "-h"}
],
"schedule": {
"mode": "absolute",
"time": "06:04.10"
}
}
```

Note:
1. If absolute time value is invalid format/not set, the launcher will ignore the given time and launch the application at the launcher activation time itself.
2. If time format given is
a. "XX", treat it as SS, and schedule the application launch at next SSth time. i.e. if absolute time given is 25 and current time is 08:10:45, then the application will be
launched at 08:11:25
b. "XX.XX" treat it as MM.SS, and scedule the application launch at next MM:SSth time. i.e. if absolute time given is 30.20 and current time is 08:10:45, then the application will be
launched at 09:30:20
c. "00:00.00" treat it as midnight.
3. If absolute time given is less than the current time, it will launch the application the same time at the subsequent day. i.e, if absolute time given is 13:00:00, it will launch
the application at same time at the next day.

### How to schedule an application/script to run in an interval

Expand All @@ -90,14 +121,18 @@ Note:
{ "option": "-h"}
],
"schedule": {
"absolute": false,
"mode": "interval",
"time": "06:04.10",
"interval": "00:40.10"
}
}
```

Note: If interval value is "00:00.00"/invalid format/not set, the launcher will treat it as invalid value and ignore the interval time settings.
Note:
1. If interval value is "00:00.00"/invalid format/not set, the launcher will treat it as invalid value and ignore the interval time settings.
2. If mode is interval (absolute with interval) and interval is set, it will identify next matching time and schedule application launch to that time.
i.e, if the absolute time given is 04:00:00, current time is 05:10:00 and interval is 00:30:00, then next scheduling time will be 05:30:00 (will be identified from the next intervals - 04:30:00, 05:00:00, 05:30:00)
3. If mode is relative or absolute, the interval time will be taken only for the subsequent scheduling

# How to launch multiple scripts/applcations

Expand Down