基于Telegram二次開發(fā) --- MTProtoKit 消息解析

內(nèi)置消息簡析

MTProtoKit 中冻记,有很多內(nèi)置的消息,除了這些消息之外来惧,還有和解析這些消息相關(guān)的類檩赢,比如 MTBufferReaderMTInternalMessageParser,這些都是用來對這些內(nèi)置消息進(jìn)行解析用的违寞;除了內(nèi)置消息贞瞒,還應(yīng)該有很多業(yè)務(wù)相關(guān)性的消息,而這些消息都不在 MTProtoKit 考慮之中趁曼,MTProtoKit 將其它消息的序列化由 MTSerialization 協(xié)議委托給了使用者(Serialization)去實(shí)現(xiàn)军浆,這樣做還是很合理的,因?yàn)?MTProto 是一個非常動態(tài)的協(xié)議挡闰,擴(kuò)展性非常強(qiáng)乒融。

內(nèi)置消息其實(shí)就像編程語言給我們提供的標(biāo)準(zhǔn)庫一樣,它是框架摄悯,也是基礎(chǔ)赞季,下面簡單選取一些消息做個介紹:

全局上下文

什么是上下文呢?
上下文就是在某個特定的場景里缨称,用于記錄該場景特定狀態(tài)的一種抽象凝果。

所謂的全局上下文,也就是 MTContext 類睦尽,這是一個使用相當(dāng)頻繁的類器净,它的主要意圖是用來給 MTProtoKit 中,其它類提供一個公共的運(yùn)行上下文当凡,也相當(dāng)于是整個 MTProtoKit 的入口點(diǎn)。所以,一些公共的狀態(tài)和方法都會被提升到這個類中铜涉,它大體記錄了以下信息:

1.客戶端運(yùn)行環(huán)境乘陪,即 MTApiEnvironment
2.非內(nèi)置消息的序列化器實(shí)現(xiàn)魄缚,即 MTSerialization 協(xié)議(Serialization)的實(shí)現(xiàn)。
3.客戶端時間,并允許設(shè)定偏差來校準(zhǔn)匙赞。
4.當(dāng)前用戶的授權(quán)相關(guān)信息和操作。
5.數(shù)據(jù)中心的相關(guān)信息和操作妖碉。
6.傳輸格式(MTTransportScheme)的相關(guān)信息和操作涌庭。

其他細(xì)節(jié)

現(xiàn)在,我們再來看看一些比較有意思的細(xì)節(jié)處理欧宜;首先是 MTBuffer 類中坐榆,字節(jié)對齊的算法實(shí)現(xiàn):

static inline int roundUp(int numToRound, int multiple)
{
    return multiple == 0 ? numToRound : ((numToRound % multiple) == 0 ? numToRound : (numToRound + multiple - (numToRound % multiple)));
}

很簡單的算法,但很有意思冗茸,使用 roundUp(17, 4)席镀,則會得到 17 按照 4 向上對齊的結(jié)果,也就是 20夏漱。

MTBuffer 中豪诲,還有一個方法,也就是追加 TL 字節(jié)挂绰,我們來看一下:

- (void)appendTLBytes:(NSData *)bytes
{
    int32_t length = (int32_t)bytes.length;
    
    if (bytes == nil || length == 0)
    {
        [self appendInt32:0];
        return;
    }
    
    int paddingBytes = 0;
    
    if (length >= 254)
    {
        uint8_t tmp = 254;
        [self appendBytes:&tmp length:1];
        
        [self appendBytes:(const uint8_t *)&length length:3];
        
        paddingBytes = roundUp(length, 4) - length;
    }
    else
    {
        [self appendBytes:(const uint8_t *)&length length:1];
        paddingBytes = roundUp(length + 1, 4) - (length + 1);
    }
    
    [self appendBytes:bytes.bytes length:length];
    
    uint8_t tmp = 0;
    for (int i = 0; i < paddingBytes; i++)
        [self appendBytes:&tmp length:1];
}

