aboutsummaryrefslogtreecommitdiff
path: root/src/stable/minicron.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/stable/minicron.cpp')
-rw-r--r--src/stable/minicron.cpp477
1 files changed, 477 insertions, 0 deletions
diff --git a/src/stable/minicron.cpp b/src/stable/minicron.cpp
new file mode 100644
index 0000000..95cf66b
--- /dev/null
+++ b/src/stable/minicron.cpp
@@ -0,0 +1,477 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include "bu/minicron.h"
9
10#include <stdlib.h>
11#include <time.h>
12
13Bu::MiniCron::MiniCron() :
14 jidNext( 1 )
15{
16}
17
18Bu::MiniCron::~MiniCron()
19{
20 while( !hJobs.isEmpty() )
21 {
22 delete hJobs.dequeue();
23 }
24}
25
26bool Bu::MiniCron::hasJobs()
27{
28 return !hJobs.isEmpty();
29}
30
31time_t Bu::MiniCron::getNextRun()
32{
33 if( hasJobs() )
34 return hJobs.peek()->getNextRun();
35 return -1;
36}
37
38time_t Bu::MiniCron::getNextRun( Bu::MiniCron::JobId jid )
39{
40 for( JobHeap::iterator i = hJobs.begin(); i; i++ )
41 {
42 if( (*i)->getId() == jid )
43 {
44 return (*i)->getNextRunTime();
45 }
46 }
47 return -1;
48}
49
50void Bu::MiniCron::poll()
51{
52 time_t tNow = time( NULL );
53
54 while( !hJobs.isEmpty() )
55 {
56 if( hJobs.peek()->getNextRun() <= tNow )
57 {
58 Job *pJob = hJobs.dequeue();
59 pJob->run();
60 if( pJob->bContinue )
61 {
62 hJobs.enqueue( pJob );
63 }
64 else
65 {
66 delete pJob;
67 }
68 }
69 else
70 {
71 break;
72 }
73 }
74}
75
76Bu::MiniCron::JobId Bu::MiniCron::addJob( const Bu::String &sName,
77 Bu::MiniCron::CronSignal sigJob, const Bu::MiniCron::Timer &t )
78{
79 JobId jid = jidNext++;
80 Job *pJob = new Job( sName, jid );
81 pJob->sigJob = sigJob;
82 pJob->pTimer = t.clone();
83 pJob->tNextRun = pJob->pTimer->nextTime();
84 hJobs.enqueue( pJob );
85
86 return jid;
87}
88
89Bu::MiniCron::JobId Bu::MiniCron::addJobOnce( const Bu::String &sName,
90 Bu::MiniCron::CronSignal sigJob, const Bu::MiniCron::Timer &t )
91{
92 JobId jid = jidNext++;
93 Job *pJob = new Job( sName, jid, false );
94 pJob->sigJob = sigJob;
95 pJob->pTimer = t.clone();
96 pJob->tNextRun = pJob->pTimer->nextTime();
97 hJobs.enqueue( pJob );
98
99 return jid;
100}
101
102void Bu::MiniCron::removeJob( JobId jid )
103{
104 Bu::List<Job *> lJobs;
105 while( !hJobs.isEmpty() )
106 {
107 Job *pJob = hJobs.dequeue();
108 if( pJob->getId() == jid )
109 {
110 delete pJob;
111 }
112 else
113 lJobs.append( pJob );
114 }
115
116 for( Bu::List<Job *>::iterator i = lJobs.begin(); i; i++ )
117 {
118 hJobs.enqueue( *i );
119 }
120}
121
122void Bu::MiniCron::runJob( JobId jid, bool bReschedule )
123{
124 Bu::List<Job *> lJobs;
125 while( !hJobs.isEmpty() )
126 {
127 Job *pJob = hJobs.dequeue();
128 if( pJob->getId() == jid )
129 {
130 pJob->run( bReschedule );
131 if( !pJob->bContinue )
132 {
133 delete pJob;
134 break;
135 }
136 lJobs.append( pJob );
137 break;
138 }
139 lJobs.append( pJob );
140 }
141
142 for( Bu::List<Job *>::iterator i = lJobs.begin(); i; i++ )
143 {
144 hJobs.enqueue( *i );
145 }
146}
147
148void Bu::MiniCron::runJob( const Bu::String &sName, bool bReschedule )
149{
150 Bu::List<Job *> lJobs;
151 while( !hJobs.isEmpty() )
152 {
153 Job *pJob = hJobs.dequeue();
154 if( pJob->getName() == sName )
155 {
156 pJob->run( bReschedule );
157 if( !pJob->bContinue )
158 {
159 delete pJob;
160 break;
161 }
162 lJobs.append( pJob );
163 break;
164 }
165 lJobs.append( pJob );
166 }
167
168 for( Bu::List<Job *>::iterator i = lJobs.begin(); i; i++ )
169 {
170 hJobs.enqueue( *i );
171 }
172}
173
174Bu::MiniCron::JobInfoList Bu::MiniCron::getJobInfo()
175{
176 JobInfoList lRet;
177 for( JobHeap::iterator i = hJobs.begin(); i; i++ )
178 {
179 lRet.append(
180 JobInfo( (*i)->getName(), (*i)->getId(), (*i)->getNextRun() )
181 );
182 }
183 lRet.sort();
184 return lRet;
185}
186
187Bu::MiniCron::Job::Job( const Bu::String &sName, JobId jid, bool bRepeat ) :
188 sName( sName ),
189 pTimer( NULL ),
190 bContinue( bRepeat ),
191 jid( jid ),
192 tAdded( time( NULL ) ),
193 iRunCount( 0 )
194{
195}
196
197Bu::MiniCron::Job::~Job()
198{
199 delete pTimer;
200 pTimer = NULL;
201}
202
203void Bu::MiniCron::Job::run( bool bReschedule )
204{
205 iRunCount++;
206 if( bReschedule )
207 tNextRun = pTimer->nextTime();
208 sigJob( *this );
209}
210
211time_t Bu::MiniCron::Job::getNextRun() const
212{
213 return tNextRun;
214}
215
216void Bu::MiniCron::Job::calcNextRun()
217{
218 if( pTimer )
219 tNextRun = pTimer->nextTime();
220}
221
222void Bu::MiniCron::Job::setTimer( const Timer &t )
223{
224 delete pTimer;
225 pTimer = t.clone();
226}
227
228void Bu::MiniCron::Job::stop()
229{
230 bContinue = false;
231}
232
233void Bu::MiniCron::Job::resume()
234{
235 bContinue = true;
236}
237
238Bu::MiniCron::JobId Bu::MiniCron::Job::getId() const
239{
240 return jid;
241}
242
243time_t Bu::MiniCron::Job::getTimeCreated() const
244{
245 return tAdded;
246}
247
248int Bu::MiniCron::Job::getRunCount() const
249{
250 return iRunCount;
251}
252
253time_t Bu::MiniCron::Job::getNextRunTime() const
254{
255 return tNextRun;
256}
257
258Bu::String Bu::MiniCron::Job::getName() const
259{
260 return sName;
261}
262
263Bu::MiniCron::JobInfo::JobInfo( const Bu::String &sName, JobId jid,
264 time_t tNext ) :
265 sName( sName ),
266 jid( jid ),
267 tNext( tNext )
268{
269}
270
271Bu::MiniCron::JobInfo::~JobInfo()
272{
273}
274
275bool Bu::MiniCron::JobInfo::operator<( const JobInfo &rhs ) const
276{
277 return jid < rhs.jid;
278}
279
280Bu::MiniCron::Timer::Timer()
281{
282}
283
284Bu::MiniCron::Timer::~Timer()
285{
286}
287
288Bu::MiniCron::TimerInterval::TimerInterval( time_t tFirst, time_t tInterval ) :
289 tNext( tFirst ),
290 tInterval( tInterval )
291{
292}
293
294Bu::MiniCron::TimerInterval::~TimerInterval()
295{
296}
297
298time_t Bu::MiniCron::TimerInterval::nextTime()
299{
300 time_t tRet = tNext;
301 tNext += tInterval;
302 return tRet;
303}
304
305Bu::MiniCron::TimerBasic::TimerBasic( const Bu::String &s ) :
306 tLast( -1 ),
307 sSpec( s )
308{
309}
310
311Bu::MiniCron::TimerBasic::~TimerBasic()
312{
313}
314
315time_t Bu::MiniCron::TimerBasic::nextTime()
316{
317 if( tLast == -1 )
318 tLast = time( NULL );
319
320 Bu::String::const_iterator i = sSpec.begin();
321 switch( lex( i ) )
322 {
323 case tokDaily:
324 {
325 int iHour = lexInt( i );
326 int iMin = lexInt( i );
327
328 struct tm t;
329 ::memcpy( &t, localtime( &tLast ), sizeof(struct tm) );
330 if( iHour < t.tm_hour ||
331 (iHour == t.tm_hour && iMin <= t.tm_min) )
332 {
333 t.tm_mday++;
334 }
335 t.tm_hour = iHour;
336 t.tm_min = iMin;
337 t.tm_sec = 0;
338 tLast = mktime( &t );
339 }
340 break;
341
342 case tokHourly:
343 {
344 int iMin = lexInt( i );
345
346 struct tm t;
347 ::memcpy( &t, localtime( &tLast ), sizeof(struct tm) );
348 if( iMin <= t.tm_min )
349 t.tm_hour++;
350 t.tm_min = iMin;
351 t.tm_sec = 0;
352 tLast = mktime( &t );
353 }
354 break;
355
356 case tokWeekly:
357 {
358 int iDay = lexInt( i );
359 int iHour = lexInt( i );
360 int iMin = lexInt( i );
361
362 struct tm t;
363 ::memcpy( &t, localtime( &tLast ), sizeof(struct tm) );
364 if( iDay < t.tm_wday ||
365 (iDay == t.tm_wday && iHour < t.tm_hour) ||
366 (iDay == t.tm_wday && iHour == t.tm_hour
367 && iMin <= t.tm_min) )
368 {
369 if( iDay <= t.tm_wday )
370 t.tm_mday += 7 - (t.tm_wday-iDay);
371 else
372 t.tm_mday += 7 - (iDay-t.tm_wday);
373 }
374 else
375 {
376 t.tm_mday += (iDay-t.tm_wday);
377 }
378 t.tm_hour = iHour;
379 t.tm_min = iMin;
380 t.tm_sec = 0;
381 tLast = mktime( &t );
382 }
383 break;
384
385 case tokMonthly:
386 break;
387
388 case tokYearly:
389 break;
390
391 default:
392 break;
393 }
394
395 return tLast;
396}
397
398Bu::MiniCron::TimerBasic::Token Bu::MiniCron::TimerBasic::lex(
399 Bu::String::const_iterator &i )
400{
401 if( !i )
402 {
403 return tokEos;
404 }
405
406 Bu::String::const_iterator b = i;
407
408 for(; b && (*b == ' ' || *b == '\t'); b++ ) { i = b+1; }
409 for(; b && *b != ' ' && *b != '\t'; b++ ) { }
410
411 Bu::String sTok( i, b );
412 i = b;
413
414 if( sTok == "daily" )
415 return tokDaily;
416 else if( sTok == "hourly" )
417 return tokHourly;
418 else if( sTok == "weekly" )
419 return tokWeekly;
420 else if( sTok == "monthly" )
421 return tokMonthly;
422 else if( sTok == "yearly" )
423 return tokYearly;
424 else if( sTok == "sun" )
425 {
426 iVal = 0;
427 return valInt;
428 }
429 else if( sTok == "mon" )
430 {
431 iVal = 1;
432 return valInt;
433 }
434 else if( sTok == "tue" )
435 {
436 iVal = 2;
437 return valInt;
438 }
439 else if( sTok == "wed" )
440 {
441 iVal = 3;
442 return valInt;
443 }
444 else if( sTok == "thu" )
445 {
446 iVal = 4;
447 return valInt;
448 }
449 else if( sTok == "fri" )
450 {
451 iVal = 5;
452 return valInt;
453 }
454 else if( sTok == "sat" )
455 {
456 iVal = 6;
457 return valInt;
458 }
459 else if( sTok[0] >= '0' && sTok[0] <= '9' )
460 {
461 iVal = strtol( sTok.getStr(), NULL, 0 );
462 return valInt;
463 }
464
465 return tokErr;
466}
467
468int Bu::MiniCron::TimerBasic::lexInt( Bu::String::const_iterator &i )
469{
470 Token t = lex( i );
471 if( t == tokEos )
472 return 0;
473 if( t != valInt )
474 throw Bu::ExceptionBase("Expected int, got something else.");
475 return iVal;
476}
477