Create main runnable, cleanup code, make it work... OMG IT WORKS!
1 parent b48a546 commit ca7e074c974767fad78fe0120b1ed0714785f455
@Jeff Rebeiro Jeff Rebeiro authored on 4 Feb 2013
Showing 4 changed files
View
5
common.py
config.read(CONFIG_FILE)
 
if not config.has_section('AUTOBACKUP'):
config.add_section('AUTOBACKUP')
config.set('AUTOBACKUP', 'uuid', uuid.uuid4())
config.set('AUTOBACKUP', 'backup_dir',
os.path.expanduser('~/PCAutoBackup'))
config.set('AUTOBACKUP', 'default_interface',
socket.gethostbyname(socket.gethostname()))
config.set('AUTOBACKUP', 'server_name', '[PC]AutoBackup')
config.set('AUTOBACKUP', 'uuid', uuid.uuid4())
with open(CONFIG_FILE, 'wb') as config_file:
config.write(config_file)
 
return config
View
232
mediaserver.py
 
__author__ = 'jeff@rebeiro.net (Jeff Rebeiro)'
 
import HTMLParser
import os
import random
import re
import string
 
from twisted.internet import reactor
from twisted.web.resource import Resource
from twisted.web.server import Site
 
import common
 
CREATE_OBJ = re.compile(r'<u:CreateObject xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1">.*<Elements>(.*)</Elements>', re.DOTALL)
CREATE_OBJ_DETAILS = re.compile(r'&lt;dc:title&gt;(.*)&lt;/dc:title&gt;.*protocolInfo="\*:\*:(.*):DLNA.ORG_PN=JPEG_LRG;DLNA.ORG_CI=0"')
 
X_BACKUP = re.compile(r'<u:X_BACKUP_(\w+) xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1">')
CREATE_OBJ = '"urn:schemas-upnp-org:service:ContentDirectory:1#CreateObject"'
CREATE_OBJ_DIDL = re.compile(r'.*<Elements>(?P<didl>.*dc:title&gt;(?P<name>.*)&lt;/dc:title.*dc:date&gt;(?P<date>.*)&lt;/dc:date.*protocolInfo=&quot;\*:\*:(?P<type>.*):DLNA.ORG_PN.*size=&quot;(?P<size>\d+)&quot;.*)</Elements>.*')
CREATE_OBJ_RESPONSE = '''<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:CreateObjectResponse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1">
<ObjectID>%(obj_id)s</ObjectID>
<Result>&lt;DIDL-Lite xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:upnp='urn:schemas-upnp-org:metadata-1-0/upnp/' xmlns:dlna="urn:schemas-dlna-org:metadata-1-0/" xmlns:sec="http://www.sec.co.kr/"&gt;&lt;item id="%(obj_id)s" parentID="%(parent_id)s" restricted="0" dlna:dlnaManaged="00000004"&gt;&lt;dc:title&gt;&lt;/dc:title&gt;&lt;res protocolInfo="http-get:*:%(obj_type)s:DLNA.ORG_PN=JPEG_LRG;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=00D00000000000000000000000000000" importUri="http://%(interface)s:52235/cd/content?didx=0_id=%(obj_id)s" dlna:resumeUpload="1" dlna:uploadedSize="0" size="%(obj_size)s"&gt;&lt;/res&gt;&lt;upnp:class&gt;object.item.imageItem&lt;/upnp:class&gt;&lt;/item&gt;&lt;/DIDL-Lite&gt;</Result>
</u:CreateObjectResponse>
</s:Body>
</s:Envelope>'''
 
X_BACKUP_DONE = '"urn:schemas-upnp-org:service:ContentDirectory:1#X_BACKUP_DONE"'
X_BACKUP_START = '"urn:schemas-upnp-org:service:ContentDirectory:1#X_BACKUP_START"'
 
X_BACKUP_RESPONSE = '''<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:X_BACKUP_%sResponse xmlns:u="urn:schemas-upnp-org:service:ContentDirectory:1"/>
</s:Body>
</s:Envelope>'''
 
