def write(self, data): """ FileTransfer.write(data) -> None Requests over 128KB will be buffered internally """ if self.mode != 'w': raise MythFileError('attempting to write to a read-only socket') while len(data) > 0: size = len(data) # check size for buffering if size > self._tsize: size = self._tsize buff = data[:size] data = data[size:] else: buff = data data = '' # push data to server self._pos += int(self.ftsock.send(buff)) if self._pos > self._size: self._size = self._pos # inform server of new data self.backendCommand('QUERY_FILETRANSFER '\ +BACKEND_SEP.join(\ [str(self._sockno), 'WRITE_BLOCK', str(size)])) return
def read(self, size): """ FileTransfer.read(size) -> string of <size> characters Requests over 128KB will be buffered internally. """ # some sanity checking if self.mode != 'r': raise MythFileError('attempting to read from a write-only socket') if size == 0: return '' if self._pos + size > self._size: size = self._size - self._pos buff = '' while len(buff) < size: ct = size - len(buff) if ct > self._tsize: # drop size and bump counter if over limit self._count += 1 ct = self._tsize # request transfer res = self.backendCommand('QUERY_FILETRANSFER '\ +BACKEND_SEP.join( [str(self._sockno), 'REQUEST_BLOCK', str(ct)])) if res == '': # complete failure, hard reset position and retry self._count = 0 self.seek(self._pos) continue if int(res) == ct: if (self._count >= 5) and (self._tsize < self._tmax): # multiple successful transfers, bump transfer limit self._count = 0 self._tsize += self._step else: if int(res) == -1: # complete failure, hard reset position and retry self._count = 0 self.seek(self._pos) continue # partial failure, reset counter and drop transfer limit ct = int(res) self._count = 0 self._tsize -= 2 * self._step if self._tsize < self._step: self._tsize = self._step # append data and move position buff += self.ftsock.recv(ct) self._pos += ct return buff
def read(self, size): """ FileTransfer.read(size) -> string of <size> characters Requests over 128KB will be buffered internally. """ # some sanity checking if self.mode != 'r': raise MythFileError('attempting to read from a write-only socket') if size == 0: return '' if self._pos + size > self._size: size = self._size - self._pos buff = '' while len(buff) < size: ct = size - len(buff) if ct > self._tsize: # drop size and bump counter if over limit self._count += 1 ct = self._tsize # request transfer res = self.backendCommand('QUERY_FILETRANSFER '\ +BACKEND_SEP.join( [str(self._sockno), 'REQUEST_BLOCK', str(ct)])) if res == '': # complete failure, hard reset position and retry self._count = 0 self.seek(self._pos) continue if int(res) == ct: if (self._count >= 5) and (self._tsize < self._tmax): # multiple successful transfers, bump transfer limit self._count = 0 self._tsize += self._step else: if int(res) == -1: # complete failure, hard reset position and retry self._count = 0 self.seek(self._pos) continue # partial failure, reset counter and drop transfer limit ct = int(res) self._count = 0 self._tsize -= 2*self._step if self._tsize < self._step: self._tsize = self._step # append data and move position buff += self.ftsock.recv(ct) self._pos += ct return buff
def fileExists(self, file, sgroup='Default'): """FileOps.fileExists() -> file path""" res = self.backendCommand(BACKEND_SEP.join((\ 'QUERY_FILE_EXISTS',file,sgroup))).split(BACKEND_SEP) if int(res[0]) == 0: return None else: return res[1]
def deleteRecording(self, program, force=False): """ FileOps.deleteRecording(program, force=False) -> retcode 'force' will force a delete even if the file cannot be found retcode will be -1 on success, -2 on failure """ command = 'DELETE_RECORDING' if force: command = 'FORCE_DELETE_RECORDING' return self.backendCommand(BACKEND_SEP.join(\ [command,program.toString()]))
def undelete_all(backend, recs): """Undeletes all recordings from the dict recs. Send an UNDELETE_RECORDING protocol message to the backend and test for failure. """ for rec in recs.values(): print('undelete ' + rec_to_string(rec)) cmd = BACKEND_SEP.join(['UNDELETE_RECORDING', rec.to_string()]) res = backend.backendCommand(cmd) if int(res) != 0: raise MythBEError("undelete failed")
def reschedule(self, recordid=-1, wait=False): """FileOps.reschedule() -> None""" if wait: eventlock = self.allocateEventLock(\ re.escape(BACKEND_SEP).join(\ ['BACKEND_MESSAGE', 'SCHEDULE_CHANGE', 'empty'])) if recordid == 0: self.backendCommand(BACKEND_SEP.join(\ ['RESCHEDULE_RECORDINGS', 'CHECK 0 0 0 Python', '', '', '', '**any**'])) else: if recordid == -1: recordid = 0 self.backendCommand(BACKEND_SEP.join(\ ['RESCHEDULE_RECORDINGS', 'MATCH ' + str(recordid) + ' 0 0 - Python'])) if wait: eventlock.wait()
def announce(self): if self.mode == 'r': cmd = 'ANN FileTransfer %s 0 0 2000' elif self.mode == 'w': cmd = 'ANN FileTransfer %s 1' res = self.backendCommand( BACKEND_SEP.join( [cmd % self.localname, self.filename, self.sgroup])) if res.split(BACKEND_SEP)[0] != 'OK': raise MythBEError(MythError.PROTO_ANNOUNCE, self.host, self.port, res) else: sp = res.split(BACKEND_SEP) self._sockno = int(sp[1]) self._size = int(sp[2])
def announce(self): if self.mode == 'r': cmd = 'ANN FileTransfer %s 0 0 2000' elif self.mode == 'w': cmd = 'ANN FileTransfer %s 1' res = self.backendCommand( BACKEND_SEP.join([cmd % self.localname, self.filename, self.sgroup])) if res.split(BACKEND_SEP)[0] != 'OK': raise MythBEError(MythError.PROTO_ANNOUNCE, self.host, self.port, res) else: sp = res.split(BACKEND_SEP) self._sockno = int(sp[1]) self._size = int(sp[2])
def downloadTo(self, url, storagegroup, filename, \ forceremote=False, openfile=False): if openfile: eventlock = self.allocateEventLock(\ re.escape(BACKEND_SEP).\ join(['BACKEND_MESSAGE', 'DOWNLOAD_FILE UPDATE', re.escape(url)])) if filename[0] != '/': filename = '/'+filename res = self.backendCommand(BACKEND_SEP.join((\ 'DOWNLOAD_FILE', url, storagegroup, filename))).\ split(BACKEND_SEP) if res[0] != 'OK': raise MythBEError('Download failed') if openfile: eventlock.wait() return ftopen(res[1], 'r', forceremote, db=self.db, download=True)
def downloadTo(self, url, storagegroup, filename, \ forceremote=False, openfile=False): if openfile: eventlock = self.allocateEventLock(\ re.escape(BACKEND_SEP).\ join(['BACKEND_MESSAGE', 'DOWNLOAD_FILE UPDATE', re.escape(url)])) if filename[0] != '/': filename = '/' + filename res = self.backendCommand(BACKEND_SEP.join((\ 'DOWNLOAD_FILE', url, storagegroup, filename))).\ split(BACKEND_SEP) if res[0] != 'OK': raise MythBEError('Download failed') if openfile: eventlock.wait() return ftopen(res[1], 'r', forceremote, db=self.db, download=True)
def seek(self, offset, whence=0): """ FileTransfer.seek(offset, whence=0) -> None Seek 'offset' number of bytes whence == 0 - from start of file 1 - from current position 2 - from end of file """ if whence == 0: if offset < 0: offset = 0 elif offset > self._size: offset = self._size elif whence == 1: if offset + self._pos < 0: offset = -self._pos elif offset + self._pos > self._size: offset = self._size - self._pos elif whence == 2: if offset > 0: offset = 0 elif offset < -self._size: offset = -self._size whence = 0 offset = self._size+offset res = self.backendCommand('QUERY_FILETRANSFER '\ +BACKEND_SEP.join( [str(self._sockno),'SEEK', str(offset), str(whence), str(self._pos)])\ ).split(BACKEND_SEP) if res[0] == '-1': raise MythFileError(MythError.FILE_FAILED_SEEK, \ str(self), offset, whence) self._pos = int(res[0])
def seek(self, offset, whence=0): """ FileTransfer.seek(offset, whence=0) -> None Seek 'offset' number of bytes whence == 0 - from start of file 1 - from current position 2 - from end of file """ if whence == 0: if offset < 0: offset = 0 elif offset > self._size: offset = self._size elif whence == 1: if offset + self._pos < 0: offset = -self._pos elif offset + self._pos > self._size: offset = self._size - self._pos elif whence == 2: if offset > 0: offset = 0 elif offset < -self._size: offset = -self._size whence = 0 offset = self._size + offset res = self.backendCommand('QUERY_FILETRANSFER '\ +BACKEND_SEP.join( [str(self._sockno),'SEEK', str(offset), str(whence), str(self._pos)])\ ).split(BACKEND_SEP) if res[0] == '-1': raise MythFileError(MythError.FILE_FAILED_SEEK, \ str(self), offset, whence) self._pos = int(res[0])
def stopRecording(self, program): """FileOps.stopRecording(program) -> None""" self.backendCommand(BACKEND_SEP.join(['STOP_RECORDING', program.toString()]))
def getHash(self, file, sgroup, host=None): """FileOps.getHash(file, storagegroup, host) -> hash string""" m = ['QUERY_FILE_HASH', file, sgroup] if host: m.append(host) return self.backendCommand(BACKEND_SEP.join(m))
def stopRecording(self, program): """FileOps.stopRecording(program) -> None""" self.backendCommand( BACKEND_SEP.join(['STOP_RECORDING', program.toString()]))
def forgetRecording(self, program): """FileOps.forgetRecording(program) -> None""" self.backendCommand( BACKEND_SEP.join(['FORGET_RECORDING', program.toString()]))
def deleteFile(self, file, sgroup): """FileOps.deleteFile(file, storagegroup) -> retcode""" return self.backendCommand(BACKEND_SEP.join(\ ['DELETE_FILE',file,sgroup]))
def __del__(self): self.backendCommand('QUERY_FILETRANSFER '+BACKEND_SEP.join( [str(self._sockno), 'DONE'])) del self.ftsock self.open = False
def toString(self): """ Program.toString() -> string representation for use with backend protocol commands """ return BACKEND_SEP.join(self._deprocess())
def forgetRecording(self, program): """FileOps.forgetRecording(program) -> None""" self.backendCommand(BACKEND_SEP.join(['FORGET_RECORDING', program.toString()]))
def __del__(self): self.backendCommand('QUERY_FILETRANSFER ' + BACKEND_SEP.join([str(self._sockno), 'DONE'])) del self.ftsock self.open = False