diff options
Diffstat (limited to 'src/stable/minicron.cpp')
-rw-r--r-- | src/stable/minicron.cpp | 477 |
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 | |||
13 | Bu::MiniCron::MiniCron() : | ||
14 | jidNext( 1 ) | ||
15 | { | ||
16 | } | ||
17 | |||
18 | Bu::MiniCron::~MiniCron() | ||
19 | { | ||
20 | while( !hJobs.isEmpty() ) | ||
21 | { | ||
22 | delete hJobs.dequeue(); | ||
23 | } | ||
24 | } | ||
25 | |||
26 | bool Bu::MiniCron::hasJobs() | ||
27 | { | ||
28 | return !hJobs.isEmpty(); | ||
29 | } | ||
30 | |||
31 | time_t Bu::MiniCron::getNextRun() | ||
32 | { | ||
33 | if( hasJobs() ) | ||
34 | return hJobs.peek()->getNextRun(); | ||
35 | return -1; | ||
36 | } | ||
37 | |||
38 | time_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 | |||
50 | void 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 | |||
76 | Bu::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 | |||
89 | Bu::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 | |||
102 | void 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 | |||
122 | void 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 | |||
148 | void 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 | |||
174 | Bu::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 | |||
187 | Bu::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 | |||
197 | Bu::MiniCron::Job::~Job() | ||
198 | { | ||
199 | delete pTimer; | ||
200 | pTimer = NULL; | ||
201 | } | ||
202 | |||
203 | void Bu::MiniCron::Job::run( bool bReschedule ) | ||
204 | { | ||
205 | iRunCount++; | ||
206 | if( bReschedule ) | ||
207 | tNextRun = pTimer->nextTime(); | ||
208 | sigJob( *this ); | ||
209 | } | ||
210 | |||
211 | time_t Bu::MiniCron::Job::getNextRun() const | ||
212 | { | ||
213 | return tNextRun; | ||
214 | } | ||
215 | |||
216 | void Bu::MiniCron::Job::calcNextRun() | ||
217 | { | ||
218 | if( pTimer ) | ||
219 | tNextRun = pTimer->nextTime(); | ||
220 | } | ||
221 | |||
222 | void Bu::MiniCron::Job::setTimer( const Timer &t ) | ||
223 | { | ||
224 | delete pTimer; | ||
225 | pTimer = t.clone(); | ||
226 | } | ||
227 | |||
228 | void Bu::MiniCron::Job::stop() | ||
229 | { | ||
230 | bContinue = false; | ||
231 | } | ||
232 | |||
233 | void Bu::MiniCron::Job::resume() | ||
234 | { | ||
235 | bContinue = true; | ||
236 | } | ||
237 | |||
238 | Bu::MiniCron::JobId Bu::MiniCron::Job::getId() const | ||
239 | { | ||
240 | return jid; | ||
241 | } | ||
242 | |||
243 | time_t Bu::MiniCron::Job::getTimeCreated() const | ||
244 | { | ||
245 | return tAdded; | ||
246 | } | ||
247 | |||
248 | int Bu::MiniCron::Job::getRunCount() const | ||
249 | { | ||
250 | return iRunCount; | ||
251 | } | ||
252 | |||
253 | time_t Bu::MiniCron::Job::getNextRunTime() const | ||
254 | { | ||
255 | return tNextRun; | ||
256 | } | ||
257 | |||
258 | Bu::String Bu::MiniCron::Job::getName() const | ||
259 | { | ||
260 | return sName; | ||
261 | } | ||
262 | |||
263 | Bu::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 | |||
271 | Bu::MiniCron::JobInfo::~JobInfo() | ||
272 | { | ||
273 | } | ||
274 | |||
275 | bool Bu::MiniCron::JobInfo::operator<( const JobInfo &rhs ) const | ||
276 | { | ||
277 | return jid < rhs.jid; | ||
278 | } | ||
279 | |||
280 | Bu::MiniCron::Timer::Timer() | ||
281 | { | ||
282 | } | ||
283 | |||
284 | Bu::MiniCron::Timer::~Timer() | ||
285 | { | ||
286 | } | ||
287 | |||
288 | Bu::MiniCron::TimerInterval::TimerInterval( time_t tFirst, time_t tInterval ) : | ||
289 | tNext( tFirst ), | ||
290 | tInterval( tInterval ) | ||
291 | { | ||
292 | } | ||
293 | |||
294 | Bu::MiniCron::TimerInterval::~TimerInterval() | ||
295 | { | ||
296 | } | ||
297 | |||
298 | time_t Bu::MiniCron::TimerInterval::nextTime() | ||
299 | { | ||
300 | time_t tRet = tNext; | ||
301 | tNext += tInterval; | ||
302 | return tRet; | ||
303 | } | ||
304 | |||
305 | Bu::MiniCron::TimerBasic::TimerBasic( const Bu::String &s ) : | ||
306 | tLast( -1 ), | ||
307 | sSpec( s ) | ||
308 | { | ||
309 | } | ||
310 | |||
311 | Bu::MiniCron::TimerBasic::~TimerBasic() | ||
312 | { | ||
313 | } | ||
314 | |||
315 | time_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 | |||
398 | Bu::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 | |||
468 | int 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 | |||