DMS_DESC = '''<?xml version="1.0"?>
DMS_DESC_RESPONSE = '''<?xml version="1.0"?>
<root xmlns="urn:schemas-upnp-org:device-1-0" xmlns:sec="http://www.sec.co.kr/dlna" xmlns:dlna="urn:schemas-dlna-org:device-1-0">
<specVersion>
<major>1</major>
<minor>0</minor>
</device>
</root>'''
 
 
class MediaServer(Resource):
 
isLeaf = True
class Backup(object):
 
backup_objects = {}
 
def __init__(self):
self.config = common.LoadOrCreateConfig()
 
def _GenerateObjectID(self, obj_date, length=10):
chars = string.letters + string.digits
rand_chars = ''.join(random.choice(chars) for i in xrange(length))
parent_id = 'UP_%s' % obj_date
obj_id = '%s_%s' % (parent_id, rand_chars)
return (parent_id, obj_id)
 
def CreateObject(self, obj_name, obj_date, obj_type, obj_size):
(parent_id, obj_id) = self._GenerateObjectID(obj_date)
self.backup_objects[obj_id] = {'obj_name': obj_name,
'obj_date': obj_date,
'obj_type': obj_type,
'parent_id': parent_id,
'obj_size': obj_size}
return obj_id
 
def FinishBackup(self):
pass
 
def GetObjectDetails(self, obj_id):
return self.backup_objects.get(obj_id)
 
def StartBackup(self):
pass
 
def WriteObject(self, obj_id, data):
obj_details = self.GetObjectDetails(obj_id)
 
obj_dir = os.path.join(self.config.get('AUTOBACKUP', 'backup_dir'),
obj_details['obj_date'])
 
if not os.path.isdir(obj_dir):
os.makedirs(obj_dir)
 
obj_file = os.path.join(obj_dir, obj_details['obj_name'])
 
with open(obj_file, 'wb') as f:
f.write(data)
 
del(self.backup_objects[obj_id])
 
 
class MediaServer(Resource):
 
isLeaf = True
 
def __init__(self, debug=False):
self.config = common.LoadOrCreateConfig()
self.debug = debug
 
def render_GET(self, request):
if self.debug:
print 'Request headers:'
print request.getAllHeaders()
if request.path == '/DMS/SamsungDmsDesc.xml':
return self.GetDMSDescriptionResponse()
else:
print 'Unhandled GET request: %s' % request.path
 
def render_POST(self, request):
if self.debug:
print 'Request args:'
print request.args
print 'Request headers:'
print request.getAllHeaders()
if request.path == '/cd/content':
return self.ReceiveUpload(request)
if request.path == '/upnp/control/ContentDirectory1':
return self.GetContentDirectoryResponse(request.content.read())
 
def GetContentDirectoryResponse(self, content):
if X_BACKUP.search(content):
action = X_BACKUP.search(content).group(1)
response = X_BACKUP_RESPONSE % action
print "Response:"
return self.GetContentDirectoryResponse(request)
else:
print 'Unhandled POST request: %s' % request.path
 
def GetContentDirectoryResponse(self, request):
soapaction = request.getHeader('soapaction')
 
response = ''
 
if soapaction == X_BACKUP_START:
response = X_BACKUP_RESPONSE % 'START'
if self.debug:
print 'Response:'
print response
if soapaction == CREATE_OBJ:
request.content.seek(0)
soap_xml = request.content.read()
 
m = CREATE_OBJ_DIDL.match(soap_xml)
if m:
obj_name = m.group('name')
obj_date = m.group('date')
obj_type = m.group('type')
obj_size = m.group('size')
 
backup = Backup()
obj_id = backup.CreateObject(obj_name, obj_date, obj_type, obj_size)
obj_details = backup.GetObjectDetails(obj_id)
 
response = CREATE_OBJ_RESPONSE % {
'interface': self.config.get('AUTOBACKUP', 'default_interface'),
'obj_id': obj_id,
'obj_type': obj_type,
'obj_size': obj_size,
'parent_id': obj_details['parent_id']}
if soapaction == X_BACKUP_DONE:
response = X_BACKUP_RESPONSE % 'DONE'
 
if self.debug:
print 'Response:'
print response
if CREATE_OBJECT.search(content):
obj_didl = CREATE_OBJ.search(content).group(1)
obj_details = CREATE_OBJ_DETAILS.search(obj_didl).groups()
obj_name = obj_details[0]
obj_type = obj_details[1]
 
return response
 
def GetDMSDescriptionResponse(self):
response = DMS_DESC % {'friendly_name': self.config.get('AUTOBACKUP',
'server_name'),
'uuid': self.config.get('AUTOBACKUP', 'uuid')}
if __name__ == '__main__':
print "Response:"
response = DMS_DESC_RESPONSE % {
'friendly_name': self.config.get('AUTOBACKUP', 'server_name'),
'uuid': self.config.get('AUTOBACKUP', 'uuid')}
if self.debug:
print 'Response:'
print response
 
return response
 
 
def StartMediaServer():
resource = MediaServer()
def ReceiveUpload(self, request):
response = ''
obj_id = request.args['didx'][0].split('=')[1]
backup = Backup()
 
data = request.content.read()
backup.WriteObject(obj_id, data)
return response
 
 
def StartMediaServer(debug=False):
resource = MediaServer(debug=debug)
factory = Site(resource)
reactor.listenTCP(52235, factory)
reactor.run()
 
 
def main():
StartMediaServer()
 
 
if __name__ == "__main__":
StartMediaServer(debug=True)
 
 
if __name__ == '__main__':
main()
View
42
pc-autobackup.py 0 → 100644
#!/usr/bin/python
#
# Copyright 2013 Jeff Rebeiro (jeff@rebeiro.net) All rights reserved
# Main runnable for PC Autobackup
 
__author__ = 'jeff@rebeiro.net (Jeff Rebeiro)'
 
import optparse
 
from twisted.internet import reactor
from twisted.web.server import Site
 
import common
import ssdp
import mediaserver
 
 
def main():
parser = optparse.OptionParser()
parser.add_option('-b', '--bind', dest='bind',
help='Bind the server to a specific IP',
metavar='IPADDRESS')
parser.add_option('-d', '--debug', dest='debug', action="store_true",
default=False, help='Print debug information')
(options, args) = parser.parse_args()
 
config = common.LoadOrCreateConfig()
if options.bind:
config.set('AUTOBACKUP', 'default_interface', options.bind)
 
#ssdp.StartSSDPServer(debug=options.debug)
#mediaserver.StartMediaServer(debug=options.debug)
resource = mediaserver.MediaServer(debug=options.debug)
factory = Site(resource)
reactor.listenMulticast(1900, ssdp.SSDPServer(debug=options.debug))
reactor.listenTCP(52235, factory)
reactor.run()
 
 
if __name__ == '__main__':
main()
View
ssdp.py