SMSc - تطبيق مركز خدمة الرسائل القصيرة
تطبيق مركز الرسائل القصيرة مبني باستخدام Phoenix/Elixir، يوفر قائمة رسائل مركزية وواجهة برمجة تطبيقات REST لتوجيه الرسائل القصيرة وتسليمها.
الوثائق
الوثائق الأساسية
- فهرس الوثائق الكاملة - ابدأ هنا للحصول على جميع الوثائق
- مرجع التكوين - خيارات التكوين الكاملة
- مرجع API - وثائق واجهة برمجة تطبيقات REST
- دليل العمليات - العمليات اليومية والمراقبة
- دليل توجيه الرسائل القصيرة - إدارة التوجيه والتكوين
- دليل ترجمة الأرقام - تطبيع الأرقام وإعادة كتابتها
- تحسين الأداء - تحسين لأحمال العمل المختلفة
- دليل القياسات - قياسات Prometheus والمراقبة
- دليل استكشاف الأخطاء وإصلاحها - القضايا الشائعة والحلول
- مخطط CDR - تنسيق سجل تفاصيل المكالمات
وثائق الامتثال
- امتثال ANSSI R226 للاعتراض - المواصفات الفنية للاعتراض القانوني الفرنسية
الأداء
- المعايير - اختبار الأداء
نظرة عامة على المعمارية
يوفر 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- معرفات IMSItp_dcs_character_set- ترميز الأحرف (gsm7، 8bit، latin1، ucs2)tp_dcs_coding_group- مجموعة ترميز DCStp_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:
| المحاولة | صيغة التراجع | التأخير | الوقت الكلي |
|---|---|---|---|
| 1st | 2^1 دقائق | 2 دقيقة | 2 دقيقة |
| 2nd | 2^2 دقائق | 4 دقائق | 6 دقائق |
| 3rd | 2^3 دقائق | 8 دقائق | 14 دقيقة |
| 4th | 2^4 دقائق | 16 دقيقة | 30 دقيقة |
| 5th | 2^5 دقائق | 32 دقيقة | 1h 2min |
| 6th | 2^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:
- فترة نبض القلب: يجب على الواجهات الأمامية التسجيل كل 30-60 ثانية
- وقت انتهاء الصلاحية: تنتهي صلاحية التسجيلات بعد 90 ثانية دون تحديث
- إدارة الحالة التلقائية:
- تنشئ الواجهات الأمامية الجديدة سجل تسجيل جديد
- تقوم الواجهات الأمامية النشطة الموجودة بتحديث تسجيلها (تمديد انتهاء الصلاحية)
- تقوم الواجهات الأمامية المنتهية صلاحيتها التي تعود إلى الإنترنت بإنشاء فترة تسجيل جديدة
نقاط نهاية تسجيل الواجهة الأمامية
تسجيل/تحديث الواجهة الأمامية (نبض القلب)
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"
# بدء تطبيق الواجهة الأمامية
الرسائل لا يتم تسليمها
الأعراض: تبقى الرسائل غير مسلمة، تزداد محاولات إعادة المحاولة
تحقق من:
- سجلات الواجهة الأمامية لأخطاء الإرسال
- الاتصال بالشبكة الخارجية
- تكوين الواجهة الأمامية (البيانات الاعتماد، العناوين)
- توافق تنسيق الرسالة
عرض الرسائل الفاشلة:
# الحصول على الرسائل مع محاولات إعادة المحاولة
curl https://localhost:8443/api/messages | jq '.data[] | select(.delivery_attempts > 0)'
زمن استجابة الرسائل مرتفع
الأعراض: تستغرق الرسائل وقتًا أطول من المتوقع، تراكم في القائمة
تحقق من:
- فترة استعلام الواجهة الأمامية (قد تحتاج إلى تقليلها للاستعلام بشكل أكثر تكرارًا)
- أداء قاعدة البيانات
- زمن الانتقال في الشبكة إلى الأنظمة الخارجية
مراقبة عمق القائمة:
watch -n 5 'curl -s https://localhost:8443/api/messages | jq ".data | length"'