OSDN Git Service

Multithreads are abandoned. Alternatly, The asyncore substitutes.(#16776)
[fukui-no-namari/fukui-no-namari.git] / src / FukuiNoNamari / misc.py
index 0ece770..9bf7d98 100644 (file)
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
+import pygtk
+pygtk.require('2.0')
+import gtk
+import gobject
 import os.path
 import re
-import time
-import threading
+from datetime import tzinfo, timedelta, datetime
+import itertools
+import traceback
 
 import config
+from BbsType import bbs_type_exception
 
-REG_EXPR_HTTPDATE = re.compile("((?:Mon)|(?:Tue)|(?:Wed)|(?:Thu)|(?:Fri)|(?:Sat)|(?:Sun)), (\d{2}) ((?:Jan)|(?:Feb)|(?:Mar)|(?:Apr)|(?:May)|(?:Jun)|(?:Jul)|(?:Aug)|(?:Sep)|(?:Oct)|(?:Nov)|(?:Dec)) (\d{4}) (\d{2}):(\d{2}):(\d{2}) GMT")
-WDAY_DICT = {"Mon":0, "Tue":1, "Wed":2, "Thu":3, "Fri":4, "Sat":5, "Sun":6}
+REG_EXPR_HTTPDATE = re.compile("[^ ,]{3}, (?P<day>\d{2}) (?P<month>(?:Jan)|(?:Feb)|(?:Mar)|(?:Apr)|(?:May)|(?:Jun)|(?:Jul)|(?:Aug)|(?:Sep)|(?:Oct)|(?:Nov)|(?:Dec)) (?P<year>\d{4}) (?P<hour>\d{2}):(?P<minute>\d{2}):(?P<second>\d{2}) GMT")
 MON_DICT = {"Jan":1, "Feb":2, "Mar":3, "Apr":4, "May":5, "Jun":6, "Jul":7,
             "Aug":8, "Sep":9, "Oct":10, "Nov":11, "Dec":12}
 
+def _check_thread(bbs_type):
+    """if bbs_type is not thread, raise BbsTypeError"""
+
+    if not bbs_type.is_thread():
+        raise bbs_type_exception.BbsTypeError, \
+              "the bbs_type does not represent thread: " + bbs_type.uri
+
 def get_logs_dir_path():
     return os.path.join(config.get_config_dir_path(), "logs")
 
-def get_thread_dat_dir_path(bbs, board):
+def get_thread_dat_dir_path(bbs_type):
     """Returns dir path for saving thread dat file"""
 
-    # if parameter is empty, raise ValueError
-    if not bbs or not board:
-        raise ValueError, "parameter must not be empty"
+    return os.path.join(get_board_dir_path(bbs_type), "dat")
 
-    return os.path.join(get_board_dir_path(bbs, board), "dat")
-
-def get_thread_idx_dir_path(bbs, board):
+def get_thread_idx_dir_path(bbs_type):
     """Returns dir path for saving thread index file"""
 
-    # if parameter is empty, raise ValueError
-    if not bbs or not board:
-        raise ValueError, "parameter must not be empty"
-
-    return os.path.join(get_board_dir_path(bbs, board), "idx")
-
-def get_thread_states_dir_path(bbs, board):
-    if not bbs or not board:
-        raise ValueError, "parameter must not be empty"
-
-    return os.path.join(get_board_dir_path(bbs, board), "states")
-
-def get_thread_dat_path(bbs, board, thread):
-    """Returns thread dat file path
-
-    bbs: bbs id
-
-    board: board id
-
-    thread: thread id
-    """
-
-    # if parameter is empty, raise ValueError
-    if not bbs or not board or not thread:
-        raise ValueError, "parameter must not be empty"
-
-    return os.path.join(get_thread_dat_dir_path(bbs, board), thread + ".dat")
-
-def get_board_subjecttxt_url(bbs, board):
-    """Returns subject.txt file url
-
-    bbs: bbs id
+    return os.path.join(get_board_dir_path(bbs_type), "idx")
 
-    board: board id
-    """
+def get_thread_states_dir_path(bbs_type):
+    """Returns dir path for saving thread states file"""
 
-    # if parameter is empty, raise ValueError
-    if not bbs or not board:
-        raise ValueError, "parameter must not be empty"
+    return os.path.join(get_board_dir_path(bbs_type), "states")
 
-    return get_board_base_url(bbs, board) + "subject.txt"
+def get_thread_dat_path(bbs_type):
+    """Returns thread dat file path"""
 
-def get_board_subjecttxt_path(bbs, board):
-    """Returns subject.txt file path
+    _check_thread(bbs_type)
 
-    bbs: bbs id
+    return os.path.join(get_thread_dat_dir_path(bbs_type),
+                        bbs_type.thread + ".dat")
 
-    board: board id
-    """
+def get_board_subjecttxt_path(bbs_type):
+    """Returns subject.txt file path"""
 
-    # if parameter is empty, raise ValueError
-    if not bbs or not board:
-        raise ValueError, "parameter must not be empty"
+    return os.path.join(get_board_dir_path(bbs_type), "subject.txt")
 
-    return os.path.join(get_logs_dir_path(), bbs, board, "subject.txt")
+def get_thread_states_path(bbs_type):
+    """Returns thread states file path"""
 
-def get_thread_states_path(bbs, board, thread):
-    # if parameter is empty, raise ValueError
-    if not bbs or not board or not thread:
-        raise ValueError, "parameter must not be empty"
+    _check_thread(bbs_type)
 
-    return os.path.join(get_thread_states_dir_path(bbs, board),
-                        thread + ".states")
+    return os.path.join(get_thread_states_dir_path(bbs_type),
+                        bbs_type.thread + ".states")
 
-def get_board_states_path(bbs, board):
-    # if parameter is empty, raise ValueError
-    if not bbs or not board:
-        raise ValueError, "parameter must not be empty"
+def get_board_states_path(bbs_type):
+    """Returns board states file path"""
 
-    return os.path.join(get_board_dir_path(bbs, board), "board.states")
+    return os.path.join(get_board_dir_path(bbs_type), "board.states")
 
-def get_board_idx_path(bbs, board):
-    """Returns board idx file path
+def get_board_idx_path(bbs_type):
+    """Returns board idx file path"""
 
-    bbs: bbs id
+    return os.path.join(get_board_dir_path(bbs_type), "subject.idx")
 
-    board: board id
-    """
+def get_board_dir_path(bbs_type):
+    """Returns board dir path"""
 
-    # if parameter is empty, raise ValueError
-    if not bbs or not board:
-        raise ValueError, "parameter must not be empty"
+    return os.path.join(get_logs_dir_path(), bbs_type.get_board_dir_path())
 
-    return os.path.join(get_logs_dir_path(), bbs, board, "subject.idx")
+def get_thread_idx_path(bbs_type):
+    """Returns idx file path of thread"""
 
-def get_board_dir_path(bbs, board):
-    """Returns board dir path
+    _check_thread(bbs_type)
 
-    bbs: bbs ID
+    return os.path.join(get_thread_idx_dir_path(bbs_type),
+                        bbs_type.thread + ".idx")
 
-    board: board ID
-    """
+def get_board_cache_path(bbs_type):
+    """Returns .cache file path of board"""
 
-    # if parameter is empty, raise ValueError
-    if not bbs or not board:
-        raise ValueError, "parameter must not be empty"
+    return os.path.join(get_thread_idx_dir_path(bbs_type), ".cache")
 
-    return os.path.join(get_logs_dir_path(), bbs, board)
+ZERO = timedelta(0)
+HOUR = timedelta(hours=1)
+class UTC(tzinfo):
+    """UTC"""
 
-def get_thread_idx_path(bbs, board, thread):
-    """Returns idx file path of thread
+    def utcoffset(self, dt):
+        return ZERO
 
-    bbs: bbs ID
+    def tzname(self, dt):
+        return "UTC"
 
-    board: board ID
+    def dst(self, dt):
+        return ZERO
 
-    thread: thread ID
+utc = UTC()
 
-    Note: if parameter is empty, raise ValueError
-    """
-
-    # if parameter is empty, raise ValueError
-    if not bbs or not board or not thread:
-        raise ValueError, "parameter must not be empty"
-
-    return os.path.join(get_thread_idx_dir_path(bbs, board), thread + ".idx")
-
-def get_board_cache_path(bbs, board):
-    """ Returns .cache file path of board
-
-    bbs: bbs ID
-
-    board: board ID
-
-    Note: if parameter is empty, raise ValueError
-    """
-
-    # if parameter is empty, raise ValueError
-    if not bbs or not board:
-        raise ValueError, "parameter must not be empty"
-
-    return os.path.join(get_thread_idx_dir_path(bbs, board), ".cache")
+epoch = datetime(1970, 1, 1, 0, 0, 0, 0, utc)
 
 def httpdate_to_secs(httpdate):
     """Returns the seconds since the epoch"""
 
+    if not httpdate:
+        return 0
+
     m = REG_EXPR_HTTPDATE.match(httpdate)
     if m:
-        tm_wday = WDAY_DICT[m.group(1)]
-        tm_mday = int(m.group(2))
-        tm_mon = MON_DICT[m.group(3)]
-        tm_year = int(m.group(4))
-        tm_hour = int(m.group(5))
-        tm_min = int(m.group(6))
-        tm_sec = int(m.group(7))
-
-        return int(time.mktime(
-            (tm_year,tm_mon,tm_mday,tm_hour,tm_min,tm_sec,tm_wday,0,-1)) \
-            - time.timezone)
+        tm_day = int(m.group("day"))
+        tm_mon = MON_DICT[m.group("month")]
+        tm_year = int(m.group("year"))
+        tm_hour = int(m.group("hour"))
+        tm_min = int(m.group("minute"))
+        tm_sec = int(m.group("second"))
+        
+        d = datetime(tm_year, tm_mon, tm_day, tm_hour, tm_min, tm_sec, 0, utc)
+        delta = d - epoch
+        return delta.days*24*60*60 + delta.seconds
     else:
         raise ValueError
 
 
-class ThreadInvoker(threading.Thread):
-    def __init__(self, on_end, *methods):
-        super(ThreadInvoker, self).__init__()
-        self.on_end = on_end
-        self.methods = methods
-    def run(self):
-        try:
-            for m in self.methods:
-                m()
-        finally:
-            self.on_end()
-
-
 class FileWrap:
-    def __init__(self, path):
-        self._file = None
-        self._path = path
+    def __init__(self, path, mode="a+"):
+        self.__file = None
+        self.__path = path
+        self.__mode = mode
     def __del__(self):
         self.close()
     def seek(self, size):
         self.file().seek(size)
     def write(self, data):
         self.file().write(data)
+    def writelines(self, sequence):
+        self.file().writelines(sequence)
     def close(self):
-        if self._file:
-            self._file.close()
-            self._file = None
+        if self.__file:
+            self.__file.close()
+            self.__file = None
     def file(self):
-        if not self._file:
-            basedir = os.path.dirname(self._path)
+        if not self.__file:
+            basedir = os.path.dirname(self.__path)
             if not os.path.isdir(basedir):
                 os.makedirs(basedir)
-            self._file = file(self._path, "a+")
-        return self._file
+            self.__file = file(self.__path, self.__mode)
+        return self.__file
+
+def unpack_ifilter(predicate, iterable):
+    """For multiple argument"""
+    for item in iterable:
+        if predicate(*item):
+            yield item
+
+def split_key_and_value(key_equal_value):
+    try:
+        index = key_equal_value.index("=")
+    except ValueError:
+        pass
+    else:
+        key = key_equal_value[:index]
+        value = key_equal_value[index+1:]
+        return key, value
+
+def tabbed_to_dict_generator(tabbed, sep="\t"):
+    iterable = tabbed.rstrip().split(sep)
+    iterable = itertools.imap(split_key_and_value, iterable)
+    iterable = itertools.ifilter(None, iterable)
+    return iterable
+
+def tabbed_to_dict(tabbed, sep="\t"):
+    """Creates a dict from key equal value pairs seperated with tab"""
+    return dict([pair for pair in tabbed_to_dict_generator(tabbed, sep)])
+
+
+class StopChainException: pass
+
+def _do_chain(function, on_end, iterable):
+    try:
+        value = iterable.next()
+        function(value)
+    except StopIteration:
+        # normal end.
+        on_end()
+    except StopChainException:
+        # normal end.
+        on_end()
+    except:
+        # an error is occurred.
+        on_end()
+        traceback.print_exc()
+    else:
+        gobject.idle_add(_do_chain, function, on_end, iterable)
+
+def chain(function, on_end, iterable):
+    gobject.idle_add(_do_chain, function, on_end, iterable)