انتقل إلى المحتوى الرئيسي

SMSc - تطبيق مركز خدمة الرسائل القصيرة

تطبيق مركز الرسائل القصيرة مبني باستخدام Phoenix/Elixir، يوفر قائمة رسائل مركزية وواجهة برمجة تطبيقات REST لتوجيه الرسائل القصيرة وتسليمها.

الوثائق

الوثائق الأساسية

وثائق الامتثال

الأداء

نظرة عامة على المعمارية

يوفر SMS_C Core قائمة رسائل غير مرتبطة بالبروتوكول وواجهة برمجة تطبيقات REST. تتصل واجهات SMSC الخارجية (SMPP، IMS، SS7/MAP) كبوابات مستقلة تتواصل مع النواة عبر واجهة برمجة تطبيقات REST.

تدفق الرسائل

تدفق الرسائل الصادرة (MT - موجهة إلى الهاتف المحمول)

تدفق الرسائل الواردة (MO - منشأ من الهاتف المحمول)

الميزات الرئيسية

1. تصميم غير مرتبط بالبروتوكول

  • يتولى SMS_C Core إدارة استمرارية الرسائل، والتوجيه، وواجهة برمجة التطبيقات
  • تتولى الواجهات الخارجية (SMPP، IMS، SS7/MAP) التواصل المحدد بالبروتوكول
  • تتواصل جميع الواجهات عبر واجهة برمجة تطبيقات REST موحدة
  • إضافة بروتوكولات جديدة دون تغيير النواة
  • يمكن توسيع كل منها بشكل مستقل

2. توجيه الرسائل

  • محرك توجيه ديناميكي مع تكوين في وقت التشغيل
  • توجيه قائم على البادئات (الأرقام المتصلة/المتلقاة)
  • تصفية نوع SMSC والمصدر (IMS/الدائرة المتصلة/SMPP)
  • توجيه قائم على الأولوية مع توازن الحمل القائم على الوزن
  • قدرات توجيه الرد التلقائي وإسقاط الرسائل
  • التحكم في الشحن لكل مسار
  • واجهة ويب لإدارة المسارات
  • تحديثات المسار في الوقت الحقيقي دون انقطاع الخدمة

📖 انظر دليل توجيه الرسائل القصيرة للحصول على وثائق شاملة

3. منطق إعادة المحاولة مع التراجع الأسي

  • إعادة المحاولة التلقائية عند فشل التسليم
  • التراجع الأسي: 1 دقيقة، 2 دقيقة، 4 دقائق، 8 دقائق، إلخ.
  • عدد محاولات إعادة المحاولة الأقصى القابل للتكوين
  • معالجة انتهاء صلاحية الرسائل
  • تتبع إعادة المحاولة لكل رسالة

دليل العمليات

نقاط الوصول:

  • واجهة برمجة التطبيقات REST: https://localhost:8443 (أو http://localhost:8080 بدون TLS)
  • لوحة التحكم: https://localhost:8086
  • وثائق API (Swagger UI): https://localhost:8443/api/docs

بدء الواجهات الخارجية: كل واجهة بروتوكول هي تطبيق مستقل. انظر وثائق الواجهة الفردية للحصول على تعليمات بدء التشغيل.

التكوين

يتم إدارة جميع التكوينات مباشرة في config/runtime.exs. لا يتم استخدام متغيرات البيئة.

تكوين النواة

لا يتم استخدام متغيرات البيئة لتكوين ��طبيق النواة حاليًا. يتم تكوين منافذ الخادم وأسماء المضيفين في config/runtime.exs:

  • خادم API: المنفذ 8443 (HTTPS)، يستمع على 0.0.0.0
  • لوحة التحكم: المنفذ 80 (HTTP)، تستمع على 0.0.0.0

تكوين قاعدة البيانات

يتم تكوين إعدادات قاعدة البيانات في config/runtime.exs:

  • اسم المستخدم: omnitouch
  • كلمة المرور: omnitouch2024
  • اسم المضيف: localhost
  • المنفذ: 3306
  • اسم قاعدة البيانات: smsc_new
  • حجم المجموعة: 1

تكوين العنقود

