Özel bir XMPP çözümüne başarılı geçiş

Yayınlanan: 2019-04-08

Müşterimiz, İngiltere merkezli bir mesajlaşma sağlık çözümü olan Forward Health için üçüncü taraf bir sohbetten özel bir XMPP tabanlı mesajlaşma çözümüne geçiş yaparken karşılaştığımız zorluklardan bahsedeceğim. Bu makale, geçişin nedenlerini, uygulama gerçeklerine karşı beklentilerimizi ve ek işlevler oluşturmanın zorluklarını ele alacaktır.

nereden başladık

Müşterimiz Forward Health, Birleşik Krallık'taki sağlık çalışanları için sohbet işlevi de dahil olmak üzere bir mobil iletişim uygulaması oluşturmak istedi. Başlangıç ​​olarak, çalışan ürünlerini hızlı bir şekilde göstermek istediler. Aynı zamanda, mesajlaşmanın güvenilir, sağlam olması ve hassas hasta verilerini güvenli bir şekilde gönderebilmesi gerekiyordu. Bunu başarmak için sohbet işlevi için mevcut üçüncü taraf çözümlerinden birini kullanmaya karar verdik .

Sohbet işlevi, özellikle sağlık sektörünü desteklemeyi amaçladığında önemsiz bir şey değildir. Uygulama büyüdükçe, üçüncü tarafın üzerinde çalışmak istemediği kitaplık tarafında daha fazla uç vaka ve bazı hatalarla karşılaştık. Ayrıca Forward Health, üçüncü taraf kitaplığı tarafından desteklenmeyen yeni özellikler eklemek istedi. Bir sonraki adım özel bir çözüme geçmekti.

İşte o zaman MongooseIM ile çalışmaya başladık. MIM, köklü XMPP protokolüne dayanan açık kaynaklı bir çözümdür. Arka uçumuzu kurmak ve özel çözümlerin uygulanması konusunda destek sağlamak için harici bir şirket olan Erlang Solutions Limited ile çalıştık.

MongooseIM kontrol paneli

İlk başta, mesajlaşmayla ilgili her şey farklı görünüyordu. Önceden, tüm ihtiyaçlarımızı SDK ve onun REST API'si ile karşılıyorduk. Şimdi, MongooseIM kullanarak, XMPP'nin doğasını anlamak ve kendi SDK'mızı uygulamak için biraz zaman ayırmamız gerekiyordu . “Çıplak” XMPP sunucusunun, istemciler arasında gerçek zamanlı olarak yalnızca kıtaları (XML mesajları) ilettiği ortaya çıktı. Kıtalar farklı türlerde olabilir, yani normal sohbet mesajları, iletişim durumu, istekler ve yanıtlar. Örneğin, mesajları depolamak ve istemcilerin bunları sorgulamasına izin vermek için sunucuya çok çeşitli modüller eklenebilir.

İstemci tarafında (Android, iOS) bazı düşük seviyeli SDK'lar vardı. Ne yazık ki, yalnızca MongooseIM ve XEP'ler (diğer şeylerin yanı sıra her mesaj için push bildirimleri göndermekten sorumlu XMPP Uzantı Protokolü) adı verilen takılabilir modüllerinden bazıları ile iletişimi sağlayan bir katman görevi görüyorlardı. Mesajların işlenmesi, saklanması ve sorgulanması için tüm mimarinin ekibimiz tarafından uygulanması gerekiyordu.

Kurtarmamıza gelen, daha önce kullandığımız üçüncü taraf kitaplığıydı . Çok iyi düşünülmüş bir API'si vardı, bu yüzden çözümümüzün benzer şekilde çalışmasını sağladık. XMPP'ye özel kodu, önceki çözümden birine karşılık gelen arayüz ile dahili SDK'mıza ayırdık. Bu, geçişten sonra uygulama kodumuzda yalnızca birkaç değişiklikle sonuçlandı.

MongooseIM'in uygulanması sırasında, standart olacağını düşündüğümüz, ancak XEP tarafından bile bizim için mevcut olmayan öğeler bizi birkaç kez şaşırttı.

XMPP tabanlı sohbetin temel özelliklerini uygulama

zaman damgaları

