Implementasi Server Pesan Kamar yang menggunakan protokol RPC dua arah untuk mengimplementasikan komunikasi seperti obrolan. Dirancang untuk menangani masalah pesan jaringan publik umum seperti pengiriman yang andal, beberapa koneksi dari satu pengguna, izin waktu nyata dan keberadaan. Pemrosesan permintaan RPC dan format pesan kamar dapat disesuaikan melalui kait, memungkinkan untuk mengimplementasikan apa pun dari server ruang obrolan hingga aplikasi kolaboratif dengan resolusi konflik yang kompleks. Pesan kamar juga dapat digunakan untuk membuat API publik atau untuk komunikasi M2M terowongan untuk perangkat IoT.
Pesan kamar yang andal menggunakan penyimpanan riwayat sisi server dan API sinkronisasi.
Format pesan sewenang -wenang hanya melalui fungsi validasi (hook), yang memungkinkan format pesan khusus/heterogen (termasuk data biner dalam pesan).
API Kehadiran Pengguna Per-Kamar dengan Pemberitahuan.
Penciptaan kamar realtime dan pengguna perizinan per kamar API. Dukungan untuk BlackList atau Mode Akses Berbasis WhiteList dan Grup Administrator Opsional.
Dukungan mulus dari koneksi beberapa pengguna dari berbagai perangkat ke instance layanan apa pun.
Ditulis sebagai layanan mikro tanpa kewarganegaraan, menggunakan REDIS (juga mendukung konfigurasi cluster) sebagai toko negara, dapat diskalakan secara horizontal berdasarkan permintaan.
Dukungan kustomisasi yang luas. Fungsionalitas khusus dapat ditambahkan melalui kait sebelum/sesudah untuk pemrosesan permintaan klien apa pun. Dan penangan permintaan (perintah) dapat dipanggil sisi server melalui API.
Transportasi jaringan yang dapat pluginable. Komunikasi klien-server dilakukan melalui protokol RPC dua arah. Socket.io Transport Implementasi disertakan.
Toko Negara yang Dapat Ditambah. Toko memori dan Redis disertakan.
Mendukung Pengguna Online yang Ringan ke Pesan Pengguna Online.
Baca artikel ini untuk lebih banyak informasi latar belakang.
Proyek ini adalah modul simpul yang tersedia melalui NPM. Periksa mereka jika Anda tidak menginstalnya secara lokal.
$ npm i chat-servicePertama -tama tentukan konfigurasi server. Pada sisi server, tentukan kait koneksi soket, karena layanan mengandalkan implementasi auth eksternal. Pengguna hanya perlu melewati cek auth, tidak diperlukan langkah penambahan pengguna eksplisit.
const ChatService = require ( 'chat-service' )
const port = 8000
function onConnect ( service , id ) {
// Assuming that auth data is passed in a query string.
let { query } = service . transport . getHandshakeData ( id )
let { userName } = query
// Actually check auth data.
// ...
// Return a promise that resolves with a login string.
return Promise . resolve ( userName )
} Membuat server adalah instantiasi objek sederhana. Catatan: Metode close harus dipanggil untuk mematikan dengan benar instance layanan (lihat Pemulihan Gagal).
const chatService = new ChatService ( { port } , { onConnect } )
process . on ( 'SIGINT' , ( ) => chatService . close ( ) . finally ( ( ) => process . exit ( ) ) ) Server sekarang berjalan di port 8000 , menggunakan status memory . Secara default '/chat-service' socket.io namespace digunakan. Tambahkan kamar dengan pengguna admin sebagai pemilik kamar. Semua kamar harus dibuat secara eksplisit (opsi untuk memungkinkan pembuatan kamar dari sisi klien juga disediakan).
// The room configuration and messages will persist if redis state is
// used. addRoom will reject a promise if the room is already created.
chatService . hasRoom ( 'default' ) . then ( hasRoom => {
if ( ! hasRoom ) {
return chatService . addRoom ( 'default' , { owner : 'admin' } )
}
} ) Di klien, hanya diperlukan implementasi socket.io-client . Untuk mengirim permintaan (perintah) Gunakan metode emit , hasilnya (atau kesalahan) akan dikembalikan di socket.io ack callback. Untuk mendengarkan pesan server digunakan on metode.
const io = require ( 'socket.io-client' )
// Use https or wss in production.
let url = 'ws://localhost:8000/chat-service'
let userName = 'user' // for example and debug
let token = 'token' // auth token
let query = `userName= ${ userName } &token= ${ token } `
let opts = { query }
// Connect to a server.
let socket = io . connect ( url , opts )
// Rooms messages handler (own messages are here too).
socket . on ( 'roomMessage' , ( room , msg ) => {
console . log ( ` ${ msg . author } : ${ msg . textMessage } ` )
} )
// Auth success handler.
socket . on ( 'loginConfirmed' , userName => {
// Join room named 'default'.
socket . emit ( 'roomJoin' , 'default' , ( error , data ) => {
// Check for a command error.
if ( error ) { return }
// Now we will receive 'default' room messages in 'roomMessage' handler.
// Now we can also send a message to 'default' room:
socket . emit ( 'roomMessage' , 'default' , { textMessage : 'Hello!' } )
} )
} )
// Auth error handler.
socket . on ( 'loginRejected' , error => {
console . error ( error )
} ) Ini adalah kode yang dapat dijalankan, file dalam direktori example .
Dimungkinkan untuk menggunakan transportasi lain selain socket.io. Ada bukti transportasi konsep, yaitu menggunakan koneksi Websocket dengan beberapa lapisan abstraksi API minimal WS-messaging dan broker emitor-pubsub sederhana sebagai abstraksi fanout pesan backend.
Berikut adalah hal -hal utama yang harus diizinkan oleh transportasi:
Kirim pesan dari server ke grup klien (berdasarkan satu string kriteria pertandingan penuh, alias pesan kamar).
Menerapkan komunikasi permintaan-reply dari klien ke server.
Menerapkan beberapa jenis koneksi persisten (atau setara secara semantik), diperlukan untuk pelacakan kehadiran.
Layanan obrolan menggunakan Redis sebagai toko bersama dengan kegigihan. Dalam aplikasi nyata, beberapa informasi ini mungkin diperlukan oleh layanan lain, tetapi tidak praktis untuk sepenuhnya mengimplementasikan toko negara. Pendekatan alternatif yang lebih baik adalah menggunakan kait. Misalnya, untuk menyimpan semua pesan kamar di dalam database lain hanya hook roomMessageAfter dapat digunakan. ServiceAPI juga dapat diekspos melalui bus pesan backend ke server internal lainnya.
Dalam keadaan normal, semua kesalahan yang dikembalikan ke pengguna layanan (melalui balasan permintaan, pesan loginConfirmed atau loginRejected ) adalah contoh ChatServiceError . Semua kesalahan lain menunjukkan bug program atau kegagalan dalam infrastruktur layanan. Untuk mengaktifkan pencatatan debug dari kesalahan tersebut, gunakan export NODE_DEBUG=ChatService . Perpustakaan menggunakan Bluebird ^3.0.0 menjanjikan implementasi, jadi untuk mengaktifkan jejak tumpukan panjang menggunakan export BLUEBIRD_DEBUG=1 . Sangat disarankan untuk menggunakan versi API Promise untuk kait dan subkelas ChatServiceError untuk mengembalikan kesalahan kustom kait.
Dokumentasi Sisi Sisi Server dan RPC tersedia secara online.
Layanan sepenuhnya mengabstraksi konsep koneksi dari konsep pengguna, sehingga satu pengguna dapat memiliki lebih dari satu koneksi (termasuk koneksi di berbagai node). Untuk kehadiran pengguna, jumlah soket yang bergabung harus lebih besar dari nol. Semua API yang dirancang untuk bekerja di tingkat pengguna, menangani beberapa koneksi pengguna yang mulus.
Koneksi sepenuhnya independen, tidak diperlukan dukungan sisi klien tambahan. Tetapi ada pesan dan perintah info yang dapat digunakan untuk mendapatkan informasi tentang koneksi pengguna lain. Dimungkinkan untuk mewujudkan pola sinkronisasi sisi klien, seperti menjaga semua koneksi untuk bergabung ke kamar yang sama.
Setiap kamar memiliki sistem izin. Ada satu pengguna pemilik tunggal, yang memiliki semua hak istimewa administrator dan dapat menugaskan pengguna ke grup administrator. Administrator dapat mengelola izin akses pengguna lain. Dua mode didukung: daftar hitam dan daftar putih. Setelah Modifikasi Daftar Akses/Mode, Layanan secara otomatis menghapus pengguna yang telah kehilangan izin akses.
Jika opsi enableRoomsManagement diaktifkan, pengguna dapat membuat kamar melalui perintah roomCreate . Pencipta ruangan akan menjadi pemiliknya dan juga dapat menghapusnya melalui perintah roomDelete .
Sebelum kait dapat digunakan untuk mengimplementasikan sistem izin tambahan.
Ketika pengguna mengirim pesan kamar, di RPC Balas id pesan dikembalikan. Ini berarti bahwa pesan tersebut telah disimpan di toko (dalam struktur yang hanya ditambahkan penyangga melingkar). ID pesan kamar adalah urutan mulai dari 1 , yang meningkat satu untuk setiap pesan yang berhasil dikirim di dalam ruangan. Klien selalu dapat memeriksa ID Pesan Kamar Terakhir melalui perintah roomHistoryInfo , dan menggunakan perintah roomHistoryGet untuk mendapatkan pesan yang hilang. Pendekatan semacam itu memastikan bahwa pesan dapat diterima, kecuali dihapus karena rotasi.
Secara default klien dapat mengirim pesan yang terbatas hanya pada {textMessage: 'Some string'} . Untuk mengaktifkan Format Pesan Kustom, menyediakan pengait directMessagesChecker atau roomMessagesChecker . Saat kait diselesaikan, format pesan diterima. Pesan dapat berupa data sewenang -wenang dengan beberapa batasan. Level atas harus menjadi Object , tanpa timestamp , author atau bidang id (layanan akan mengisi bidang ini sebelum mengirim pesan). Level bersarang dapat mencakup tipe data yang sewenang -wenang (bahkan biner), tetapi tidak ada objek bersarang dengan type lapangan yang diatur ke 'Buffer' (digunakan untuk manipulasi data biner).
Setiap perintah pengguna mendukung penambahan hook sebelum dan sesudah, dan kait koneksi/pemutusan klien juga didukung. Perintah dan kait dieksekusi secara berurutan: Sebelum Hook - Command - After Hook (itu akan dipanggil pada kesalahan perintah juga). Penghentian urutan di sebelum kait dimungkinkan. Klien dapat mengirim argumen perintah tambahan, kait dapat membacanya, dan membalas dengan argumen tambahan.
Untuk menjalankan execUserCommand Sisi Server Perintah Pengguna disediakan. Juga ada beberapa metode sisi server saja yang disediakan oleh ServiceAPI dan TransportInterface . Cari beberapa kasus penyesuaian dalam contoh kustomisasi.
Layanan membuat kehadiran pengguna dan data koneksi di toko, yang mungkin gigih atau dibagikan. Jadi, jika suatu instance tidak benar (tanpa menelepon atau menunggu metode close untuk menyelesaikan) atau kehilangan koneksi jaringan sepenuhnya ke toko, data keberadaan akan menjadi salah. Untuk memperbaiki kasus ini metode instanceRecovery disediakan.
Juga ada lebih banyak kasus halus mengenai konsistensi data yang bergantung pada koneksi. Instansi komunikasi transportasi dan instance menyimpan dapat mengalami berbagai jenis kegagalan jaringan, perangkat lunak atau perangkat keras. Dalam beberapa kasus tepi (seperti operasi pada beberapa pengguna) kegagalan seperti itu dapat menyebabkan ketidakkonsistenan (sebagian besar kesalahan akan dikembalikan ke penerbit perintah). Peristiwa ini dilaporkan melalui pemancar instan (seperti acara storeConsistencyFailure ), dan data dapat disinkronkan melalui metode RecoveryAPI .
Secara default setiap pengguna diasumsikan memiliki login unik (nama pengguna). Alih -alih mengelola pembuatan nama, integrasi dengan transportasi terpisah dapat digunakan (atau koneksi multiplexed, misalnya namespace socket.io lain). Pesan kamar dapat diteruskan dari roomMessage setelah kait ke transportasi, yang dapat diakses tanpa login. Dan sebaliknya beberapa perintah layanan dapat dieksekusi oleh pengguna anonim melalui execUserCommand dengan opsi izin bypass dihidupkan.
roomMessage demi kait juga dapat digunakan untuk meneruskan pesan dari satu ruangan ke ruang lainnya. Jadi kamar dapat digunakan untuk agregasi pesan dari kamar lain. Karena kait hanyalah fungsi dan memiliki akses penuh ke konten pesan, memungkinkan untuk mengimplementasikan aturan penerusan berbasis konten yang sewenang-wenang. Termasuk sistem implementasi dengan umpan spesifik pengguna (klien) yang sangat personal.
Secara default tidak ada cara bagi pengguna lain untuk mengetahui jumlah dan jenis koneksi pengguna yang bergabung ke sebuah ruangan. Informasi tersebut dapat dilewati, misalnya dalam string kueri dan kemudian disimpan melalui kait koneksi. Pengumuman ini dapat dibuat di onJoin dan onLeave Hooks, menggunakan metode langsung sendToChannel Transport. Juga informasi tambahan mengenai jenis perangkat yang bergabung harus dikirim dari roomGetAccessList setelah hook (ketika nama daftar sama dengan 'userlist' ).
Tidak ada operasi hapus atau edit, karena mereka akan membuat ketidakkonsistenan di dalam sejarah kamar. Alternatif umum untuk menghapus dan mengedit adalah dengan menggunakan pesan kamar dengan makna khusus yang akan digunakan klien untuk menyembunyikan atau mengubah pesan.
Jika Anda menemukan bug di paket ini, silakan kirim laporan bug ke masalah repo GitHub.
PR juga diterima.
Mit