يتم تكوين إعدادات العنقود في config/runtime.exs:

  • عقد العنقود: "" (فارغ - لا يوجد عنقود بشكل افتراضي)
  • استعلام DNS للعنقود: nil

تكوين قائمة الرسائل

يتم تكوين إعدادات قائمة الرسائل في config/runtime.exs:

  • وقت الرسالة الميتة: 1440 دقيقة (24 ساعة قبل انتهاء صلاحية الرسالة)

تكامل الشحن

يتم تكوين إعدادات الشحن في config/runtime.exs:

  • URL: http://localhost:2080/jsonrpc
  • المستأجر: mnc057.mcc505.3gppnetwork.org
  • الوجهة: 55512341234
  • المصدر: 00101900000257
  • الموضوع: 00101900000257
  • الحساب: 00101900000257

تكوين توجيه الرسائل القصيرة

يستخدم نظام توجيه الرسائل القصيرة مسارات ديناميكية مدعومة بقاعدة البيانات يمكن إدارتها عبر واجهة الويب أو ملف التكوين. يتم تحميل المسارات من config/runtime.exs عند بدء التشغيل الأول.

مثال على التكوين:

config :sms_c, :sms_routes, [
%{
called_prefix: "+44",
dest_smsc: "InternationalGW",
weight: 100,
priority: 100,
description: "UK International SMS",
enabled: true
},
%{
called_prefix: "1900",
dest_smsc: "PremiumGW",
charged: :yes,
priority: 50,
description: "US Premium Numbers",
enabled: true
}
]

الميزات:

  • المطابقة القائمة على البادئات (الأرقام المتصلة/المتلقاة)
  • تصفية SMSC المصدر والنوع
  • توجيه قائم على الأولوية والوزن
  • قدرات الرد التلقائي والإسقاط
  • التحكم في الشحن لكل مسار
  • الإدارة في وقت التشغيل عبر واجهة الويب في /routing

📖 انظر دليل توجيه الرسائل القصيرة للحصول على وثائق كاملة، وأمثلة، ومرجع API.

نقاط نهاية واجهة برمجة التطبيقات REST

عمليات قائمة الرسائل

إرسال رسالة قصيرة (إنشاء رسالة)

POST /api/messages
Content-Type: application/json

{
"source_msisdn": "+1234567890",
"destination_msisdn": "+0987654321",
"message_body": "Hello, World!",
"source_smsc": "web-app",
"dest_smsc": "smpp-provider", # اختياري - يتم تعيينه بواسطة محرك التوجيه إذا كان فارغًا
"tp_dcs_character_set": "gsm7", # اختياري: gsm7، 8bit، latin1، ucs2
"tp_dcs_coding_group": "general_data_coding",
"expires": "2025-10-17T10:30:00Z" # اختياري - الافتراضي هو 24 ساعة من الآن
}

الحقول المطلوبة:

  • destination_msisdn - رقم الهاتف الوجهة
  • message_body - محتوى نص الرسالة
  • source_msisdn - رقم الهاتف المصدر
  • source_smsc - معرف النظام المصدر

الحقول الاختيارية:

  • dest_smsc - بوابة الوجهة (يتم تعيينها بواس��ة محرك التوجيه إذا لم يتم توفيرها)
  • source_imsi، dest_imsi - معرفات IMSI
  • tp_dcs_character_set - ترميز الأحرف (gsm7، 8bit، latin1، ucs2)
  • tp_dcs_coding_group - مجموعة ترميز DCS
  • tp_dcs_compressed - علامة الضغط (boolean)
  • tp_dcs_has_message_class - علامة فئة الرسالة (boolean)
  • tp_dcs_message_class - قيمة فئة الرسالة
  • tp_user_data_header - رأس بيانات المستخدم (خريطة)
  • message_part_number، message_parts - حقول الرسالة متعددة الأجزاء
  • expires - طابع انتهاء الصلاحية (الافتراضي هو 24 ساعة)
  • deliver_after - طابع تسليم مؤجل
  • deadletter، raw_data_flag، raw_sip_flag - علامات boolean

الاستجابة:

