1#!/usr/bin/env python 2# 3# Copyright (C) 2012 Adam Sutton <dev@adamsutton.me.uk> 4# 5# This program is free software: you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation, version 3 of the License. 8# 9# This program is distributed in the hope that it will be useful, 10# but WITHOUT ANY WARRANTY; without even the implied warranty of 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12# GNU General Public License for more details. 13# 14# You should have received a copy of the GNU General Public License 15# along with this program. If not, see <http://www.gnu.org/licenses/>. 16# 17""" 18This is a very simple HTSP client library written in python mainly just 19for demonstration purposes. 20 21Much of the code is pretty rough, but might help people get started 22with communicating with HTSP server 23""" 24 25import tvh.log as log 26import tvh.htsmsg as htsmsg 27 28# ########################################################################### 29# HTSP Client 30# ########################################################################### 31 32HTSP_PROTO_VERSION = 25 33 34 35# Create passwd digest 36def htsp_digest(user, passwd, chal): 37 import hashlib 38 salted = passwd.encode('utf-8') + chal 39 return hashlib.sha1(salted).digest() 40 41 42# Client object 43class HTSPClient(object): 44 # Setup connection 45 def __init__(self, addr, name='HTSP PyClient'): 46 import socket 47 48 # Setup 49 self._sock = socket.create_connection(addr) 50 self._name = name 51 self._auth = None 52 self._user = None 53 self._auser = None 54 self._apass = None 55 56 # Send 57 def send(self, func, args={}): 58 args['method'] = func 59 if self._auser: args['username'] = self._auser 60 if self._apass: args['digest'] = htsmsg.HMFBin(self._apass) 61 log.debug('htsp tx:') 62 log.debug(args, pretty=True) 63 self._sock.send(htsmsg.serialize(args)) 64 65 # Receive 66 def recv(self): 67 ret = htsmsg.deserialize(self._sock, False) 68 log.debug('htsp rx:') 69 log.debug(ret, pretty=True) 70 return ret 71 72 # Setup 73 def hello(self): 74 args = { 75 'htspversion': HTSP_PROTO_VERSION, 76 'clientname': self._name 77 } 78 self.send('hello', args) 79 resp = self.recv() 80 81 # Store 82 self._version = min(HTSP_PROTO_VERSION, resp['htspversion']) 83 self._auth = resp['challenge'] 84 85 # Return response 86 return resp 87 88 # Authenticate 89 def authenticate(self, user, passwd=None): 90 self._auser = user 91 if passwd: 92 self._apass = htsp_digest(user, passwd, self._auth) 93 self.send('authenticate') 94 self._auser = None 95 self._apass = None 96 resp = self.recv() 97 if 'noaccess' in resp: 98 raise Exception('Authentication failed') 99 self._user = user 100 101 # Enable async receive 102 def enableAsyncMetadata(self, args={}): 103 self.send('enableAsyncMetadata', args) 104 105 def disconnect(self): 106 self._sock.close() 107 108