ข้ามไปที่เนื้อหา

WebSocket API

ภาพรวม

WebSocket API ให้บริการการสื่อสารกับเซิร์ฟเวอร์ Socket เพื่อให้บริการแชท รองรับการเชื่อมต่อของไคลเอนต์เกม การส่งข้อความในช่องต่างๆ

ฟีเจอร์หลักของ WebSocket API มีดังนี้

  • การเชื่อมต่อ / ยกเลิกการเชื่อมต่อของลูกค้า
  • PING / PONG
  • การส่ง / รับข้อความแชท
    • แชทช่อง
    • แชท 1:1
  • การกรองผู้ใช้ที่ถูกบล็อก
    • ไม่ส่งข้อความไปยังผู้ใช้ที่ถูกบล็อก
    • ไม่รับข้อความจากผู้ใช้ที่ถูกบล็อก
  • การแจ้งเตือนเมื่อเข้าหรือออกจากช่อง

ข้อมูลพื้นฐาน

เมื่อใช้ WebSocket API จะมีข้อมูลพื้นฐานที่ต้องทราบโดยทั่วไป

คำศัพท์หลัก

  • ช่อง: ห้องแชท
  • ข้อความช่อง: ข้อความแชทที่ส่งไปยังผู้ใช้ทุกคนในช่องที่เข้าร่วม
  • ข้อความ 1:1: ข้อความแชทที่ส่งไปยังผู้ใช้เฉพาะ

ประเภทแพ็กเก็ต

ประเภทแพ็กเก็ตที่ส่งและรับกับเซิร์ฟเวอร์ Socket มีดังนี้

ชื่อแพ็กเก็ต คำอธิบาย
CONNECT การเชื่อมต่อกับเซิร์ฟเวอร์ Socket
RESPONSE_CONNECT การตอบสนองต่อคำขอ CONNECT
DISCONNECT การยกเลิกการเชื่อมต่อเซิร์ฟเวอร์ Socket
RESPONSE_DISCONNECT การตอบสนองต่อคำขอ DISCONNECT
PING การรักษาการเชื่อมต่อ
เมื่อคำขอ PING ถูกส่งในขณะที่การเชื่อมต่อ CONNECT ไม่สำเร็จ เซิร์ฟเวอร์จะยกเลิกการเชื่อมต่อ
PONG การตอบสนองต่อคำขอ PING
CHANNEL_CHAT การแชทในช่อง
RESPONSE_CHANNEL_CHAT การตอบสนองต่อคำขอ CHANNEL_CHAT
DIRECT_CHAT การแชทแบบ 1:1
RESPONSE_DIRECT_CHAT การตอบสนองต่อคำขอ DIRECT_CHAT
NOTIFY_ENTER_CHANNEL ข้อความเข้าช่อง
NOTIFY_EXIT_CHANNEL ข้อความออกจากช่อง
NOTIFY_DELETE_CHANNEL ข้อความลบช่อง
NOTIFY_CHANNEL_NOTICE ข้อความประกาศช่อง
NOTIFY_CHANNEL_CHAT ข้อความแชทในช่อง
NOTIFY_DIRECT_CHAT ข้อความแชทแบบ 1:1
NOTIFY_DISCONNECT ข้อความยกเลิกการเชื่อมต่อ
เมื่อการเชื่อมต่อ WebSocket อยู่ในสถานะ idle และรูปแบบ Json ไม่ถูกต้อง จะตอบสนองด้วยประเภทแพ็กเก็ตนี้

กระบวนการเชื่อมต่อ Socket

  1. ขอให้ส่งคำขอการออกโทเค็นผ่าน API Http ของการแชทจากเซิร์ฟเวอร์เกม ※ โทเค็นที่ออกจะถูกใช้ในการเชื่อมต่อกับเซิร์ฟเวอร์ Socket การแชท

  2. การขอเชื่อมต่อจากเกมไคลเอนต์ไปยังเซิร์ฟเวอร์ Socket

    • การสื่อสารด้วย WebSocket
    • ใช้โทเค็นที่ออกในขั้นตอนที่ 1
    • หากเชื่อมต่อสำเร็จ เซิร์ฟเวอร์ Socket จะส่งข้อมูลด้านล่างกลับ
    {
        "packetType":"RESPONSE_CONNECT",
        "status": 200,
        "message": "OK",
        "body":{
            "sessionId":"005056fffea3fd10-000400fd-00000797-f67881178d98d1cd-64ae9a76"
        }
    }
    