{
"status": "success",
"data": {
"id": 123,
"source_msisdn": "+1234567890",
"destination_msisdn": "+0987654321",
"dest_smsc": "smpp-provider",
"message_body": "Hello, World!",
"deliver_time": null,
"delivery_attempts": 0,
"expires": "2025-10-17T10:30:00Z",
"inserted_at": "2025-10-16T10:30:00Z"
}
}

الحصول على الرسائل لـ SMSC

GET /api/messages/get_by_smsc?smsc=my-smsc-name

يعيد جميع الرسائل غير المرسلة حيث:

  • destination_smsc فارغ أو يتطابق مع اسم SMSC المقدم
  • الرسالة غير منتهية الصلاحية
  • جاهزة للإرسال (deliver_after فارغ أو في الماضي)

الاستجابة:

{
"status": "success",
"data": [
{
"id": 123,
"source_msisdn": "+1234567890",
"destination_msisdn": "+0987654321",
"message_body": "Hello",
"destination_smsc": "my-smsc-name",
"delivery_attempts": 0
}
]
}

قائمة الرسائل مع تصفية SMSC الاختيارية

# قائمة بجميع الرسائل في القائمة
GET /api/messages

# قائمة الرسائل لـ SMSC محدد (مع تصفية الرأس)
GET /api/messages
SMSc: my-smsc-name

بدون رأس SMSc: يعيد جميع الرسائل في القائمة بغض النظر عن حالة التسليم أو انتهاء الصلاحية.

مع رأس SMSc: يعيد الرسائل غير المرسلة حيث:

  • dest_smsc يتطابق مع قيمة الرأس أو dest_smsc فارغ
  • deliver_time فارغ (لم يتم تسليمه بعد)
  • deliver_after فارغ أو قبل/يساوي الوقت الحالي (جاهز للتسليم)
  • expires بعد الوقت الحالي (لم تنتهي صلاحيتها)
  • مرتبة حسب وقت الإدراج (الأقدم أولاً)

ملاحظة: يسمح نهج رأس SMSc للواجهات الخارجية بالاستعلام عن رسائلها باستخدام نفس نمط نقطة النهاية، مع التحكم في سلوك التصفية عبر الرأس.

الاستجابة:

[
{
"id": 123,
"source_msisdn": "+1234567890",
"destination_msisdn": "+0987654321",
"message_body": "Hello, World!",
"dest_smsc": "my-smsc-name",
"deliver_time": null,
"delivery_attempts": 0,
"expires": "2025-10-17T10:30:00Z",
"inserted_at": "2025-10-16T10:30:00Z"
}
]

الحصول على رسالة واحدة

GET /api/messages/{id}

تحديث الرسالة

PATCH /api/messages/{id}
Content-Type: application/json

{
"status": "delivered",
"delivered_at": "2025-10-16T10:30:00Z"
}

حذف رسالة قصيرة

DELETE /api/messages/{id}

التعامل مع فشل التسليم (زيادة عداد إعادة المحاولة)

عند فشل تسليم رسالة مؤقتًا، قم بزيادة عداد محاولة التسليم وجدولة إعادة المحاولة مع التراجع الأسي.

الطريقة 1: باستخدام PUT (موصى بها)

# بسيطة ودلالية - PUT تشير إلى تحديث حالة التسليم
PUT /api/messages/{id}

الطريقة 2: باستخدام نقطة نهاية صريحة

# نقطة نهاية بديلة صريحة
POST /api/messages/{id}/increment_delivery_attempt

تقوم كلا الطريقتين بزيادة delivery_attempts وتعيين تأخير التراجع الأسي عبر deliver_after:

المحاولةصيغة التراجعالتأخيرالوقت الكلي
1st2^1 دقائق2 دقيقة2 دقيقة
2nd2^2 دقائق4 دقائق6 دقائق
3rd2^3 دقائق8 دقائق14 دقيقة
4th2^4 دقائق16 دقيقة30 دقيقة
5th2^5 دقائق32 دقيقة1h 2min
6th2^6 دقائق64 دقيقة2h 6min

الاستجابة:

{
"id": 123,
"delivery_attempts": 1,
"deliver_after": "2025-10-20T19:05:00Z",
"deliver_time": null,
"expires": "2025-10-21T19:03:00Z",
...
}