Bizim yaptığımız gibi, zaman damgalarının "Bir mesaj alıyorum, bunu kullanıcı arayüzünde bir zaman damgasıyla görüntülüyorum" kadar basit olacağını düşünebilirsiniz. Hayır, o kadar kolay değil. Varsayılan olarak, mesaj kıtalarının bir zaman damgası alanı yoktur. Neyse ki ekibimiz için XMPP, kolayca genişletilebilir bir protokoldür. Arka uçta, MongooseIM sunucusundan geçen her mesaja bir zaman damgası ekleyerek özel bir özellik uyguladık. Daha sonra alıcı, mesaja eklenmiş zaman damgasına sahip olacaktır.

Neden bir gönderen kendisi bir zaman damgası ekleyemedi? Telefonlarında doğru saati ayarlamışlar mı bilmiyoruz.

Neden bunun için herhangi bir XEP yok? Belki de XMPP gerçek zamanlı bir protokol olduğundan, teorik olarak gönderilen her mesaj hemen alınır.

EDIT: Florian Schmaus'un işaret ettiği gibi: "Aslında bir tane var, ancak kafa karıştırıcı adı nedeniyle kolayca gözden kaçabilir: XEP-0203: Gecikmeli Teslimat." İletiye yalnızca teslimi geciktiğinde bir zaman damgası ekler. Aksi takdirde, mesaj az önce gönderildi.

Çevrimdışı Mesajlar

Her iki kullanıcı da uygulamaya giriş yaptığında, gerçek zamanlı olarak birbirlerine mesaj gönderebilirler. Ama ya onlardan biri çevrimdışıysa? Hızlı cevap şudur: mesajların arka uçta arabelleğe alınması gerekir . Çevrimdışı mesajlar özelliği bu işi halleder ve arabelleğe alınmış tüm kıtaları kullanıcı tekrar oturum açtıktan sonra gönderir.

Ama sonra birkaç soru ortaya çıkıyor:

  • Bu iletiler ne kadar süreyle arabelleğe alınmalıdır?
  • Onlardan kaçı?
  • Tekrar giriş yaptıktan hemen sonra tekrar mı gönderilmeliler? Ama müşteriyi mesajlarla dolduracak, değil mi?
  • Bir kullanıcı yalnızca oturum açar, ancak yeni mesajlarla sohbete girmezse ne olur? Hepsi gitmiş olacak mı?
  • Bir kullanıcı birden fazla cihazda oturum açtıysa ne olur?

Çevrimdışı Mesaj özelliğinin yalnızca tekrar çevrimiçi olan ilk cihaza mesaj gönderebildiği ve bu mesajların diğer tüm cihazlarda kaybolacağı ortaya çıktı. Bu özelliği kaldırmaya ve mesajları XMPP arka ucunda farklı, kalıcı bir şekilde depolamaya karar verdik.

Mesaj Arşivi Yönetimi (MAM)

MAM, mesajlar için sunucu üzerinde depolamadır. Bir istemci oturum açtığında, sunucuyu mesajlar için sorgulayabilir. Sayfalara göre sorgulama yapabilir, tarihlere göre sorgulama yapabilirsiniz. Esnektir — belirli bir kimliğe sahip bir mesajdan önce veya sonra bir sayfa için bile sorgulayabilir, tam konuşmadaki mesajlar için filtreler ekleyebilirsiniz.

Ama işin püf noktası burada. Normal sohbet mesajları, kendi benzersiz kimlikleri olan MAM mesajlarının içine sarılı olarak saklanır. Bir kullanıcı bir akışta sohbet mesajı aldığında, MAM Kimliğini içermez. Onu almak için MAM'ı sorgulamaları gerekiyor.

MAM'den alma bir ağ isteğidir, yani nispeten uzun zaman alabilir. Bir kullanıcı sohbete girdiğinde mesajları hemen görmek ister. Bu yüzden yerel bir veritabanına da ihtiyacımız var.

Bir kullanıcı bir akışta (çevrimiçi bir mesaj) bir mesaj aldığında, bunu yerel veritabanına kaydeder ve kullanıcıya gösteririz. Bu sayede gerçek zamanlı olarak hızlı bir şekilde kullanıcıya ulaşan mesajları görüntülüyoruz.

Ek olarak, sohbet ekranına her girdiklerinde, şu andan itibaren tüm mesajları o konuşma için yerel DB'de depolanan en yeni MAM mesajına indirir ve yinelemeleri yok sayarak bir veritabanına koyarız.

