3

我在我的服务器上运行这个脚本,以便在新邮件到达时发送推送通知。它工作得很好,但有时脚本会因以下错误而崩溃。我不知道它为什么会崩溃,我自己也无法重现它。当它失败时,它不会进入 except 部分。我试过了:except self.abort: except M.abort: except M.error:

  1. 知道为什么会崩溃吗?

  2. 对于短期解决方案,是否有可能杀死所有线程并从该except部分重新启动脚本?

…………

import socket, ssl, json, struct, re
import imaplib2, time
from threading import *

# enter gmail login details here
USER="YOUR.NAME@gmail.com"
PASSWORD="YOUR-GMAIL-PASSWORD"
# enter device token here
deviceToken = 'XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX '
deviceToken = deviceToken.replace(' ','').decode('hex')
currentBadgeNum = -1

def getUnseen():
    (resp, data) = M.status("INBOX", '(UNSEEN)')
    print data
    return int(re.findall("UNSEEN (\d)*\)", data[0])[0])    

def sendPushNotification(badgeNum):
    global currentBadgeNum, deviceToken
    if badgeNum != currentBadgeNum:
        currentBadgeNum = badgeNum
        thePayLoad = {
             'aps': {
        #          'alert':'Hello world!',
                  'sound':'',
                  'badge': badgeNum,
                  },
             'test_data': { 'foo': 'bar' },
             }
        theCertfile = 'certfile.pem'
        theHost = ('gateway.sandbox.push.apple.com', 2195)

        data = json.dumps(thePayLoad)
        theFormat = '!BH32sH%ds' % len(data)
        theNotification = struct.pack(theFormat, 0, 32, deviceToken, len(data), data)

        ssl_sock = ssl.wrap_socket(socket.socket(socket.AF_INET, socket.SOCK_STREAM), certfile=theCertfile)
        ssl_sock.connect(theHost)
        ssl_sock.write(theNotification)
        ssl_sock.close()
        print "Sent Push alert."

# This is the threading object that does all the waiting on 
# the event
class Idler(object):
    def __init__(self, conn):
        self.thread = Thread(target=self.idle)
        self.M = conn
        self.event = Event()

    def start(self):
        self.thread.start()

    def stop(self):
        # This is a neat trick to make thread end. Took me a 
        # while to figure that one out!
        self.event.set()

    def join(self):
        self.thread.join()

    def idle(self):
        # Starting an unending loop here
        while True:
            # This is part of the trick to make the loop stop 
            # when the stop() command is given
            if self.event.isSet():
                return
            self.needsync = False
            # A callback method that gets called when a new 
            # email arrives. Very basic, but that's good.
            def callback(args):
                if not self.event.isSet():
                    self.needsync = True
                    self.event.set()
            # Do the actual idle call. This returns immediately, 
            # since it's asynchronous.
            self.M.idle(callback=callback)
            # This waits until the event is set. The event is 
            # set by the callback, when the server 'answers' 
            # the idle call and the callback function gets 
            # called.
            self.event.wait()
            # Because the function sets the needsync variable,
            # this helps escape the loop without doing 
            # anything if the stop() is called. Kinda neat 
            # solution.
            if self.needsync:
                self.event.clear()
                self.dosync()

    # The method that gets called when a new email arrives. 
    def dosync(self):
        print "Got an event!"
        numUnseen = getUnseen()
        sendPushNotification(numUnseen)

try:
    # Set the following two lines to your creds and server
    print 'starting'
    global M
    M = imaplib2.IMAP4_SSL("imap.gmail.com")
    M.login(USER, PASSWORD)
    # We need to get out of the AUTH state, so we just select 
    # the INBOX.
    #M.list()
    M.select('INBOX', readonly=True)
    numUnseen = getUnseen()
    getText()
    #print M.status("INBOX", '(UNSEEN)')
    # Start the Idler thread
    sendPushNotification(numUnseen)
    idler = Idler(M)
    idler.start()
    # Sleep forever, one minute at a time
    while True:
        time.sleep(60)

except self.abort:
    print 'we had a problem, dont worry! Ill fix it!'
    idler = Idler(M)
finally:
    # Clean up.
    idler.stop()
    idler.join()
    M.close()
    # This is important!
    M.logout()

.....................

.....................

  17:35.99 imap.gmail.com reader last 20 log messages:
  17:36.02 imap.gmail.com handler last 20 log messages:
Got an event!
Exception in thread Thread-4:
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/threading.py", line 551, in __bootstrap_inner
    self.run()
  File "/usr/local/lib/python2.7/threading.py", line 504, in run
    self.__target(*self.__args, **self.__kwargs)
  File "serverx.py", line 229, in idle
    self.dosync()
  File "serverx.py", line 235, in dosync
    numUnseen = getUnseen()
  File "serverx.py", line 150, in getUnseen
    (resp, data) = M.status("INBOX", '(UNSEEN)')
  File "/home/myuser/lib/python2.7/imaplib2/imaplib2.py", line 1121, in status
    return self._simple_command(name, mailbox, names, **kw)
  File "/home/myuser/lib/python2.7/imaplib2/imaplib2.py", line 1607, in _simple_command
    return self._command_complete(self._command(name, *args), kw)
  File "/home/myuser/lib/python2.7/imaplib2/imaplib2.py", line 1305, in _command
    raise self.abort('connection closed')
abort: connection closed
4

2 回答 2

0

尝试捕捉imaplib2.IMAP4.abort

try:
    # ...
except imaplib2.IMAP4.abort:
    # Oh no! An error!
于 2013-05-14T06:13:39.793 回答
0

我试图解决同样的问题并且我成功了。

您需要将其包装self.M.idle(callback=callback)起来try-except,然后在主线程中重新提升它。然后通过在主线程中重新运行代码以重新启动连接来处理异常。

您可以在此答案中找到解决方案的更多详细信息和可能的原因:https ://stackoverflow.com/a/50163971/1544154

完整的解决方案在这里:https ://www.github.com/Elijas/email-notifier

于 2018-05-05T08:15:39.560 回答