當(dāng)這個塊的長度小于 254 時屎篱,第一個字節(jié)就是用來標(biāo)識內(nèi)容的長度;而當(dāng)這個塊的長度大于或等于 254 時葵蒂,第一個字節(jié)只是一個標(biāo)志交播,后面 3 個字節(jié)才是真正的長度,所以践付,每個塊的最大長度是 24 位值堪侯,而不是 32 位;這樣做荔仁,長度值所占用的字節(jié)就可以被壓縮了伍宦。

再來看一個 MTInternalMessageParser 中的 decompressGZip 方法,因?yàn)橄⑹强梢苑胖迷?gzip 容器中進(jìn)行傳輸?shù)姆α海钥蛻舳诵枰鈮鹤止?jié)流:

+ (NSData *)decompressGZip:(NSData *)data
{
    const int kMemoryChunkSize = 1024;
    
    NSUInteger length = [data length];
    int windowBits = 15 + 32; //Default + gzip header instead of zlib header
    int retCode;
    unsigned char output[kMemoryChunkSize];
    uInt gotBack;
    NSMutableData *result;
    z_stream stream;
    
    if ((length == 0) || (length > UINT_MAX)) //FIXME: Support 64 bit inputs
        return nil;
    
    bzero(&stream, sizeof(z_stream));
    stream.avail_in = (uInt)length;
    stream.next_in = (unsigned char*)[data bytes];
    
    retCode = inflateInit2(&stream, windowBits);
    if(retCode != Z_OK)
    {
        NSLog(@"%s: inflateInit2() failed with error %i", __PRETTY_FUNCTION__, retCode);
        return nil;
    }
    
    result = [NSMutableData dataWithCapacity:(length * 4)];
    do
    {
        stream.avail_out = kMemoryChunkSize;
        stream.next_out = output;
        retCode = inflate(&stream, Z_NO_FLUSH);
        if ((retCode != Z_OK) && (retCode != Z_STREAM_END))
        {
            NSLog(@"%s: inflate() failed with error %i", __PRETTY_FUNCTION__, retCode);
            inflateEnd(&stream);
            return nil;
        }
        gotBack = kMemoryChunkSize - stream.avail_out;
        if (gotBack > 0)
            [result appendBytes:output length:gotBack];
    } while( retCode == Z_OK);
    inflateEnd(&stream);
    
    return (retCode == Z_STREAM_END ? result : nil);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末次洼,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子遇骑,更是在濱河造成了極大的恐慌卖毁,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異亥啦,居然都是意外死亡炭剪,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門翔脱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來奴拦,“玉大人,你說我怎么就攤上這事届吁〈硌” “怎么了?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵疚沐,是天一觀的道長暂氯。 經(jīng)常有香客問我,道長亮蛔,這世上最難降的妖魔是什么痴施? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮究流,結(jié)果婚禮上辣吃,老公的妹妹穿的比我還像新娘。我一直安慰自己梯嗽,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布沽损。 她就那樣靜靜地躺著灯节,像睡著了一般。 火紅的嫁衣襯著肌膚如雪绵估。 梳的紋絲不亂的頭發(fā)上炎疆,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機(jī)與錄音国裳,去河邊找鬼形入。 笑死,一個胖子當(dāng)著我的面吹牛缝左,可吹牛的內(nèi)容都是我干的亿遂。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼渺杉,長吁一口氣:“原來是場噩夢啊……” “哼蛇数!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起是越,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤耳舅,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后倚评,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浦徊,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡馏予,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了盔性。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片霞丧。...
    茶點(diǎn)故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖纯出,靈堂內(nèi)的尸體忽然破棺而出蚯妇,到底是詐尸還是另有隱情,我是刑警寧澤暂筝,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布箩言,位于F島的核電站,受9級特大地震影響焕襟,放射性物質(zhì)發(fā)生泄漏陨收。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一鸵赖、第九天 我趴在偏房一處隱蔽的房頂上張望务漩。 院中可真熱鬧,春花似錦它褪、人聲如沸饵骨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽居触。三九已至,卻和暖如春老赤,著一層夾襖步出監(jiān)牢的瞬間轮洋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工抬旺, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留弊予,地道東北人。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓开财,卻偏偏與公主長得像汉柒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子责鳍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容