โครงสร้างการสื่อสารด้วยซ็อกเก็ต

  • JSON รูปแบบของประเภทแพ็คเกจที่เริ่มต้นด้วย 'RESPONSE_'

    {
            "packetType":"ประเภทแพ็คเกจ",
            "status":"รหัสสถานะ",
            "message":"ข้อความสถานะ",
            "body": JSON Object
    }
    

  • รูปแบบแพ็กเกจอื่น ๆ

    {
            "packetType":"ประเภทแพ็กเกจ",
            "body":{
                    //ข้อมูล JSON ตาม packetType
            }
    }
    

กรณีที่เซิร์ฟเวอร์ตัดการเชื่อมต่อ WebSocket มีดังนี้

  • หากไม่มีการร้องขอใด ๆ จากฝั่งไคลเอนต์เป็นเวลา 1 นาที
  • เมื่อไม่ใช่รูปแบบ JSON
  • เมื่อค่า status เป็น 401, 403
    • 401 unauthorized
    • 403 forbidden

รหัสการตอบกลับ

รหัสสถานะการตอบกลับ

รหัสสถานะ ข้อความสถานะ คำอธิบาย
200 สำเร็จ. สำเร็จ
400 การร้องขอที่ไม่ถูกต้อง การร้องขอที่ไม่ถูกต้อง
401 ไม่มีสิทธิ์ ไม่มีสิทธิ์
403 ห้าม ถูกปฏิเสธโดยเซิร์ฟเวอร์
408 หมดเวลาการร้องขอ ไม่มีการร้องขอจากไคลเอนต์เป็นเวลา 60 วินาที เซิร์ฟเวอร์จึงตัดการเชื่อมต่อ
409 ข้อขัดแย้ง การร้องขอของผู้ใช้ขัดแย้งกับสถานะของเซิร์ฟเวอร์ (เช่น เมื่อคู่สนทนาในแชท 1:1 ออฟไลน์)
500 ข้อผิดพลาดของเซิร์ฟเวอร์ภายใน ข้อผิดพลาดของเซิร์ฟเวอร์ภายใน

ฟังก์ชัน WebSocket API

อธิบายคำขอและการตอบกลับ API ตามฟังก์ชันของ WebSocket API ที่ใช้ในบริการแชท พร้อมตัวอย่างโค้ด

การเชื่อมต่อของลูกค้า

พารามิเตอร์คำขอ

ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่
packetType คำสั่งการเชื่อมต่อของไคลเอนต์ (CONNECT) สตริง Y
body ข้อมูลการร้องขอ อ็อบเจ็กต์ Y
พารามิเตอร์คำขอ > เนื้อหา
ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่ ตัวอย่าง
gameIndex ดัชนีเกม Hive integer Y e.g. 1
playerId รหัสบัญชี
Hive player ID
long Y e.g. 1234
loginKey โทเค็นที่ใช้ในการเข้าถึง
Chat Http API ที่ออกให้
string Y "eyJhbGciOiJIUzI1NiJ9.eyJnYW1lSW5kZXgiOjEsInBsYXllcklkIjoxMjM0LCJpYXQiOjE3MzAzNjY4MjksImV4cCI6MTczMDM3MDQyOX0.fpg6kqwqp1QN3KuYcjVBr8j0mzjN2doefJ_D6xFxcFY"
extraData ข้อมูลเพิ่มเติมของผู้ใช้ (UTF-8 기준)
(สูงสุด 256 Byte)
string N e.g. "{\"nickname\":\"Test1234\",\"guildname\":\"together\"}"

เนื้อหาการตอบกลับ

