[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[or-cvs] r21936: {weather} Add user-selected grace time that will be waited until the u (in weather/trunk: . lib/weather)



Author: kaner
Date: 2010-03-13 20:13:07 +0000 (Sat, 13 Mar 2010)
New Revision: 21936

Added:
   weather/trunk/LICENSE
Modified:
   weather/trunk/Weather.py
   weather/trunk/lib/weather/config.py
   weather/trunk/lib/weather/constants.py
   weather/trunk/lib/weather/poller.py
   weather/trunk/lib/weather/queries.py
Log:
Add user-selected grace time that will be waited until the user is notified, add copyright notice


Added: weather/trunk/LICENSE
===================================================================
--- weather/trunk/LICENSE	                        (rev 0)
+++ weather/trunk/LICENSE	2010-03-13 20:13:07 UTC (rev 21936)
@@ -0,0 +1,31 @@
+gettor is distributed under this license:
+
+Copyright (c) 2008, The Tor Project, Inc.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+
+    * Neither the names of the copyright owners nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Modified: weather/trunk/Weather.py
===================================================================
--- weather/trunk/Weather.py	2010-03-13 18:41:34 UTC (rev 21935)
+++ weather/trunk/Weather.py	2010-03-13 20:13:07 UTC (rev 21936)
@@ -1,5 +1,11 @@
 #!/usr/bin/python
 
+__program__ = 'Weather.py'
+__url__ = 'https://svn.torproject.org/svn/weather/'
+__author__ = 'Jacob Appelbaum <jacob@xxxxxxxxxxxxx>, Christian Fromme <kaner@xxxxxxxxxx>'
+__copyright__ = 'Copyright (c) 2009, 2010 The Tor Project'
+__license__ = 'See LICENSE for licensing information'
+
 import os
 import re
 import sys
@@ -11,7 +17,7 @@
 from weather.constants import PAGE_TEMPLATE, PAGE_SIGNUP, CONFIRMATION_MAIL, THANKS_OUT, PAGE_SUB_FIN
 from weather.queries import CHECK_SUBS_Q, INSERT_SUBS_Q, CHECK_SUBS_AUTH_Q, ACK_SUB_Q, UNSUBSCRIBE_Q
 from weather.poller import WeatherPoller
-from weather.config import pollPeriod, URLbase, mailFrom
+from weather.config import pollPeriod, URLbase, mailFrom, databaseName
 import weather.utils as utils
 
 class WeatherIndex(resource.Resource):
@@ -27,6 +33,12 @@
         self.request = request
         self.email = request.args['email'][0]
         self.node = request.args['node'][0]
+        self.downtime = int(request.args['downtime'][0])
+        # Don't accept downtime grace values longer than 8760 hours = 1 year
+        if self.downtime > 8760:
+            self.downtime = 8760
+        if self.downtime < 1:
+            self.downtime = 1
 
         if not utils.checkMail(self.email):
             return "Error: Bad email address '%s'" % self.email
@@ -54,7 +66,7 @@
 
     def _runSaveQuery(self):
         dbQuery = INSERT_SUBS_Q % (self.email, self.node, \
-                              self.subs_auth, self.unsubs_auth)
+                              self.subs_auth, self.unsubs_auth, self.downtime)
         q = self.dbConn.runOperation(dbQuery)
         q.addCallback(self._saved)
         q.addErrback(self._errback)
@@ -111,7 +123,8 @@
     def _checkRet(self, result, request):
         if len(result) is 0:
             request.setResponseCode(http.OK)
-            request.write(utils.pageOut("Error: No subscription with your auth code"))
+            text = "Error: No subscription with your auth code"
+            request.write(utils.pageOut(text))
             request.finish()
         else:
             self.unsubs_auth = str(result[0][0])
@@ -177,7 +190,7 @@
 
 def main():
     # Set up database connection
-    dbConn = utils.setupDBConn("subscriptions.db")
+    dbConn = utils.setupDBConn(databaseName)
     # Set up polling timer
     weatherPoller = WeatherPoller(dbConn)
     pollTimer = LoopingCall(weatherPoller.poller)