ملاحظة: يتم تصفية الرسائل التي تحتوي على deliver_after في المستقبل تلقائيًا من طلبات GET حتى تنتهي فترة التراجع.

تحديث الرسالة (تحديث جزئي)

لتحديث حقول رسالة معينة (سلوك غير متغير):

PATCH /api/messages/{id}
Content-Type: application/json

{
"dest_smsc": "updated-gateway",
"status": "delivered"
}

مهم: تتصرف PUT و PATCH بشكل مختلف:

  • PUT → يزيد من محاولات التسليم مع التراجع (لا يتطلب جسمًا)
  • PATCH → يقوم بتحديث جزئي للحقول (يتطلب جسمًا)

تتبع صحة الواجهة الأمامية

يتتبع SMS_C Core صحة وتوافر الواجهات الأمامية الخارجية من خلال نظام تسجيل. يتيح ذلك مراقبة وقت تشغيل الواجهة الأمامية، واكتشاف الفشل، والحفاظ على بيانات التوافر التاريخية.

ملاحظة: لا يتم استخدام تسجيل الواجهة الأمامية لتسليم الرسائل أو توجيهها. يتم توجيه الرسائل بناءً على حقل dest_smsc. يوجد نظام التسجيل فقط لمراقبة الصحة والرؤية التشغيلية.

كيفية عمل تسجيل الواجهة الأمامية

ترسل كل واجهة أمام��ة خارجية (بوابة SMPP، IMS، SS7/MAP) بشكل دوري تسجيل نبضات القلب إلى SMS_C Core:

  1. فترة نبض القلب: يجب على الواجهات الأمامية التسجيل كل 30-60 ثانية
  2. وقت انتهاء الصلاحية: تنتهي صلاحية التسجيلات بعد 90 ثانية دون تحديث
  3. إدارة الحالة التلقائية:
    • تنشئ الواجهات الأمامية الجديدة سجل تسجيل جديد
    • تقوم الواجهات الأمامية النشطة الموجودة بتحديث تسجيلها (تمديد انتهاء الصلاحية)
    • تقوم الواجهات الأمامية المنتهية صلاحيتها التي تعود إلى الإنترنت بإنشاء فترة تسجيل جديدة

نقاط نهاية تسجيل الواجهة الأمامية

تسجيل/تحديث الواجهة الأمامية (نبض القلب)
POST /api/frontends
Content-Type: application/json

{
"frontend_name": "smpp-gateway-1",
"frontend_type": "SMPP",
"ip_address": "10.0.1.5",
"hostname": "smpp-gw-01",
"uptime_seconds": 3600,
"configuration": "{\"port\": 2775, \"system_id\": \"smpp_user\"}"
}

الحقول المطلوبة:

  • frontend_name - معرف فريد لحالة الواجهة الأمامية
  • frontend_type - نوع الواجهة الأمامية (SMPP، IMS، MAP، إلخ.)

الحقول الاختيارية:

  • ip_address - عنوان IP للواجهة الأمامية (يتم اكتشافه تلقائيًا من مصدر الطلب إذا لم يتم توفيره)
  • hostname - اسم مضيف خادم الواجهة الأمامية
  • uptime_seconds - الثواني منذ بدء تشغيل الواجهة الأمامية
  • configuration - سلسلة JSON مع تكوين محدد للواجه�� الأمامية

ملاحظة: إذا لم يتم توفير ip_address، سيستخدم SMS_C Core تلقائيًا عنوان IP المصدر لطلب HTTP. يعمل هذا مع كل من الاتصالات المباشرة والطلبات الموجهة (عبر رأس X-Forwarded-For).

الاستجابة:

{
"id": 42,
"frontend_name": "smpp-gateway-1",
"frontend_type": "SMPP",
"ip_address": "10.0.1.5",
"hostname": "smpp-gw-01",
"uptime_seconds": 3600,
"status": "active",
"last_seen_at": "2025-10-20T10:30:00Z",
"expires_at": "2025-10-20T10:31:30Z",
"inserted_at": "2025-10-20T10:00:00Z"
}
قائمة بجميع تسجيلات الواجهة الأمامية
GET /api/frontends