ชื่อฟิลด์ คำอธิบาย ประเภท ความจำเป็น
packetType การตอบกลับสำหรับคำขอการเชื่อมต่อ (RESPONSE_CONNECT) string Y
status รหัสสถานะ integer Y
message ข้อความสถานะ string Y
body ข้อมูลที่ส่งกลับ object Y
เนื้อหาการตอบกลับ > body
ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่ ตัวอย่าง
sessionId ค่าที่ส่งคืนเมื่อเชื่อมต่อสำเร็จ string Y e.g. "005056fffea3fd10-000400fd-00000797-f67881178d98d1cd-64ae9a76"

ตัวอย่างคำขอ

{
    "packetType": "CONNECT",
    "body":{
        "gameIndex":1,
        "playerId": 1234,
        "loginKey": JWT generated by API server,
                "extraData": Additional information
}

ตัวอย่างการตอบกลับ

{
    "packetType":"RESPONSE_CONNECT",
    "status": 200,
    "message":"OK",
    "body":{
        "sessionId":"005056fffea3fd10-000400fd-00000797-f67881178d98d1cd-64ae9a76"
    }
}

การตัดการเชื่อมต่อของไคลเอนต์

พารามิเตอร์การร้องขอ

ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่
packetType คำสั่งยกเลิกการเชื่อมต่อของไคลเอนต์ (DISCONNECT) string Y
body ข้อมูลการร้องขอ object Y
พารามิเตอร์การร้องขอ > เนื้อหา
ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่ ตัวอย่าง
sessionId sessionId ที่ส่งคืนเมื่อเชื่อมต่อสำเร็จ string N e.g. "6c2408fffe8c91a8-00002f24-00000032-093b757cdc668383-54b4fbc1"
  • หากไม่ได้กำหนด sessionId จะมีการจัดการการตัดการเชื่อมต่อสำหรับ sessionId ที่กำหนดให้กับ websocket
  • หากกำหนด sessionId จะมีการจัดการการตัดการเชื่อมต่อสำหรับค่าดังกล่าว

เนื้อหาการตอบกลับ

ชื่อฟิลด์ คำอธิบาย ประเภท ความจำเป็น
packetType การตอบสนองต่อคำขอการตัดการเชื่อมต่อ (RESPONSE_DISCONNECT) string Y
status รหัสสถานะ integer Y
message ข้อความสถานะ string Y

ตัวอย่างคำขอ

  • หากไม่ได้ระบุ sessionId

    {
            "packetType":"DISCONNET"
    }
    

  • หากระบุ sessionId

    {
            "packetType":"DISCONNECT",
            "body":{
                    "sessionId":"6c2408fffe8c91a8-00002f24-00000032-093b757cdc668383-54b4fbc1"
            }
    }
    

ตัวอย่างการตอบกลับ

{
    "packetType": "RESPONSE_DISCONNECT",
    "status": 200,
    "message":"OK"
}

PING / PONG

  • การร้องขอจะมีผลเฉพาะเมื่อเชื่อมต่อกับเซิร์ฟเวอร์ Socket และเสร็จสิ้นการเชื่อมต่อแล้ว
  • หากไม่มีการตอบกลับ PONG จำเป็นต้องเข้าสู่ระบบใหม่

พารามิเตอร์การร้องขอ

ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่
packetType คำสั่งขอ PING (PING) string Y

เนื้อหาการตอบกลับ

ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่
packetType คำสั่งตอบกลับ PONG (PONG) string Y

ตัวอย่างคำขอ

{
    "packetType":"PING"   
}

ตัวอย่างการตอบกลับ

{
    "packetType": "PONG"   
}

การส่งข้อความช่อง

พารามิเตอร์การร้องขอ

ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่
packetType คำสั่งส่งข้อความช่อง (CHANNEL_CHAT) string Y
body ข้อมูลการร้องขอ object Y
พารามิเตอร์การร้องขอ > เนื้อหา
ชื่อฟิลด์ คำอธิบาย ประเภท ความจำเป็น ตัวอย่าง
gameIndex ดัชนีเกม Hive integer Y e.g. 1
from ตัวระบุบัญชีที่ส่งข้อความไปยังช่อง
Hive player ID
long Y e.g. 1234
to ID ช่องที่จะส่งข้อความไปยังช่อง
API Http แชท ที่สร้าง
string Y e.g. "open:1"
message ข้อความที่จะส่งไปยังช่อง
(สูงสุด 200 ตัวอักษร)
string Y e.g. "Hello World!"
langCode รหัสภาษาของ Hive
(อิงตาม ISO 639 alpha-2 และภาษาที่ไม่แยกตาม ISO 639 alpha-2 จะต้องมีแท็ก Script เพื่อแยก)
string Y e.g. "en"

เนื้อหาการตอบกลับ

ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่
packetType การตอบกลับเกี่ยวกับการส่งข้อความช่อง (RESPONSE_CHANNEL_CHAT) string Y
status รหัสสถานะ integer Y
message ข้อความสถานะ string Y

ตัวอย่างคำขอ

{
    "packetType":"CHANNEL_CHAT",
    "body": {
        "gameIndex": 1,
        "from": 1234,
        "to": "open:1",
        "message": "Hello World!",
        "langCode": "en"
    }
}

ตัวอย่างการตอบกลับ

{
    "packetType": "RESPONSE_CHANNEL_CHAT",
    "status": 200,
    "message":"OK"
}

การส่งข้อความ 1:1

พารามิเตอร์คำขอ

ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่
packetType คำสั่งส่งข้อความ 1:1 (DIRECT_CHAT) string Y
body ข้อมูลการร้องขอ object Y
พารามิเตอร์การร้องขอ > เนื้อหา
ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่ ตัวอย่าง
gameIndex ดัชนีเกม Hive จำนวนเต็ม Y e.g. 1
from ตัวระบุบัญชีที่จะส่งข้อความ 1:1
Hive Player ID
ยาว Y e.g. 1234
to ตัวระบุบัญชีที่จะรับข้อความ 1:1
Hive Player ID
ยาว Y e.g. 2222
message ข้อความที่จะส่งแบบ 1:1
(สูงสุด 200 ตัวอักษร)
สตริง Y e.g. "Hello World!"
langCode รหัสภาษาของ Hive
(อิงจาก ISO 639 alpha-2 และสำหรับภาษาที่ไม่แยกตาม ISO 639 alpha-2 ให้ใช้ Script tag เพื่อแยก)
สตริง Y e.g. "en"

เนื้อหาการตอบกลับ

ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่
packetType การตอบกลับสำหรับการส่งข้อความ 1:1 (RESPONSE_DIRECT_CHAT) string Y
status รหัสสถานะ integer Y
message ข้อความสถานะ string Y
เนื้อหาการตอบกลับ > body
ชื่อฟิลด์ คำอธิบาย ประเภท ความจำเป็น ตัวอย่าง
status รหัสสถานะการตอบกลับ integer Y เช่น 200

ตัวอย่างคำขอ

{
  "packetType": "DIRECT_CHAT",
  "body": {
    "gameIndex": 1,
    "from": 2222,
    "to": 1234,
    "message": "안녕하세요",
    "langCode": "ko"
  }
}

ตัวอย่างการตอบกลับ

{
    "packetType": "RESPONSE_DIRECT_CHAT",
    "status": 200,
    "message":"OK"
}

ข้อความเหตุการณ์เซิร์ฟเวอร์ซ็อกเก็ต

เมื่อเกิดเหตุการณ์ จะอธิบายข้อความที่ส่งจาก Server ไปยัง Client

ข้อความนี้เริ่มต้นด้วย packetType เป็น NOTIFY

ข้อความเข้าช่อง

ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่
packetType ข้อความเข้าช่อง (NOTIFY_ENTER_CHANNEL) string Y
body ข้อมูลคำขอ object Y

เนื้อหา

ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่ ตัวอย่าง
gameIndex ดัชนีเกม Hive integer Y e.g. 1
channelId ID ช่องที่เข้าร่วม string Y e.g. "open:10"
playerId ตัวระบุบัญชีที่เข้าร่วมช่อง
ID ผู้เล่น Hive
long Y e.g. 1234
extraData ข้อมูลเพิ่มเติมของผู้ใช้ (UTF-8 기준)
(สูงสุด 256 Byte)
string Y e.g. "abcd"
timestamp วันที่และเวลาที่เข้าร่วมช่อง (UTC+0 기준, รูปแบบ yyyy-MM-dd'T'HH:mm:ss.SSSZ) string Y e.g. "2024-11-12T08:59:59.497Z"

ตัวอย่าง

{
  "packetType": "NOTIFY_ENTER_CHANNEL",
  "body": {
    "gameIndex": 1,
    "channelId": "open:10",
    "playerId": 1234,
    "extraData": "abcd",
    "timestamp": "2024-11-12T08:59:59.497Z"
  }
}

ข้อความออกจากช่อง

ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่
packetType ข้อความออกจากช่อง (NOTIFY_EXIT_CHANNEL) string ใช่
body ข้อมูลคำขอ object ใช่

เนื้อหา

ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่ ตัวอย่าง
gameIndex ดัชนีเกม Hive จำนวนเต็ม Y เช่น 1
channelId ID ช่องที่ออก สตริง Y เช่น "open:10"
playerId รหัสประจำตัวบัญชีที่ออกจากช่อง
รหัสผู้เล่น Hive
ยาว Y เช่น 2222
extraData ข้อมูลเพิ่มเติมของผู้ใช้ (UTF-8 기준)
(สูงสุด 256 ไบต์)
สตริง Y เช่น "abcd"
timestamp วันที่และเวลาที่ออกจากช่อง (UTC+0 기준, รูปแบบ yyyy-MM-dd'T'HH:mm:ss.SSSZ) สตริง Y เช่น "2024-11-12T08:59:59.497Z"

ตัวอย่าง

{
  "packetType": "NOTIFY_EXIT_CHANNEL",
  "body": {
    "gameIndex": 1,
    "channelId": "open:10",
    "playerId": 2222,
    "extraData": "abcd",
    "timestamp": "2024-11-12T09:29:35.872Z"
  }
}

ข้อความลบช่อง

ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่
packetType ข้อความลบช่อง (NOTIFY_DELETE_CHANNEL) string Y
body ข้อมูลการร้องขอ object Y

เนื้อหา

ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่ ตัวอย่าง
gameIndex ดัชนีเกม Hive จำนวนเต็ม Y e.g. 1
channelId รหัสช่องที่ถูกลบ สตริง Y e.g. "open:10"
timestamp วันที่และเวลาที่ลบช่อง (UTC+0 อิงตาม, รูปแบบ yyyy-MM-dd'T'HH:mm:ss.SSSZ) สตริง Y e.g. "2024-11-12T08:59:59.497Z"

ตัวอย่าง

{
  "packetType": "NOTIFY_DELETE_CHANNEL",
  "body": {
    "gameIndex": 1,
    "channelId": "owner:1",
    "timestamp": "2024-11-13T05:06:29.198Z"
  }
}

ข้อความประกาศช่อง

ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่
packetType ข้อความประกาศ (NOTIFY_CHANNEL_NOTICE) string Y
body ข้อมูลการร้องขอ object Y

เนื้อหา

ชื่อฟิลด์ คำอธิบาย ประเภท ความจำเป็น ตัวอย่าง
gameIndex ดัชนีเกม Hive จำนวนเต็ม Y เช่น 1
channelId ID ช่องที่ได้รับข้อความประกาศ สตริง N เช่น "open:10"
from ตัวระบุบัญชีที่ส่งข้อความประกาศ สตริง Y เช่น SYSTEM
message เนื้อหาข้อความประกาศ สตริง Y เช่น "นี่คือข้อความประกาศ."
timestamp วันที่และเวลาที่ส่งข้อความประกาศ (UTC+0 อิงตามรูปแบบ yyyy-MM-dd'T'HH:mm:ss.SSSZ) สตริง Y เช่น "2024-11-13T05:06:29.198Z"

ตัวอย่าง

// Announcement to specific channel
{
  "packetType": "NOTIFY_CHANNEL_NOTICE",
  "body": {
    "gameIndex": 1,
    "channelId": "open:10",
    "from": "SYSTEM",
    "message": "Notice message.",
    "timestamp": "2024-11-13T05:06:29.198Z"
  }
}

ข้อความช่อง

ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่
packetType ข้อความช่อง (NOTIFY_CHANNEL_CHAT) string Y
body ข้อมูลคำขอ object Y

เนื้อหา

ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่ ตัวอย่าง
gameIndex ดัชนีเกม Hive integer Y e.g. 1
from ตัวระบุบัญชีที่ส่งข้อความในช่อง
รหัสผู้เล่น Hive
long Y e.g. 2222
fromExtra ข้อมูลเพิ่มเติมของผู้ใช้ (UTF-8 기준)
(สูงสุด 256 Byte)
string Y e.g. "bbbb"
to รหัสช่องที่ส่งข้อความในช่อง string Y e.g. "open:10"
langCode รหัสภาษาของ Hive
(ตามมาตรฐาน ISO 639 alpha-2 และภาษาที่ไม่แยกตาม ISO 639 alpha-2 จะต้องมี Script tag เพื่อแยก)
string Y e.g. "ko"
timestamp วันที่และเวลาที่ส่งข้อความในช่อง (UTC+0 기준, yyyy-MM-dd'T'HH:mm:ss.SSSZ 형식) string Y e.g. "2024-11-13T05:12:18.385Z"

ตัวอย่าง

{
  "packetType": "NOTIFY_CHANNEL_CHAT",
  "body": {
    "gameIndex": 1,
    "from": 2222,
    "fromExtra": "bbbb",
    "to": "open:10",
    "message": "Hello World!",
    "langCode": "ko",
    "timestamp": "2024-11-13T05:12:18.385Z"
  }
}

1:1 ข้อความ

ชื่อฟิลด์ คำอธิบาย ประเภท จำเป็นหรือไม่
packetType ข้อความ 1:1 (NOTIFY_DIRECT_CHAT) string Y
body ข้อมูลการร้องขอ object Y

เนื้อหา

ชื่อฟิลด์ คำอธิบาย ประเภท ความจำเป็น ตัวอย่าง
gameIndex ดัชนีเกม Hive จำนวนเต็ม Y e.g. 1
from รหัสประจำตัวบัญชีที่ได้รับข้อความ 1:1
รหัสผู้เล่น Hive
ยาว Y e.g. 1234
fromExtra ข้อมูลเพิ่มเติมของผู้ใช้ (UTF-8 기준)
(สูงสุด 256 ไบต์)
สตริง Y e.g. "abcd"
to รหัสประจำตัวบัญชีที่ส่งข้อความ 1:1
รหัสผู้เล่น Hive
ยาว Y e.g. 2222
message เนื้อหาข้อความ 1:1 สตริง Y e.g. "สวัสดีครับ นี่คือการสนทนา 1:1"
langCode รหัสภาษาของ Hive
(อิงจาก ISO 639 alpha-2 และสำหรับภาษาที่ไม่แยกตาม ISO 639 alpha-2 ให้ใช้ Script tag แยก)
สตริง Y e.g. "ko"
timestamp วันที่และเวลาที่ส่งข้อความ 1:1 (UTC+0 기준, yyyy-MM-dd'T'HH:mm:ss.SSSZ 형식) สตริง Y e.g. "2024-11-13T05:12:50.060Z"

ตัวอย่าง

{
  "packetType": "NOTIFY_DIRECT_CHAT",
  "body": {
    "gameIndex": 1,
    "from": 1234,
    "fromExtra": "abcd",
    "to": 2222,
    "message": "안녕하세요. 1:1 채팅입니다.",
    "langCode": "ko",
    "timestamp": "2024-11-13T05:12:50.060Z"
  }
}