Modified: weather/trunk/lib/weather/config.py
===================================================================
--- weather/trunk/lib/weather/config.py	2010-03-13 18:41:34 UTC (rev 21935)
+++ weather/trunk/lib/weather/config.py	2010-03-13 20:13:07 UTC (rev 21936)
@@ -13,4 +13,6 @@
 failureThreshold = 4 # this number of failures in a row counts as being
                       # down
 
-pollPeriod = 10 # try to wait this number of seconds in between polling
+pollPeriod = 10 # Check every hour
+
+databaseName = "subscriptions.db"

Modified: weather/trunk/lib/weather/constants.py
===================================================================
--- weather/trunk/lib/weather/constants.py	2010-03-13 18:41:34 UTC (rev 21935)
+++ weather/trunk/lib/weather/constants.py	2010-03-13 20:13:07 UTC (rev 21936)
@@ -84,7 +84,12 @@
 </p><p>
 Node fingerprint:<br>
 <input type="text" name="node" size="50" maxlength="255" value="Enter one Tor node ID" onclick="if (this.value == 'Enter one Tor node ID') {this.value = ''}" />
-</p><p>
+</p>
+<p>
+How many hours of downtime until we send a notification:<br>
+<input type="text" name="downtime" size="50" maxlength="255" value="Default is 1 hour, enter up to 8760 (1 year)" onclick="if (this.value == 'Default is 1 hour, enter up to 8760 (1 year)') {this.value = ''}" />
+</p>
+<p>
 <input type="submit" class="submit" value="Subscribe to Tor Weather" name="sa"/>
 </p>
 <hr>

Modified: weather/trunk/lib/weather/poller.py
===================================================================
--- weather/trunk/lib/weather/poller.py	2010-03-13 18:41:34 UTC (rev 21935)
+++ weather/trunk/lib/weather/poller.py	2010-03-13 20:13:07 UTC (rev 21936)
@@ -2,8 +2,8 @@
 
 import smtplib
 
+import weather.queries as queries
 from twisted.web import server
-from weather.queries import GETALL_SUBS_Q
 from weather.torping import TorPing
 from weather.config import URLbase, mailFrom
 from weather.constants import REPORT_MAIL
@@ -18,7 +18,7 @@
         return server.NOT_DONE_YET
 
     def _checkAll(self):
-        dbQuery = GETALL_SUBS_Q
+        dbQuery = queries.GETALL_SUBS_Q
         q = self.dbConn.runQuery(dbQuery)
         q.addCallback(self._checkRet)
         q.addErrback(self._errBack)
@@ -32,8 +32,11 @@
                 self._handleOfflineNode(result)
             else:
                 print "Server %s is ok" % checkHost
+                # Reset possible seen_down counter
+                self._resetSeendown(result)
     
     def _errBack(self, failure):
+        # XXX: Log
         print "Error: ", failure.getErrorMessage()
 
     def _checkHost(self, hostID):
@@ -41,17 +44,56 @@
         return torPing.ping(hostID)
 
     def _handleOfflineNode(self, dbRow):
-        # Log, mail
-        if self._decideNotice(dbRow):
-            self._sendNotice(dbRow)
+        self._getDowntimes(dbRow[0])
+        self._updateDowntime(dbRow[0])
 
-    def _decideNotice(self, dbRow):
-        # This is just a placeholder for now. We'll decide later what 
-        # conditions we want to check
-        return True
+    def _getDowntimes(self, id):
+        dbQuery = queries.ALL_BY_ID_Q % id
+        q = self.dbConn.runQuery(dbQuery)
+        q.addCallback(self._decideNotice)
+        q.addErrback(self._errBack)
 