يعيد جميع تسجيلات الواجهة الأمامية (النشطة والمنتهية)، مرتبة حسب أحدث نشاط.

قائمة الواجهات الأمامية النشطة فقط
GET /api/frontends/active

يعيد فقط الواجهات الأمامية النشطة حاليًا (غير المنتهية).

الحصول على إحصائيات الواجهة الأمامية
GET /api/frontends/stats

يعيد إحصائيات ملخصة:

{
"active": 5,
"expired": 12,
"unique_frontends": 8
}
الحصول على تاريخ الواجهة الأمامية
GET /api/frontends/history/{frontend_name}

يعيد جميع التسجيلات التاريخية لواجهة أمامية معينة، مما يساعد في تحليل أنماط وقت التشغيل/التوقف.

مثال:

GET /api/frontends/history/smpp-gateway-1
الحصول على تسجيل محدد
GET /api/frontends/{id}

التنفيذ في الواجهات الأمامية الخارجية

يجب على الواجهات الأمامية الخارجية تنفيذ مهمة خلفية ترسل نبضات القلب:

مثال (كود زائف):

import time
import requests

def send_heartbeat():
"""Send heartbeat every 30 seconds"""
while True:
try:
data = {
"frontend_name": "my-smpp-gateway",
"frontend_type": "SMPP",
"ip_address": get_local_ip(),
"hostname": get_hostname(),
"uptime_seconds": get_uptime()
}

response = requests.post(
"https://smsc-core:8443/api/frontends",
json=data,
timeout=5
)

if response.status_code in [200, 201]:
logger.debug("Heartbeat sent successfully")
else:
logger.error(f"Heartbeat failed: {response.status_code}")

except Exception as e:
logger.error(f"Heartbeat error: {e}")

time.sleep(30) # Send every 30 seconds

# Start heartbeat in background thread
threading.Thread(target=send_heartbeat, daemon=True).start()

مراقبة صحة الواجهة الأمامية

لوحة التحكم - تعرض واجهة الويب في https://localhost:8086:

  • الواجهات الأمامية النشطة حاليًا
  • طابع آخر ظهور لكل واجهة أمامية
  • تتبع وقت التشغيل
  • التوافر التاريخي

استعلامات API:

# الحصول على جميع الواجهات الأمامية النشطة
curl https://localhost:8443/api/frontends/active

# التحقق مما إذا كانت واجهة أمامية معينة تعمل
curl https://localhost:8443/api/frontends/history/smpp-gateway-1 | jq '.[0].status'

# الحصول على إحصائيات الصحة
curl https://localhost:8443/api/frontends/stats

نقاط نهاية أخرى

الحالة

GET /api/status

المواقع

GET /api/locations
POST /api/locations
GET /api/locations/{id}
PATCH /api/locations/{id}
DELETE /api/locations/{id}

أحداث SS7

GET /api/ss7_events
POST /api/ss7_events
GET /api/ss7_events/{id}
PATCH /api/ss7_events/{id}
DELETE /api/ss7_events/{id}

قائمة رسائل MMS

GET /api/mms_message_queues
POST /api/mms_message_queues
GET /api/mms_message_queues/{id}
PATCH /api/mms_message_queues/{id}
DELETE /api/mms_message_queues/{id}

الأداء

يوفر SMS_C Core إنتاجية استثنائية باستخدام Mnesia لتخزين الرسائل في الذاكرة مع أرشفة تلقائية إلى SQL للاحتفاظ بسجلات CDR على المدى الطويل.

نتائج المعايير

تم قياسها على Intel i7-8650U @ 1.90GHz (8 نوى):

أداء إدراج الرسائل:

  • insert_message (مع التوجيه): 1,750 msg/sec (0.58ms متوسط زمن الاستجابة)
  • insert_message (بسيط): 1,750 msg/sec (0.57ms متوسط زمن الاستجابة)
  • سعة ~150 مليون رسالة في اليوم

أداء الاستعلام:

  • get_messages_for_smsc: 800 msg/sec (1.25ms متوسط)
  • list_message_queues: وصول سريع في الذاكرة
  • استخدام الذاكرة: 62 كيلوبايت لكل عملية إدراج

