add estimated time and speed to FT

This commit is contained in:
Dimitur Kirov 2005-09-08 22:12:14 +00:00
parent 02be379d83
commit ba4fadc5cc
3 changed files with 122 additions and 28 deletions

View File

@ -24,6 +24,7 @@ import select
import os import os
import struct import struct
import sha import sha
import time
from errno import EWOULDBLOCK from errno import EWOULDBLOCK
from errno import ENOBUFS from errno import ENOBUFS
@ -169,6 +170,8 @@ running instance of Gajim. \nFile Transfer will be canceled.\n==================
reader.file_props['completed'] = False reader.file_props['completed'] = False
reader.file_props['paused'] = False reader.file_props['paused'] = False
reader.file_props['stalled'] = False reader.file_props['stalled'] = False
reader.file_props['elapsed-time'] = 0
reader.file_props['last-time'] = time.time()
reader.file_props['received-len'] = 0 reader.file_props['received-len'] = 0
reader.pauses = 0 reader.pauses = 0
reader.send_raw(reader._get_nl_byte()) reader.send_raw(reader._get_nl_byte())
@ -186,6 +189,8 @@ running instance of Gajim. \nFile Transfer will be canceled.\n==================
result = sender.send_file() result = sender.send_file()
self.process_result(result, sender) self.process_result(result, sender)
else: else:
file_props['elapsed-time'] = 0
file_props['last-time'] = time.time()
file_props['received-len'] = 0 file_props['received-len'] = 0
sender.file_props = file_props sender.file_props = file_props
@ -248,7 +253,9 @@ running instance of Gajim. \nFile Transfer will be canceled.\n==================
sender.file_props['type'] == 'r': sender.file_props['type'] == 'r':
result = sender.get_file_contents(0) result = sender.get_file_contents(0)
self.process_result(result, sender) self.process_result(result, sender)
elif sender.state == 7 and not sender.file_props['paused']: elif sender.state == 7:
if sender.file_props['paused']:
break
if not sender.connected: if not sender.connected:
self.process_result(-1, sender) self.process_result(-1, sender)
break break
@ -354,6 +361,7 @@ class Socks5:
def open_file_for_reading(self): def open_file_for_reading(self):
self.fd = open(self.file_props['file-name'],'rb') self.fd = open(self.file_props['file-name'],'rb')
self.fd.seek(self.size) self.fd.seek(self.size)
def close_file(self): def close_file(self):
try: try:
self.fd.close() self.fd.close()
@ -369,6 +377,8 @@ class Socks5:
else: else:
fd = open(self.file_props['file-name'],'wb') fd = open(self.file_props['file-name'],'wb')
self.file_props['fd'] = fd self.file_props['fd'] = fd
self.file_props['elapsed-time'] = 0
self.file_props['last-time'] = time.time()
self.file_props['received-len'] = 0 self.file_props['received-len'] = 0
return fd return fd
@ -442,6 +452,10 @@ class Socks5:
self.file_props['error'] = -1 self.file_props['error'] = -1
return -1 return -1
self.size += lenn self.size += lenn
current_time = time.time()
self.file_props['elapsed-time'] += current_time - \
self.file_props['last-time']
self.file_props['last-time'] = current_time
self.file_props['received-len'] = self.size self.file_props['received-len'] = self.size
if self.size == int(self.file_props['size']): if self.size == int(self.file_props['size']):
self.state = 8 # end connection self.state = 8 # end connection
@ -483,6 +497,10 @@ class Socks5:
fd = self.get_fd() fd = self.get_fd()
fd.write(self.remaining_buff) fd.write(self.remaining_buff)
lenn = len(self.remaining_buff) lenn = len(self.remaining_buff)
current_time = time.time()
self.file_props['elapsed-time'] += current_time - \
self.file_props['last-time']
self.file_props['last-time'] = current_time
self.file_props['received-len'] += lenn self.file_props['received-len'] += lenn
self.remaining_buff = '' self.remaining_buff = ''
if self.file_props['received-len'] == int(self.file_props['size']): if self.file_props['received-len'] == int(self.file_props['size']):
@ -505,6 +523,11 @@ class Socks5:
if ord(buff[0]) == 0xD: if ord(buff[0]) == 0xD:
first_byte = True first_byte = True
buff = buff[1:] buff = buff[1:]
current_time = time.time()
self.file_props['elapsed-time'] += current_time - \
self.file_props['last-time']
self.file_props['last-time'] = current_time
self.file_props['received-len'] += len(buff) self.file_props['received-len'] += len(buff)
fd.write(buff) fd.write(buff)
if len(buff) == 0 and first_byte is False: if len(buff) == 0 and first_byte is False:
@ -667,6 +690,8 @@ class Socks5Sender(Socks5):
self.file_props['paused'] = False self.file_props['paused'] = False
self.file_props['stalled'] = False self.file_props['stalled'] = False
self.file_props['connected'] = True self.file_props['connected'] = True
self.file_props['elapsed-time'] = 0
self.file_props['last-time'] = time.time()
self.file_props['received-len'] = 0 self.file_props['received-len'] = 0
self.pauses = 0 self.pauses = 0
return self.write_next(initial = True) # initial for nl byte return self.write_next(initial = True) # initial for nl byte
@ -692,7 +717,7 @@ class Socks5Sender(Socks5):
self.state += 1 # go to the next step self.state += 1 # go to the next step
return None return None
def pending_data(self,timeout=0.01): def pending_data(self,timeout=0):
''' return true if there is a data ready to be read ''' ''' return true if there is a data ready to be read '''
if self._sock is None: if self._sock is None:
return False return False
@ -752,7 +777,7 @@ class Socks5Listener:
_sock[0].setblocking(False) _sock[0].setblocking(False)
return _sock return _sock
def pending_connection(self,timeout=0.005): def pending_connection(self,timeout=0):
''' Returns true if there is a data ready to be read. ''' ''' Returns true if there is a data ready to be read. '''
if self._serv is None: if self._serv is None:
return False return False
@ -872,6 +897,8 @@ class Socks5Receiver(Socks5):
self.file_props['completed'] = False self.file_props['completed'] = False
self.file_props['paused'] = False self.file_props['paused'] = False
self.file_props['stalled'] = False self.file_props['stalled'] = False
self.file_props['elapsed-time'] = 0
self.file_props['last-time'] = time.time()
self.file_props['received-len'] = 0 self.file_props['received-len'] = 0
self.pauses = 0 self.pauses = 0
self.send_raw(self._get_nl_byte()) self.send_raw(self._get_nl_byte())
@ -887,7 +914,7 @@ class Socks5Receiver(Socks5):
return False return False
try: try:
if self.state in [2, 4, 6]: # auth response, connect, file data if self.state in [2, 4, 6]: # auth response, connect, file data
return self.pending_read(0.01) return self.pending_read(0)
elif self.state in [1, 3, 5]: # auth types, connect request elif self.state in [1, 3, 5]: # auth types, connect request
return True return True
except Exception, e: except Exception, e:

View File

@ -24,6 +24,7 @@ import gobject
import pango import pango
import os import os
import sys import sys
import time
import gtkgui_helpers import gtkgui_helpers
import tooltips import tooltips
@ -39,7 +40,16 @@ gtk.glade.bindtextdomain (APP, i18n.DIR)
gtk.glade.textdomain (APP) gtk.glade.textdomain (APP)
GTKGUI_GLADE = 'gtkgui.glade' GTKGUI_GLADE = 'gtkgui.glade'
SID_INDEX = 5
C_IMAGE = 0
C_LABELS = 1
C_FILE = 2
C_PROGRESS = 3
C_PERCENT = 4
C_TIME = 5
C_SID = 6
class FileTransfersWindow: class FileTransfersWindow:
def __init__(self, plugin): def __init__(self, plugin):
self.files_props = {'r' : {}, 's': {}} self.files_props = {'r' : {}, 's': {}}
@ -58,7 +68,7 @@ class FileTransfersWindow:
self.notify_ft_checkbox.set_active(True) self.notify_ft_checkbox.set_active(True)
else: else:
self.notify_ft_checkbox.set_active(False) self.notify_ft_checkbox.set_active(False)
self.model = gtk.ListStore(gtk.gdk.Pixbuf, str, str, str, int, str) self.model = gtk.ListStore(gtk.gdk.Pixbuf, str, str, str, int, str, str)
self.tree.set_model(self.model) self.tree.set_model(self.model)
col = gtk.TreeViewColumn() col = gtk.TreeViewColumn()
@ -74,11 +84,11 @@ class FileTransfersWindow:
col = gtk.TreeViewColumn(_('File')) col = gtk.TreeViewColumn(_('File'))
renderer = gtk.CellRendererText() renderer = gtk.CellRendererText()
col.pack_start(renderer, expand=False) col.pack_start(renderer, expand=False)
col.add_attribute(renderer, 'markup' , 1) col.add_attribute(renderer, 'markup' , C_LABELS)
renderer.set_property('yalign', 0.) renderer.set_property('yalign', 0.)
renderer = gtk.CellRendererText() renderer = gtk.CellRendererText()
col.pack_start(renderer, expand=True) col.pack_start(renderer, expand=True)
col.add_attribute(renderer, 'markup' , 2) col.add_attribute(renderer, 'markup' , C_FILE)
renderer.set_property('xalign', 0.) renderer.set_property('xalign', 0.)
renderer.set_property('yalign', 0.) renderer.set_property('yalign', 0.)
renderer.set_property('ellipsize', pango.ELLIPSIZE_END) renderer.set_property('ellipsize', pango.ELLIPSIZE_END)
@ -92,9 +102,24 @@ class FileTransfersWindow:
renderer.set_property('xalign', 0.5) renderer.set_property('xalign', 0.5)
col.pack_start(renderer, expand = False) col.pack_start(renderer, expand = False)
col.set_expand(False) col.set_expand(False)
col.add_attribute(renderer, 'text' , 3) col.add_attribute(renderer, 'text' , C_PROGRESS)
col.add_attribute(renderer, 'value' , 4) col.add_attribute(renderer, 'value' , C_PERCENT)
col.set_resizable(True)
self.tree.append_column(col) self.tree.append_column(col)
col = gtk.TreeViewColumn(_('Time'))
renderer = gtk.CellRendererText()
col.pack_start(renderer, expand=False)
col.add_attribute(renderer, 'markup' , C_TIME)
renderer.set_property('yalign', 0.5)
renderer.set_property('xalign', 0.5)
renderer = gtk.CellRendererText()
renderer.set_property('ellipsize', pango.ELLIPSIZE_END)
col.set_resizable(True)
col.set_expand(False)
self.tree.append_column(col)
self.set_images() self.set_images()
self.tree.get_selection().set_mode(gtk.SELECTION_SINGLE) self.tree.get_selection().set_mode(gtk.SELECTION_SINGLE)
self.tree.get_selection().connect('changed', self.selection_changed) self.tree.get_selection().connect('changed', self.selection_changed)
@ -348,14 +373,15 @@ _('Connection with peer cannot be established.'))
iter = self.get_iter_by_sid(typ, sid) iter = self.get_iter_by_sid(typ, sid)
if iter is None: if iter is None:
return return
sid = self.model[iter][SID_INDEX].decode('utf-8') sid = self.model[iter][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]] file_props = self.files_props[sid[0]][sid[1:]]
if status == 'stop': if status == 'stop':
file_props['stopped'] = True file_props['stopped'] = True
elif status == 'ok': elif status == 'ok':
file_props['completed'] = True file_props['completed'] = True
self.model.set(iter, 0, self.images[status]) self.model.set(iter, C_IMAGE, self.images[status])
def format_percent(self, percent):
def _format_percent(self, percent):
''' add extra spaces from both sides of the percent, so that ''' add extra spaces from both sides of the percent, so that
progress string has always a fixed size''' progress string has always a fixed size'''
_str = ' ' _str = ' '
@ -366,6 +392,32 @@ _('Connection with peer cannot be established.'))
_str += unicode(percent) + '% \n' _str += unicode(percent) + '% \n'
return _str return _str
def _format_time(self, _time):
times = { 'hours': 0, 'minutes': 0, 'seconds': 0 }
_time = int(_time)
times['seconds'] = _time % 60
if _time >= 60:
_time /= 60
times['minutes'] = _time % 60
if _time >= 60:
times['hours'] = _time / 60
#Print remaining time in format 00:00:00
#You can change the places of hours, minutes, seconds -
#they are not translatable.
return _('%(hours)02.d:%(minutes)02.d:%(seconds)02.d') % times
def _get_eta_and_speed(self, full_size, transfered_size, elapsed_time):
if elapsed_time == 0:
return 0., 0.
speed = round(float(transfered_size) / elapsed_time)
if speed == 0.:
return 0., 0.
remaining_size = full_size - transfered_size
eta = remaining_size / speed
return eta, speed
def set_progress(self, typ, sid, transfered_size, iter = None): def set_progress(self, typ, sid, transfered_size, iter = None):
''' change the progress of a transfer with new transfered size''' ''' change the progress of a transfer with new transfered size'''
if not self.files_props[typ].has_key(sid): if not self.files_props[typ].has_key(sid):
@ -379,14 +431,27 @@ _('Connection with peer cannot be established.'))
if iter is None: if iter is None:
iter = self.get_iter_by_sid(typ, sid) iter = self.get_iter_by_sid(typ, sid)
if iter is not None: if iter is not None:
text = self.format_percent(percent) text = self._format_percent(percent)
if transfered_size == 0: if transfered_size == 0:
text += '0' text += '0'
else: else:
text += helpers.convert_bytes(transfered_size) text += helpers.convert_bytes(transfered_size)
text += '/' + helpers.convert_bytes(full_size) text += '/' + helpers.convert_bytes(full_size)
self.model.set(iter, 3, text) # Kb/s
self.model.set(iter, 4, int(percent))
# remaining time
eta, speed = self._get_eta_and_speed(full_size, transfered_size,
file_props['elapsed-time'])
#This should make the string Kb/s,
#where 'Kb' part is taken from %s.
#Only the last 's' should be translated.
text += _(' (%s/s)') % helpers.convert_bytes(speed)
self.model.set(iter, C_PROGRESS, text)
self.model.set(iter, C_PERCENT, int(percent))
self.model.set(iter, C_TIME,
self._format_time(eta))
if file_props['type'] == 'r': if file_props['type'] == 'r':
status = 'download' status = 'download'
else: else:
@ -406,7 +471,7 @@ _('Connection with peer cannot be established.'))
session id''' session id'''
iter = self.model.get_iter_root() iter = self.model.get_iter_root()
while iter: while iter:
if typ + sid == self.model[iter][SID_INDEX].decode('utf-8'): if typ + sid == self.model[iter][C_SID].decode('utf-8'):
return iter return iter
iter = self.model.iter_next(iter) iter = self.model.iter_next(iter)
@ -427,6 +492,7 @@ _('Connection with peer cannot be established.'))
if os.path.exists(file_path) and os.path.isfile(file_path): if os.path.exists(file_path) and os.path.isfile(file_path):
stat = os.stat(file_path) stat = os.stat(file_path)
os.stat(file_path) os.stat(file_path)
file_props['elapsed-time'] = 0
file_props['size'] = unicode(stat[6]) file_props['size'] = unicode(stat[6])
file_props['sid'] = self.get_sid() file_props['sid'] = self.get_sid()
file_props['completed'] = False file_props['completed'] = False
@ -441,6 +507,7 @@ _('Connection with peer cannot be established.'))
self.on_transfers_list_leave_notify_event(None) self.on_transfers_list_leave_notify_event(None)
if file_props is None: if file_props is None:
return return
file_props['elapsed-time'] = 0
self.files_props[file_props['type']][file_props['sid']] = file_props self.files_props[file_props['type']][file_props['sid']] = file_props
iter = self.model.append() iter = self.model.append()
text_labels = '<b>' + _('Name: ') + '</b>\n' text_labels = '<b>' + _('Name: ') + '</b>\n'
@ -455,9 +522,8 @@ _('Connection with peer cannot be established.'))
file_name = file_props['name'] file_name = file_props['name']
text_props = gtkgui_helpers.escape_for_pango_markup(file_name) + '\n' text_props = gtkgui_helpers.escape_for_pango_markup(file_name) + '\n'
text_props += gtkgui_helpers.escape_for_pango_markup(contact.name) text_props += gtkgui_helpers.escape_for_pango_markup(contact.name)
self.model.set(iter, 1, text_labels, 2, text_props, SID_INDEX, \ self.model.set(iter, 1, text_labels, 2, text_props, C_SID, \
file_props['type'] + file_props['sid']) file_props['type'] + file_props['sid'])
#~ self.model.set(iter, 4, 40)
self.set_progress(file_props['type'], file_props['sid'], 0, iter) self.set_progress(file_props['type'], file_props['sid'], 0, iter)
if file_props.has_key('started') and file_props['started'] is False: if file_props.has_key('started') and file_props['started'] is False:
status = 'waiting' status = 'waiting'
@ -486,7 +552,7 @@ _('Connection with peer cannot be established.'))
except: except:
self.tooltip.hide_tooltip() self.tooltip.hide_tooltip()
return return
sid = self.model[iter][SID_INDEX].decode('utf-8') sid = self.model[iter][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]] file_props = self.files_props[sid[0]][sid[1:]]
if file_props is not None: if file_props is not None:
if self.tooltip.timeout == 0 or self.tooltip.id != props[0]: if self.tooltip.timeout == 0 or self.tooltip.id != props[0]:
@ -567,7 +633,7 @@ _('Connection with peer cannot be established.'))
self.set_all_insensitive() self.set_all_insensitive()
return return
current_iter = self.model.get_iter(path) current_iter = self.model.get_iter(path)
sid = self.model[current_iter][SID_INDEX].decode('utf-8') sid = self.model[current_iter][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]] file_props = self.files_props[sid[0]][sid[1:]]
self.remove_menuitem.set_sensitive(is_row_selected) self.remove_menuitem.set_sensitive(is_row_selected)
self.open_folder_menuitem.set_sensitive(is_row_selected) self.open_folder_menuitem.set_sensitive(is_row_selected)
@ -624,7 +690,7 @@ _('Connection with peer cannot be established.'))
i = len(self.model) - 1 i = len(self.model) - 1
while i >= 0: while i >= 0:
iter = self.model.get_iter((i)) iter = self.model.get_iter((i))
sid = self.model[iter][SID_INDEX].decode('utf-8') sid = self.model[iter][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]] file_props = self.files_props[sid[0]][sid[1:]]
if file_props.has_key('completed') and file_props['completed']: if file_props.has_key('completed') and file_props['completed']:
self.model.remove(iter) self.model.remove(iter)
@ -661,9 +727,10 @@ _('Connection with peer cannot be established.'))
if selected is None or selected[1] is None: if selected is None or selected[1] is None:
return return
s_iter = selected[1] s_iter = selected[1]
sid = self.model[s_iter][SID_INDEX].decode('utf-8') sid = self.model[s_iter][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]] file_props = self.files_props[sid[0]][sid[1:]]
if self.is_transfer_paused(file_props): if self.is_transfer_paused(file_props):
file_props['last-time'] = time.time()
file_props['paused'] = False file_props['paused'] = False
types = {'r' : 'download', 's' : 'upload'} types = {'r' : 'download', 's' : 'upload'}
self.set_status(file_props['type'], file_props['sid'], types[sid[0]]) self.set_status(file_props['type'], file_props['sid'], types[sid[0]])
@ -678,7 +745,7 @@ _('Connection with peer cannot be established.'))
if selected is None or selected[1] is None: if selected is None or selected[1] is None:
return return
s_iter = selected[1] s_iter = selected[1]
sid = self.model[s_iter][SID_INDEX].decode('utf-8') sid = self.model[s_iter][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]] file_props = self.files_props[sid[0]][sid[1:]]
if not file_props.has_key('tt_account'): if not file_props.has_key('tt_account'):
return return
@ -699,7 +766,7 @@ _('Connection with peer cannot be established.'))
# check if the current pointer is at the same path # check if the current pointer is at the same path
# as it was before setting the timeout # as it was before setting the timeout
iter = self.model.get_iter(props[0]) iter = self.model.get_iter(props[0])
sid = self.model[iter][SID_INDEX].decode('utf-8') sid = self.model[iter][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]] file_props = self.files_props[sid[0]][sid[1:]]
rect = self.tree.get_cell_area(props[0],props[1]) rect = self.tree.get_cell_area(props[0],props[1])
position = widget.window.get_origin() position = widget.window.get_origin()
@ -795,7 +862,7 @@ _('Connection with peer cannot be established.'))
if selected is None or selected[1] is None: if selected is None or selected[1] is None:
return return
s_iter = selected[1] s_iter = selected[1]
sid = self.model[s_iter][SID_INDEX].decode('utf-8') sid = self.model[s_iter][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]] file_props = self.files_props[sid[0]][sid[1:]]
if not file_props.has_key('file-name'): if not file_props.has_key('file-name'):
return return
@ -818,7 +885,7 @@ _('Connection with peer cannot be established.'))
if selected is None or selected[1] is None: if selected is None or selected[1] is None:
return return
s_iter = selected[1] s_iter = selected[1]
sid = self.model[s_iter][SID_INDEX].decode('utf-8') sid = self.model[s_iter][C_SID].decode('utf-8')
file_props = self.files_props[sid[0]][sid[1:]] file_props = self.files_props[sid[0]][sid[1:]]
if not file_props.has_key('tt_account'): if not file_props.has_key('tt_account'):
# file transfer is not set yet # file transfer is not set yet

View File

@ -1012,7 +1012,7 @@ class Interface:
if gajim.connections[account].connected: if gajim.connections[account].connected:
gajim.connections[account].process(0.01) gajim.connections[account].process(0.01)
if gajim.socks5queue.connected: if gajim.socks5queue.connected:
gajim.socks5queue.process(0.01) gajim.socks5queue.process(0)
for account in gajim.events_for_ui: #when we create a new account we don't have gajim.connection for account in gajim.events_for_ui: #when we create a new account we don't have gajim.connection
while len(gajim.events_for_ui[account]): while len(gajim.events_for_ui[account]):
gajim.mutex_events_for_ui.lock(self.exec_event, account) gajim.mutex_events_for_ui.lock(self.exec_event, account)