thomasvs - in flumotion/trunk: . flumotion/component
flumotion/component/base flumotion/test
flumotion-commit at lists.fluendo.com
flumotion-commit at lists.fluendo.com
Fri Mar 2 12:25:29 CET 2007
Author: thomasvs
Date: Fri Mar 2 12:25:26 2007
New Revision: 4552
Added:
flumotion/trunk/flumotion/test/test_feedcomponent010.py
Modified:
flumotion/trunk/ChangeLog
flumotion/trunk/flumotion/component/base/admin_gtk.py
flumotion/trunk/flumotion/component/base/feeders.glade
flumotion/trunk/flumotion/component/feedcomponent010.py
Log:
* flumotion/component/base/admin_gtk.py:
* flumotion/component/base/feeders.glade:
* flumotion/component/feedcomponent010.py:
Make Feeder track FeederClient over multiple reconnects.
Add additional uiState keys, so we can get information
like total reconnects, total bytes read/buffers dropped,
and connect/disconnect times.
* flumotion/test/test_feedcomponent010.py:
Add a unit test for the FeederClient behaviour.
Modified: flumotion/trunk/ChangeLog
==============================================================================
--- flumotion/trunk/ChangeLog (original)
+++ flumotion/trunk/ChangeLog Fri Mar 2 12:25:26 2007
@@ -1,3 +1,15 @@
+2007-03-02 Thomas Vander Stichele <thomas at apestaart dot org>
+
+ * flumotion/component/base/admin_gtk.py:
+ * flumotion/component/base/feeders.glade:
+ * flumotion/component/feedcomponent010.py:
+ Make Feeder track FeederClient over multiple reconnects.
+ Add additional uiState keys, so we can get information
+ like total reconnects, total bytes read/buffers dropped,
+ and connect/disconnect times.
+ * flumotion/test/test_feedcomponent010.py:
+ Add a unit test for the FeederClient behaviour.
+
2007-03-01 Michael Smith <msmith at fluendo.com>
* common/gendoc.py:
Modified: flumotion/trunk/flumotion/component/base/admin_gtk.py
==============================================================================
--- flumotion/trunk/flumotion/component/base/admin_gtk.py (original)
+++ flumotion/trunk/flumotion/component/base/admin_gtk.py Fri Mar 2 12:25:26 2007
@@ -1,4 +1,4 @@
-# -*- Mode: Python -*-
+# -*- Mode: Python; test-case-name: flumotion.test.test_feedcomponent010 -*-
# vi:si:et:sw=4:sts=4:ts=4
#
# Flumotion - a streaming media server
@@ -24,6 +24,7 @@
"""
import os
+import time
import gtk
import gtk.glade
@@ -381,8 +382,8 @@
yield self.widget
render = defer_generator_method(render)
-# this class is a bit of an experiment, and is private, dudes and ladies
-class StateWatcher(object):
+# this class is a bit of an experiment
+class _StateWatcher(object):
def __init__(self, state, setters, appenders, removers):
self.state = state
self.setters = setters
@@ -434,10 +435,14 @@
def __init__(self, state, admin):
BaseAdminGtkNode.__init__(self, state, admin, title=_("Feeders"))
+ # tree model is a model of id, uiState, _StateWatcher, type
+ # tree model contains feeders and their feeder clients
self.treemodel = None
self.treeview = None
self.selected = None
self.labels = {}
+ self._lastConnect = 0
+ self._lastDisconnect = 0
def select(self, watcher):
if self.selected:
@@ -454,38 +459,102 @@
def setFeederClientName(self, state, value):
self.labels['feeder-name'].set_markup(_('Feeding to <b>%s</b>')
% value)
- def setFeederClientBytesRead(self, state, value):
+
+ def setFeederClientBytesReadCurrent(self, state, value):
+ txt = value and (common.formatStorage(value) + _('Byte')) or ''
+ self.labels['bytes-read-current'].set_text(txt)
+ self.updateConnectionTime()
+ self.updateDisconnectionTime()
+
+ def setFeederClientBuffersDroppedCurrent(self, state, value):
+ self.labels['buffers-dropped-current'].set_text(str(value))
+ self.updateConnectionTime()
+ self.updateDisconnectionTime()
+
+ def setFeederClientBytesReadTotal(self, state, value):
txt = value and (common.formatStorage(value) + _('Byte')) or ''
- self.labels['feeder-client-bytesread'].set_text(txt)
- def setFeederClientBuffersDropped(self, state, value):
- self.labels['feeder-client-buffersdropped'].set_text(str(value))
+ self.labels['bytes-read-total'].set_text(txt)
+
+ def setFeederClientBuffersDroppedTotal(self, state, value):
+ self.labels['buffers-dropped-total'].set_text(str(value))
+
+ def setFeederClientReconnects(self, state, value):
+ self.labels['connections-total'].set_text(str(value))
+
+ def setFeederClientLastConnect(self, state, value):
+ if value:
+ text = time.strftime("%c", time.localtime(value))
+ self.labels['connected-since'].set_text(text)
+ self._lastConnect = value
+ self.updateConnectionTime()
+
+ def setFeederClientLastDisconnect(self, state, value):
+ if value:
+ text = time.strftime("%c", time.localtime(value))
+ self.labels['disconnected-since'].set_text(text)
+ self._lastDisconnect = value
+ self.updateDisconnectionTime()
+
+ def setFeederClientFD(self, state, value):
+ if value == None:
+ # disconnected
+ self._table_connected.hide()
+ self._table_disconnected.show()
+ else:
+ self._table_disconnected.hide()
+ self._table_connected.show()
+
+ # FIXME: add a timeout to update this ?
+ def updateConnectionTime(self):
+ if self._lastConnect:
+ text = common.formatTime(time.time() - self._lastConnect)
+ self.labels['connection-time'].set_text(text)
+
+ # FIXME: add a timeout to update this ?
+ def updateDisconnectionTime(self):
+ if self._lastDisconnect:
+ text = common.formatTime(time.time() - self._lastDisconnect)
+ self.labels['disconnection-time'].set_text(text)
def addFeeder(self, uiState, state):
+ """
+ @param uiState: the component's uiState
+ @param state: the feeder's uiState
+ """
feederId = state.get('feedId')
i = self.treemodel.append(None)
self.treemodel.set(i, 0, feederId, 1, state)
- w = StateWatcher(state,
+ w = _StateWatcher(state,
{'feedId': self.setFeederName},
{'clients': self.addFeederClient},
{'clients': self.removeFeederClient})
- self.treemodel.set(i, 2, w)
+ self.treemodel.set(i, 2, w, 3, 'feeder')
self.treeview.expand_all()
def addFeederClient(self, feederState, state):
+ """
+ @param uiState: the component's uiState
+ @param state: the feeder client's uiState
+ """
+
clientId = state.get('clientId')
for row in self.treemodel:
if self.treemodel.get_value(row.iter, 1) == feederState:
break
i = self.treemodel.append(row.iter)
self.treemodel.set(i, 0, clientId, 1, state)
- w = StateWatcher(state,
- {'clientId': self.setFeederClientName,
- 'bytesRead': self.setFeederClientBytesRead,
- 'buffersDropped':
- self.setFeederClientBuffersDropped},
- {},
- {})
- self.treemodel.set(i, 2, w)
+ w = _StateWatcher(state, {
+ 'clientId': self.setFeederClientName,
+ 'bytesReadCurrent': self.setFeederClientBytesReadCurrent,
+ 'buffersDroppedCurrent': self.setFeederClientBuffersDroppedCurrent,
+ 'bytesReadTotal': self.setFeederClientBytesReadTotal,
+ 'buffersDroppedTotal': self.setFeederClientBuffersDroppedTotal,
+ 'reconnects': self.setFeederClientReconnects,
+ 'lastConnect': self.setFeederClientLastConnect,
+ 'lastDisconnect': self.setFeederClientLastDisconnect,
+ 'fd': self.setFeederClientFD,
+ }, {}, {})
+ self.treemodel.set(i, 2, w, 3, 'client')
self.treeview.expand_all()
def removeFeederClient(self, feederState, state):
@@ -512,7 +581,7 @@
self.labels = {}
self.widget = self.wtree.get_widget('feeders-widget')
self.treeview = self.wtree.get_widget('treeview-feeders')
- self.treemodel = gtk.TreeStore(str, object, object)
+ self.treemodel = gtk.TreeStore(str, object, object, str)
self.treeview.set_model(self.treemodel)
col = gtk.TreeViewColumn('Feeder', gtk.CellRendererText(),
text=0)
@@ -522,17 +591,40 @@
def sel_changed(sel):
model, i = sel.get_selected()
self.select(i and model.get_value(i, 2))
+ # don't show the feeder client stuff for a feeder
+ if model.get_value(i, 3) == 'feeder':
+ self._table_feedclient.hide()
+ else:
+ self._table_feedclient.show()
+
sel.connect('changed', sel_changed)
def set_label(name):
self.labels[name] = self.wtree.get_widget('label-' + name)
+ # zeroes out all value labels
self.labels[name].set_text('')
- for type in ('name', ):
- set_label('feeder-' + type)
- for type in ('bytesread', 'buffersdropped'):
- set_label('feeder-client-' + type)
- # do not show all; hide bytes fed and buffers dropped until something
- # is selected
+ set_label('feeder-name')
+ for type in (
+ 'bytes-read-current', 'buffers-dropped-current',
+ 'connected-since', 'connection-time',
+ 'disconnected-since', 'disconnection-time',
+ 'bytes-read-total', 'buffers-dropped-total',
+ 'connections-total',
+ ):
+ set_label(type)
+
+ self._table_connected = self.wtree.get_widget('table-current-connected')
+ self._table_disconnected = self.wtree.get_widget(
+ 'table-current-disconnected')
+ self._table_feedclient = self.wtree.get_widget('table-feedclient')
+ self._table_connected.hide()
+ self._table_disconnected.hide()
+ self._table_feedclient.hide()
+ self.wtree.get_widget('box-right').hide()
+
+ # FIXME: do not show all;
+ # hide bytes fed and buffers dropped until something is selected
+ # see #575
return self.widget
class EffectAdminGtkNode(BaseAdminGtkNode):
Modified: flumotion/trunk/flumotion/component/base/feeders.glade
==============================================================================
--- flumotion/trunk/flumotion/component/base/feeders.glade (original)
+++ flumotion/trunk/flumotion/component/base/feeders.glade Fri Mar 2 12:25:26 2007
@@ -47,114 +47,20 @@
</widget>
<packing>
<property name="padding">0</property>
- <property name="expand">True</property>
+ <property name="expand">False</property>
<property name="fill">True</property>
</packing>
</child>
<child>
- <widget class="GtkTable" id="table1">
+ <placeholder/>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="box-right">
<property name="visible">True</property>
- <property name="n_rows">3</property>
- <property name="n_columns">2</property>
<property name="homogeneous">False</property>
- <property name="row_spacing">6</property>
- <property name="column_spacing">0</property>
-
- <child>
- <widget class="GtkLabel" id="label13">
- <property name="visible">False</property>
- <property name="label" translatable="yes">Bytes fed: </property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">12</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label14">
- <property name="visible">False</property>
- <property name="label" translatable="yes">Buffers dropped: </property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">12</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="left_attach">0</property>
- <property name="right_attach">1</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label-feeder-client-buffersdropped">
- <property name="can_focus">True</property>
- <property name="label">58910</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">True</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
- <property name="x_options">fill</property>
- <property name="y_options"></property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkLabel" id="label-feeder-client-bytesread">
- <property name="can_focus">True</property>
- <property name="label">1092</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">True</property>
- <property name="xalign">0</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- </widget>
- <packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
- <property name="y_options"></property>
- </packing>
- </child>
+ <property name="spacing">0</property>
<child>
<widget class="GtkAlignment" id="alignment2">
@@ -185,19 +91,547 @@
</child>
</widget>
<packing>
- <property name="left_attach">0</property>
- <property name="right_attach">2</property>
- <property name="top_attach">0</property>
- <property name="bottom_attach">1</property>
- <property name="x_options">fill</property>
- <property name="y_options">fill</property>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
</packing>
</child>
+
+ <child>
+ <widget class="GtkTable" id="table-feedclient">
+ <property name="border_width">6</property>
+ <property name="visible">True</property>
+ <property name="n_rows">9</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label16">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"><b>Current connection</b></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label34">
+ <property name="label" translatable="yes">Connections made:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">12</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label-connections-total">
+ <property name="can_focus">True</property>
+ <property name="label">3</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">5</property>
+ <property name="bottom_attach">6</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label36">
+ <property name="label" translatable="yes">Bytes read:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">12</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">6</property>
+ <property name="bottom_attach">7</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label-bytes-read-total">
+ <property name="can_focus">True</property>
+ <property name="label">1092</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">6</property>
+ <property name="bottom_attach">7</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label38">
+ <property name="label" translatable="yes">Buffers dropped: </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">12</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">7</property>
+ <property name="bottom_attach">8</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label-buffers-dropped-total">
+ <property name="can_focus">True</property>
+ <property name="label">3</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">7</property>
+ <property name="bottom_attach">8</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table-current-connected">
+ <property name="border_width">6</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label-desc-connected-since">
+ <property name="label" translatable="yes">Connected since:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">12</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label17">
+ <property name="label" translatable="yes">Bytes read:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">12</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label21">
+ <property name="label" translatable="yes">Buffers dropped: </property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">12</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label-desc-connection-time">
+ <property name="label" translatable="yes">Connection time:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">12</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label-bytes-read-current">
+ <property name="can_focus">True</property>
+ <property name="label">1092</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label-buffers-dropped-current">
+ <property name="can_focus">True</property>
+ <property name="label">3</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label-connected-since">
+ <property name="can_focus">True</property>
+ <property name="label">December 25th, 0</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label-connection-time">
+ <property name="can_focus">True</property>
+ <property name="label">2007 years</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table-current-disconnected">
+ <property name="border_width">6</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label26">
+ <property name="label" translatable="yes">Disconnected since:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">12</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label29">
+ <property name="label" translatable="yes">Disconnection time:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">12</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label-disconnected-since">
+ <property name="can_focus">True</property>
+ <property name="label">December 25th, 0</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label-disconnection-time">
+ <property name="can_focus">True</property>
+ <property name="label">2007 years</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">True</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label15">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"><b>All Connections</b></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="y_padding">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <placeholder/>
+ </child>
</widget>
<packing>
<property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
</packing>
</child>
</widget>
Modified: flumotion/trunk/flumotion/component/feedcomponent010.py
==============================================================================
--- flumotion/trunk/flumotion/component/feedcomponent010.py (original)
+++ flumotion/trunk/flumotion/component/feedcomponent010.py Fri Mar 2 12:25:26 2007
@@ -51,31 +51,53 @@
self.uiState.addKey('feedId')
self.uiState.set('feedId', feedId)
self.uiState.addListKey('clients')
- self._clients = {}
+ self._fdToClient = {} # fd -> FeederClient
+ self._clients = {} # id -> FeederClient
- def addClient(self, clientId, fd):
+
+ def clientConnected(self, clientId, fd):
"""
+ The given client has connected on the given file descriptor.
+
@param clientId: id of the client of the feeder
- @param fd: file descriptor representing the client
+ @param fd: file descriptor representing the client
"""
- client = FeederClient(clientId, fd)
- self._clients[fd] = client
- self.uiState.append('clients', client.uiState)
+ if clientId not in self._clients.keys():
+ # first time we see this client, create an object
+ client = FeederClient(clientId, fd)
+ self._clients[clientId] = client
+ self.uiState.append('clients', client.uiState)
+
+ client = self._clients[clientId]
+ self._fdToClient[fd] = client
+
+ client.connected(fd)
+
return client
- def removeClient(self, fd):
+ def clientDisconnected(self, fd):
"""
+ Called when the client disconnects.
+ The client object stays around so we can track over multiple
+ connections.
+
@type fd: file descriptor
"""
- client = self._clients.pop(fd)
- self.uiState.remove('clients', client.uiState)
+ client = self._fdToClient.pop(fd)
+ client.disconnected()
def getClients(self):
- return self._clients
+ """
+ @rtype: dict of int -> L{FeederClient}
+ """
+ return self._fdToClient
class FeederClient:
"""
This class groups information related to the client of a feeder.
+ The client is identified by an id.
+ The information remains valid for the lifetime of the feeder, so it
+ can track reconnects of the client.
@ivar clientId: id of the client of the feeder
@ivar fd: file descriptor representing the client
@@ -85,8 +107,22 @@
self.uiState = componentui.WorkerComponentUIState()
self.uiState.addKey('clientId', clientId)
self.uiState.addKey('fd', fd)
- self.uiState.addKey('bytesRead')
- self.uiState.addKey('buffersDropped')
+
+ for key in (
+ 'bytesReadCurrent', # bytes dropped over current connection
+ 'buffersDroppedCurrent', # buffers dropped over current connection
+ 'bytesReadTotal', # bytes dropped over all connections
+ 'buffersDroppedTotal', # buffers dropped over all connections
+ 'reconnects', # number of connections made by this client
+ 'lastConnect', # last client connection, in epoch seconds
+ 'lastDisconnect', # last client disconnect, in epoch seconds
+ ):
+ self.uiState.addKey(key)
+ self.uiState.set(key, 0)
+
+ # internal state allowing us to track global numbers
+ self._buffersDroppedBefore = 0
+ self._bytesReadBefore = 0
def setStats(self, stats):
"""
@@ -103,9 +139,40 @@
else:
buffersDropped = None
- self.uiState.set('bytesRead', bytesSent)
- self.uiState.set('buffersDropped', buffersDropped)
-
+ self.uiState.set('bytesReadCurrent', bytesSent)
+ self.uiState.set('buffersDroppedCurrent', buffersDropped)
+ self.uiState.set('bytesReadTotal', self._bytesReadBefore + bytesSent)
+ self.uiState.set('buffersDroppedTotal',
+ self._buffersDroppedBefore + buffersDropped)
+
+ def connected(self, fd, when=None):
+ """
+ The client has connected.
+ Update related stats.
+ """
+ if not when:
+ when = time.time()
+ self.uiState.set('fd', fd)
+ self.uiState.set('lastConnect', when)
+ self.uiState.set('reconnects', self.uiState.get('reconnects', 0) + 1)
+
+ def disconnected(self, when=None):
+ """
+ The client has disconnected.
+ Update related stats.
+ """
+ if not when:
+ when = time.time()
+ self.uiState.set('fd', None)
+ self.uiState.set('lastDisconnect', when)
+
+ # update our internal counters
+ self._bytesReadBefore += self.uiState.get('bytesReadCurrent')
+ self._buffersDroppedBefore += self.uiState.get('buffersDroppedCurrent')
+
+ # reset the current ones to zero
+ self.uiState.set('bytesReadCurrent', 0)
+ self.uiState.set('buffersDroppedCurrent', 0)
class FeedComponent(basecomponent.BaseComponent):
"""
@@ -808,16 +875,16 @@
self.debug("fdcleanup registered")
self._fdCleanup[fd] = cleanup
element.emit('add', fd)
- self._feeders[feedId].addClient(eaterId or ('client-%d' % fd), fd)
+ self._feeders[feedId].clientConnected(eaterId or ('client-%d' % fd), fd)
def removeClientCallback(self, sink, fd, _):
"""
- Called as a signal callback when the FD should no longer be used, but
- before it may be closed
+ Called as a signal callback from multifdsink when the FD should no
+ longer be used, but before it may be closed.
"""
self.debug("removing client for fd %d", fd)
feedId = ':'.join(sink.get_name().split(':')[1:])
- self._feeders[feedId].removeClient(fd)
+ self._feeders[feedId].clientDisconnected(fd)
def removeFDCallback(self, sink, fd):
"""
Added: flumotion/trunk/flumotion/test/test_feedcomponent010.py
==============================================================================
--- (empty file)
+++ flumotion/trunk/flumotion/test/test_feedcomponent010.py Fri Mar 2 12:25:26 2007
@@ -0,0 +1,79 @@
+# -*- Mode: Python; test-case-name: flumotion.test.test_feedcomponent010 -*-
+# vi:si:et:sw=4:sts=4:ts=4
+#
+# Flumotion - a streaming media server
+# Copyright (C) 2004,2005,2006,2007 Fluendo, S.L. (www.fluendo.com).
+# All rights reserved.
+
+# This file may be distributed and/or modified under the terms of
+# the GNU General Public License version 2 as published by
+# the Free Software Foundation.
+# This file is distributed without any warranty; without even the implied
+# warranty of merchantability or fitness for a particular purpose.
+# See "LICENSE.GPL" in the source distribution for more information.
+
+# Licensees having purchased or holding a valid Flumotion Advanced
+# Streaming Server license may use this file in accordance with the
+# Flumotion Advanced Streaming Server Commercial License Agreement.
+# See "LICENSE.Flumotion" in the source distribution for more information.
+
+# Headers in this file shall remain intact.
+
+from twisted.trial import unittest
+
+import common
+
+from twisted.python import failure
+from twisted.internet import defer
+
+from flumotion.component import feedcomponent010 as fc
+
+class TestFeeder(unittest.TestCase):
+ def setUp(self):
+ self.feeder = fc.Feeder('video:default')
+
+ def test_addClient(self):
+ clientId = '/default/muxer-video'
+ self.feeder.addClient(clientId, 3)
+ clients = self.feeder.getClients()
+ self.failUnless(3 in clients.keys())
+ client = clients[3]
+ self.assertEquals(client.uiState.get('clientId'), clientId)
+
+ def testReconnect(self):
+ clientId = '/default/muxer-video'
+
+ # connect
+ c = self.feeder.addClient(clientId, 3)
+
+ # verify some stuff
+ self.clientAssertStats(c, 0, 0, 0, 0, 1)
+
+ # read 10 bytes, drop 1 buffer
+ c.setStats((10, None, None, None, None, 1))
+ self.clientAssertStats(c, 10, 1, 10, 1, 1)
+
+ # disconnect
+ self.feeder.removeClient(3)
+ self.clientAssertStats(c, 0, 0, 10, 1, 1)
+
+ # connect again
+ self.feeder.addClient(clientId, 3)
+ self.clientAssertStats(c, 0, 0, 10, 1, 2)
+
+ # read 20 bytes, drop 2 buffers
+ c.setStats((20, None, None, None, None, 2))
+ self.clientAssertStats(c, 20, 2, 30, 3, 2)
+
+ def clientAssertEquals(self, client, key, value):
+ self.assertEquals(client.uiState.get(key), value)
+
+ def clientAssertStats(self, client, brc, bdc, brt, bdt, reconnects):
+ self.clientAssertEquals(client, 'bytesReadCurrent', brc)
+ self.clientAssertEquals(client, 'buffersDroppedCurrent', bdc)
+ self.clientAssertEquals(client, 'bytesReadTotal', brt)
+ self.clientAssertEquals(client, 'buffersDroppedTotal', bdt)
+ self.clientAssertEquals(client, 'reconnects', reconnects)
+
+if __name__ == '__main__':
+ unittest.main()
More information about the flumotion-commit
mailing list