Eski mesajların saklanmasını bu şekilde hallediyoruz. Ayrıca, veritabanında MAM'den gelen ilk ve son mesaj arasındaki belirli bir konuşma için eksiksiz bir mesaj seti bulunduğundan eminiz.

MAM'den indirilen mesajları takip etmek için konuşma varlıklarına iki özellik ekledik:

  1. Veritabanındaki en yeni MAM mesajının MAM kimliği
  2. Veritabanındaki en eski MAM mesajının MAM kimliği

Yerel bir veritabanında parçalanmış MAM mesajlarını işlemek çok sorunlu olurdu.

Ek olarak, her konuşma için bu iki özelliğe sahip olmak, sarmalayıcı - MAM mesajını yok sayarken normal sohbet mesajlarını veritabanında saklamamıza olanak tanır. Ve kullanıcı sohbete girdiğinde, veritabanından en son mesajları gösterebilir ve arka planda MAM'den eksik mesajları alabiliriz.

Gelen kutusu

Her sohbet tabanlı uygulamanın, adları, son mesajları ve okunmamış mesaj sayısını görebileceğiniz bir sohbet listesi içeren bir ekrana ihtiyacı vardır. Buna bir çözüm bulunmalı!

Aslında yok… Kadro adı verilen bir şey var — “arkadaş” olarak etiketlenen kullanıcıların bir listesini tutabilir. Ne yazık ki, bunlara eklenmiş son mesaj veya okunmamış mesaj sayısı yok. Elbette, gerekli bilgileri arka uçtan parçalar halinde alabilirsiniz. İlk başta bu şekilde yapmak istedik, ancak yavaş çalışacak ve yapılması karmaşık olacaktı. İşte o zaman, Erlang Solutions ile açık kaynağa da giden Gelen Kutusu özelliği üzerinde çalışmaya başladık.

XMPP tabanlı sohbet - gelen kutusu ekranı
Gelen kutusu ekranı — tüm sohbet verileri gelen kutusu özelliği tarafından sağlanır

Bir kullanıcı XMPP arka ucuna bağlandığında, uygulama, hem bire bir hem de ekip sohbetleri olmak üzere bu kullanıcının tüm konuşmalarını içeren gelen kutusunu getirir. Her birinin kendisine eklenmiş son mesajı ve bir dizi okunmamış mesajı vardır. Uygulama tüm gelen kutusunu yerel veritabanına kaydeder. Bir kullanıcı uygulamadayken ve yeni bir mesaj geldiğinde, gelen kutusu durumunu yerel olarak güncelleriz. Bu şekilde, uygulamanın her yeni mesaj için gelen kutusunu alması gerekmez.

Özet

Bazı üçüncü taraf sohbet çözümleri yüksek düzeyde soyutlama sağlar. Basit bir sohbet uygulaması oluşturmak istiyorsanız bu sorun değil. Forward uygulamasında kendi XMPP tabanlı çözümümüzü uygulayarak, çok daha iyi düşük seviyeli erişim elde edebildik ve bu da sorunları çözmeyi çok daha kolay hale getirdi. Elbette, biraz zaman aldı, ancak artık Birleşik Krallık'taki doktorların NHS tarafından onaylanan güvenli ve kolay bir şekilde iletişim kurmasına yardımcı olacak herhangi bir özel özellik sağlayabileceğimizi biliyoruz.

Mesajlaşma tamamen yüksek performans, gerçek zamanlı iletişim ile ilgilidir. MIM'e geçerek, hızı, güvenilirliği ve nihayetinde güveni artırmak için çözümün her parçasını optimize edebildik. Şu anda, kodun tamamına sahibiz, bu nedenle onları izlemek kolaydır. Ayrıca, stabilizasyon aşamasının peşindeyiz ve mesajlaşmaya bağlı bir dizi rapor büyük ölçüde azaldı. Kullanıcılar platforma güvenebilmekten memnunlar.

Kendi SDK'mızı tasarlamak ve yazmak zorlu bir işti ve bu bizim için çok hoştu. Bir sunucudan veri alıp ekranda göstermeniz gereken basit uygulamalardan farklı bir şeydi. Uygulama sırasında, daha önce kullandığımız üçüncü taraf kitaplık API'sinin birçok tasarım seçeneğini anladık. Neden? Niye? Çünkü aynı sorunlarla karşılaştık.