VOIP + TORRENTS + BANDWIDTH – How to solve with python!

Το παρακάτω δεν είναι προς γενική χρήση, μιας και αναφέρεται σε πολύ συγκεκριμένο configuration (το δικό μου! :-)) Παρόλα αυτά να τι μπορεί να κάνει κάποιος με λίγη python.

Το δίκτυο του σπιτιού μου περιλαμβάνει τα εξής: Ένα δικτυακό σκληρό δίσκο της Wedstern Digital (My Book World Edition II – Blue rings) ο οποίος τρέχει μια έκδοση linux και εκτός των άλλων τρέχει και το transmission για κατέβασμα torrents, και ένα voip ΑΤΑ adapter της linksys (Sipura SPA 1001) πάνω στο οποίο συνδέεται μια ασύρματη απλή τηλεφωνική συσκευή για voip κλήσεις μέσω της omnivoice.

Το πρόβλημα είναι το συνηθισμένο: Έχω ADSL Connx 2MBs με αποτέλεσμα όταν κατεβάζω torrents από το transmission του MyBook να έχω πολλές διακοπές κατά τη διάρκεια voip κλήσης.

Η λύση που ακολουθεί: Ένα σκιπτάκι με python που:

  • να ελέγχει αν το τηλέφωνο είναι σε κατάσταση ομιλίας ή κλειστό, ανά κάποια δευτερόλεπτα.
  • αν πράγματι είναι σε κατάσταση ομιλίας, να κάνει pause όλα τα torrents του transmission, αλλιώς να τα κάνει resume.
  • ΠΡΟΑΙΡΕΤΙΚΑ να τρέχει στο background ως δαίμονας
  • ΠΡΟΑΙΡΕΤΙΚΑ να χρησιμοποιεί το dbus για να επικοινωνει με ένα screenlet γραμμένο για να εμφανίζει πληροφορίες περι των διεργασιών που λαμβάνουν χώρα…
  • ΠΡΟΑΙΡΕΤΙΚΑ να χρησιμοποιεί το notification (python) api του gnome για να εμφανίζει το ξεκίνημα και σταμάτημα του δαίμονα!

Για το script χρησιμοποιήθηκαν οι ακόλουθες βιβλιοθήκες (python modules) ανοικτού κώδικα:

  1. Daemonize

Το script (transipd.py daemon) είναι το ακόλουθο:

#!/usr/bin/env python
'''
    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 3 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    Copyright (C) 2010 Nikiforakis Manos (nikiforakis.m@gmail.com)
'''

import urllib
from subprocess import call
import pynotify
import re
import gobject
import dbus
import dbus.service
import dbus.mainloop.glib

#set sipura's ip address
SIPURA_IP = '192.168.x.y'

#set transmission's options
TRANSMISSION_IP='192.168.x.z'
TRANSMISSION_PORT='9091'
TRANSMISSION_USER='transmission-username'
TRANSMISSION_PWD='transmission-password'
class transmission():
	def __init__(self, ip=TRANSMISSION_IP, port=TRANSMISSION_PORT, user=TRANSMISSION_USER, passwd=TRANSMISSION_PWD):
		self.ip=ip
		self.port=port
		self.user=user
		self.passwd=passwd

	def transcmd(self, state):
		cmd=[]
		cmd.append('transmission-remote')
		cmd.append(self.ip)
		cmd.append('-p')
		cmd.append(self.port)
		cmd.append('-n')
		cmd.append(self.user + ':' + self.passwd)
		cmd.append('-t all')
		cmd.append('-' + state)
		return cmd

def notify(message=""):
    n = pynotify.Notification("transipd daemon says:", message, "dialog-info") #other options are 'dialog-warning'
    n.set_urgency(pynotify.URGENCY_CRITICAL) #other options are URGENCY_LOW, URGENCY_NORMAL
    n.show()

