def subtest_receptionOfSUBSTwoRequestsOneAvailable(self): """ Asking for two subtitles while the recipent of the request has only one. The response should contain only the one available subtitle content, plus a bitmask that reflects the contents of the response. """ print >> sys.stderr, time.asctime(),'-', "test: test_subtitles_msgs_2_1 -----------------------" ol_conn = OLConnection(self.my_keypair,'localhost',self.hisport) bitmask = LanguagesProvider.getLanguagesInstance().langCodesToMask(['nld','eng']) binmask = utilities.uintToBinaryString(bitmask, length=4) request = GET_SUBS + \ bencode(( self.anotherpermid, self.testInfohash, binmask )) subshandler = SubtitlesHandler() subshandler.register(ol_conn, self.richMetadata_db, self.session) ol_conn.send(request) subs_data = ol_conn.recv() self.assertEquals(SUBS, subs_data[0]) data = bdecode(subs_data[1:]) print >> sys.stderr, time.asctime(),'-', "test: subtitles_messages : received SUBS repsonse: ", data #check on the format of the response self.assertTrue(isinstance(data,list)) self.assertEquals(4, len(data)) # for fields self.assertEquals(self.mdto.channel,data[0]) self.assertEquals(self.mdto.infohash, data[1]) #the receiver had only one of the two requested subtitles # so I expect a different bitmask bitmask = LanguagesProvider.getLanguagesInstance().langCodesToMask(['nld']) expectedBinarymask = utilities.uintToBinaryString(bitmask, length=4) self.assertEquals(expectedBinarymask, data[2]) self.assertTrue(isinstance(data[3],list)) self.assertEquals(1, len(data[3])) with codecs.open(self.sub1, "rb", "utf-8") as sub: expectedContents = sub.read() self.assertEquals(expectedContents, data[3][0]) ol_conn.close() print >> sys.stderr, time.asctime(),'-', "test: subtitles_messages: received content is valid." print >> sys.stderr, time.asctime(),'-', "End of test_subtitles_msgs_2_1 test --------------------"
def subtest_invalidRequest3(self): """ Trying to send an invalid message (valid for everythin except that there is one field more) The connection should be closed by the receiver """ print >> sys.stderr, time.asctime(),'-', "test: test_subtitles_msgs_invalid_request_3 ------------------" ol_conn = OLConnection(self.my_keypair,'localhost',self.hisport) bitmask = LanguagesProvider.getLanguagesInstance().langCodesToMask(['nld','eng']) binmask = utilities.uintToBinaryString(bitmask, length=4) request = GET_SUBS + \ bencode(( self.anotherpermid, self.testInfohash, binmask, 42 )) ol_conn.send(request) self.assertEquals(0, len(ol_conn.recv())) print >> sys.stderr, time.asctime(),'-', "test: test_subtitles_msgs_invalid_request_3: connection closed as expected" ol_conn.close() print >> sys.stderr, time.asctime(),'-', "End of test_subtitles_msgs_invalid_request_3 ------------------"
def _packData(self): """ Creates a bencode binary representation of this metadata instance. This representation is the one that is sent with ChannelCast messages. """ if self.description is not None: assert isinstance(self.description, unicode) if self.description is None: self.description = u"" bitmask, checksums = self._getSubtitlesMaskAndChecksums() binaryMask = uintToBinaryString(bitmask) # The signature is taken over the bencoding of # binary representations of (channel,infohash,description,timestamp,bitmask) # that is the same message that is sent with channelcast tosign = (self.channel, self.infohash, self.description.encode("utf-8"), self.timestamp, binaryMask, checksums ) bencoding = bencode(tosign) return bencoding
def test_receivedSUBSOtherRequest(self): langUtil = LanguagesProvider.getLanguagesInstance() data = { 'permid' : testDestPermId, 'channel_id' : testChannelId, 'infohash' : testInfohash, 'subtitles' : {"eng" : "This is content 1", "nld": "This is content 2", "ita" : "This is content 3"}, 'selversion' : OLPROTO_VER_FOURTEENTH } langs = data['subtitles'].keys() bitmask = langUtil.langCodesToMask(langs) binaryBitmask = uintToBinaryString(bitmask, length=4) expextedMessage = SUBS + \ bencode(( data['channel_id'], data['infohash'], binaryBitmask, [data['subtitles']['eng'], data['subtitles']['ita'], data['subtitles']['nld']] )) list = MockMsgListener() self.underTest.registerListener(list) #invalid bitmask self.underTest._addToRequestedSubtitles(testChannelId, testInfohash, int(0xFFFFFFFF & ~bitmask), None) val = self.underTest.handleMessage(testDestPermId, OLPROTO_VER_FOURTEENTH, expextedMessage) # never had a request for this message should be dropped self.assertFalse(val) self.assertEquals(0,list.subsCount)
def test_createSingleResponseMessage(self): langUtil = LanguagesProvider.getLanguagesInstance() data = { 'permid' : testDestPermId, 'channel_id' : testChannelId, 'infohash' : testInfohash, 'subtitles' : {"eng" : "This is content 1", "nld": "This is content 2", "ita" : "This is content 3"}, 'selversion' : OLPROTO_VER_FOURTEENTH } langs = data['subtitles'].keys() bitmask = langUtil.langCodesToMask(langs) binaryBitmask = uintToBinaryString(bitmask, length=4) expextedMessage = SUBS + \ bencode(( data['channel_id'], data['infohash'], binaryBitmask, [data['subtitles']['eng'], data['subtitles']['ita'], data['subtitles']['nld']] )) msg = self.underTest._createSingleResponseMessage(data) decoded = bdecode(msg[1:]) self.assertEquals(expextedMessage, msg)
def _createGETSUBSMessage(self, channel_id, infohash, bitmask): """ Bencodes a GET_SUBS message and adds the appropriate header. """ binaryBitmask = uintToBinaryString(bitmask) body = bencode((channel_id, infohash, binaryBitmask)) head = GET_SUBS return head + body
def test_decodeGETSUBSMessageInvalid(self): langUtil = LanguagesProvider.getLanguagesInstance() binaryBitmask = uintToBinaryString(langUtil.langCodesToMask(["kor", "spa"])) invalidTypeMsg = chr(25) + \ bencode(( testChannelId, testInfohash, binaryBitmask )) self.assertRaises(AssertionError, self.underTest._decodeGETSUBSMessage, (invalidTypeMsg,)) invalidMsgField = GET_SUBS + \ bencode(( 42, testChannelId, testInfohash, binaryBitmask )) decoded = \ self.underTest._decodeGETSUBSMessage(invalidMsgField) #when something in the body is wrong returns None self.assertTrue(decoded is None) invalidBitamsk = uintToBinaryString(0xFFFFFFFF11, 5) invalidMsgField = GET_SUBS + \ bencode(( testChannelId, testInfohash, invalidBitamsk #40 bit bitmask!) )) decoded = \ self.underTest._decodeGETSUBSMessage(invalidMsgField) #when something in the body is wrong returns None self.assertTrue(decoded is None)
def test_decodeGETSUBSMessage(self): langUtil = LanguagesProvider.getLanguagesInstance() binaryBitmask = uintToBinaryString(langUtil.langCodesToMask(["kor", "spa"])) bencodedMessage = GET_SUBS + \ bencode(( testChannelId, testInfohash, binaryBitmask )) channel_id, infohash, languages = \ self.underTest._decodeGETSUBSMessage(bencodedMessage) self.assertEquals(testChannelId, channel_id) self.assertEquals(testInfohash, infohash) self.assertEquals(["kor", "spa"], languages)
def _createSingleResponseMessage(self, responseData): """ Create a bencoded SUBS message to send in response to a GET_SUBS The format of the sent message is a not encoded SUBS character and then the bencoded form of (channel_id,infohash,bitmask,[listOfSubtitleContents]) the list of subtitle contents is ordered as the bitmask """ orderedKeys = sorted(responseData['subtitles'].keys()) payload = list() #read subtitle contents for lang in orderedKeys: fileContent = responseData['subtitles'][lang] if fileContent is not None and len(fileContent) <= self._maxSubSize: payload.append(fileContent) else: print >> sys.stderr, "Warning: Subtitle in % for ch: %s, infohash:%s dropped. Bigger then %d" % \ (lang, responseData['channel_id'], responseData['infohash'], self._maxSubSize) if not len(payload) > 0: if DEBUG: print >> sys.stderr, SUBS_LOG_PREFIX + "No payload to send in SUBS" return None bitmask = \ self._languagesUtility.langCodesToMask(orderedKeys) binaryBitmask = uintToBinaryString(bitmask, length=4) header = (responseData['channel_id'], responseData['infohash'], binaryBitmask) message = bencode(( header[0], header[1], header[2], payload )) return SUBS + message
def subtest_receptionOfSUBS(self): ''' Asking for the single available subtitle. The response should be a valid SUBS message containing its contents ''' print >> sys.stderr, time.asctime(),'-', "test: test_subtitles_msgs_1_1 -----------------------" ol_conn = OLConnection(self.my_keypair,'localhost',self.hisport) bitmask = LanguagesProvider.getLanguagesInstance().langCodesToMask(['nld']) binmask = utilities.uintToBinaryString(bitmask, length=4) request = GET_SUBS + \ bencode(( self.anotherpermid, self.testInfohash, binmask )) subshandler = SubtitlesHandler() subshandler.register(ol_conn, self.richMetadata_db, self.session) ol_conn.send(request) subs_data = ol_conn.recv() print >> sys.stderr, time.asctime(),'-', "test: subtitles_messages : received SUBS response: len",len(subs_data) self.assertEquals(SUBS, subs_data[0]) data = bdecode(subs_data[1:]) print >> sys.stderr, time.asctime(),'-', "test: subtitles_messages : received SUBS response: ", data #check on the format of the response self.assertTrue(isinstance(data,list)) self.assertEquals(4, len(data)) # for fields self.assertEquals(self.mdto.channel,data[0]) self.assertEquals(self.mdto.infohash, data[1]) self.assertEquals(binmask, data[2]) self.assertTrue(isinstance(data[3],list)) self.assertEquals(1, len(data[3])) with codecs.open(self.sub1, "rb", "utf-8") as sub: expectedContents = sub.read() self.assertEquals(expectedContents, data[3][0]) ol_conn.close() print >> sys.stderr, time.asctime(),'-', "test: subtitles_messages: received content is valid." print >> sys.stderr, time.asctime(),'-', "End of test_subtitles_msgs_1_1 test --------------------"
def testSendSubtitlesRequestConnected(self): langUtil = LanguagesProvider.getLanguagesInstance() request = {} request['channel_id'] = testChannelId request['infohash'] = testInfohash request['languages'] = ["kor"] self.underTest.sendSubtitleRequest(testDestPermId, request, None, None, OLPROTO_VER_FOURTEENTH) self.assertEquals(0, self.ol_bridge.connect_count) #selversion was 1 self.assertEquals(1, self.ol_bridge.send_count) #send called one time binaryBitmask = uintToBinaryString(langUtil.langCodesToMask(["kor"])) expectedMsg = GET_SUBS + \ bencode(( testChannelId, testInfohash, binaryBitmask )) passedParameters = self.ol_bridge.sendParametersHistory[0] self.assertEquals(testDestPermId, passedParameters[0]) self.assertEquals(expectedMsg, passedParameters[1])
def test_receivedGETSUBSSimple(self): langUtil = LanguagesProvider.getLanguagesInstance() bitmask = langUtil.langCodesToMask(["eng", "rus"]) binaryBitmask = uintToBinaryString(bitmask, length=4) request = GET_SUBS + \ bencode(( testChannelId, testInfohash, binaryBitmask )) list = MockMsgListener() self.underTest.registerListener(list) self.underTest.handleMessage(testDestPermId, OLPROTO_VER_FOURTEENTH, request) self.assertEquals(1,list.receivedCount) self.assertEquals(testDestPermId, list.receivedParams[0][0]) self.assertEquals(OLPROTO_VER_FOURTEENTH,list.receivedParams[0][2]) self.assertEquals((testChannelId,testInfohash,["eng","rus"]),list.receivedParams[0][1])
def test_packDataWithSubs(self): badInfohash = str2bin("GEh/o8rtTLB1wZJzFcSZSS4u9qo=") dto = MetadataDTO(test_perm_id, badInfohash) subtitles = [SubtitleInfo(lang,path) for lang,path in self._srtSubs.iteritems()] for sub in subtitles : sub.computeChecksum() dto.addSubtitle(sub) packed = dto._packData() decoded = bdecode(packed) self.assertTrue(len(decoded) == 6) decodedChannelId = decoded[0] decodedInfohash = decoded[1] decodedDescription = decoded[2] decodedTimestamp = decoded[3] decodedBitmask = decoded[4] checksums = decoded[5] expectedMask = \ LanguagesProvider.getLanguagesInstance().langCodesToMask(self._srtSubs.keys()) binaryExpexted = uintToBinaryString(expectedMask) self.assertEquals(dto.channel, decodedChannelId) self.assertEquals(dto.infohash, decodedInfohash) self.assertEquals(dto.description,decodedDescription) self.assertAlmostEquals(dto.timestamp,decodedTimestamp) self.assertEquals(binaryExpexted,decodedBitmask) self.assertEquals(3,len(checksums)) subs = dto.getAllSubtitles() i=0 for key in sorted(subs.iterkeys()): self.assertEquals(subs[key].checksum, checksums[i]) i += 1
def addRichMetadataContent(self,channelCastMessage, destPermid = None, fromQuery = False): ''' Takes plain channelcast message (from OLProto v.13) and adds to it a 'rich_metadata' field. @param channelCastMessage: the old channelcast message in the format of protocol v13 @param destPermid: the destination of the message. If not None it is used for logging purposes only. If None, nothing bad happens. @return: the "enriched" channelcast message ''' if not len(channelCastMessage) > 0: if DEBUG: print >> sys.stderr, "no entries to enrich with rmd" return channelCastMessage if DEBUG: if fromQuery: print >> sys.stderr, "Intercepted a channelcast message as answer to a query" else: print >> sys.stderr, "Intercepted a channelcast message as normal channelcast" #otherwise I'm modifying the old one (even if there's nothing bad #it's not good for the caller to see its parameters changed :) newMessage = dict() # a channelcast message is made up of a dictionary of entries # keyed the signature. Every value in the dictionary is itself # a dictionary with the item informatino for key in iter(channelCastMessage): entryContent = copy(channelCastMessage[key]) newMessage[key] = entryContent channel_id = entryContent['publisher_id'] infohash = entryContent['infohash'] #not clean but the fastest way :( # TODO: make something more elegant metadataDTO = self.rmdDb.getMetadata(channel_id, infohash) if metadataDTO is not None: try: if DEBUG: print >> sys.stderr, "Enriching a channelcast message with subtitle contents" metadataPack = metadataDTO.serialize() # I can remove from the metadata pack the infohash, and channelId # since they are already in channelcast and they would be redundant metadataPack.pop(0) metadataPack.pop(0) #adding the haveMask at the end of the metadata pack havemask = self.peerHaveManager.retrieveMyHaveMask(channel_id, infohash) binary_havemask = uintToBinaryString(havemask) metadataPack.append(binary_havemask) entryContent['rich_metadata'] = metadataPack if DEBUG: size = self._computeSize(metadataPack) # if available records also the destination of the message dest = "NA" if destPermid is None else show_permid_short(destPermid) id = "SQ" if fromQuery else "S" # format (S (for sent) | SQ (for sent as response to a query), channel, infohash, destination, timestampe, size) print >> sys.stderr, "%c, %s, %s, %s, %d, %d" % \ (id, bin2str(metadataDTO.channel), \ bin2str(metadataDTO.infohash), \ dest, metadataDTO.timestamp, size) except Exception,e: print >> sys.stderr, "Warning: Error serializing metadata: %s", str(e) return channelCastMessage else: # better to put the field to None, or to avoid adding the # metadata field at all? ##entryContent['rich_metadata'] = None pass