def __init__(self, backend=None, port=None, db=None): if backend and port: XMLConnection.__init__(self, backend, port) self.db = db return self.db = DBCache(db) self.log = MythLog('Python XML Connection') if backend is None: # use master backend backend = self.db.getMasterBackend() # assume hostname from settings host = self.db._getpreferredaddr(backend) if host: port = int(self.db.settings[backend].BackendStatusPort) else: # assume ip address hostname = self.db._gethostfromaddr(backend) host = backend port = int(self.db.settings[hostname].BackendStatusPort) # resolve ip address from name reshost, resport = resolve_ip(host, port) if not reshost: raise MythDBError(MythError.DB_SETTING, backend + ': BackendServerAddr') if not resport: raise MythDBError(MythError.DB_SETTING, backend + ': BackendStatusPort') self.host = host self.port = port
def __init__(self, backend=None, blockshutdown=False, events=False, db=None): self.db = DBCache(db) self.log = MythLog(self.logmodule, db=self.db) self.hostname = None self.sendcommands = True self.blockshutdown = blockshutdown self.receiveevents = events if backend is None: # use master backend backend = self.db.getMasterBackend() else: backend = backend.strip('[]') # assume backend is hostname from settings host = self.db._getpreferredaddr(backend) if host: port = int(self.db.settings[backend].BackendServerPort) self.hostname = backend else: # assume ip address self.hostname = self.db._gethostfromaddr(backend) host = backend port = int(self.db.settings[self.hostname].BackendServerPort) # resolve ip address from name reshost, resport = resolve_ip(host,port) if not reshost: raise MythDBError(MythError.DB_SETTING, backend+': BackendServerAddr') if not resport: raise MythDBError(MythError.DB_SETTING, backend+': BackendServerPort') self.host = host self.port = port self._ident = '%s:%d' % (self.host, self.port) if self._ident in self._shared: # existing connection found self._conn = self._shared[self._ident] if self.sendcommands: if self._conn.command is None: self._conn.command = self._newcmdconn() elif self.blockshutdown: # upref block of shutdown # issue command to backend if needed self._conn.blockshutdown += 1 if self._conn.blockshutdown == 1: self._conn.command.blockShutdown() if self.receiveevents: if self._conn.event is None: self._conn.event = self._neweventconn() else: # no existing connection, create new self._conn = self._ConnHolder() if self.sendcommands: self._conn.command = self._newcmdconn() if self.blockshutdown: self._conn.blockshutdown = 1 if self.receiveevents: self._conn.event = self._neweventconn() self._shared[self._ident] = self._conn self._events = self._listhandlers() for func in self._events: self.registerevent(func)
def ftopen(file, mode, forceremote=False, nooverwrite=False, db=None, \ chanid=None, starttime=None, recordedid=None, download=False): """ ftopen(file, mode, forceremote=False, nooverwrite=False, db=None) -> FileTransfer object -> file object Method will attempt to open file locally, falling back to remote access over mythprotocol if necessary. 'forceremote' will force a FileTransfer object if possible. 'file' takes a standard MythURI: myth://<group>@<host>:<port>/<path> 'mode' takes a 'r' or 'w' 'nooverwrite' will refuse to open a file writable, if a local file is found. """ db = DBCache(db) log = MythLog('Python File Transfer', db=db) reuri = re.compile(\ r'myth://((?P<group>.*)@)?(?P<host>[\[\]a-zA-Z0-9_\-\.]*)(:[0-9]*)?/(?P<file>.*)') reip = re.compile(r'(?:\d{1,3}\.){3}\d{1,3}') if mode not in ('r','w'): raise TypeError("File I/O must be of type 'r' or 'w'") # process URI (myth://<group>@<host>[:<port>]/<path/to/file>) match = None try: match = reuri.match(file) except: pass if match: host = match.group('host') filename = match.group('file') sgroup = match.group('group') if sgroup is None: sgroup = 'Default' elif len(file) == 3: host, sgroup, filename = file else: raise MythError('Invalid FileTransfer input string: '+file) # prefer hostname from settings over IP address host = host.strip('[]') if ( not db._getpreferredaddr(host) and \ resolve_ip(host, None)[0] ): # host is either IPv4, IPv6 or an (aliased) name host = db._gethostfromaddr(host) # select the correct transfer function: if chanid and starttime and not recordedid: # get recordedid from FileOps class recordedid = \ FileOps(host, db=db).getRecording(chanid, starttime).recordedid if recordedid: protoopen = lambda host, file, storagegroup: \ RecordFileTransfer(host, file, storagegroup,\ mode, recordedid, db) elif download: protoopen = lambda host, lfile, storagegroup: \ DownloadFileTransfer(host, lfile, storagegroup, \ mode, file, db) else: protoopen = lambda host, file, storagegroup: \ FileTransfer(host, file, storagegroup, mode, db) # user forced to remote access if forceremote: if (mode == 'w') and (filename.find('/') != -1): raise MythFileError(MythError.FILE_FAILED_WRITE, file, 'attempting remote write outside base path') if nooverwrite and FileOps(host, db=db).fileExists(filename, sgroup): raise MythFileError(MythError.FILE_FAILED_WRITE, file, 'refusing to overwrite existing file') return protoopen(host, filename, sgroup) if mode == 'w': # check for pre-existing file path = FileOps(host, db=db).fileExists(filename, sgroup) sgs = list(db.getStorageGroup(groupname=sgroup)) if path is not None: if nooverwrite: raise MythFileError(MythError.FILE_FAILED_WRITE, file, 'refusing to overwrite existing file') for sg in sgs: if sg.dirname in path: if sg.local: return open(os.path.join(sg.dirname, filename), mode+'b') else: return protoopen(host, filename, sgroup) # prefer local storage for new files for i,v in reversed(list(enumerate(sgs))): if not v.local: sgs.pop(i) else: st = os.statvfs(v.dirname) v.free = st[0]*st[3] if len(sgs) > 0: # choose path with most free space sg = sorted(sgs, key=lambda sg: sg.free, reverse=True)[0] # create folder if it does not exist if filename.find('/') != -1: path = os.path.join(sg.dirname, filename.rsplit('/',1)[0]) if not os.access(path, os.F_OK): os.makedirs(path) log(log.FILE, log.INFO, 'Opening local file (wb)', os.path.join(sg.dirname, filename)) return open(os.path.join(sg.dirname, filename), mode+'b') # fallback to remote write else: if filename.find('/') != -1: raise MythFileError(MythError.FILE_FAILED_WRITE, file, 'attempting remote write outside base path') return protoopen(host, filename, sgroup) else: # search for file in local directories sg = findfile(filename, sgroup, db) if sg is not None: # file found, open local log(log.FILE, log.INFO, 'Opening local file (rb)', os.path.join(sg.dirname, filename)) return open(os.path.join(sg.dirname, filename), mode+'b') else: # file not found, open remote return protoopen(host, filename, sgroup)