class DBUS_Object(dbus.service.Object):

	@dbus.service.method("com.daemon.transipInterface",
                         in_signature='s', out_signature='as')
	def SipuraStatus(self, message):
		pass
	        return prevmode

	@dbus.service.method("com.daemon.transipInterface",
        	                 in_signature='', out_signature='')
	def Exit(self):
		notify("daemon stopped")
        	mainloop.quit()

def check():
	global prevmode
	if sipura_hook_state()=='On': #phone idle
		if prevmode=='dial':
			print 'The phone changed from dial mode to idle'
			print 'Resuming all torrents...'
			call(d.transcmd('s'))
			prevmode='idle'
		else:
			print 'The phone is idle - Nothing to do!'
	else:
		if prevmode=='idle':
			print 'The phone is currently in dial mode'
			print 'Pausing all torrents...'
			call(d.transcmd('S'))
			prevmode='dial'
		else:
			print 'The phone is still in dialing mode - Nothing to do!'
	return True

def sipura_hook_state():

	#build sipura's url
	sipura_url=[]
	sipura_url.append('http://')
	sipura_url.append(SIPURA_IP)

	#open sipura's url and read the html code
	f = urllib.urlopen(''.join(sipura_url))
	s = f.read()
	f.close()

	get_hookstate=re.compile('On|Off')
	state = get_hookstate.findall(s)

	return state[0]

def main():
	dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
	session_bus = dbus.SessionBus()
	name = dbus.service.BusName("com.daemon.transipService", session_bus)
	object = DBUS_Object(session_bus, '/TransipScreenlet')

	global d
	d = transmission()
	global prevmode
	prevmode='idle' #Initialisation of the previous dial mode 

	gobject.timeout_add(4000, check)

	notify("daemon initialized")
	global mainloop
	mainloop = gobject.MainLoop()
	mainloop.run()

pynotify.init("transip daemon")
import daemonize
daemonize.start(main, debug=True)
#main()

και ο κώδικας του screenlet:

#!/usr/bin/env python

# This application is released under the GNU General Public License
# v3 (or, at your option, any later version). You can find the full
# text of the license under http://www.gnu.org/licenses/gpl.txt.
# By using, editing and/or distributing this software you agree to
# the terms and conditions of this license.
# Thank you for using free software!

#TransipScreenlet (c) Nikiforakis Manos nikiforakis.m@gmail.com 

import screenlets
from screenlets.options import FloatOption, BoolOption, StringOption, FontOption, ColorOption, IntOption
from screenlets import Plugins
import cairo
import pango
import gobject
import urllib
import dbus
from subprocess import call
import os

HOME_DIR = os.path.expanduser("~")