المعمارية

استراتيجية التخزين:

  • الرسائل النشطة: مخزنة في Mnesia (في الذاكرة + القرص) للوصول الفائق السرعة
  • أرشيف الرسائل: مؤرشفة تلقائيًا إلى SQL للاحتفاظ بسجلات CDR على المدى الطويل
  • فترة الاحتفاظ: فترة احتفاظ قابلة للتكوين (الافتراضي: 24 ساعة)
  • لا توجد عنق الزجاجة SQL: جميع عمليات الرسائل النشطة تتجاوز SQL

التكوين

يتم تكوين تخزين الرسائل وفترة الاحتفاظ في config/runtime.exs:

config :sms_c,
message_retention_hours: 24, # أرشفة الرسائل التي تزيد عن 24 ساعة
batch_insert_batch_size: 100, # حجم دفعة CDR لأرشفة SQL
batch_insert_flush_interval_ms: 100 # فترة تفريغ CDR

للحصول على إرشادات تفصيلية حول الضبط، انظر: docs/PERFORMANCE_TUNING.md

المراقبة

لوحة التحكم - واجهة الويب في https://localhost:8086

  • عرض قائمة الرسائل
  • إرسال رسائل اختبار
  • إدارة توجيه الرسائل القصيرة (انظر دليل التوجيه)
  • محاكاة قرارات التوجيه
  • عرض موارد النظام
  • تتبع إحصائيات العمالة الدفعة

إحصائيات العمالة الدفعة:

# الحصول على إحصائيات العمالة الدفعة الحالية
SmsC.Messaging.BatchInsertWorker.stats()

يعيد:

%{
total_enqueued: 10000,
total_flushed: 9900,
current_queue_size: 100,
last_flush_duration_ms: 45
}

السجلات - سجلات التطبيق مكتوبة إلى stdout

# عرض السجلات في الوقت الحقيقي
tail -f log/dev.log

استكشاف الأخطاء وإصلاحها

المنفذ مستخدم بالفعل

# العثور على العملية التي تستخدم المنفذ
lsof -i :4000

# إنهاء العملية
kill -9 <PID>

الواجهة الأمامية الخارجية لا تتصل

الأعراض: الرسائل عالقة في القائمة، سجلات الواجهة الأمامية تظهر أخطاء في الاتصال

تحقق من:

  • تأكد من تعيين API_BASE_URL بشكل صحيح في الواجهة الأمامية
  • تحقق من أن SMS_C Core يعمل ويمكن الوصول إليه
  • مراجعة قواعد الشبكة/الجدار الناري
  • تحقق من تكوين الواجهة الأمامية

الحل:

# اختبار الاتصال بواجهة برمجة التطبيقات من الواجهة الأمامية
curl http://localhost:4000/api/status

# إعادة تشغيل الواجهة الأمامية
export API_BASE_URL="http://localhost:4000"
# بدء تطبيق الواجهة الأمامية

الرسائل لا يتم تسليمها

الأعراض: تبقى الرسائل غير مسلمة، تزداد محاولات إعادة المحاولة

تحقق من:

  1. سجلات الواجهة الأمامية لأخطاء الإرسال
  2. الاتصال بالشبكة الخارجية
  3. تكوين الواجهة الأمامية (البيانات الاعتماد، العناوين)
  4. توافق تنسيق الرسالة

عرض الرسائل الفاشلة:

# الحصول على الرسائل مع محاولات إعادة المحاولة
curl https://localhost:8443/api/messages | jq '.data[] | select(.delivery_attempts > 0)'

زمن استجابة الرسائل مرتفع

الأعراض: تستغرق الرسائل وقتًا أطول من المتوقع، تراكم في القائمة

تحقق من:

  1. فترة استعلام الواجهة الأمامية (قد تحتاج إلى تقليلها للاستعلام بشكل أكثر تكرارًا)
  2. أداء قاعدة البيانات
  3. زمن الانتقال في الشبكة إلى الأنظمة الخارجية

مراقبة عمق القائمة:

watch -n 5 'curl -s https://localhost:8443/api/messages | jq ".data | length"'