-    def _sendNotice(self, dbRow):
-        nodeId = dbRow[2]
-        unsubsURL =  URLbase + "/unsubscribe?auth=" + str(dbRow[4])
-        mailText = REPORT_MAIL % (nodeId, unsubsURL)
-        utils.sendMail(mailFrom, dbRow[1], mailText)
+    def _decideNotice(self, result):
+        downGrace = result[0][6] 
+        seenDown = result[0][7]
+        email = result[0][1]
+        node = result[0][2]
+        id = result[0][0]
+        noticed = result[0][8]
+        unsubs_auth = result[0][4]
+        if noticed is 0 and (seenDown + 1) >= downGrace:
+            # XXX: Log
+            self._sendNotice(email, node, id, unsubs_auth)
+
+    def _sendNotice(self, email, node, id, unsubs_auth):
+        unsubsURL =  URLbase + "/unsubscribe?auth=" + str(unsubs_auth)
+        mailText = REPORT_MAIL % (node, unsubsURL)
+        try:
+            utils.sendMail(mailFrom, email, mailText)
+        except:
+            # XXX: Log
+            print "Error, exception!"
+        else:
+            # Set 'noticed' flag so we don't bother that user again
+            self._setNoticed(id)
+
+    def _setNoticed(self, id):
+        dbQuery = queries.UPDATE_NOTICED_Q % id
+        q = self.dbConn.runQuery(dbQuery)
+        q.addCallback(self._updateDone)
+        q.addErrback(self._errBack)
+
+    def _updateDowntime(self, id):
+        dbQuery =  queries.UPDATE_DOWN_Q % id
+        q = self.dbConn.runQuery(dbQuery)
+        q.addCallback(self._updateDone)
+        q.addErrback(self._errBack)
+
+    def _updateDone(self, result):
+        print "Query ok"        
+
+    def _resetSeendown(self, dbRow):
+        dbQuery = queries.RESET_COUNT_Q % dbRow[0]
+        q = self.dbConn.runQuery(dbQuery)
+        q.addCallback(self._updateDone)
+        q.addErrback(self._errBack)

Modified: weather/trunk/lib/weather/queries.py
===================================================================
--- weather/trunk/lib/weather/queries.py	2010-03-13 18:41:34 UTC (rev 21935)
+++ weather/trunk/lib/weather/queries.py	2010-03-13 20:13:07 UTC (rev 21936)
@@ -3,12 +3,16 @@
 # Query strings
 CHECK_SUBS_Q = "SELECT id FROM subscriptions WHERE email='%s' and node='%s'"
 INSERT_SUBS_Q = """
-    INSERT INTO subscriptions (email, node, subs_auth, unsubs_auth, subscribed) VALUES ('%s', '%s', '%s', '%s', 0)
+    INSERT INTO subscriptions (email, node, subs_auth, unsubs_auth, subscribed, downtime_grace, seen_down, noticed) VALUES ('%s', '%s', '%s', '%s', 0, '%s', 0, 0)
 """
 CHECK_SUBS_AUTH_Q = "SELECT unsubs_auth FROM subscriptions WHERE subs_auth='%s'"
 ACK_SUB_Q = "UPDATE subscriptions SET subscribed=1 WHERE subs_auth='%s'"
 UNSUBSCRIBE_Q = "DELETE from subscriptions where unsubs_auth='%s'"
 GETALL_SUBS_Q = "SELECT * from subscriptions WHERE subscribed=1"
 CREATE_TABLE_Q = """
-    CREATE TABLE IF NOT EXISTS %s (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, email VARCHAR(255) NOT NULL, node VARCHAR(255) NOT NULL, subs_auth VARCHAR(255) NOT NULL, unsubs_auth VARCHAR(255) NOT NULL, subscribed INTEGER NOT NULL)
+    CREATE TABLE IF NOT EXISTS '%s' (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, email VARCHAR(255) NOT NULL, node VARCHAR(255) NOT NULL, subs_auth VARCHAR(255) NOT NULL, unsubs_auth VARCHAR(255) NOT NULL, subscribed INTEGER NOT NULL, downtime_grace INTEGER NOT NULL, seen_down INTEGER NOT NULL, noticed INTEGER NOT NULL)
 """
+ALL_BY_ID_Q = "SELECT * from subscriptions WHERE id = '%s'"
+UPDATE_DOWN_Q = "UPDATE subscriptions SET seen_down = seen_down + 1 WHERE id = '%s'" 
+UPDATE_NOTICED_Q = "UPDATE subscriptions SET noticed = 1 WHERE id = '%s'"
+RESET_COUNT_Q = "UPDATE subscriptions SET seen_down = 0, noticed = 0 WHERE (id = '%s') AND (seen_down > 0) AND (noticed > 0)"