Мы собираем файлы cookie и применяемрекомендательные технологии

Прокачиваем собственный SMPP сервер по максимуму - 571 - МТС Exolve

Прокачиваем собственный SMPP сервер по максимуму

Время идет, а хочется обновления на собственном сервере SMPP Exolve. Наверное сегодня буду краток в словах, но богат кодом. Пожалуй сразу начну с изменений:

Изменил заголовки страниц, тексты. Теперь статус подключения показывает более детальную информацию.

Поработал над версткой, в частности добавил счетик сообщений, сортировку по времени и табличное отображение. Теперь удобно искать сообщения по времени.

А теперь сам код:

Код
import smpplib.clientimport smpplib.constsimport smpplib.gsmimport smpplib.exceptionsfrom flask import Flask, jsonify, render_template, request, redirect, url_for, sessionfrom flask_sqlalchemy import SQLAlchemyimport threadingimport atexitfrom datetime import datetime, timedelta
# Настройки Flask и базы данныхapp = Flask(__name__)app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///sms.db'app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = Falseapp.config['SECRET_KEY'] = 'your_secret_key'  # Для безопасности сессийdb = SQLAlchemy(app)
# Модель для хранения SMS сообщенийclass SMSMessage(db.Model):    id = db.Column(db.Integer, primary_key=True)    source = db.Column(db.String(20))    destination = db.Column(db.String(20))    message = db.Column(db.String(160))    timestamp = db.Column(db.DateTime, default=db.func.current_timestamp())
# Создаем таблицы в базе данныхwith app.app_context():    db.create_all()
# Глобальные переменные для состояния SMPP клиентаclient = Noneconnection_status = "Not connected"
# Функция для обработки входящих сообщенийdef handle_message(pdu):    try:        # Попытка декодировать сообщение с разными кодировками        try:            if pdu.data_coding == 0x08:  # UCS2 кодировка                message = pdu.short_message.decode('utf-16-be')            else:                message = pdu.short_message.decode('utf-8')        except UnicodeDecodeError:            # Если не удалось, пробуем GSM 7-бит (возможные латинские символы)            try:                message = smpplib.gsm.decode(pdu.short_message)            except:                # Если ничего не помогло, сохраняем как есть                message = pdu.short_message.decode('latin1')
        source = pdu.source_addr.decode('utf-8') if isinstance(pdu.source_addr, bytes) else pdu.source_addr        destination = pdu.destination_addr.decode('utf-8') if isinstance(pdu.destination_addr, bytes) else pdu.destination_addr
        # Создаем контекст приложения Flask        with app.app_context():            # Сохраняем сообщение в базе данных            sms = SMSMessage(source=source, destination=destination, message=message)            db.session.add(sms)            db.session.commit()
        print(f"Received message: {message}")        print(f"From: {source}")        print(f"To: {destination}")
    except UnicodeDecodeError as e:        print(f"Ошибка декодирования сообщения: {e}")    except smpplib.exceptions.ConnectionError as e:        global connection_status        connection_status = "Connection lost"        print("Connection lost with SMPP server:", e)
# Функция для подключения к SMPP серверуdef connect_to_smpp(system_id, password):    global client, connection_status    SMPP_SERVER = "smpp.exolve.ru"    SMPP_PORT = 2775
    try:        client = smpplib.client.Client(SMPP_SERVER, SMPP_PORT)        client.set_message_received_handler(handle_message)        client.connect()        client.bind_receiver(system_id=system_id, password=password)        connection_status = "Connected"        listener_thread = threading.Thread(target=client.listen, daemon=True)        listener_thread.start()    except Exception as e:        connection_status = f"Failed to connect: {str(e)}"
# Функция для корректного закрытия SMPP клиентаdef close_smpp_client():    global client, connection_status    if client:        try:            client.unbind()        finally:            client.disconnect()        connection_status = "Disconnected"
# Регистрация функции закрытия соединения при завершении работы приложенияatexit.register(close_smpp_client)
# Маршрут для отображения формы логина и обработки подключения@app.route('/', methods=['GET', 'POST'])def login():    if request.method == 'POST':        system_id = request.form['system_id']        password = request.form['password']        connect_to_smpp(system_id, password)        session['logged_in'] = True        return redirect(url_for('index'))    return render_template('login.html', connection_status=connection_status)
# Веб-интерфейс для отображения полученных SMS@app.route('/messages', methods=['GET'])def index():    if not session.get('logged_in'):        return redirect(url_for('login'))
    sort_order = request.args.get('sort', 'desc')    if sort_order == 'asc':        messages = SMSMessage.query.order_by(SMSMessage.timestamp.asc()).all()    else:        messages = SMSMessage.query.order_by(SMSMessage.timestamp.desc()).all()
    message_count = SMSMessage.query.count()    return render_template('index.html', messages=messages, message_count=message_count, connection_status=connection_status, sort_order=sort_order)