class TransipScreenlet(screenlets.Screenlet):
	"""A Screenlet that communicates with transip daemon through dbus calls"""

	# default meta-info for Screenlets
	__name__ = 'TransipScreenlet'
	__version__ = '0.1'
	__author__ = 'Nikiforakis Manos (c) 2009'
	__desc__ = 'A Screenlet that communicates with transip daemon through dbus calls'

	font_color = (1,1,1, 0.8)
	background_color = (0,0,0, 0.8)
	hstate = "Please right click to start transip daemon..."
	prevstate = ''
	stopd = True
	def __init__(self, **keyword_args):
		screenlets.Screenlet.__init__(self, width=200, height=50,uses_theme=True, **keyword_args) 

		self.theme_name = "default"

                self.add_options_group('Options',
                        'The Options widget settings')
		self.add_option(ColorOption('Options','font_color',
			self.font_color, 'Text color', 'font_color'))
		self.add_option(ColorOption('Options','background_color',
			self.background_color, 'Back color(only with default theme)', 'only works with default theme'))

		#self.__timeout = gobject.timeout_add(3000, self.update)

	def __setattr__(self, name, value):
		# call Screenlet.__setattr__ in baseclass (ESSENTIAL!!!!)
		screenlets.Screenlet.__setattr__(self, name, value)

	def on_init (self):
		print "Screenlet has been initialized."
		# add custom menuitems
		self.add_menuitem("stopdaemon","Stop the daemon")
		self.add_menuitem("startdaemon","Start the daemon")
		# add default menuitems
		self.add_default_menuitems()
		#start transip daemon via subprocess
		#call(HOME_DIR + '/.screenlets/Transip/transipd.py')
		#set the dbus interface
		#self.set_dbus()

	def set_dbus(self):
		bus = dbus.SessionBus()
		remote_object = bus.get_object("com.daemon.transipService",
                                     "/TransipScreenlet")
		global iface
		iface = dbus.Interface(remote_object, "com.daemon.transipInterface")

	def update (self):
		if self.stopd==True:
			return False
		else:
			self.hstate = self.check_dbus()
			if self.prevstate == self.hstate:
				pass
			else:
				self.prevstate = self.hstate
				self.redraw_canvas()
			return True # keep running this event	

	def check_dbus(self):
		a=iface.SipuraStatus('')
		return ''.join(a)

	def on_draw(self, ctx):
		ctx.scale(self.scale, self.scale)
		ctx.set_operator(cairo.OPERATOR_OVER)
		if self.theme:
			self.theme.render(ctx,'background')
			ctx.set_source_rgba(*self.background_color)
			if self.theme_name == 'default':self.draw_rounded_rectangle(ctx,0,0,6,200,40)
			ctx.set_source_rgba(1, 1, 1, 1)
			ctx.set_source_rgba(*self.font_color)
			if self.hstate=='idle':
				self.draw_text(ctx,'Voip Status : '+self.hstate+'\nAll Torrents Resumed',4,10, 'FreeSans',10, self.width,allignment = pango.ALIGN_LEFT)
			elif self.hstate=='dial':
				self.draw_text(ctx,'Voip Status : '+self.hstate+'\nAll Torrents Paused',4,10, 'FreeSans',10, self.width,allignment = pango.ALIGN_LEFT)
			else:
				self.draw_text(ctx,'Voip Status : '+self.hstate,4,10, 'FreeSans',10, self.width,allignment = pango.ALIGN_LEFT)
			try:self.theme.render(ctx,'glass')
			except:pass

	def on_draw_shape(self,ctx):
		ctx.rectangle(0,0,self.width,self.height)
		ctx.fill()
		self.on_draw(ctx)

	def menuitem_callback(self, widget, id):
		screenlets.Screenlet.menuitem_callback(self, widget, id)
		if id == "stopdaemon":
			iface.Exit()
			self.stopd=True
			self.hstate='transip daemon not running...'
			self.redraw_canvas()
		elif id == 'startdaemon':
			call(HOME_DIR + '/.screenlets/Transip/transipd.py')
			self.set_dbus()
			self.stopd = False
			self.prevstate = ''
			self.__timeout = gobject.timeout_add(3000, self.update)

	def on_quit(self):
		if self.stopd == False:
			iface.Exit()
		return True

if __name__ == "__main__":

	import screenlets.session
	screenlets.session.create_session(TransipScreenlet)

Σχολιάστε

Εισάγετε τα παρακάτω στοιχεία ή επιλέξτε ένα εικονίδιο για να συνδεθείτε:

Λογότυπο WordPress.com

Σχολιάζετε χρησιμοποιώντας τον λογαριασμό WordPress.com. Αποσύνδεση / Αλλαγή )

Φωτογραφία Twitter

Σχολιάζετε χρησιμοποιώντας τον λογαριασμό Twitter. Αποσύνδεση / Αλλαγή )

Φωτογραφία Facebook

Σχολιάζετε χρησιμοποιώντας τον λογαριασμό Facebook. Αποσύνδεση / Αλλαγή )

Φωτογραφία Google+

Σχολιάζετε χρησιμοποιώντας τον λογαριασμό Google+. Αποσύνδεση / Αλλαγή )

Σύνδεση με %s

Αρέσει σε %d bloggers: