22import requests
33import socket
44from zeroconf import ServiceInfo , Zeroconf , ServiceBrowser
5- import threading
65
76app = Flask (__name__ )
87
98# --- CONFIGURATION ---
10- THIS_NAME = "KIDA00" # Change per app
11- THIS_PORT = 5003 # Change per app
12- TYPE = "_flask-link._tcp.local."
9+ THIS_NAME = "KIDA00"
10+ THIS_PORT = 5003
11+ TYPE = "_flask-link._tcp.local."
1312
1413found_servers = {}
1514
1615def get_ip ():
17- """Helper to find the actual local network IP address"""
1816 s = socket .socket (socket .AF_INET , socket .SOCK_DGRAM )
1917 try :
20- # doesn't even have to be reachable
2118 s .connect (('10.255.255.255' , 1 ))
22- IP = s .getsockname ()[0 ]
19+ return s .getsockname ()[0 ]
2320 except Exception :
24- IP = '127.0.0.1'
21+ return '127.0.0.1'
2522 finally :
2623 s .close ()
27- return IP
2824
29- # --- ZEROCONF SETUP ---
3025my_ip = get_ip ()
31- zeroconf = Zeroconf ( interfaces = [ my_ip ]) # Explicitly bind to the LAN IP
26+ print ( f"Starting { THIS_NAME } on { my_ip } : { THIS_PORT } " )
3227
3328class MyListener :
34- def remove_service (self , zeroconf , type , name ):
35- short_name = name .split ('.' )[0 ]
36- if short_name in found_servers :
37- del found_servers [short_name ]
29+ def remove_service (self , zc , type_ , name ):
30+ short = name .split ('.' )[0 ]
31+ found_servers .pop (short , None )
3832
39- def add_service (self , zeroconf , type , name ):
40- self .update_service (zeroconf , type , name ) # Redirect to update logic
33+ def add_service (self , zc , type_ , name ):
34+ self .update_service (zc , type_ , name )
4135
42- def update_service (self , zeroconf , type , name ):
43- info = zeroconf .get_service_info (type , name )
36+ def update_service (self , zc , type_ , name ):
37+ info = zc .get_service_info (type_ , name )
4438 if info :
4539 addresses = [socket .inet_ntoa (addr ) for addr in info .addresses ]
4640 if addresses :
47- short_name = name .split ('.' )[0 ]
48- if short_name != THIS_NAME :
49- found_servers [short_name ] = f"http://{ addresses [0 ]} :{ info .port } "
50-
51- # --- ZEROCONF SETUP ---
52- my_ip = get_ip ()
53- print (f"Starting { THIS_NAME } on { my_ip } :{ THIS_PORT } " )
41+ short = name .split ('.' )[0 ]
42+ if short != THIS_NAME :
43+ found_servers [short ] = f"http://{ addresses [0 ]} :{ info .port } "
5444
45+ # --- SINGLE Zeroconf instance ---
5546zeroconf = Zeroconf ()
56- info = ServiceInfo (
47+ zc_info = ServiceInfo (
5748 TYPE ,
5849 f"{ THIS_NAME } .{ TYPE } " ,
5950 addresses = [socket .inet_aton (my_ip )],
6051 port = THIS_PORT ,
61- properties = {'version' : '1.0' }
52+ properties = {'version' : '1.0' },
6253)
63- zeroconf .register_service (info )
64- browser = ServiceBrowser (zeroconf , TYPE , MyListener ())
54+ zeroconf .register_service (zc_info )
55+ ServiceBrowser (zeroconf , TYPE , MyListener ())
6556
6657@app .route ("/" )
6758def dashboard ():
68- status_html = f'<div style="margin:10px;"><span style="color:green;">●</span> <b>{ THIS_NAME } </b> (Self)</div>'
59+ status_html = (
60+ f'<div style="margin:10px;">'
61+ f'<span style="color:green;">●</span> <b>{ THIS_NAME } </b> '
62+ f'(Self — { my_ip } :{ THIS_PORT } )</div>'
63+ )
6964
70- # Copy dict keys to avoid "dictionary changed size during iteration" errors
7165 for name in list (found_servers .keys ()):
7266 url = found_servers [name ]
7367 try :
7468 r = requests .get (f"{ url } /ping" , timeout = 0.5 )
75- if r .status_code == 200 :
76- status_html += f'<div style="margin:10px;"><span style="color:green;">●</span> <b>{ name } </b> Online</div>'
77- except :
78- continue
69+ colour = "green" if r .status_code == 200 else "orange"
70+ label = "Online" if r .status_code == 200 else f"HTTP { r .status_code } "
71+ except Exception :
72+ colour = "red"
73+ label = "Unreachable"
74+ status_html += (
75+ f'<div style="margin:10px;">'
76+ f'<span style="color:{ colour } ;">●</span> '
77+ f'<b>{ name } </b> { label } — { url } </div>'
78+ )
7979
8080 return render_template_string (f"""
8181 <html>
82- <head>
83- <script >
84- setTimeout(function(){{ window.location.reload(1); }}, 3000);
85- </script >
86- </head >
87- <body style="text-align:center; font-family:sans-serif; padding-top:50px; background-color:#f4f4f9;">
88- <div style="display:inline-block; padding:20px; border-radius:15px; background:white; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">
89- <h1>Active Network</h1>
90- <p style="color:gray; font-size:0.8em;">My IP : { my_ip } </p>
91- <hr>
92- { status_html }
93- </div>
94- </body>
82+ <head>
83+ <title> { THIS_NAME } — Active Network</title >
84+ <script> setTimeout(function(){{ window.location.reload(1); }}, 3000);</script>
85+ </head >
86+ <body style="text-align:center;font-family:sans-serif;padding-top:50px;background:#f4f4f9;" >
87+ <div style="display:inline-block; padding:20px;border-radius:15px; background:white;
88+ box-shadow:0 4px 6px rgba(0,0,0,0.1);">
89+ <h1>Active Network</h1>
90+ <p style="color:gray;font-size:0.8em;">Zeroconf type : { TYPE } </p>
91+ <hr>
92+ { status_html }
93+ </div>
94+ </body>
9595 </html>
9696 """ )
9797
@@ -101,9 +101,8 @@ def ping():
101101
102102if __name__ == "__main__" :
103103 try :
104- # Use threaded=True so the ping requests don't block the UI
105104 app .run (host = "0.0.0.0" , port = THIS_PORT , debug = False , threaded = True )
106105 finally :
107- print (" Shutting down..." )
108- zeroconf .unregister_service (info )
109- zeroconf .close ()
106+ print (f"[ { THIS_NAME } ] Shutting down Zeroconf ..." )
107+ zeroconf .unregister_service (zc_info )
108+ zeroconf .close ()
0 commit comments