# Маршрут для получения сообщений в формате JSON@app.route('/get_messages', methods=['GET'])def get_messages():    if not session.get('logged_in'):        return jsonify([])
    sort_order = request.args.get('sort', 'desc')    if sort_order == 'asc':        messages = SMSMessage.query.order_by(SMSMessage.timestamp.asc()).all()    else:        messages = SMSMessage.query.order_by(SMSMessage.timestamp.desc()).all()
    messages_data = []    for sms in messages:        # Переводим время на часовой пояс Москвы (UTC+3)        local_time = sms.timestamp + timedelta(hours=3)        messages_data.append({            "source": sms.source.decode('utf-8') if isinstance(sms.source, bytes) else sms.source,            "destination": sms.destination.decode('utf-8') if isinstance(sms.destination, bytes) else sms.destination,            "message": sms.message,            "timestamp": local_time.strftime('%Y-%m-%d %H:%M:%S')        })    return jsonify(messages_data)
# Запуск веб-приложения на порту 5001if __name__ == '__main__':    app.run(debug=True, port=5001)

Состав страницы index.html
Код
<!DO CTYPE html><ht ml lang="ru"><head>    <met a charset="UTF-8">    <met a name="viewport" content="width=device-width, initial-scale=1.0">    <title>Сервис входящих SMS Exolve</title>    <li nk href="<https://fonts.googleapis.com/css2?family=Ubuntu:wght@400;700&display=swap>;" rel="stylesheet">    <st yle>        body {            font-family: 'Ubuntu', sans-serif;        }        .status {            margin-bottom: 20px;            font-weight: bold;        }        .message-count {            margin-bottom: 20px;            font-size: 18px;        }        table {            width: 100%;            border-collapse: collapse;            margin-bottom: 20px;        }        table, th, td {            border: 1px solid black;        }        th, td {            padding: 8px;            text-align: left;        }        th {            background-color: #f2f2f2;        }        .message-text {            color: green;            font-weight: bold;        }        .sort-buttons {            margin-bottom: 20px;        }        .sort-buttons button {            padding: 10px;            margin-right: 10px;            cursor: pointer;            font-weight: bold;        }    </style>    <sc ript>        // Функция для загрузки сообщений        function loadMessages(sortOrder = 'desc') {            fetch(`/get_messages?sort=${sortOrder}`)                .then(response => response.json())                .then(data => {                    const tableBody = document.getElementById('message-table-body');                    tableBody.innerHTML = '';  // Очищаем таблицу сообщений                    data.forEach(sms => {                        const row = document.createElement('tr');                        row.innerHTML = `<td>${sms.timestamp}</td><td>${sms.source}</td><td>${sms.destination}</td><td class="message-text">${sms.message}</td>`;                        tableBody.appendChild(row);                    });                })                .catch(error => console.error('Error loading messages:', error));        }
        // Обновляем сообщения каждые 5 секунд        setInterval(() => loadMessages(document.querySelector('input[name="sortOrder"]:checked').value), 5000);
        // Загрузка сообщений при загрузке страницы        window.onl oad = () => loadMessages(document.querySelector('input[name="sortOrder"]:checked').value);    </sc ript></head><body>    <h1>Сервис входящих SMS Exolve</h1>    <div class="status">        Статус подключения к серверу SMPP: {{ connection_status }}    </div>    <div class="message-count">        Всего сообщений: {{ message_count }}    </div>    <div class="sort-buttons">        <label>            <input type="radio" name="sortOrder" value="desc" oncha nge="loadMessages(this.value)" {% if sort_order == 'desc' %}checked{% endif %}> Новые вверху        </label>        <label>            <input type="radio" name="sortOrder" value="asc" oncha nge
="loadMessages(this.value)" {% if sort_order == 'asc' %}checked{% endif %}> Старые вверху        </label>    </div>    <table>        <thead>            <tr>                <th>Получено в</th>                <th>От</th>                <th>Кому</th>                <th>Сообщение</th>            </tr>        </thead>        <tbody id="message-table-body">            <!-- Сообщения будут динамически добавляться сюда -->        </tbody>    </table></body></html>

И последний файл login.html
Код
<!DO CTYPE html><ht ml lang="ru"><head>    <met a charset="UTF-8">    <met a name="viewport" content="width=device-width, initial-scale=1.0">    <title>Подключение к SMPP Exolve серверу</title>    <li nk href="<https://fonts.googleapis.com/css2?family=Ubuntu:wght@400;700&display=swap>;" rel="stylesheet">    <st yle>        body {            font-family: 'Ubuntu', sans-serif;        }        .form-container {            margin: 0 auto;            max-width: 300px;            padding: 20px;            border: 1px solid #ccc;            border-radius: 5px;        }        .form-container h1 {            text-align: center;        }        .form-container label {            display: block;            margin-bottom: 10px;        }        .form-container input {            width: 100%;            padding: 8px;            margin-bottom: 20px;        }        .form-container button {            width: 100%;            padding: 10px;            background-color: #4CAF50;            color: white;            border: none;            border-radius: 5px;            cursor: pointer;        }        .form-container button:hover {            background-color: #45a049;        }        .status {            margin-bottom: 20px;            font-weight: bold;            text-align: center;        }    </style></head><body>    <div class="form-container">        <h1>Подключение к SMPP Exolve серверу</h1>        <div class="status">            Статус подключения к серверу SMPP: {{ connection_status }}        </div>        <fo rm method="POST" action="/">            <label for="system_id">Логин:</label>            <input type="text" id="system_id" name="system_id" required>
            <label for="password">Пароль:</label>            <input type="password" id="password" name="password" required>
            <button type="submit">Подключиться</button>        </form>    </div></body></html>

Пошаговое объяснение работы

1. Запуск приложения и база данных:
  • Flask приложение запускается, подключается к SQLite базе данных, и создает таблицы для хранения SMS сообщений, если они еще не существуют.

2. Авторизация через login.html:
  • Пользователь заходит на главную страницу, где его просят ввести логин и пароль для подключения к SMPP серверу. Введенные данные отправляются на сервер, где происходит подключение к SMPP серверу с использованием введенных учетных данных.

3. Подключение к SMPP серверу:
  • Функция connect_to_smpp используется для подключения к SMPP серверу и прослушивания входящих сообщений. Если подключение успешно, приложение начинает слушать входящие сообщения в фоновом потоке.

4. Обработка входящих сообщений:
  • При получении SMS сообщения оно обрабатывается функцией handle_message. Сообщение декодируется, и информация о нем сохраняется в базу данных.

5. Отображение сообщений через index.html:
  • После успешного подключения пользователь перенаправляется на страницу с таблицей, где отображаются все полученные сообщения. Пользователь может сортировать сообщения по дате — либо показывая сначала новые, либо сначала старые.

  • Таблица данных обновляется автоматически каждые 5 секунд, подгружая новые сообщения.

6. Коррекция времени на московский часовой пояс:
  • Временные метки сообщений корректируются, добавляя три часа к UTC времени, чтобы отображать время в московском часовом поясе.

7. Отключение от SMPP сервера:
  • Когда приложение закрывается, функция close_smpp_client корректно завершает соединение с SMPP сервером.

Таким образом, это приложение предоставляет удобный веб-интерфейс для просмотра входящих SMS сообщений с возможностью сортировки по времени и корректным отображением времени в московском часовом поясе.

И на этом пора заканчивать с модернизацией собственного SMPP сервера, который работает МТС Exolve. Если есть идеи как еще улучшить отображение входящих СМС, то пишите в комментариях.

Всем пока!

7
207
Открытая тема
0 баллов

Для того, чтобы оставлять комментарии, необходимо пройти авторизацию

Авторизоваться
код нечитаьельный
oleg
oleg
0 баллов
27 сентября 2024 в 04:33
в notepad++ норм
oleg
oleg
0 баллов
27 сентября 2024 в 04:33
Однозначно это пока самое объемное приложение на форуме. Осталось по вашим текстам воссоздать.  
moderator
moderator
0 баллов
01 октября 2024 в 12:14
Благодарю за вклад!
moderator
moderator
0 баллов
01 октября 2024 в 12:15
спасибо!
e.litviakova@gmail.com
e.litviakova@*****.***
0 баллов
23 октября 2024 в 12:45