📄 ftp_engine.py
字号:
#!/usr/bin/env python# -*- coding: utf-8 -*-# Copyright (C) 1994 Ling Li## This program is free software; you can redistribute it and/or modify# it under the terms of the GNU General Public License as published by# the Free Software Foundation; either version 2 of the License, or# (at your option) any later version.## This program is distributed in the hope that it will be useful,# but WITHOUT ANY WARRANTY; without even the implied warranty of# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the# GNU Library General Public License for more details.## You should have received a copy of the GNU General Public License# along with this program; if not, write to the Free Software# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.import gobjectfrom gtk import idle_addimport logging, os, os.path, string, sys, thread, timefrom threading import Thread, Event, Timerfrom Queue import Queue, Emptyfrom ftplib_client import *#from lftp_client import *from ftp_exception import *from utils import *CMD_QUIT = 0CMD_OPEN = 1CMD_CD = 2CMD_LIST = 3CMD_LISTD = 4CMD_PWD = 5CMD_PUT = 6CMD_GET = 7CMD_MKDIR = 8CMD_CHOWN = 9CMD_CHMOD = 10CMD_DELETE = 11CMD_MOVE = 12CMD_ABOR = 13CMD_SIMPLE = 14STATUS_NONE = 0STATUS_CONNECTING = 1STATUS_IDLE = 2STATUS_RUNNING = 3STATUS_ABORT = 4ERRNO_ABORT = -1ERRNO_TIMEDOUT = -2class FTPEngine(gobject.GObject, Thread): """ This is a control object for FTP task. All the FTP request from remote view is sent to this object, this object will process them using real ftp program wrapper one by one. Every FTPEngine object has a is_idle Event object, when a request is processed, the object is clear, all the following command should wait until the previous command finished. FTPEngine use a real ftp program(such as lftp) wrapper to process FTP command, in all the cases it will wait until the FTP command return. So FTPEngine has a thread to process FTP commands. FTPEngine is also a sub-class of GObject class. When process of FTP command finished, signals are emitted via gtk_idle. """ __gsignals__ = { 'interrupted' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT,)), 'idle' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT,)), 'delay' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT,)), 'log-message': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT, gobject.TYPE_STRING)), 'quit' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), 'idle-connection-closed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), 'open-succeeded' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), 'open-failed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT, gobject.TYPE_STRING)), 'welcome-message' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,)), 'list-succeeded' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), 'list-failed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT, gobject.TYPE_STRING)), 'listd-succeeded' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), 'listd-failed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT, gobject.TYPE_STRING)), 'pwd-succeeded' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), 'pwd-failed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT, gobject.TYPE_STRING)), 'cd-succeeded' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), 'cd-failed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT, gobject.TYPE_STRING)), 'move-succeeded' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), 'move-failed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT, gobject.TYPE_STRING)), 'delete-succeeded' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), 'delete-failed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT, gobject.TYPE_STRING)), 'mkdir-succeeded' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), 'mkdir-failed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT, gobject.TYPE_STRING)), 'put-succeeded' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), 'put-failed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT, gobject.TYPE_STRING)), 'get-succeeded' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), 'get-failed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_INT, gobject.TYPE_STRING)), } # the status of the ftp engine status = None # total_idle is idle time since last useful command total_idle = 0 # Timer object for idle idle_timer = None # Timer object for delay delay_timer = None # If true, start/stop idle will change idle time and start/stop send of # idle event, otherwise, only __is_idle event will be changed. __change_idle = TRUE # __queue_lock is used to make command_queue be visited on in one thread. __queue_lock = None # __command_queue is a place which is used to store ftp commands need # processed. FTPEngine object will add command to the queue and FTPClient # object fetch command from the queue. # __command_queue can be visited in only one thread, and the access to # it is restricted by __queue_lock __command_queue = None __welcome_message = None def __init__(self, rview): self.__gobject_init__() Thread.__init__(self) self.__remote_view = rview self.__coralftp = rview.main_window.coralftp self.__is_idle = Event() self.__queue_lock = Event() self.__quit_event = Event() self.__ftp_client = FTPLibClient(self) self.__command_queue = Queue(8) self.__read_config() self.status = STATUS_NONE def __read_config(self): config = self.config self.connect_retry_delay = config_value( config, 'general', 'connect_retry_delay') self.connect_retry_count = config_value( config, 'general', 'connect_retry_count') self.send_keep_alive_command = config_value( config, 'general', 'send_keep_alive_command') self.keep_alive_command = config_value( config, 'general', 'keep_alive_command') self.send_keep_alive_interval = config_value( config, 'general', 'send_keep_alive_interval') self.stop_send_keep_alive = config_value( config, 'general', 'stop_send_keep_alive') self.stop_keep_alive_after = 60 * config_value( config, 'general', 'stop_keep_alive_after') def run(self): self.__pid = thread.get_ident() logging.debug('ftp thread start, pid is %d' % self.__pid) self.__coralftp.register_thread('ftp') self.__ftp_client.run() self.__queue_lock.set() self.__is_idle.set() while not self.quit_event.isSet(): try: func = args = change_idle = None self.__queue_lock.wait() func, args, change_idle = self.__command_queue.get(TRUE, 1) logging.debug("ftp thread get new command %s, %s, %s" \ % (func, args, change_idle)) if self.__is_idle.isSet(): self.stop_idle(change_idle) self.__result = func(*args) if self.__command_queue.empty(): self.start_idle(change_idle) except Empty, e: pass logging.debug('before emit quit') idle_add(self.emit, 'quit') logging.debug('ftp thread quit') return def __execute_in_thread(self, func, *args): """This function make put the method into command queue, and make it run in ftp thread.""" if not self.__queue_lock.isSet(): raise RuntimeError self.__command_queue.put((func, args, self.__change_idle), TRUE) def __getattr__(self, name): if name == 'remote_view': return self.__remote_view elif name == 'is_idle_event': return self.__is_idle elif name == 'is_idle': return self.status == STATUS_IDLE elif name == 'quit_event': return self.__quit_event elif name == 'config': return self.__remote_view.config elif name == 'log_updater': return self.__remote_view.main_window.log_view.updater elif name == 'site_info': return self.__site_info elif name == 'welcome_message': return self.__welcome_message elif name == 'coralftp': return self.__coralftp else: raise AttributeError, name def do_idle_connection_closed(self): self.status = STATUS_NONE idle_add(self.quit) def abort(self): logging.debug("ftp_engine.abort runs in %s" \ % self.__coralftp.get_thread_name()) if self.delay_timer: self.delay_timer.cancel() self.delay_timer = None self.delayed = None self.__queue_lock.clear() while not self.__command_queue.empty(): self.__command_queue.get_nowait() if self.status == STATUS_RUNNING: self.status = STATUS_ABORT try: self.__ftp_client.interrupt() except EOFError: self.__queue_lock.set() self.quit() self.__queue_lock.set() def quit(self): logging.debug('quit command execute in %s' % \ self.__coralftp.get_thread_name()) if not self.__is_idle.isSet(): self.abort() self.__is_idle.wait() self.__quit_event.set() self.__change_idle = FALSE # send ftp quit commnad if self.status > STATUS_CONNECTING: try: self.__ftp_client.quit() except FTPTempException, (errno, errmsg): if errno == 421: pass else: raise ValueError self.status = STATUS_NONE self.stop_idle(FALSE) logging.debug('quit command finished') return def start_idle(self, change_idle, finished_event = None): def idle(): if self.status == STATUS_IDLE: self.total_idle = self.total_idle + 1 idle_add(self.emit, 'idle', self.total_idle) self.idle_timer = Timer(1, idle) self.idle_timer.start() return self.__is_idle.set() if self.status > STATUS_CONNECTING: self.__ftp_client.start_monitor() if change_idle and self.status > STATUS_CONNECTING: self.status = STATUS_IDLE self.total_idle = 0 logging.debug('start idle') self.idle_timer = Timer(1, idle) self.idle_timer.start() if finished_event != None: finished_event.set()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -