Show device country next to its IP address, resolved via ip-api.com
This commit is contained in:
@@ -31,6 +31,7 @@ import pathlib
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from bson import ObjectId
|
from bson import ObjectId
|
||||||
import urllib.request
|
import urllib.request
|
||||||
|
import ipaddress
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -75,6 +76,8 @@ settings_collection = db_iptv['settings']
|
|||||||
devices_db = db_iptv['devices']
|
devices_db = db_iptv['devices']
|
||||||
devices = []
|
devices = []
|
||||||
active_xtream_imports = {}
|
active_xtream_imports = {}
|
||||||
|
sio_session_ips = {}
|
||||||
|
ip_country_cache = {}
|
||||||
|
|
||||||
# Configure Socket IO
|
# Configure Socket IO
|
||||||
sio = socketio.AsyncServer(logger=True, engineio_logger=True, cors_allowed_origins='*')
|
sio = socketio.AsyncServer(logger=True, engineio_logger=True, cors_allowed_origins='*')
|
||||||
@@ -1417,6 +1420,34 @@ app.router.add_post('/gemini_search', gemini_search)
|
|||||||
app.router.add_get('/channels_epg', channels_epg)
|
app.router.add_get('/channels_epg', channels_epg)
|
||||||
app.router.add_get('/epg', epg_programs)
|
app.router.add_get('/epg', epg_programs)
|
||||||
|
|
||||||
|
def resolve_ip_country(ip_address):
|
||||||
|
if not ip_address:
|
||||||
|
return ''
|
||||||
|
if ip_address in ip_country_cache:
|
||||||
|
return ip_country_cache[ip_address]
|
||||||
|
try:
|
||||||
|
ip_obj = ipaddress.ip_address(ip_address)
|
||||||
|
if ip_obj.is_private or ip_obj.is_loopback or ip_obj.is_link_local:
|
||||||
|
ip_country_cache[ip_address] = ''
|
||||||
|
return ''
|
||||||
|
except ValueError:
|
||||||
|
return ''
|
||||||
|
country = ''
|
||||||
|
try:
|
||||||
|
response = requests.get(
|
||||||
|
f'http://ip-api.com/json/{ip_address}',
|
||||||
|
params={'fields': 'status,country'},
|
||||||
|
timeout=5,
|
||||||
|
)
|
||||||
|
data = response.json()
|
||||||
|
if data.get('status') == 'success':
|
||||||
|
country = data.get('country', '') or ''
|
||||||
|
except requests.RequestException as exc:
|
||||||
|
logger.warning("IP country lookup failed for %s: %s", ip_address, exc)
|
||||||
|
ip_country_cache[ip_address] = country
|
||||||
|
return country
|
||||||
|
|
||||||
|
|
||||||
# SIO FUNCTIONS
|
# SIO FUNCTIONS
|
||||||
|
|
||||||
def messageReceived():
|
def messageReceived():
|
||||||
@@ -1424,7 +1455,12 @@ def messageReceived():
|
|||||||
|
|
||||||
@sio.event
|
@sio.event
|
||||||
def connect(sid, environ):
|
def connect(sid, environ):
|
||||||
print("connect ", sid, flush=True)
|
# engineio's aiohttp integration hardcodes REMOTE_ADDR to 127.0.0.1;
|
||||||
|
# the real peer address is only available via the underlying aiohttp request.
|
||||||
|
aiohttp_request = environ.get('aiohttp.request')
|
||||||
|
ip_address = aiohttp_request.remote if aiohttp_request else ''
|
||||||
|
sio_session_ips[sid] = ip_address
|
||||||
|
print("connect ", sid, ip_address, flush=True)
|
||||||
|
|
||||||
|
|
||||||
@sio.event
|
@sio.event
|
||||||
@@ -1432,11 +1468,12 @@ async def communication(fromSid, data):
|
|||||||
print("search request from ", fromSid, flush=True)
|
print("search request from ", fromSid, flush=True)
|
||||||
toSidDevice = data['toSidDevice']
|
toSidDevice = data['toSidDevice']
|
||||||
print("send signal to ", toSidDevice, flush=True)
|
print("send signal to ", toSidDevice, flush=True)
|
||||||
await sio.emit('communication', data, room=toSidDevice ,callback=messageReceived)
|
await sio.emit('communication', data, room=toSidDevice ,callback=messageReceived)
|
||||||
|
|
||||||
|
|
||||||
@sio.event
|
@sio.event
|
||||||
def disconnect(sid):
|
def disconnect(sid):
|
||||||
|
sio_session_ips.pop(sid, None)
|
||||||
print('disconnect ', sid, flush=True)
|
print('disconnect ', sid, flush=True)
|
||||||
|
|
||||||
|
|
||||||
@@ -1455,14 +1492,21 @@ async def polling(sid, data):
|
|||||||
try:
|
try:
|
||||||
vpn_status = data['vpn_status']
|
vpn_status = data['vpn_status']
|
||||||
except:
|
except:
|
||||||
vpn_status = 'unknown'
|
vpn_status = 'unknown'
|
||||||
device_data = devices_db.find_one({ 'id_device':IdDevice})
|
|
||||||
|
ip_address = sio_session_ips.get(sid, '')
|
||||||
|
if ip_address in ip_country_cache:
|
||||||
|
ip_country = ip_country_cache[ip_address]
|
||||||
|
else:
|
||||||
|
ip_country = await asyncio.get_event_loop().run_in_executor(None, resolve_ip_country, ip_address)
|
||||||
|
|
||||||
|
device_data = devices_db.find_one({ 'id_device':IdDevice})
|
||||||
if device_data:
|
if device_data:
|
||||||
query = { 'id_device':IdDevice}
|
query = { 'id_device':IdDevice}
|
||||||
update = { "$set": { "last_datetime": device_last_datetime ,"name": device_name, "sid":sid, "mediaRunning":mediaRunning, 'vpn_status':vpn_status, 'data_running':data_running, 'auto_snapshot_enabled': auto_snapshot_enabled, 'snapshot_interval_seconds': snapshot_interval_seconds} }
|
update = { "$set": { "last_datetime": device_last_datetime ,"name": device_name, "sid":sid, "mediaRunning":mediaRunning, 'vpn_status':vpn_status, 'data_running':data_running, 'auto_snapshot_enabled': auto_snapshot_enabled, 'snapshot_interval_seconds': snapshot_interval_seconds, 'ip_address': ip_address, 'ip_country': ip_country} }
|
||||||
devices_db.update_one(query, update)
|
devices_db.update_one(query, update)
|
||||||
else:
|
else:
|
||||||
new_device = { 'id_device': IdDevice, 'name' : device_name, 'last_datetime' : device_last_datetime, 'sid':sid ,'mediaRunning' : mediaRunning, 'vpn_status':vpn_status, 'data_running':data_running, 'auto_snapshot_enabled': auto_snapshot_enabled, 'snapshot_interval_seconds': snapshot_interval_seconds}
|
new_device = { 'id_device': IdDevice, 'name' : device_name, 'last_datetime' : device_last_datetime, 'sid':sid ,'mediaRunning' : mediaRunning, 'vpn_status':vpn_status, 'data_running':data_running, 'auto_snapshot_enabled': auto_snapshot_enabled, 'snapshot_interval_seconds': snapshot_interval_seconds, 'ip_address': ip_address, 'ip_country': ip_country}
|
||||||
devices_db.insert_one(new_device)
|
devices_db.insert_one(new_device)
|
||||||
|
|
||||||
if data_running:
|
if data_running:
|
||||||
|
|||||||
+10
-1
@@ -180,6 +180,11 @@
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
.device-ip {
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #9ca3af;
|
||||||
|
}
|
||||||
.device-status {
|
.device-status {
|
||||||
color: var(--success);
|
color: var(--success);
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
@@ -2618,10 +2623,14 @@
|
|||||||
status2 = '#ffe6e6'
|
status2 = '#ffe6e6'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ipAddress = dataJSON[i].ip_address || '';
|
||||||
|
var ipCountry = dataJSON[i].ip_country || '';
|
||||||
|
var ipLine = ipAddress ? `<div class="device-ip text-truncate">${ipAddress}${ipCountry ? ' · ' + ipCountry : ''}</div>` : '';
|
||||||
|
|
||||||
var activeClass = (selectedDeviceId && selectedDeviceId === dataJSON[i].id_device) ? 'active' : '';
|
var activeClass = (selectedDeviceId && selectedDeviceId === dataJSON[i].id_device) ? 'active' : '';
|
||||||
html += `<div class="device-card ${activeClass}" id="btn_select_device_${dataJSON[i].id_device}" data-param1="${dataJSON[i].id_device}" data-param2="${dataJSON[i].name}" data-param3="${dataJSON[i].sid}" data-param4="${dataJSON[i].vpn_status}">
|
html += `<div class="device-card ${activeClass}" id="btn_select_device_${dataJSON[i].id_device}" data-param1="${dataJSON[i].id_device}" data-param2="${dataJSON[i].name}" data-param3="${dataJSON[i].sid}" data-param4="${dataJSON[i].vpn_status}">
|
||||||
<div class="device-card-header">
|
<div class="device-card-header">
|
||||||
<div class="device-name text-truncate">${dataJSON[i].name}</div>
|
<div class="device-name text-truncate">${dataJSON[i].name}${ipLine}</div>
|
||||||
<div class="device-actions">
|
<div class="device-actions">
|
||||||
<div class="device-status">${status}</div>
|
<div class="device-status">${status}</div>
|
||||||
<div>${vpn_status_icon}</div>
|
<div>${vpn_status_icon}</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user