13.10.2026
Havacılık Data Link iletilerini, ana yönlendirici veya doğrudan tek bir besleyiciden alıp alınan iletileri hem uç yazılıma aktaran hem de veri tabanına kaydeden, python tabanlı arka yazılım.
Ibosoft ATC sistemi içerisinde bu yazılım kullanılmaktadır. https://atc.ibosoft.net.tr
Yazılımın canlı aldığı veya veri tabanına kaydettiği verilerin görüntülenebilmesi için, web tabanlı uç yazılım ile birlikte kullanılmalıdır.
Özellikler:
- acarsdec ve acarshub yazılımlarının JSON formatını destekler.
- İletileri, uç yazılıma iletir.
- İletileri, MySQL türevi veri tabanına kaydeder.
- Veri bağlantısı koparsa, yeniden bağlanmayı kısa aralıklarla sürekli dener.
- Windows ve Linux üzerinde hizmet olarak çalıştırılabilir.
Data Link Yazılımlarımız:
- ACARS Viewer
- ACARS Backend
- ACARS Decoding Library
- ACARS Tester
Havacılık iletişim ve data link sistemleri hakkında daha fazla bilgi için: https://egitim.ibosoft.net.tr/
Projede kullanılan kısaltmalar için bakınız: Ibosoft Kısaltmalar Veri Tabanı
Lisans:
Bu proje Elastic License 2.0 ile lisanslanmıştır.
Kaynak kodu herkese açıktır. Kişisel ve ticari projelerde kullanım serbesttir. Kod üzerinde değişiklik yapılabilir; ancak projenin kendisi veya değiştirilmiş hâlleri, açık izin alınmadan yeniden paylaşılamaz, yayımlanamaz veya bir servis olarak sunulamaz.
A Python-based backend software that receives aviation Data Link messages from a main router or directly from a single feeder and forwards the received messages to both the frontend software and records them to a database.
This software is used within the Ibosoft ATC system. https://atc.ibosoft.net.tr
To view the data that the software receives live or stores in the database, it must be used together with the web-based frontend software.
Features:
- Supports JSON format of acarsdec and acarshub software.
- Forwards messages to frontend software.
- Records messages to MySQL-based database.
- If connection is lost, continuously retries reconnection at short intervals.
- Can be run as a service on Windows and Linux.
Our Data Link Software Series:
- ACARS Viewer
- ACARS Backend
- ACARS Decoding Library
- ACARS Tester
For more information about aviation communication and data link systems: https://egitim.ibosoft.net.tr/
For abbreviations used in the project, see: Ibosoft Abbreviations Database
License:
This project is licensed under Elastic License 2.0.
The source code is publicly available. Use in personal and commercial projects is free. The code can be modified; however, the project itself or its modified versions cannot be redistributed, published, or offered as a service without explicit permission.
- Windows veya Linux (x86_64) işletim sistemi.
- Python 3.x (Windows'ta
python, Linux'tapython3olarak sistem PATH'inde erişilebilir olmalı) - Linux'ta ek olarak:
python3-venvpaketi ve zlib (libz.so.1; Ubuntu/Debian'da varsayılan olarak kuruludur) - Şu ek python paketleri (requirements.txt üzerinden otomatik kurulur):
- mysql-connector-python==8.2.0
- Flask==3.0.0
- Flask-Cors==4.0.0
- PyJWT==2.8.0
Yazılım taşınabilirdir, indirip sunucuda uygun bir dizine yerleştiriniz.
İlk kurulumda (ve requirements.txt her güncellendiğinde) sanal ortam (venv) kurmak için yazılım dizinindeki kurulum betiğini bir kez çalıştırınız (Windows: install-venv.bat, Linux: install-venv.sh):
install-venv.bat
./install-venv.shBu betik:
- Yoksa
venvdizini altında izole bir Python sanal ortamı oluşturur. - Bu sanal ortamın içindeki
pip'i günceller. requirements.txtiçindeki tüm paketleri sanal ortama kurar.
Sistem genelindeki Python kurulumu kirletilmez; bağımlılıklar yalnızca bu projeye ait venv dizininde yaşar. venv/ dizini .gitignore'da olduğundan repo'ya commit edilmez.
Gerekli ayarları yaptıktan sonra Windows'ta start.bat, Linux'ta start.sh betik dosyasını çalıştırınız. Kendiliğinden çalıştırma için bir görev zamanlaması veya hizmet oluşturabilirsiniz.
start.bat, sanal ortamdaki Python (venv\Scripts\python.exe) ilemain.py'yi çalıştırır. Sanal ortam yoksa hata verir veinstall-venv.bat'in çalıştırılması gerektiğini bildirir.start.sh, sanal ortamdaki Python (venv/bin/python) ilemain.py'yi çalıştırır. Sanal ortam yoksa hata verir veinstall-venv.sh'in çalıştırılması gerektiğini bildirir. Python'uexecile başlattığı için systemd'nin durdurma sinyali (SIGTERM) doğrudan yazılıma ulaşır.- Bat betiği, doğrudan hizmet olarak çalıştırmaya uygun hazırlanmıştır. Uygun komutlar veya Servy gibi bir Windows hizmeti oluşturma aracı ile bat dosyasını çalıştıracak bir hizmet ekleyebilirsiniz.
- Bat betiği, herhangi bir dizinden başlatıldığında bulunduğu dizini çalışma dizini olarak ayarlamaktadır. Bu yüzden, görev zamanlamasında veya hizmet ayarlarında, çalışma dizini olarak yazılımın bulunduğu dizin ayarlanmasa bile yazılım doğru şekilde çalışacaktır.
start.shde aynı şekilde, herhangi bir dizinden veya systemd'den başlatıldığında kendi dizinini çalışma dizini olarak ayarlar. - Linux'ta systemd hizmeti örneği (
/etc/systemd/system/atc-data-link-backend.service; kullanıcı ve yol kuruluma göre düzenlenmelidir):
[Unit]
Description=Ibosoft ACARS Backend
After=network-online.target
Wants=network-online.target
[Service]
User=administrator
ExecStart=/home/administrator/ibosoft/atc-data-link-backend/start.sh
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.targetNOT: Henüz bağlantı kopukluğu tespitinde bazı sorunlar bulunmaktadır ve uzun süreli çalışmalarda bazen kendiliğinden yeniden bağlanma özelliği çalışmamaktadır. Bu yüzden görev zamanlamasını veya hizmet ayarlarını, şimdilik görevin/hizmetin günde 1-2 kere yeniden başlatılacağı şekilde yapınız.
- Windows or Linux (x86_64) operating system.
- Python 3.x (must be reachable on the system PATH as
pythonon Windows,python3on Linux). - Additionally on Linux: the
python3-venvpackage and zlib (libz.so.1; installed by default on Ubuntu/Debian). - The following additional Python packages (installed automatically through
requirements.txt):- mysql-connector-python==8.2.0
- Flask==3.0.0
- Flask-Cors==4.0.0
- PyJWT==2.8.0
The software is portable, download and place it in an appropriate directory on the server.
On first checkout (and whenever requirements.txt is updated), run the setup script in the software directory once to set up a virtual environment (Windows: install-venv.bat, Linux: install-venv.sh):
install-venv.bat
./install-venv.shThis script:
- Creates an isolated Python virtual environment under the
venvdirectory if one does not already exist. - Upgrades
pipinside that virtual environment. - Installs every package listed in
requirements.txtinto the virtual environment.
The system-wide Python installation is left untouched; the dependencies live only inside this project's venv directory. venv/ is included in .gitignore, so it is never committed to the repository.
After configuring the necessary settings, run the start.bat script file on Windows or the start.sh script file on Linux. You can create a task schedule or a service for automatic startup.
start.batrunsmain.pyusing the virtual environment's Python (venv\Scripts\python.exe). If the virtual environment is missing, the script errors out and tells you to runinstall-venv.batfirst.start.shrunsmain.pyusing the virtual environment's Python (venv/bin/python). If the virtual environment is missing, the script errors out and tells you to runinstall-venv.shfirst. Because it starts Python withexec, the stop signal (SIGTERM) from systemd reaches the software directly.- The bat script is prepared to run directly as a service. You can add a service that will run the bat file using appropriate commands or a Windows service creation tool like Servy.
- The bat script sets its own directory as the working directory when started from any directory. Therefore, even if the software's directory is not set as the working directory in the task schedule or service settings, the software will work correctly.
start.shlikewise sets its own directory as the working directory when started from any directory or from systemd. - Example systemd service on Linux (
/etc/systemd/system/atc-data-link-backend.service; adjust the user and path to your installation):
[Unit]
Description=Ibosoft ACARS Backend
After=network-online.target
Wants=network-online.target
[Service]
User=administrator
ExecStart=/home/administrator/ibosoft/atc-data-link-backend/start.sh
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.targetNOTE: There are still some issues with connection loss detection, and sometimes the automatic reconnection feature does not work during long-term operations. Therefore, for now, configure the task schedule or service settings so that the task/service is restarted 1-2 times a day.
Yazılımın çalışabilmesi için, data link subnetwork'larının sinyallerini demodüle edip çözümledikten sonra, ACARS ağının iletilerini (Şu anlık ATN ağı desteklenmiyor.) uygun JSON biçiminde TCP sunucusu üzerinden iletebilen bir yazılımın kurulmuş ve çalışıyor olması gerekmektedir. Ayrıca ara bir yazılım ile birden fazla besleyiciden gelen iletiler tek bir TCP sunucusunda toplanıp sonra arka yazılıma iletilebilir.
- Birden fazla besleyiciden farklı protokollerle veri toplayıp TCP sunucusu olarak arka yazılıma veri iletmek için şu yazılımı kullanabilirsiniz: acars_router
- acars_router, "TCP server" olarak ayarlanmalıdır.
Aşağıdaki yazılımlardan bazıları, doğrudan TCP ile iletim desteklemez ama acars_router veya başka bir aktarım yazılımı aracılığıyla veri sağlamada kullanılabilirler.
- VDL M0/A subnetwork'ü üzerinden ACARS ağı çözümlemek için: acarsdec
- VDL M2 subnetwork'ü üzerinden ACARS ağı çözümlemek için: vdlm2dec
- HFDL subnetwork'ü üzerinden ACARS ağı çözümlemek için: acarshfdl
- INMARSAT Classic Aero subnetwork'ü üzerinden ACARS ağı çözümlemek için: JAERO
Henüz desteklenmiyor ama ATN ağı için:
- VDL M2 subnetwork'ü üzerinden ATN ağı çözümlemek için: dumpvdl2
Kayıtlar için MySQL türevi bir veri tabanı sunucusu gereklidir ve içerisinde boş bir veri tabanı oluşturulmalıdır. Veri tabanının içerisine gerekli tablolar, yazılım tarafından eklenecektir.
Ayarlar, config.ini dosyası aracılığıyla yapılmaktadır. Ayarların açıklamaları şu şekildedir:
- [DATABASE]
- host = MySQL türevi veri tabanı sunucusunun IP adresi (Ör: localhost)
- port = Veri tabanı sunucusunun port numarası (Ör: 3306)
- user = Veri tabanı kullanıcı adı.
- password = Veri tabanı kullanıcı parolası.
- database = Kullanılacak veri tabanının adı.
- read_pool_size = Okuma sorguları (ACARS Application API + istatistik sayacı) için kullanılan ayrı bağlantı havuzunun boyutu. TCP alıcı iş parçacığının kullandığı tek yazıcı bağlantısı ile okuyucular karışmaz; böylece eşzamanlı API sorguları yazma yolunu bozamaz. (Ör: 8)
- [BACKEND]
- host = Uç yazılımın bağlanabilmesi için web sunucusunun IP adresi (Ör: localhost)
- port = Uç yazılımın bağlanabilmesi için web sunucusunun port numarası (Ör: 10002)
- [LISTENER]
- host = İletileri yollayacak TCP sunucusunun IP adresi (Ör: localhost)
- port = İletileri yollayacak TCP sunucusunun port numarası (Ör: 15551)
- max_idle_time = Anlık bağlantı kopukluğu tespiti haricinde, yedek olarak bağlantı kopukluğu tespiti için izin verilen en uzun boşta kalma süresi (saniye cinsinden). Bu süre sonunda hala yeni bir ileti gelmemişse, yeniden bağlanma işlemi başlatılır. (Ör: 600)
- [RECORDING]
- max_messages = Veri tabanında saklanacak azami ileti sayısı. Bu sayıya ulaşıldığında, en eski iletiler silinerek yeni iletiler kaydedilir. (Ör: 100000)
- [LOGGING]
- max_log_size_mb = Log dosyasının azami boyutu (MB cinsinden) (Ör: 10)
- backup_count = Log dosyası yedek sayısı (Ör: 2)
- [DECODING]
- enabled = true ya da false. ACARS ağı ARINC 622 uygulamalarının çözülmesi ile ilgili arka yazılım işlevlerinin etkinleştirilip etkinleştirilmeyeceğini belirler.
- [ACARS_APP_API]
- enabled = true ya da false. Harici uygulamaların ATS uygulama iletilerine sorgu atabilmesi için ACARS Application API modülünün etkinleştirilip etkinleştirilmeyeceğini belirler. Şu an
datisvedcluygulamaları destekleniyor; ileride yeni ATS uygulamaları (pdc, aoc vb.) modüldeki handler kaydına satır ekleyerek aktive edilebilir. - host = ACARS Application API sunucusunun IP adresi (Ör: 0.0.0.0).
- port = ACARS Application API sunucusunun port numarası (Ör: 10012). Mevcut [BACKEND] portu ile çakışmamalıdır.
- max_count_per_type = D-ATIS: tek bir API çağrısında tip başına (DEP/ARR) döndürülebilecek azami ileti sayısı. Çağıranın istediği
countbu değerle sınırlandırılır. (Ör: 5) - dcl_max_count = DCL: tek bir API çağrısında döndürülebilecek azami DCL ileti sayısı. Çağıranın istediği
countbu değerle sınırlandırılır. Zorunludur. (Ör: 30) - rate_limit_window_sec = IP başına hız sınırı için kayan pencerenin süresi (saniye). Bilinçli olarak kısa tutulur: ani istek sellerini kısar ama istemciyi uzun süre kilitlemez; pencere dolar dolmaz yeniden istek atılabilir. (Ör: 1)
- rate_limit_max = Her
rate_limit_window_secpenceresinde, IP başına izin verilen azami istek sayısı. Aşıldığında istek429 Too Many Requests+Retry-Afterile reddedilir.0verilirse hız sınırı tamamen kapatılır. (Ör: 2) - trust_proxy = true ya da false. Yazılım nginx reverse proxy arkasında çalışıyorsa
trueyapılır; böylece hız sınırı için proxy adresi yerineX-Forwarded-Forbaşlığındaki gerçek istemci IP'si kullanılır.
- enabled = true ya da false. Harici uygulamaların ATS uygulama iletilerine sorgu atabilmesi için ACARS Application API modülünün etkinleştirilip etkinleştirilmeyeceğini belirler. Şu an
- [SECURITY]
- enabled = true ya da false. /stream, /decode ve /acars-app/* endpoint'lerinde bağlanma anı kimlik doğrulamasının etkinleştirilip etkinleştirilmeyeceğini belirler. /health endpoint'leri her durumda muaftır.
- api_keys = Virgülle ayrılmış statik API key listesi. Harici (server-to-server) tüketiciler bu key'i
X-API-KeyHTTP header'ında gönderir. Browser tarafından kullanılmaz; tarayıcıya hiç inmez. - jwt_secret = atcweb tarafından üretilen oturum JWT'lerinin doğrulandığı paylaşılan HS256 anahtarı. atcweb
.htaccess'tekiDATALINK_JWT_SECRETile aynı olmalıdır. - jwt_cookie_name = JWT'nin taşındığı çerez adı (eski yöntem, varsayılan:
datalink_session). JWT ayrıcaAuthorization: Bearerbaşlığı ya da?token=parametresiyle kabul edilir.
Uç yazılım, yerel ağda değil de internet ortamında yayınlanacaksa ve de uç yazılımı ayarlarken doğrudan IP erişimi yerine alan adı kullanmak istiyorsanız Reverse Proxy kullanabilirsiniz. Uygun bir yazılım (IIS, Nginx, Apache vb.) ve ayarlamalar ile, dışarıdan belirli bir domain adı ve/veya alt alan adı ile gelen istekleri, arka yazılımın çalıştığı sunucu ve porta yönlendirebilirsiniz. Reverse Proxy ayarlanırken, SSE (Server-Sent Events) desteği olan bir yazılım kullanmanız ve SSE isteklerinin doğru şekilde yönlendirildiğinden emin olmanız gerekmektedir.
Örnek Nginx ayarı:
server {
listen xxx.xxx.xxx.xxx:2053 ssl; // nginx'in dinleyeceği IP adresi ve port
server_name dlink-api.ibosoft.net.tr; // Uç yazılıma erişim için kullanılacak alan adı
ssl_certificate ssl/cert.pem; // SSL sertifikası (isteğe bağlı)
ssl_certificate_key ssl/key.pem; // SSL sertifikası anahtarı (isteğe bağlı)
location ~ ^/error_docs/.*\.htm$ {
root ./;
internal;
}
// (İsteğe bağlı) Uç yazılımı yayınlayacağınız web sitesinin dışından erişimi zorlaştırmak için http_referer kontrolü, kendi alan adınızı ve arka yazılıma erişim için kullandığınız alan adını ekleyebilirsiniz. (Ör: atc.ibosoft.net.tr ve dlink-api.ibosoft.net.tr:2053)
if ($http_referer !~ "^https://(atc\.ibosoft\.net\.tr|dlink-api\.ibosoft\.net\.tr(:2053)?)/") {
return 403;
}
// SSE istekleri için gerekli ayarlar
location / {
proxy_pass http://127.0.0.1:10002; // Arka yazılımın çalıştığı sunucu ve port ([BACKEND] ayarları), http:// ile SSL düşürme yazpılmıştır.
proxy_http_version 1.1;
# Önemli SSE ayarları:
proxy_set_header Connection '';
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 6h;
proxy_send_timeout 60s;
tcp_nodelay on;
# SSE başlıkları
add_header Cache-Control no-cache;
add_header X-Accel-Buffering no;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
- Reverse Proxy ile birlikte Cloudflare proxy hizmetini kullanabilirsiniz. Cloudflare'ın ücretsiz planında proxy hizmetinden yararlanmak için desteklenen portlardan biri kullanılmalıdır. Örneğin 443 (varsayılan https portu), 2053, 2083, 2087, 2096 veya 8443 portları kullanılabilir. Reverse Proxy örneğinde 2053 portu kullanılmıştır.
For the software to work, a software that can demodulate and decode data link subnetwork signals and transmit ACARS network messages (ATN network is not currently supported) in appropriate JSON format via TCP server must be installed and running. Additionally, messages from multiple feeders can be collected in a single TCP server via intermediate software and then forwarded to the backend software.
- To collect data from multiple feeders with different protocols and transmit it to the backend software as a TCP server, you can use this software: acars_router
- acars_router should be configured as "TCP server".
Some of the following software does not directly support TCP transmission, but can be used to provide data via acars_router or other relay software.
- For ACARS network decoding via VDL M0/A subnetwork: acarsdec
- For ACARS network decoding via VDL M2 subnetwork: vdlm2dec
- For ACARS network decoding via HFDL subnetwork: acarshfdl
- For ACARS network decoding via INMARSAT Classic Aero subnetwork: JAERO
Not yet supported but for ATN network:
- For ATN network decoding via VDL M2 subnetwork: dumpvdl2
A MySQL-based database server is required for records, and an empty database must be created in it. The required tables will be added to the database by the software.
Settings are made via the config.ini file. The explanations of the settings are as follows:
- [DATABASE]
- host = IP address of MySQL-based database server (e.g., localhost)
- port = Port number of database server (e.g., 3306)
- user = Database username.
- password = Database user password.
- database = Name of the database to be used.
- read_pool_size = Size of the separate connection pool used for read queries (ACARS Application API + stats counter). Keeps readers off the single writer connection used by the TCP receiver thread, so concurrent API queries cannot corrupt the write path. (e.g., 8)
- [BACKEND]
- host = IP address of the web server for frontend software to connect (e.g., localhost)
- port = Port number of the web server for frontend software to connect (e.g., 10002)
- [LISTENER]
- host = IP address of the TCP server that will send messages (e.g., localhost)
- port = Port number of the TCP server that will send messages (e.g., 15551)
- max_idle_time = Maximum idle time (in seconds) allowed for connection loss detection as a backup, apart from instant connection loss detection. If no new message is received after this time, the reconnection process is initiated. (e.g., 600)
- [RECORDING]
- max_messages = Maximum number of messages to be stored in the database. When this number is reached, the oldest messages are deleted and new messages are recorded. (e.g., 100000)
- [LOGGING]
- max_log_size_mb = Maximum size of the log file (in MB) (e.g., 10)
- backup_count = Number of log file backups (e.g., 2)
- [DECODING]
- enabled = true or false. Determines whether backend software functions related to decoding ACARS network ARINC 622 applications are enabled.
- [ACARS_APP_API]
- enabled = true or false. Determines whether the ACARS Application API module is enabled. This module lets external applications query ATS application messages collected by the backend. The
datisanddclapplications are currently supported; new ATS applications (pdc, aoc, ...) can be enabled later by adding a handler entry inside the module. - host = IP address of the ACARS Application API server (e.g., 0.0.0.0).
- port = Port number of the ACARS Application API server (e.g., 10012). Must not conflict with the [BACKEND] port.
- max_count_per_type = D-ATIS: maximum number of messages a single API call may return per type (DEP/ARR). The caller-supplied
countis clamped to this value. (e.g., 5) - dcl_max_count = DCL: maximum number of DCL messages a single API call may return. The caller-supplied
countis clamped to this value. Required. (e.g., 30) - rate_limit_window_sec = Length (in seconds) of the sliding window used for per-IP rate limiting. Kept deliberately short: it throttles bursts/floods without locking a client out for long — a client may retry as soon as the window rolls over. (e.g., 1)
- rate_limit_max = Maximum number of requests allowed per IP within each
rate_limit_window_secwindow. When exceeded, the request is rejected with429 Too Many Requests+Retry-After. Set to0to disable rate limiting entirely. (e.g., 2) - trust_proxy = true or false. Set to
truewhen running behind the nginx reverse proxy so that the real client IP from theX-Forwarded-Forheader is used for rate limiting instead of the proxy address.
- enabled = true or false. Determines whether the ACARS Application API module is enabled. This module lets external applications query ATS application messages collected by the backend. The
- [SECURITY]
- enabled = true or false. Determines whether connection-level authentication is enforced on /stream, /decode and /acars-app/* endpoints. /health endpoints are always exempt.
- api_keys = Comma-separated list of accepted static API keys. External (server-to-server) callers send the key in the
X-API-KeyHTTP header. Not used by browsers; the static key never reaches the browser. - jwt_secret = Shared HS256 secret used to verify session JWTs issued by atcweb. Must match
DATALINK_JWT_SECRETset in atcweb's.htaccess. - jwt_cookie_name = Cookie name carrying the JWT (legacy channel, default:
datalink_session). The JWT is also accepted as anAuthorization: Bearerheader or a?token=query parameter.
If the frontend software will be published in an internet environment rather than a local network and you want to use a domain name instead of direct IP access when configuring the frontend software, you can use a Reverse Proxy. With appropriate software (IIS, Nginx, Apache, etc.) and configurations, you can redirect requests from outside with a specific domain name and/or subdomain to the server and port where the backend software is running. When configuring the Reverse Proxy, you must use software that supports SSE (Server-Sent Events) and ensure that SSE requests are properly redirected.
Example Nginx configuration:
server {
listen xxx.xxx.xxx.xxx:2053 ssl; // IP address and port that nginx will listen to
server_name dlink-api.ibosoft.net.tr; // Domain name to be used for frontend software access
ssl_certificate ssl/cert.pem; // SSL certificate (optional)
ssl_certificate_key ssl/key.pem; // SSL certificate key (optional)
location ~ ^/error_docs/.*\.htm$ {
root ./;
internal;
}
// (Optional) To make access from outside the website where you will publish the frontend software more difficult, you can add http_referer control with your own domain name and the domain name you use for backend software access. (e.g., atc.ibosoft.net.tr and dlink-api.ibosoft.net.tr:2053)
if ($http_referer !~ "^https://(atc\.ibosoft\.net\.tr|dlink-api\.ibosoft\.net\.tr(:2053)?)/") {
return 403;
}
// Required settings for SSE requests
location / {
proxy_pass http://127.0.0.1:10002; // Server and port where the backend software is running ([BACKEND] settings), SSL termination is done with http://
proxy_http_version 1.1;
# Important SSE settings:
proxy_set_header Connection '';
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 6h;
proxy_send_timeout 60s;
tcp_nodelay on;
# SSE headers
add_header Cache-Control no-cache;
add_header X-Accel-Buffering no;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
- You can use Cloudflare proxy service along with Reverse Proxy. To benefit from the proxy service on Cloudflare's free plan, one of the supported ports must be used. For example, 443 (default https port), 2053, 2083, 2087, 2096, or 8443 ports can be used. Port 2053 is used in the Reverse Proxy example.
Yazılım, TCP ile getirilen ASCII kodlu iletilerden JSON verisini ayrıştırır. Beklenen JSON yapısı örneği aşağıdaki gibidir:
{
"freq": 131.725,
"channel": 1,
"error": 0,
"level": -36.2,
"timestamp": 1760840065.479974,
"app": {
"name": "acarsdec",
"ver": ""
},
"station_id": "ANTALYA1",
"assstat": "skipped",
"mode": "2",
"label": "43",
"block_id": "9",
"ack": false,
"tail": "TC-IBO",
"text": "IBO8U,0214,00039,0000, 55,0226,N 37.078,E 30.527,",
"msgno": "M37A",
"flight": "IB008U"
}Açıklamaları:
freq: Frekans (MHz cinsinden)channel: Kanal numarası (Uç yazılımda işlevsiz)error: Hata durumu (0 = hata yok) (uç yazılımda işlevsiz)level: Sinyal seviyesi (dBm cinsinden)timestamp: İletinin içerisindeki zaman damgası (Unix epoch formatında) (Uç yazılımda işlevsiz.)app: İleti oluşturan uygulama bilgileriname: Uygulama adı (Uç yazılım, uygulama türüne göre Subnetwork ve Network türünü belirler. Ayrıntılar için uç yazılımın rehberine bakınız.)ver: Uygulama sürümü (Uç yazılımda işlevsiz.)
station_id: İstasyon kimliği (Farklı alıcılara sahip kurulumlarda, alıcılara farklı istasyon kimlikleri atanabilir.)assstat: Çok bloklu ACARS iletilerinde, blokların ilişkilendirme durumu (Uç yazılımın rehberine bakınız.)mode: ACARS ileti modu (Subnetwork türü değildir. VDL M0/A, M2 vs. ile karıştırmayın.) (Uç yazılımda işlevsiz.)label: ACARS ileti Label'iNOT:
_DELlabel'i (DEL ASCII DEL karakteridir, 0x7F) metin kodlama kısıtlamaları nedeniyle_dolarak gönderilmelidir.block_id: ACARS ileti Blok numarasıack: ACARS ileti ACK bayrağı (true/false)tail: ARINC 618/620 Aircraft Address (Uçak kuyruk numarası)text: ACARS ileti metin içeriğimsgno: Downlink iletileri için ARINC 618/620 Downlink Sequence Number (Uç yazılımda işlevsiz.)flight: ARINC 618/620 Flight Identifier
Bu modül, harici uygulamaların (3. taraf araçlar, entegrasyonlar, başka iç sistemler) data link arka yazılımının topladığı ATS uygulama iletilerine erişebilmesi için tasarlanmıştır. Modül genişlemeye uygundur: her ATS uygulaması ayrı bir alt yol (sub-path) altında, kendi sorgu parametre şemasıyla servis edilir. Şu an datis ve dcl uygulamaları destekleniyor; ileride pdc, aoc gibi uygulamalar modüldeki handler kaydına satır eklenerek aktive edilebilir.
Erişim yalnızca ACARS network trafiği (app.name ∈ acarsdec, vdlm2dec, jaero, dumphfdl) içinden filtrelenir; CPDLC, ATN vb. diğer network mesajları sonuç dışında tutulur.
Endpoint deseni:
GET /acars-app/<application>?<application-specific params>
<application>whitelist'te yer almalıdır (unsupported application: ...400 hatası aksi halde döner)./healthendpoint'i yok — endpoint yanıt veriyorsa servis ayakta demektir; servis ayakta mı sorusunu SSE server'ın/health'ı yanıtlıyor.
Şu anki uygulama: datis (D-ATIS)
GET /acars-app/datis?icao=<ICAO>&type=<dep|arr|dep,arr>&count=<N>&days=<D> — Belirtilen havalimanı ICAO'su için talep edilen tipler (DEP, ARR ya da her ikisi) bazında son N adet D-ATIS iletisini JSON olarak döner.
| Parametre | Zorunlu | Format | Açıklama |
|---|---|---|---|
icao |
Evet | 4 harf (A–Z, küçük/büyük harf duyarsız; uppercase'e normalize edilir) | Havalimanı ICAO kodu |
type |
Hayır (varsayılan dep,arr) |
dep, arr ya da dep,arr (sıra önemsiz) |
Hangi ATIS türleri istenir |
count |
Hayır (varsayılan 1) |
1 ≤ N ≤ max_count_per_type |
Her tipten kaç mesaj döneceği |
days |
Hayır (varsayılan: yok) | Pozitif tam sayı | Yalnızca son N gün içindeki iletilerde arama yapılır; verilmezse tüm geçmiş taranır |
Veri kaynağı ve eşleşme deseni: ACARS network D-ATIS iletilerinin metni genellikle şu desenle başlar:
/ESBDTYA.TI2/LTAI DEP ATIS S 1030Z ...
/ISTATYA.TI2/LTFM ARR ATIS Z 1100Z ...
Backend ICAO'yu bu metinde /<ICAO>[ -]DEP[ -]ATIS[ -] veya /<ICAO>[ -]ARR[ -]ATIS[ -] desenine göre, ACARS A9 label'lı kayıtlar içinde arar (REGEXP). DEP/ARR ile ATIS arasındaki ve ICAO ile DEP/ARR arasındaki ayraç boşluk ya da tire olabilir; her iki varyant da eşleşir.
Yanıt JSON yapısı örneği (/acars-app/datis?icao=LTFM&type=dep,arr&count=3):
{
"icao": "LTFM",
"count": 3,
"dep": [
{ "timestamp": 1760840065.479974, "text": "/ESBDTYA.TI2/LTFM DEP ATIS S ..." },
{ "timestamp": 1760830000.0, "text": "/ESBDTYA.TI2/LTFM DEP ATIS R ..." }
],
"arr": [
{ "timestamp": 1760830500.0, "text": "/ISTATYA.TI2/LTFM ARR ATIS Z ..." }
]
}- Talep edilen tipler için yanıtta her zaman bir dizi alanı yer alır; o tipte mesaj bulunamamışsa
[]döner. - Talep edilmeyen tip yanıtta hiç görünmez (örn.
type=depsorgusunda yanıttaarralanı bulunmaz). countalanı, çağıranın istediği değerin (sınırlandırma sonrası) etkili tavanını yansıtır.daysverilmezse zaman kısıtı uygulanmaz; tüm kayıt geçmişi taranır.- Mesajlar
timestampalanına göre azalan (en yeni üstte) sıralanır.
Uygulama: dcl (DCL — Departure Clearance)
GET /acars-app/dcl?icao=<ICAO>&count=<N>&days=<D> — Belirtilen havalimanı ICAO'su için son N adet DCL iletisini JSON olarak döner. Sorgu D-ATIS ile aynıdır; farkı ACARS A3 label'lı kayıtlar içinde aranması ve ICAO'nun DCL başlığındaki yerinde /CLD <HHMM> <YYMMDD> <ICAO> desenine göre (REGEXP) eşleşmesidir (örn. /ESBCTYA.DC1/CLD 1142 261013 LTAI PDC 075). Klerans metninde sonradan geçen ICAO'lar (örn. CLRD TO LCEN) eşleşmez. type parametresi yoktur.
| Parametre | Zorunlu | Format | Açıklama |
|---|---|---|---|
icao |
Evet | 4 harf (A–Z, küçük/büyük harf duyarsız; uppercase'e normalize edilir) | Havalimanı ICAO kodu |
count |
Hayır (varsayılan 1) |
1 ≤ N ≤ dcl_max_count |
Kaç mesaj döneceği |
days |
Hayır (varsayılan: yok) | Pozitif tam sayı | Yalnızca son N gün içindeki iletilerde arama yapılır; verilmezse tüm geçmiş taranır |
Yanıt JSON yapısı: {"icao": "LTFM", "count": 30, "dcl": [{"timestamp": ..., "text": "..."}]} — eşleşme yoksa dcl [] döner; mesajlar en yeni üstte sıralanır.
Hız sınırı ve eşzamanlılık: Modül, IP başına kısa pencereli bir hız sınırı uygular (bkz. [ACARS_APP_API].rate_limit_window_sec / rate_limit_max); eşiği aşan istekler 429 Too Many Requests + Retry-After ile geri çevrilir. Bu, çok sayıda eşzamanlı istek geldiğinde (örn. arayan bir sitenin istek seli) veri tabanının aşırı yüklenmesini önler. Okuma sorguları ayrı bir bağlantı havuzundan ([DATABASE].read_pool_size) yürütülür; bu sayede API sorguları TCP alıcı iş parçacığının yazma yolunu etkilemez ve yoğun okuma trafiği ileti kaydını kesintiye uğratmaz.
Arka yazılım, /stream, /decode ve /acars-app/* endpoint'lerinde bağlanma anında kimlik doğrulaması yapar; bağlantı bir kez kurulduktan sonra mesaj akışı sırasında ek doğrulama yapılmaz. SSE server'ın /health endpoint'i her durumda korumadan muaftır. Yapılandırma [SECURITY] bölümünden yapılır; enabled = false ile geçiş/dev için tamamen devre dışı bırakılabilir.
İki ayrı kabul kanalı vardır ve endpoint sınıfına göre farklı kanallar açıktır:
| Endpoint | X-API-Key header |
JWT (Authorization: Bearer, ?token=, datalink_session çerezi) |
|---|---|---|
/stream, /decode |
✓ | ✓ |
/acars-app/* |
✓ | ✗ (kabul edilmez) |
SSE /health |
— (muaf) | — (muaf) |
/acars-app/* modülü tarayıcı tarafından çağrılmadığı için JWT yolu bilinçli olarak kapalıdır; harici (server-to-server) tüketiciler yalnız X-API-Key ile kimlik doğrular.
X-API-Key HTTP header'ı (harici uygulamalar için): Sunucudan sunucuya çağıran harici uygulamalar, [SECURITY].api_keys listesindeki statik bir anahtarı bu header ile gönderir. Anahtar tarayıcıya hiç inmez; uygulamanın kendi yapılandırmasında saklı kalır.
HS256 JWT (yalnız /stream ve /decode için, tarayıcı): Statik anahtar tarayıcıya inmediği için, atcweb PHP'si oturum açmış kullanıcıya kısa ömürlü (8 saat) bir JWT üretir ve sayfaya verir. Tarayıcı JWT'yi /stream bağlantısında ?token= sorgu parametresiyle (EventSource başlık gönderemez), /decode isteklerinde Authorization: Bearer başlığıyla gönderir. Bu taşıma şekli uç yazılım ile arka yazılımın hangi alan adlarında çalıştığından bağımsızdır. Geriye dönük uyumluluk için datalink_session çerezi de kabul edilir; ancak çerez yalnızca iki taraf aynı üst alan adını paylaşıyorsa çalışır. Arka yazılım, JWT'nin imzasını [SECURITY].jwt_secret ile doğrular ve süre dolma kontrolü yapar. Statik anahtarın kendisi tarayıcıya, JavaScript'e, URL'ye veya HTML kaynağına hiçbir şekilde yazılmaz; tarayıcıda yalnızca oturuma özel, süresi dolan JWT bulunur. ?token= ile gönderilen JWT ters vekil erişim loglarında görünebilir; JWT süreli olduğu ve statik anahtarı içermediği için bu kabul edilmiştir.
Geçersiz/eksik kimlik bilgisinde arka yazılım 401 Unauthorized + {"error":"unauthorized"} döner. SSE bağlantısı bir kez kurulduktan sonra JWT süresi dolsa bile akış kesilmez; yalnızca yeniden bağlanma denemesi sırasında yeni bir JWT gerekir (kullanıcı sayfayı yenilediğinde atcweb yeni bir JWT üretir).
JWT imzalamak için kullanılan statik anahtar, atcweb tarafında .htaccess SetEnv DATALINK_JWT_SECRET ile, arka yazılım tarafında config.ini [SECURITY].jwt_secret ile tanımlıdır; iki değer birebir aynı olmak zorundadır.
İki kabul kanalı vardır:
-
X-API-KeyHTTP header'ı (harici uygulamalar için): Sunucudan sunucuya çağıran harici uygulamalar,[SECURITY].api_keyslistesindeki statik bir anahtarı bu header ile gönderir. Anahtar tarayıcıya hiç inmez; uygulamanın kendi yapılandırmasında saklı kalır. -
HS256 JWT (tarayıcı için): Statik anahtar tarayıcıya inmediği için, atcweb PHP'si oturum açmış kullanıcıya kısa ömürlü (8 saat) bir JWT üretir ve sayfaya verir. Tarayıcı JWT'yi
/streambağlantısında?token=sorgu parametresiyle (EventSource başlık gönderemez),/decodeisteklerindeAuthorization: Bearerbaşlığıyla gönderir. Bu taşıma şekli uç yazılım ile arka yazılımın hangi alan adlarında çalıştığından bağımsızdır. Geriye dönük uyumluluk içindatalink_sessionçerezi de kabul edilir; ancak çerez yalnızca iki taraf aynı üst alan adını paylaşıyorsa çalışır. Arka yazılım, JWT'nin imzasını[SECURITY].jwt_secretile doğrular ve süre dolma kontrolü yapar. Statik anahtarın kendisi tarayıcıya, JavaScript'e, URL'ye veya HTML kaynağına hiçbir şekilde yazılmaz; tarayıcıda yalnızca oturuma özel, süresi dolan JWT bulunur.?token=ile gönderilen JWT ters vekil erişim loglarında görünebilir; JWT süreli olduğu ve statik anahtarı içermediği için bu kabul edilmiştir.
Geçersiz/eksik kimlik bilgisinde arka yazılım 401 Unauthorized + {"error":"unauthorized"} döner. SSE bağlantısı bir kez kurulduktan sonra JWT süresi dolsa bile akış kesilmez; yalnızca yeniden bağlanma denemesi sırasında yeni bir JWT gerekir (kullanıcı sayfayı yenilediğinde atcweb yeni bir JWT üretir).
JWT imzalamak için kullanılan statik anahtar, atcweb tarafında .htaccess SetEnv DATALINK_JWT_SECRET ile, arka yazılım tarafında config.ini [SECURITY].jwt_secret ile tanımlıdır; iki değer birebir aynı olmak zorundadır.
Yazılım, veri tabanında messages_json_raw adında bir tablo oluşturur ve iletileri bu tabloya kaydeder. Tablo yapısı, JSON yapısı ile uyumlu olacak şekilde ayarlanmıştır ve aşağıdaki gibidir:
| Sütun Adı | Tür | Açıklama |
|---|---|---|
| id | INT (Auto Increment) | Birincil anahtar |
| received_at | TIMESTAMP | İletinin alındığı zaman |
| source_ip | VARCHAR(45) | İletinin kaynak IP adresi |
| source_port | INT | İletinin kaynak portu |
| timestamp_msg | DOUBLE | İleti içerisindeki zaman damgası |
| station_id | VARCHAR(50) | İstasyon kimliği |
| channel | INT | Kanal numarası |
| freq | DOUBLE | Frekans |
| level | DOUBLE | Sinyal seviyesi |
| error | INT | Hata durumu |
| mode | VARCHAR(10) | Mod |
| label | VARCHAR(20) | Label |
| block_id | VARCHAR(10) | Blok kimliği |
| ack | BOOLEAN | ACK bayrağı |
| tail | VARCHAR(20) | Aircraft Address |
| text | TEXT | İleti metin içeriği |
| msgno | VARCHAR(20) | Downlink Sequence Number |
| flight | VARCHAR(20) | Flight Identifier |
| assstat | VARCHAR(50) | İlişkilendirme durumu |
| app_name | VARCHAR(50) | Uygulama adı |
| app_ver | VARCHAR(50) | Uygulama sürümü |
Sorgu başarımı için, tabloya tekil sütun indekslerinin yanı sıra iki hedefli indeks eklenir: idx_label_ts (label, timestamp_msg) ve idx_timestamp_msg (timestamp_msg). Bunlar hem D-ATIS API sorgusunu (aday kayıtları ilgili label'a ve zaman sırasına daraltarak tam tablo taraması ve filesort'u önler) hem de uç yazılımın Geçmiş (History) sayfasındaki zaman aralığı filtresi + ORDER BY timestamp_msg sorgusunu hızlandırır. İndeksler başlangıçta yoksa otomatik eklenir; mevcut kurulumlarda ilk çalıştırmada ALTER TABLE birkaç saniye sürebilir, sonraki açılışlarda atlanır.
- ACARS iletilerinin, ARINC 620 ve ICAO SARP'larına göre uygun uygulama (ACARS Application) türlerine göre sınıflandırılması, uç yazılım tarafından Ibosoft Acars Decoding Library ve uç yazılım içerisindeki bazı kodlar aracılığıyla yapılmaktadır.
- ARINC 620 dahilinde çözümlenmesi açıklanan iletilerin/uygulamalarının çözümlenmesi, uç yazılım tarafında Ibosoft Acars Decoding Library aracılığıyla yapılmaktadır.
- Uç yazılımın; ACARS ağı üzerinden işleyen ARINC 622 uygulamalarının (ADS-C, CPDLC, MIAM ve bazı "H1" Label'li mühendislik iletileri) çözebilmesi için hazır bir kütüphane kullanılmıştır, derlenmiş kütüphane dosyaları (Windows:
libacars-2.dll, Linux:libacars-2.so) doğrudan projeye dahil edilmiştir. Yazılım, çalıştığı işletim sistemine göre uygun dosyayı yükler. Bakınız: libacars - Linux kütüphanesi (
libacars-2.so), libacars 2.2.0 kaynak kodundan Ubuntu 24.04 x86_64 üzerinde, Windows DLL'i ile aynı ayarlarla (zlib açık, libxml2 kapalı) derlenmiştir. Tek dış bağımlılığı sistemdeki zlib'dir (libz.so.1). - libacars, "SA" Label'li (Media Advisory) iletileri de çözebilmektedir ancak bu Label'li iletilerin çözümlemesi, uç yazılım tarafında Ibosoft Acars Decoding Library ile yapılmaktadır.
- libacars kütüphanesinin yapısı gereği, kütüphanenin arka yazılıma dahil edilmesi kararı alınmıştır.
- ARINC 622 uygulamları çözülürken, canlı iletiler için, ileti ACARS ağı iletisi ise ve ileti Label'i AA (CPDLC), BA (CPDLC), A6 (ADS-C), B6 (ADS-C), MA (MIAM), H1 ise ileti arka yazılımda çözülür ve canlı ileti bilgisiyle birlikte uç yazılıma iletilir.
- Geçmiş iletilerde, uç yazılım doğrudan PHP aracılığıyla veritabanına eriştiği için arka yazılımı doğrudan kullanmaz. ARINC 622 uygulamaları ise arka yazılım tarafında çözümlemesi yapıldığı için, arka yazılıma bir API uç noktası eklenmiştir. Uç yazılım, geçmiş iletiler için ARINC 622 uygulamalarını çözmek istediğinde, arka yazılıma bir istek gönderir ve arka yazılım iletiyi çözüp sonucu uç yazılıma iletir. Bu işlev için, iletinin ACARS ağı iletisi ve ileti Label'inin AA (CPDLC), BA (CPDLC), A6 (ADS-C), B6 (ADS-C), MA (MIAM), H1 olması gerekmektedir.
Yazılım, TCP bağlantısı koptuğunda veya bağlantı kurulamadığında, kısa aralıklarla yeniden bağlanmayı dener. Yeniden bağlanma denemeleri sırasında, bağlantı kurulana kadar bekler ve bu sırada yeni iletiler alınamaz. Bağlantı kopukluğunun tespit edilememesi durumları için, ayarlarda belirtilen süre boyunca yeni bir ileti alınmazsa yeniden bağlanma işlemi başlatılır.
acars-backend/
├── main.py # Ana uygulama
├── database_handler.py # Veritabanı işlemleri modülü
├── decode_handler.py # ACARS ileti çözücü (libacars sarmalayıcı)
├── tcp_client.py # TCP istemci modülü
├── sse_server.py # SSE sunucu modülü
├── acars_app_api.py # ACARS Application API modülü (D-ATIS, DCL + ileride diğer ATS uygulamaları)
├── rate_limiter.py # ACARS Application API için IP başına kısa pencereli hız sınırlayıcı
├── config.ini # Yapılandırma dosyası
├── requirements.txt # Python bağımlılıkları
├── install-venv.bat # Sanal ortamı (venv) kuran ve bağımlılıkları yükleyen ilk kurulum betiği
├── start.bat # Windows başlatma betiği (sanal ortamdaki python ile çalıştırır)
├── install-venv.sh # Linux ilk kurulum betiği (venv oluşturur, bağımlılıkları yükler)
├── start.sh # Linux başlatma betiği (sanal ortamdaki python ile çalıştırır, systemd uyumlu)
├── LICENSE # Lisans dosyası
├── README.md # Bu dosya
├── SSE_MIGRATION.md # SSE geçiş dokümantasyonu
├── libacars/ # libacars kütüphane klasörü
│ ├── libacars-2.dll # libacars ARINC 622 çözücü kütüphanesi
│ ├── zlib1.dll # zlib sıkıştırma kütüphanesi (bağımlılık)
│ ├── libacars-2.so # libacars kütüphanesi, Linux x86_64 derlemesi (zlib sistemden kullanılır)
│ └── LICENSE.md # libacars lisans dosyası
└── atc_datalink.log # Log dosyası (Yazılım çalıştırılınca oluşturulur.)
- Windows or Linux (x86_64) operating system.
- Python 3.x (must be reachable on the system PATH as
pythonon Windows,python3on Linux). - Additionally on Linux: the
python3-venvpackage and zlib (libz.so.1; installed by default on Ubuntu/Debian). - The following additional Python packages (installed automatically through
requirements.txt):- mysql-connector-python==8.2.0
- Flask==3.0.0
- Flask-Cors==4.0.0
- PyJWT==2.8.0
The software is portable, download and place it in an appropriate directory on the server.
On first checkout (and whenever requirements.txt is updated), run the setup script in the software directory once to set up a virtual environment (Windows: install-venv.bat, Linux: install-venv.sh):
install-venv.bat
./install-venv.shThis script:
- Creates an isolated Python virtual environment under the
venvdirectory if one does not already exist. - Upgrades
pipinside that virtual environment. - Installs every package listed in
requirements.txtinto the virtual environment.
The system-wide Python installation is left untouched; the dependencies live only inside this project's venv directory. venv/ is included in .gitignore, so it is never committed to the repository.
After configuring the necessary settings, run the start.bat script file on Windows or the start.sh script file on Linux. You can create a task schedule or a service for automatic startup.
start.batrunsmain.pyusing the virtual environment's Python (venv\Scripts\python.exe). If the virtual environment is missing, the script errors out and tells you to runinstall-venv.batfirst.start.shrunsmain.pyusing the virtual environment's Python (venv/bin/python). If the virtual environment is missing, the script errors out and tells you to runinstall-venv.shfirst. Because it starts Python withexec, the stop signal (SIGTERM) from systemd reaches the software directly.- The bat script is prepared to run directly as a service. You can add a service that will run the bat file using appropriate commands or a Windows service creation tool like Servy.
- The bat script sets its own directory as the working directory when started from any directory. Therefore, even if the software's directory is not set as the working directory in the task schedule or service settings, the software will work correctly.
start.shlikewise sets its own directory as the working directory when started from any directory or from systemd. - Example systemd service on Linux (
/etc/systemd/system/atc-data-link-backend.service; adjust the user and path to your installation):
[Unit]
Description=Ibosoft ACARS Backend
After=network-online.target
Wants=network-online.target
[Service]
User=administrator
ExecStart=/home/administrator/ibosoft/atc-data-link-backend/start.sh
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.targetNOTE: There are still some issues with connection loss detection, and sometimes the automatic reconnection feature does not work during long-term operations. Therefore, for now, configure the task schedule or service settings so that the task/service is restarted 1-2 times a day.
For the software to work, a software that can demodulate and decode data link subnetwork signals and transmit ACARS network messages (ATN network is not currently supported) in appropriate JSON format via TCP server must be installed and running. Additionally, messages from multiple feeders can be collected in a single TCP server via intermediate software and then forwarded to the backend software.
- To collect data from multiple feeders with different protocols and transmit it to the backend software as a TCP server, you can use this software: acars_router
- acars_router should be configured as "TCP server".
Some of the following software does not directly support TCP transmission, but can be used to provide data via acars_router or other relay software.
- For ACARS network decoding via VDL M0/A subnetwork: acarsdec
- For ACARS network decoding via VDL M2 subnetwork: vdlm2dec
- For ACARS network decoding via HFDL subnetwork: acarshfdl
- For ACARS network decoding via INMARSAT Classic Aero subnetwork: JAERO
Not yet supported but for ATN network:
- For ATN network decoding via VDL M2 subnetwork: dumpvdl2
A MySQL-based database server is required for records, and an empty database must be created in it. The required tables will be added to the database by the software.
Settings are made via the config.ini file. The explanations of the settings are as follows:
- [DATABASE]
- host = IP address of MySQL-based database server (e.g., localhost)
- port = Port number of database server (e.g., 3306)
- user = Database username.
- password = Database user password.
- database = Name of the database to be used.
- read_pool_size = Size of the separate connection pool used for read queries (ACARS Application API + stats counter). Keeps readers off the single writer connection used by the TCP receiver thread, so concurrent API queries cannot corrupt the write path. (e.g., 8)
- [BACKEND]
- host = IP address of the web server for frontend software to connect (e.g., localhost)
- port = Port number of the web server for frontend software to connect (e.g., 10002)
- [LISTENER]
- host = IP address of the TCP server that will send messages (e.g., localhost)
- port = Port number of the TCP server that will send messages (e.g., 15551)
- max_idle_time = Maximum idle time (in seconds) allowed for connection loss detection as a backup, apart from instant connection loss detection. If no new message is received after this time, the reconnection process is initiated. (e.g., 600)
- [RECORDING]
- max_messages = Maximum number of messages to be stored in the database. When this number is reached, the oldest messages are deleted and new messages are recorded. (e.g., 100000)
- [LOGGING]
- max_log_size_mb = Maximum size of the log file (in MB) (e.g., 10)
- backup_count = Number of log file backups (e.g., 2)
- [DECODING]
- enabled = true or false. Determines whether backend software functions related to decoding ACARS network ARINC 622 applications are enabled.
- [ACARS_APP_API]
- enabled = true or false. Determines whether the ACARS Application API module is enabled. This module lets external applications query ATS application messages collected by the backend. The
datisanddclapplications are currently supported; new ATS applications (pdc, aoc, ...) can be enabled later by adding a handler entry inside the module. - host = IP address of the ACARS Application API server (e.g., 0.0.0.0).
- port = Port number of the ACARS Application API server (e.g., 10012). Must not conflict with the [BACKEND] port.
- max_count_per_type = D-ATIS: maximum number of messages a single API call may return per type (DEP/ARR). The caller-supplied
countis clamped to this value. (e.g., 5) - dcl_max_count = DCL: maximum number of DCL messages a single API call may return. The caller-supplied
countis clamped to this value. Required. (e.g., 30) - rate_limit_window_sec = Length (in seconds) of the sliding window used for per-IP rate limiting. Kept deliberately short: it throttles bursts/floods without locking a client out for long — a client may retry as soon as the window rolls over. (e.g., 1)
- rate_limit_max = Maximum number of requests allowed per IP within each
rate_limit_window_secwindow. When exceeded, the request is rejected with429 Too Many Requests+Retry-After. Set to0to disable rate limiting entirely. (e.g., 2) - trust_proxy = true or false. Set to
truewhen running behind the nginx reverse proxy so that the real client IP from theX-Forwarded-Forheader is used for rate limiting instead of the proxy address.
- enabled = true or false. Determines whether the ACARS Application API module is enabled. This module lets external applications query ATS application messages collected by the backend. The
- [SECURITY]
- enabled = true or false. Determines whether connection-level authentication is enforced on /stream, /decode and /acars-app/* endpoints. /health endpoints are always exempt.
- api_keys = Comma-separated list of accepted static API keys. External (server-to-server) callers send the key in the
X-API-KeyHTTP header. Not used by browsers; the static key never reaches the browser. - jwt_secret = Shared HS256 secret used to verify session JWTs issued by atcweb. Must match
DATALINK_JWT_SECRETset in atcweb's.htaccess. - jwt_cookie_name = Cookie name carrying the JWT (legacy channel, default:
datalink_session). The JWT is also accepted as anAuthorization: Bearerheader or a?token=query parameter.
If the frontend software will be published in an internet environment rather than a local network and you want to use a domain name instead of direct IP access when configuring the frontend software, you can use a Reverse Proxy. With appropriate software (IIS, Nginx, Apache, etc.) and configurations, you can redirect requests from outside with a specific domain name and/or subdomain to the server and port where the backend software is running. When configuring the Reverse Proxy, you must use software that supports SSE (Server-Sent Events) and ensure that SSE requests are properly redirected.
Example Nginx configuration:
server {
listen xxx.xxx.xxx.xxx:2053 ssl; // IP address and port that nginx will listen to
server_name dlink-api.ibosoft.net.tr; // Domain name to be used for frontend software access
ssl_certificate ssl/cert.pem; // SSL certificate (optional)
ssl_certificate_key ssl/key.pem; // SSL certificate key (optional)
location ~ ^/error_docs/.*\.htm$ {
root ./;
internal;
}
// (Optional) To make access from outside the website where you will publish the frontend software more difficult, you can add http_referer control with your own domain name and the domain name you use for backend software access. (e.g., atc.ibosoft.net.tr and dlink-api.ibosoft.net.tr:2053)
if ($http_referer !~ "^https://(atc\.ibosoft\.net\.tr|dlink-api\.ibosoft\.net\.tr(:2053)?)/") {
return 403;
}
// Required settings for SSE requests
location / {
proxy_pass http://127.0.0.1:10002; // Server and port where the backend software is running ([BACKEND] settings), SSL termination is done with http://
proxy_http_version 1.1;
# Important SSE settings:
proxy_set_header Connection '';
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 6h;
proxy_send_timeout 60s;
tcp_nodelay on;
# SSE headers
add_header Cache-Control no-cache;
add_header X-Accel-Buffering no;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
- You can use Cloudflare proxy service along with Reverse Proxy. To benefit from the proxy service on Cloudflare's free plan, one of the supported ports must be used. For example, 443 (default https port), 2053, 2083, 2087, 2096, or 8443 ports can be used. Port 2053 is used in the Reverse Proxy example.
The software parses JSON data from ASCII-encoded messages received via TCP. An example of the expected JSON structure is as follows:
{
"freq": 131.725,
"channel": 1,
"error": 0,
"level": -36.2,
"timestamp": 1760840065.479974,
"app": {
"name": "acarsdec",
"ver": ""
},
"station_id": "ANTALYA1",
"assstat": "skipped",
"mode": "2",
"label": "43",
"block_id": "9",
"ack": false,
"tail": "TC-IBO",
"text": "IBO8U,0214,00039,0000, 55,0226,N 37.078,E 30.527,",
"msgno": "M37A",
"flight": "IB008U"
}Descriptions:
freq: Frequency (in MHz)channel: Channel number (non-functional in frontend software)error: Error status (0 = no error) (non-functional in frontend software)level: Signal level (in dBm)timestamp: Timestamp in the message (Unix epoch format) (Non-functional in frontend software.)app: Message generating application informationname: Application name (Frontend software determines Subnetwork and Network type according to application type. See frontend software guide for details.)ver: Application version (Non-functional in frontend software.)
station_id: Station identifier (In installations with different receivers, different station identifiers can be assigned to receivers.)assstat: Association status of blocks in multi-block ACARS messages (See frontend software guide.)mode: ACARS message mode (Not a Subnetwork type. Do not confuse with VDL M0/A, M2, etc.) (Non-functional in frontend software.)label: ACARS message LabelNOTE: The
_DELlabel (DEL is the ASCII DEL character, 0x7F) should be sent as_ddue to text encoding limitations.block_id: ACARS message Block numberack: ACARS message ACK flag (true/false)tail: ARINC 618/620 Aircraft Address (Aircraft tail number)text: ACARS message text contentmsgno: ARINC 618/620 Downlink Sequence Number for downlink messages (Non-functional in frontend software.)flight: ARINC 618/620 Flight Identifier
This module is designed to let external applications (third-party tools, integrations, other internal systems) query ATS-application messages collected by the data link backend. The module is extensible: each ATS application is served under its own sub-path with its own query schema. The datis and dcl applications are currently supported; future applications (pdc, aoc, ...) can be enabled by adding a handler entry inside the module.
Results are filtered to ACARS-network traffic only (app.name ∈ acarsdec, vdlm2dec, jaero, dumphfdl); CPDLC, ATN and other non-ACARS messages are excluded.
Endpoint pattern:
GET /acars-app/<application>?<application-specific params>
<application>must be in the whitelist (unsupported application: ...400 is returned otherwise).- There is no
/healthon this module — if the endpoint responds, the service is up. For service liveness checks use the SSE server's/health.
Current application: datis (D-ATIS)
GET /acars-app/datis?icao=<ICAO>&type=<dep|arr|dep,arr>&count=<N>&days=<D> — Returns up to N D-ATIS messages for the requested types (DEP, ARR or both) for the given airport ICAO.
| Parameter | Required | Format | Description |
|---|---|---|---|
icao |
Yes | 4 letters (A–Z, case-insensitive; normalised to uppercase) | Airport ICAO code |
type |
No (default dep,arr) |
dep, arr or dep,arr (order does not matter) |
Which ATIS directions to return |
count |
No (default 1) |
1 ≤ N ≤ max_count_per_type |
How many messages per type |
days |
No (default: none) | Positive integer | Restrict search to messages from the last N days; omit to search all history |
Data source and match pattern: D-ATIS messages on the ACARS network typically begin with a pattern such as:
/ESBDTYA.TI2/LTAI DEP ATIS S 1030Z ...
/ISTATYA.TI2/LTFM ARR ATIS Z 1100Z ...
The backend searches A9-labelled rows with a REGEXP of the form /<ICAO>[ -]DEP[ -]ATIS[ -] or /<ICAO>[ -]ARR[ -]ATIS[ -]. The separator between ICAO, direction (DEP/ARR) and the literal ATIS may be either a space or a hyphen; all variants are matched.
Example JSON response (/acars-app/datis?icao=LTFM&type=dep,arr&count=3):
{
"icao": "LTFM",
"count": 3,
"dep": [
{ "timestamp": 1760840065.479974, "text": "/ESBDTYA.TI2/LTFM DEP ATIS S ..." },
{ "timestamp": 1760830000.0, "text": "/ESBDTYA.TI2/LTFM DEP ATIS R ..." }
],
"arr": [
{ "timestamp": 1760830500.0, "text": "/ISTATYA.TI2/LTFM ARR ATIS Z ..." }
]
}- Requested types always appear as an array in the response; when there is no match for a type, the array is empty (
[]). - Types that were not requested do not appear in the response (e.g.
type=depproduces a response with noarrfield). - The
countfield reflects the effective per-type cap after clamping. - When
daysis omitted no time filter is applied; the entire message history is searched. - Messages are sorted by
timestampin descending order (newest first).
Application: dcl (DCL — Departure Clearance)
GET /acars-app/dcl?icao=<ICAO>&count=<N>&days=<D> — Returns up to N DCL messages for the given airport ICAO. The query is the same as D-ATIS, except that it searches A3-labelled rows and matches the ICAO at its position in the DCL header with a REGEXP of the form /CLD <HHMM> <YYMMDD> <ICAO> (e.g. /ESBCTYA.DC1/CLD 1142 261013 LTAI PDC 075). ICAOs appearing later in the clearance text (e.g. CLRD TO LCEN) do not match. There is no type parameter.
| Parameter | Required | Format | Description |
|---|---|---|---|
icao |
Yes | 4 letters (A–Z, case-insensitive; normalised to uppercase) | Airport ICAO code |
count |
No (default 1) |
1 ≤ N ≤ dcl_max_count |
How many messages to return |
days |
No (default: none) | Positive integer | Restrict search to messages from the last N days; omit to search all history |
Response JSON: {"icao": "LTFM", "count": 30, "dcl": [{"timestamp": ..., "text": "..."}]} — dcl is [] when there is no match; messages are sorted newest first.
Rate limiting and concurrency: The module enforces a short-window per-IP rate limit (see [ACARS_APP_API].rate_limit_window_sec / rate_limit_max); requests over the threshold are rejected with 429 Too Many Requests + Retry-After. This protects the database from overload under a burst of concurrent requests (e.g. a calling site flooding the endpoint). Read queries run on a separate connection pool ([DATABASE].read_pool_size), so API queries never touch the TCP receiver thread's write path and heavy read traffic cannot interrupt message recording.
The backend authenticates at connection establishment for the /stream, /decode and /acars-app/* endpoints; once a connection is open no per-message check is performed. The SSE server's /health endpoint is always exempt. Configuration lives in the [SECURITY] section; setting enabled = false disables the check entirely (useful for migrations or local development).
Two credential channels exist, but which channels are accepted depends on the endpoint class:
| Endpoint | X-API-Key header |
JWT (Authorization: Bearer, ?token=, datalink_session cookie) |
|---|---|---|
/stream, /decode |
✓ | ✓ |
/acars-app/* |
✓ | ✗ (not accepted) |
SSE /health |
— (exempt) | — (exempt) |
The /acars-app/* module is not called by browsers, so the JWT path is deliberately closed there; external (server-to-server) callers authenticate exclusively with X-API-Key.
X-API-Key HTTP header (external applications): Server-to-server callers send a static key from the [SECURITY].api_keys list in this header. The static key never reaches a browser; it stays in the caller application's own configuration.
HS256 JWT (/stream and /decode only, browsers): Because the static key must not be exposed to the browser, atcweb's PHP issues a short-lived (8 hours) JWT for an authenticated user and hands it to the page. The browser sends it as a ?token= query parameter on the /stream connection (EventSource cannot send headers) and as an Authorization: Bearer header on /decode requests. This transport works regardless of which domains the frontend and backend are served from. The datalink_session cookie is still accepted for backward compatibility, but a cookie only works when both sides share a parent domain. The backend verifies the JWT signature with [SECURITY].jwt_secret and checks the expiry. The static key itself is never written to the browser, to JavaScript, to URLs or to the HTML source — the browser only ever carries the per-session, expiring JWT. A JWT sent via ?token= may appear in reverse-proxy access logs; this is accepted because the JWT expires and does not contain the static secret.
When the credential is missing or invalid the backend responds with 401 Unauthorized + {"error":"unauthorized"}. Once an SSE connection is open, expiry of the underlying JWT does not break the stream; a fresh JWT is required only on reconnect (reloading the page in atcweb mints a new one).
The static secret used to sign JWTs is defined in atcweb's .htaccess (SetEnv DATALINK_JWT_SECRET) and in the backend's config.ini ([SECURITY].jwt_secret). The two values must match exactly.
The software creates a table named messages_json_raw in the database and records messages to this table. The table structure is configured to be compatible with the JSON structure and is as follows:
| Column Name | Type | Description |
|---|---|---|
| id | INT (Auto Increment) | Primary key |
| received_at | TIMESTAMP | Time when the message was received |
| source_ip | VARCHAR(45) | Source IP address of the message |
| source_port | INT | Source port of the message |
| timestamp_msg | DOUBLE | Timestamp in the message |
| station_id | VARCHAR(50) | Station identifier |
| channel | INT | Channel number |
| freq | DOUBLE | Frequency |
| level | DOUBLE | Signal level |
| error | INT | Error status |
| mode | VARCHAR(10) | Mode |
| label | VARCHAR(20) | Label |
| block_id | VARCHAR(10) | Block identifier |
| ack | BOOLEAN | ACK flag |
| tail | VARCHAR(20) | Aircraft Address |
| text | TEXT | Message text content |
| msgno | VARCHAR(20) | Downlink Sequence Number |
| flight | VARCHAR(20) | Flight Identifier |
| assstat | VARCHAR(50) | Association status |
| app_name | VARCHAR(50) | Application name |
| app_ver | VARCHAR(50) | Application version |
For query performance, in addition to the single-column indexes the table gets two targeted indexes: idx_label_ts (label, timestamp_msg) and idx_timestamp_msg (timestamp_msg). These speed up both the D-ATIS API query (narrowing candidate rows to the relevant label in timestamp order, avoiding a full table scan and filesort) and the frontend History page's time-range filter + ORDER BY timestamp_msg query. The indexes are created automatically at startup if missing; on existing installs the first run's ALTER TABLE may take a few seconds, and subsequent startups skip it.
- Classification of ACARS messages according to appropriate application (ACARS Application) types according to ARINC 620 and ICAO SARPs is done by the frontend software through Ibosoft Acars Decoding Library and some codes in the frontend software.
- Decoding of messages/applications that are described to be decoded within ARINC 620 is done by Ibosoft Acars Decoding Library on the frontend software side.
- For the frontend software to decode ARINC 622 applications (ADS-C, CPDLC, MIAM, and some "H1" labeled engineering messages) operating via ACARS network, a ready-made library has been used, and the compiled library files (Windows:
libacars-2.dll, Linux:libacars-2.so) are directly included in the project. The software loads the appropriate file for the operating system it runs on. See: libacars - The Linux library (
libacars-2.so) was built from the libacars 2.2.0 source code on Ubuntu 24.04 x86_64 with the same options as the Windows DLL (zlib enabled, libxml2 disabled). Its only external dependency is the system zlib (libz.so.1). - libacars can also decode "SA" labeled (Media Advisory) messages, but the decoding of these labeled messages is done by Ibosoft Acars Decoding Library on the frontend software side.
- Due to the structure of the libacars library, a decision was made to include the library in the backend software.
- When decoding ARINC 622 applications, for live messages, if the message is an ACARS network message and the message Label is AA (CPDLC), BA (CPDLC), A6 (ADS-C), B6 (ADS-C), MA (MIAM), H1, the message is decoded in the backend software and forwarded to the frontend software along with live message information.
- For historical messages, the frontend software accesses the database directly via PHP, so it does not use the backend software directly. Since ARINC 622 applications are decoded on the backend software side, an API endpoint has been added to the backend software. When the frontend software wants to decode ARINC 622 applications for historical messages, it sends a request to the backend software, and the backend software decodes the message and forwards the result to the frontend software. For this function, the message must be an ACARS network message and the message Label must be AA (CPDLC), BA (CPDLC), A6 (ADS-C), B6 (ADS-C), MA (MIAM), H1.
When the TCP connection is lost or connection cannot be established, the software tries to reconnect at short intervals. During reconnection attempts, it waits until the connection is established, and new messages cannot be received during this time. For cases where connection loss cannot be detected, if no new message is received for the duration specified in the settings, the reconnection process is initiated.
acars-backend/
├── main.py # Main application
├── database_handler.py # Database operations module
├── decode_handler.py # ACARS message decoder (libacars wrapper)
├── tcp_client.py # TCP client module
├── sse_server.py # SSE server module
├── acars_app_api.py # ACARS Application API module (D-ATIS, DCL + future ATS applications)
├── rate_limiter.py # Per-IP short-window rate limiter for the ACARS Application API
├── config.ini # Configuration file
├── requirements.txt # Python dependencies
├── install-venv.bat # First-time setup script: creates the venv and installs dependencies
├── start.bat # Windows startup script (runs main.py via the venv's python)
├── install-venv.sh # Linux first-time setup script: creates the venv and installs dependencies
├── start.sh # Linux startup script (runs main.py via the venv's python, systemd compatible)
├── LICENSE # License file
├── README.md # This file
├── SSE_MIGRATION.md # SSE migration documentation
├── libacars/ # libacars library folder
│ ├── libacars-2.dll # libacars ARINC 622 decoder library
│ ├── zlib1.dll # zlib compression library (dependency)
│ ├── libacars-2.so # libacars library, Linux x86_64 build (uses the system zlib)
│ └── LICENSE.md # libacars license file
└── atc_datalink.log # Log file (Created when the software is run.)