การใช้งานเซิร์ฟเวอร์การส่งข้อความถึงห้องพักที่ใช้โปรโตคอล RPC แบบสองทิศทางเพื่อใช้การสื่อสารที่คล้ายกับแชท ออกแบบมาเพื่อจัดการกับปัญหาการส่งข้อความเครือข่ายสาธารณะทั่วไปเช่นการส่งมอบที่เชื่อถือได้การเชื่อมต่อหลายครั้งจากผู้ใช้รายเดียวสิทธิ์และการแสดงตนแบบเรียลไทม์ การประมวลผลคำขอ RPC และรูปแบบข้อความห้องพักสามารถปรับแต่งได้ผ่าน hooks ช่วยให้สามารถใช้งานอะไรก็ได้จากเซิร์ฟเวอร์ห้องแชทไปจนถึงแอปพลิเคชันที่ทำงานร่วมกันด้วยการแก้ไขข้อขัดแย้งที่ซับซ้อน ข้อความห้องพักยังสามารถใช้เพื่อสร้าง API สาธารณะหรือเพื่อการสื่อสาร M2M Tunnel M2M สำหรับอุปกรณ์ IoT
การส่งข้อความห้องพักที่เชื่อถือได้โดยใช้ที่เก็บประวัติด้านเซิร์ฟเวอร์และ API การซิงโครไนซ์
รูปแบบข้อความโดยพลการผ่านฟังก์ชั่นการตรวจสอบความถูกต้อง (HOOK) ช่วยให้รูปแบบข้อความที่กำหนดเอง/ต่างกัน (รวมถึงข้อมูลไบนารีภายในข้อความ)
API ต่อหน้าผู้ใช้ต่อห้องพร้อมการแจ้งเตือน
การสร้างห้องแบบเรียลไทม์และ APIs การจัดการสิทธิ์การจัดการผู้ใช้ต่อห้อง รองรับโหมดการเข้าถึงบัญชีดำหรือโหมดการอนุญาตที่ได้รับการอนุญาตและกลุ่มผู้ดูแลระบบเสริม
การสนับสนุนอย่างราบรื่นของการเชื่อมต่อของผู้ใช้หลายคนจากการใช้งานที่หลากหลายไปจนถึงอินสแตนซ์บริการใด ๆ
เขียนเป็น microservice ไร้สัญชาติใช้ REDIS (ยังรองรับการกำหนดค่าคลัสเตอร์) เป็นร้านค้าของรัฐสามารถปรับขนาดในแนวนอนตามความต้องการ
การสนับสนุนการปรับแต่งอย่างกว้างขวาง ฟังก์ชั่นที่กำหนดเองสามารถเพิ่มผ่าน hooks ก่อน/หลังสำหรับการประมวลผลคำขอไคลเอนต์ใด ๆ และคำขอ (คำสั่ง) ตัวจัดการสามารถเรียกใช้ฝั่งเซิร์ฟเวอร์ผ่าน API
การขนส่งเครือข่ายปลั๊กอิน การสื่อสารของลูกค้า-เซิร์ฟเวอร์ทำได้ผ่านโปรโตคอล RPC แบบสองทิศทาง Socket.io มีการใช้งานการขนส่ง
ปลั๊กอินสเตตสโตร์ มีการรวมหน่วยความจำและ redis
รองรับผู้ใช้ออนไลน์ที่มีน้ำหนักเบาในการส่งข้อความผู้ใช้ออนไลน์
อ่านบทความนี้สำหรับข้อมูลพื้นหลังเพิ่มเติม
โครงการนี้เป็นโมดูลโหนดที่มีให้ผ่าน NPM ไปตรวจสอบพวกเขาหากคุณไม่ได้ติดตั้งในเครื่อง
$ npm i chat-serviceก่อนกำหนดการกำหนดค่าเซิร์ฟเวอร์ บนฝั่งเซิร์ฟเวอร์กำหนดเบ็ดการเชื่อมต่อซ็อกเก็ตเนื่องจากบริการนั้นใช้การใช้งานการรับรองความถูกต้องภายนอก ผู้ใช้เพียงแค่ต้องผ่านการตรวจสอบความถูกต้องไม่จำเป็นต้องมีขั้นตอนการเพิ่มผู้ใช้อย่างชัดเจน
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 )
} การสร้างเซิร์ฟเวอร์เป็นอินสแตนซ์ของวัตถุอย่างง่าย หมายเหตุ: วิธี close จะต้อง ถูกเรียกให้ปิดอินสแตนซ์บริการอย่างถูกต้อง (ดูการกู้คืนความล้มเหลว)
const chatService = new ChatService ( { port } , { onConnect } )
process . on ( 'SIGINT' , ( ) => chatService . close ( ) . finally ( ( ) => process . exit ( ) ) ) เซิร์ฟเวอร์กำลังทำงานบนพอร์ต 8000 โดยใช้สถานะหน่วย memory โดยค่าเริ่มต้น '/chat-service' socket.io เนมสเปซใช้ เพิ่มห้องกับผู้ใช้ admin เป็นเจ้าของห้อง ห้องพักทุกห้องจะต้องสร้างขึ้นอย่างชัดเจน (ตัวเลือกเพื่ออนุญาตให้มีการสร้างห้องพักจากฝั่งไคลเอ็นต์ด้วย)
// 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' } )
}
} ) บนไคลเอนต์เพียงแค่การใช้งาน socket.io-client จะต้องใช้ ในการส่งคำขอ (คำสั่ง) ใช้เมธอด emit ผลลัพธ์ (หรือข้อผิดพลาด) จะถูกส่งกลับใน Socket.io ACK Callback หากต้องการฟังข้อความเซิร์ฟเวอร์ใช้ on
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 )
} ) มันเป็นรหัสที่เรียกใช้ได้ไฟล์อยู่ในไดเรกทอรี example
เป็นไปได้ที่จะใช้การขนส่งอื่น ๆ นอกเหนือจาก socket.io มีหลักฐานการขนส่งแนวคิดที่ใช้การเชื่อมต่อ WebSocket กับ API Abstraction Layer WS-Messaging และ Emitter-Pubsub-Broker อย่างง่าย
นี่คือสิ่งสำคัญที่การขนส่งต้องอนุญาตให้ทำ:
ส่งข้อความจากเซิร์ฟเวอร์ไปยังกลุ่มไคลเอนต์ (ขึ้นอยู่กับเกณฑ์การจับคู่แบบเต็มสตริงเดียว AKA Room Messaging)
ใช้การสื่อสารแบบขอแนะนำจากไคลเอนต์ไปยังเซิร์ฟเวอร์
ใช้การเชื่อมต่อแบบถาวร (หรือเทียบเท่าความหมาย) จำเป็นสำหรับการติดตามการแสดงตน
บริการแชทกำลังใช้ Redis เป็นร้านค้าที่ใช้ร่วมกันด้วยความเพียร ในแอปพลิเคชั่นจริงข้อมูลบางอย่างนี้อาจจำเป็นสำหรับบริการอื่น ๆ แต่ก็ไม่สามารถนำเสนอร้านค้าของรัฐได้อย่างเต็มที่ ทางเลือกที่ดีกว่าคือการใช้ตะขอ ตัวอย่างเช่นเพื่อบันทึกข้อความห้องทั้งหมดภายในฐานข้อมูลอื่นเพียงแค่เบ็ด roomMessageAfter หลังจากนั้นสามารถใช้งานได้ นอกจากนี้ ServiceAPI ยังสามารถเปิดเผยได้ผ่านรถบัสส่งข้อความแบ็กเอนด์ไปยังเซิร์ฟเวอร์ภายในอื่น ๆ
ภายใต้สถานการณ์ปกติข้อผิดพลาดทั้งหมดที่ถูกส่งกลับไปยังผู้ใช้บริการ (ผ่านการตอบกลับคำขอข้อความ loginConfirmed หรือ loginRejected ) เป็นอินสแตนซ์ของ ChatServiceError ข้อผิดพลาดอื่น ๆ ทั้งหมดระบุข้อผิดพลาดของโปรแกรมหรือความล้มเหลวในโครงสร้างพื้นฐานบริการ ในการเปิดใช้งานการบันทึกข้อผิดพลาดของข้อผิดพลาดดังกล่าวให้ใช้ export NODE_DEBUG=ChatService ห้องสมุดกำลังใช้บลูเบิร์ด ^3.0.0 สัญญาการใช้งานดังนั้นเพื่อให้สามารถใช้ร่องรอยสแต็กยาวได้ให้ใช้ export BLUEBIRD_DEBUG=1 ขอแนะนำอย่างยิ่งให้ใช้ API รุ่นสัญญาสำหรับ Hooks และ ChatServiceError subclasses สำหรับการส่งคืนข้อผิดพลาดที่กำหนดเอง
Server Side API และเอกสาร RPC พร้อมใช้งานออนไลน์
บริการสรุปแนวคิดการเชื่อมต่ออย่างสมบูรณ์จากแนวคิดผู้ใช้ดังนั้นผู้ใช้รายเดียวสามารถมีการเชื่อมต่อได้มากกว่าหนึ่งครั้ง (รวมถึงการเชื่อมต่อข้ามโหนดที่แตกต่างกัน) สำหรับสถานะของผู้ใช้จำนวนซ็อกเก็ตที่เข้าร่วมจะต้องมากกว่าศูนย์ API ทั้งหมดที่ออกแบบมาเพื่อทำงานในระดับผู้ใช้จัดการการเชื่อมต่อที่หลากหลายของผู้ใช้อย่างราบรื่น
การเชื่อมต่อมีความเป็นอิสระอย่างสมบูรณ์ไม่จำเป็นต้องมีการสนับสนุนด้านลูกค้าเพิ่มเติม แต่มีข้อความและคำสั่งข้อมูลที่สามารถใช้เพื่อรับข้อมูลเกี่ยวกับการเชื่อมต่อของผู้ใช้รายอื่น มันทำให้เป็นไปได้ที่จะตระหนักถึงรูปแบบการซิงค์ฝั่งไคลเอ็นต์เช่นการทำให้การเชื่อมต่อทั้งหมดเข้าร่วมกับห้องเดียวกัน
แต่ละห้องมีระบบการอนุญาต มีผู้ใช้เจ้าของรายเดียวที่มีสิทธิ์ผู้ดูแลระบบทั้งหมดและสามารถกำหนดผู้ใช้ให้กับกลุ่มผู้ดูแลระบบ ผู้ดูแลระบบสามารถจัดการสิทธิ์การเข้าถึงของผู้ใช้รายอื่น รองรับสองโหมด: Blacklist และ Whitelist หลังจากการปรับเปลี่ยนรายการ/โหมดการเข้าถึงบริการจะลบผู้ใช้ที่สูญเสียสิทธิ์การเข้าถึงโดยอัตโนมัติ
หากตัวเลือก enableRoomsManagement เปิดใช้งานผู้ใช้สามารถสร้างห้องพักผ่านคำสั่ง roomCreate ผู้สร้างห้องจะเป็นเจ้าของและยังสามารถลบออกผ่านคำสั่ง roomDelete
ก่อนที่จะใช้ตะขอเพื่อใช้ระบบการอนุญาตเพิ่มเติม
เมื่อผู้ใช้ส่งข้อความห้องใน RPC ตอบกลับ id ข้อความจะถูกส่งคืน หมายความว่าข้อความได้รับการบันทึกไว้ในร้านค้า (ในผนวกเฉพาะบัฟเฟอร์แบบวงกลมเช่นโครงสร้าง) รหัสข้อความห้องพักเป็นลำดับที่เริ่มต้นจาก 1 ซึ่งเพิ่มขึ้นหนึ่งรายการสำหรับแต่ละข้อความที่ส่งข้อความที่ประสบความสำเร็จในห้อง ไคลเอนต์สามารถตรวจสอบรหัสข้อความห้องสุดท้ายผ่านคำสั่ง roomHistoryInfo และใช้คำสั่ง roomHistoryGet เพื่อรับข้อความที่หายไป วิธีการดังกล่าวทำให้มั่นใจได้ว่าสามารถรับข้อความได้เว้นแต่จะถูกลบเนื่องจากการหมุน
โดยค่าเริ่มต้นไคลเอนต์สามารถส่งข้อความที่ จำกัด เพียงแค่ {textMessage: 'Some string'} ในการเปิดใช้งานรูปแบบข้อความที่กำหนดเองให้ directMessagesChecker หรือ Hooks Hooks roomMessagesChecker เมื่อตะขอแก้ไขรูปแบบข้อความจะได้รับการยอมรับ ข้อความสามารถเป็นข้อมูลโดยพลการโดยมีข้อ จำกัด เล็กน้อย ระดับบนสุดจะต้องเป็น Object โดยไม่มี timestamp author หรือฟิลด์ id (บริการจะเติมเต็มฟิลด์นี้ก่อนส่งข้อความ) ระดับที่ซ้อนกันอาจรวมถึงชนิดข้อมูลโดยพลการ (แม้แต่ไบนารี) แต่ไม่มีวัตถุซ้อนกันที่มี type ฟิลด์ที่ตั้งค่าเป็น 'Buffer' (ใช้สำหรับการจัดการข้อมูลไบนารี)
คำสั่งผู้ใช้แต่ละคนรองรับก่อนและหลังการเพิ่มตะขอและรองรับการเชื่อมต่อไคลเอนต์/การเชื่อมต่อของไคลเอนต์ก็รองรับได้เช่นกัน คำสั่งและตะขอจะถูกดำเนินการตามลำดับ: ก่อนที่จะขอคำสั่ง - หลังจากเบ็ด (มันจะถูกเรียกใช้ข้อผิดพลาดคำสั่งด้วย) การยกเลิกลำดับก่อนที่จะเป็นไปได้ ลูกค้าสามารถส่งอาร์กิวเมนต์คำสั่งเพิ่มเติมตะขอสามารถอ่านและตอบกลับพร้อมอาร์กิวเมนต์เพิ่มเติม
ในการเรียกใช้งาน execUserCommand ด้านเซิร์ฟเวอร์คำสั่งผู้ใช้ นอกจากนี้ยังมีวิธีการทางเซิร์ฟเวอร์เพิ่มเติมเพียงอย่างเดียวโดย ServiceAPI และ TransportInterface มองหากรณีการปรับแต่งบางอย่างในตัวอย่างการปรับแต่ง
บริการช่วยให้ข้อมูลผู้ใช้และข้อมูลการเชื่อมต่อในร้านค้าซึ่งอาจคงอยู่หรือแชร์ ดังนั้นหากอินสแตนซ์ถูกปิดอย่างไม่ถูกต้อง (โดยไม่ต้องโทรหรือรอให้วิธี close เสร็จ) หรือสูญเสียการเชื่อมต่อเครือข่ายอย่างสมบูรณ์ไปยังร้านค้าข้อมูลสถานะจะไม่ถูกต้อง เพื่อแก้ไขกรณีนี้มีวิธี instanceRecovery
นอกจากนี้ยังมีกรณีที่ละเอียดยิ่งขึ้นเกี่ยวกับความสอดคล้องของข้อมูลที่ขึ้นกับการเชื่อมต่อ อินสแตนซ์การสื่อสารการขนส่งและอินสแตนซ์ของร้านค้าสามารถสัมผัสกับความล้มเหลวของเครือข่ายซอฟต์แวร์หรือฮาร์ดแวร์ประเภทต่างๆ ในบางกรณี (เช่นการดำเนินการกับผู้ใช้หลายคน) ความล้มเหลวดังกล่าวอาจทำให้เกิดความไม่สอดคล้องกัน (สำหรับข้อผิดพลาดส่วนใหญ่จะถูกส่งกลับไปยังผู้ออกคำสั่ง) เหตุการณ์เหล่านี้ได้รับการรายงานผ่านตัวส่งสัญญาณอินสแตนซ์ (เช่นเหตุการณ์ storeConsistencyFailure ) และข้อมูลสามารถซิงค์ผ่านวิธีการ RecoveryAPI
โดยค่าเริ่มต้นผู้ใช้ทุกคนจะถือว่ามีการเข้าสู่ระบบที่ไม่ซ้ำกัน (ชื่อผู้ใช้) แทนที่จะจัดการการสร้างชื่อการรวมเข้ากับการขนส่งแยกต่างหากสามารถใช้งานได้ (หรือการเชื่อมต่อแบบมัลติเพล็กซ์เช่นซ็อกเก็ตอื่นเนมสเปซ) ข้อความห้องพักสามารถส่งต่อจาก roomMessage หลังจากขอการขนส่งซึ่งสามารถเข้าถึงได้โดยไม่ต้องเข้าสู่ระบบ และในทางกลับกันคำสั่งบริการบางอย่างสามารถดำเนินการโดยผู้ใช้ที่ไม่ระบุชื่อผ่าน execUserCommand ด้วยตัวเลือกการผ่านการอนุญาตที่เปิดใช้งาน
สามารถใช้ roomMessage หลังจาก Hook เพื่อส่งต่อข้อความจากห้องหนึ่งไปยังอีกห้องหนึ่ง ดังนั้นห้องพักสามารถใช้สำหรับการรวมข้อความจากห้องอื่น เนื่องจากตะขอเป็นเพียงฟังก์ชั่นและมีการเข้าถึงเนื้อหาข้อความอย่างเต็มที่จึงอนุญาตให้ใช้กฎการส่งต่อตามเนื้อหาโดยพลการ รวมถึงระบบการใช้งานด้วยฟีดเฉพาะผู้ใช้ (ไคลเอนต์) ที่เป็นส่วนตัวสูง
โดยค่าเริ่มต้นไม่มีทางที่ผู้ใช้รายอื่นจะทราบจำนวนและประเภทของการเชื่อมต่อผู้ใช้ที่เข้าร่วมกับห้อง ข้อมูลดังกล่าวสามารถส่งผ่านตัวอย่างในสตริงการสืบค้นแล้วบันทึกผ่านตะขอเชื่อมต่อ การประกาศสามารถทำได้ใน onJoin และ onLeave hooks โดยใช้วิธีการขนส่งโดยตรง sendToChannel นอกจากนี้ข้อมูลเพิ่มเติมเกี่ยวกับประเภทอุปกรณ์ที่เข้าร่วมควรถูกส่งจาก roomGetAccessList หลังจาก Hook (เมื่อชื่อรายการเท่ากับ 'userlist' )
ไม่มีการลบหรือแก้ไขการดำเนินการเนื่องจากพวกเขาจะสร้างความไม่สอดคล้องกันภายในประวัติห้อง ทางเลือกทั่วไปสำหรับการลบและแก้ไขคือการใช้ข้อความห้องที่มีความหมายพิเศษที่ลูกค้าจะใช้เพื่อซ่อนหรือแก้ไขข้อความ
หากคุณพบข้อผิดพลาดในแพ็คเกจนี้โปรดส่งรายงานข้อผิดพลาดไปยังปัญหา Repo ของ GitHub
PRS ได้รับการยอมรับเช่นกัน
มิกซ์