1 /** 2 * @fileOverview A collection of utilities for scheduling tasks in the 3 * future. 4 */ 5 6 if (!appjet) { 7 throw new Error('appjet library is required for util library.'); 8 } 9 10 function _paramObjectToParamArray(params, enc) { 11 var pa = []; 12 eachProperty(params, function(k, v) { 13 pa.push(enc ? encodeURIComponent(k.toString()) : k.toString()); 14 pa.push(enc ? encodeURIComponent(v.toString()) : v.toString()); 15 }); 16 return pa; 17 } 18 19 _radixChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 20 _radix = _radixChars.length 21 22 function _longToString(n) { 23 if (n < _radix) return _radixChars[n]; 24 else return _longToString(Math.floor(n/_radix)) + _radixChars[n%_radix]; 25 } 26 27 function _cronId(date, path, period, params, published) { 28 return "cron-"+ _longToString(appjet._native.storage_time()) + _longToString(Math.floor(Math.random()*_radix*_radix)); 29 } 30 31 /** 32 * <p>Schedules a CRON request to execute once at an exact date in 33 * the future.</p> 34 * 35 * <p>The generated request appears as any other request, but uses HTTP 36 * method <code>CRON</code> to distinguish itself from external HTTP 37 * requests. It is not possible to generate a CRON request in any way 38 * other than by scheduling one.</p> 39 * 40 * <p>To prevent abuse, only about 2000 CRON requests can be executed 41 * by an app in any given minute. (This limit is lower for requests 42 * that are very expensive, such as those that call 43 * <code>wget()</code> and perform other high-cost operations.) 44 * Requsts beyond this limit are rescheduled for the next minute but 45 * ultimately canceled if the reschedule queue grows too large.</p> 46 * 47 * @example 48 result = schedule(new Date("Jan 12, 2008"), "/dosomething"); 49 * 50 * @example 51 function cron_dosomething() { 52 sendEmail("you@example.com", "A scheduled message.", "Greetings!"); 53 } 54 * 55 * @param {Date} date The date the request should trigger. 56 * @param {string} path The path to be specified by the HTTP CRON request. Maximum length of 100 characters. 57 * @param {object} [params] Optional parameters to be given with the HTTP CRON request. Maximum of 256 bytes of data; use storage if you need more. 58 * @param {boolean} [published] Whether the request should be sent to 59 * the published version of the app, or the most recent preview 60 * version. By default only requests scheduled in published mode go to 61 * the published version of the app. 62 * @param {boolean} [mailOnError] Whether to email this app's owner if the cron request fails or is canceled; defaults to false. 63 * @return {string} A unique identifier for this cron task. 64 */ 65 function schedule(date, path, params, published, mailOnError) { 66 if (date === undefined) { 67 throw new Error("Must specify a date for schedule"); 68 } 69 var ps = _paramObjectToParamArray(params, true); 70 var id = _cronId(date, path, -1, params, published); 71 if (published === undefined) { 72 published = !(appjet._native.isPreview() || appjet._native.isShell()); 73 } 74 if (path === undefined) { 75 path = "/"; 76 } 77 if (path[0] != "/") throw new Error("Paths must be absolute."); 78 if (mailOnError === undefined) { 79 mailOnError = false; 80 } 81 var ret = appjet._native.cron_scheduleSingleEvent(date.getTime(), path, ps, published, mailOnError, id); 82 if (ret != "") 83 throw new Error("Scheduling error: "+ret); 84 return id; 85 } 86 87 /** 88 * <p>Schedules a CRON request to execute every <code>period</code> minutes, 89 * starting at <code>date</code>. 90 * 91 * <p>The generated request appears as any other request, but uses 92 * HTTP method <code>CRON</code> to distinguish itself from other external HTTP 93 * requests. It is not possible to generate a CRON request in any way 94 * other than by scheduling one.</p> 95 * 96 * <p>A CRON request cannot schedule a repeating CRON request.</p> 97 * 98 * @example 99 result = schedule(new Date("Jan 12, 2008"), "/dosomething"); 100 * 101 * @param {Date} date The exact date the cron requests should start. 102 * @param {number} period The delay between subsequent requests in minutes. Minimum of 1 minute. 103 * @param {string} path The path specified by the HTTP CRON requests. Maximum length of 100 characters. 104 * @param {object} [params] Optional parameters to be given with the HTTP CRON requests. Maximum of 256 bytes of data. 105 * @param {boolean} [published] Whether the CRON requests should be sent to 106 * the published version of the app, or the most recent preview 107 * version. By default only requests scheduled in published mode go to 108 * the published version of the app. 109 * @param {boolean} [mailOnError] Whether to email this app's owner if the cron request fails or is canceled; defaults to false. 110 * @return {string} A unique identifier for this cron task. 111 */ 112 function scheduleRepeating(date, period, path, params, published, mailOnError) { 113 if (date === undefined || period === undefined) { 114 throw new Error("Must specify a date and a period for scheduleRepeating"); 115 } 116 var ps = _paramObjectToParamArray(params, true); 117 var id = _cronId(date, path, period, params, published) 118 if (published === undefined) { 119 published = !(appjet._native.isPreview() || appjet._native.isShell()); 120 } 121 if (path === undefined) { 122 path = "/"; 123 } 124 if (path[0] != "/") throw new Error("Paths must be absolute."); 125 if (mailOnError === undefined) { 126 mailOnError = false; 127 } 128 var ret = appjet._native.cron_scheduleRepeatingEvent(date.getTime(), period*60000, path, ps, published, mailOnError, id); 129 if (ret != "") 130 throw new Error("Scheduling error: "+ret); 131 return id; 132 } 133 134 /** 135 * <p>Returns an array of objects describing all scheduled CRON tasks. 136 * Modifications to these objects are not reflected in the scheduled 137 * tasks.</p> 138 * 139 * <p>The returned objects have property names that are the same as 140 * the arguments to <code>schedule()</code> and 141 * <code>scheduleRepeating()</code>, namely:</o> 142 * <ul> 143 * <li><strong>name:</strong> the task's identifier</li> 144 * <li><strong>date:</strong> date the task is (or was) first scheduled to run</li> 145 * <li><strong>period:</strong> delay between repeated requests, in minutes</li> 146 * <li><strong>path:</strong> path to request</li> 147 * <li><strong>params:</strong> query string containing the parameters on the request</li> 148 * <li><strong>published:</strong> whether to send the request to the published or preview version of the code</li> 149 * <li><strong>mailOnError:</strong> whether to send mail if there's an error 150 * </ul> 151 * 152 * @return {Array} An array of objects describing all scheduled CRON tasks. 153 */ 154 function listAll() { 155 var ret = appjet._native.cron_allEvents(); 156 ret.forEach(function (e) { 157 e.date = new Date(e.date); 158 if (e.period) 159 e.period = e.period / 60000; 160 eachProperty(e, function(name, value) { 161 e.__defineGetter__(name, function() { return value; }); 162 e.__defineSetter__(name, function() { 163 throw new Error("Scheduled requests are not mutable; you must cancel this one and "+ 164 "schedule a new one if you'd like to change any properties."); 165 }); 166 }); 167 }); 168 return ret; 169 } 170 171 /** 172 * Unschedules the CRON task identified by <code>name</code>. 173 * 174 * <p>If the CRON task is non-repeating and has already been executed, 175 * this function has no effect.</p> 176 * 177 * @example 178 result = schedule(new Date("Jan 12, 2008"), "/dosomething"); 179 unschedule(result); 180 * 181 * @param {string} name The identifier of the CRON task to cancel. 182 */ 183 function unschedule(name) { 184 appjet._native.cron_unschedule(name); 185 } 186 187 /** 188 * Unschedules all CRON tasks. 189 *