Skip to content

Commit 26d6916

Browse files
authored
Merge pull request #100 from chvvkumar/dev
Bugfix: Fix client connection duration display in UI
2 parents a0c232e + 823862e commit 26d6916

File tree

5 files changed

+58
-12
lines changed

5 files changed

+58
-12
lines changed

.github/workflows/build-and-release.yml

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,17 @@ jobs:
3535
release_type: ${{ steps.version.outputs.release_type }}
3636
docker_tag: ${{ steps.docker_tags.outputs.tag }}
3737
steps:
38+
- name: Clean workspace
39+
if: always()
40+
run: |
41+
sudo chown -R $USER:$USER ${{ github.workspace }} || true
42+
sudo rm -rf ${{ github.workspace }}/* ${{ github.workspace }}/.* 2>/dev/null || true
43+
3844
- name: Checkout repository
3945
uses: actions/checkout@v4
4046
with:
4147
fetch-depth: 0
48+
clean: false
4249

4350
- name: Determine Docker tags and cache
4451
id: docker_tags
@@ -145,10 +152,17 @@ jobs:
145152
platform: linux/arm64
146153
platform_tag: arm64
147154
steps:
155+
- name: Clean workspace
156+
if: always()
157+
run: |
158+
sudo chown -R $USER:$USER ${{ github.workspace }} || true
159+
sudo rm -rf ${{ github.workspace }}/* ${{ github.workspace }}/.* 2>/dev/null || true
160+
148161
- name: Checkout repository
149162
uses: actions/checkout@v4
150163
with:
151164
fetch-depth: 0
165+
clean: false
152166

153167
- name: Set up Docker Buildx
154168
uses: docker/setup-buildx-action@v3
@@ -192,7 +206,9 @@ jobs:
192206
if: always()
193207
run: |
194208
rm -rf ${{ env.CACHE_PATH }}
195-
mv ${{ env.CACHE_PATH_NEW }} ${{ env.CACHE_PATH }}
209+
if [ -d "${{ env.CACHE_PATH_NEW }}" ]; then
210+
mv ${{ env.CACHE_PATH_NEW }} ${{ env.CACHE_PATH }}
211+
fi
196212
197213
merge:
198214
name: Merge Multi-Arch Image
@@ -229,6 +245,8 @@ jobs:
229245
- name: Checkout repository
230246
if: github.ref == 'refs/heads/main'
231247
uses: actions/checkout@v4
248+
with:
249+
clean: false
232250

233251
- name: Docker Hub Description
234252
if: github.ref == 'refs/heads/main'
@@ -252,6 +270,7 @@ jobs:
252270
uses: actions/checkout@v4
253271
with:
254272
fetch-depth: 0
273+
clean: false
255274

256275
- name: Generate commit history
257276
id: changelog
@@ -350,6 +369,7 @@ jobs:
350369
uses: actions/checkout@v4
351370
with:
352371
fetch-depth: 0
372+
clean: false
353373

354374
- name: Collect commit information
355375
id: collect
@@ -585,4 +605,4 @@ jobs:
585605
body: newBody
586606
});
587607
588-
console.log(`✅ Updated PR #${context.issue.number}`);
608+
console.log(`✅ Updated PR #${context.issue.number}`);

.github/workflows/snd.yml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,17 @@ jobs:
2323
platform: linux/arm64
2424
platform_tag: arm64
2525
steps:
26+
- name: Clean workspace
27+
if: always()
28+
run: |
29+
sudo chown -R $USER:$USER ${{ github.workspace }} || true
30+
sudo rm -rf ${{ github.workspace }}/* ${{ github.workspace }}/.* 2>/dev/null || true
31+
2632
- name: Checkout repository
2733
uses: actions/checkout@v4
2834
with:
2935
ref: snd
36+
clean: false
3037

3138
- name: Set up Docker Buildx
3239
uses: docker/setup-buildx-action@v3
@@ -70,7 +77,9 @@ jobs:
7077
if: always()
7178
run: |
7279
rm -rf ${{ env.CACHE_PATH }}
73-
mv ${{ env.CACHE_PATH_NEW }} ${{ env.CACHE_PATH }}
80+
if [ -d "${{ env.CACHE_PATH_NEW }}" ]; then
81+
mv ${{ env.CACHE_PATH_NEW }} ${{ env.CACHE_PATH }}
82+
fi
7483
7584
merge:
7685
name: Merge Multi-Arch Image
@@ -102,5 +111,3 @@ jobs:
102111
docker pull ${{ vars.DOCKERHUB_USERNAME }}/simpleclouddetect:snd
103112
IMAGE_SIZE=$(docker images --format "{{.Size}}" ${{ vars.DOCKERHUB_USERNAME }}/simpleclouddetect:snd | head -n1)
104113
echo "Docker image size: $IMAGE_SIZE"
105-
106-

alpaca/device.py

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ def __init__(self, alpaca_config: AlpacaConfig, detect_config: DetectConfig):
3232
self.transaction_lock = threading.Lock()
3333

3434
# Device state
35-
self.connected_clients: Dict[Tuple[str, int], datetime] = {} # (IP, ClientID) -> ConnectionTime
35+
self.connected_clients: Dict[Tuple[str, int], datetime] = {} # (IP, ClientID) -> Connection Start Time
36+
self.client_last_seen: Dict[Tuple[str, int], datetime] = {} # (IP, ClientID) -> Last Heartbeat Time
3637
self.disconnected_clients: Dict[Tuple[str, int], Tuple[datetime, datetime]] = {} # (IP, ClientID) -> (ConnectionTime, DisconnectionTime)
3738
self.connection_lock = threading.Lock()
3839
self.connecting = False
@@ -167,24 +168,36 @@ def _prune_stale_clients(self):
167168
cutoff_time = now - timedelta(seconds=CLIENT_TIMEOUT_SECONDS)
168169

169170
stale_clients = []
170-
for key, last_seen in list(self.connected_clients.items()):
171+
# Check last_seen for staleness, not initial connection time
172+
for key, last_seen in list(self.client_last_seen.items()):
171173
if last_seen < cutoff_time:
172174
stale_clients.append(key)
173175

174176
for key in stale_clients:
175177
client_ip, client_id = key
176-
conn_time = self.connected_clients[key]
178+
179+
# Retrieve original connection time for the record
180+
conn_time = self.connected_clients.get(key, now)
181+
182+
# Move to disconnected list
177183
self.disconnected_clients[key] = (conn_time, now)
178-
del self.connected_clients[key]
184+
185+
# Remove from active tracking
186+
if key in self.connected_clients:
187+
del self.connected_clients[key]
188+
if key in self.client_last_seen:
189+
del self.client_last_seen[key]
190+
179191
logger.warning(f"Watchdog: Pruned stale client {client_ip} (ID: {client_id}) - "
180-
f"inactive for {(now - conn_time).total_seconds():.0f}s")
192+
f"inactive for {(now - last_seen).total_seconds():.0f}s")
181193

182194
def register_heartbeat(self, client_ip: str, client_id: int):
183195
"""Update the last seen timestamp for a connected client"""
184196
with self.connection_lock:
185197
key = (client_ip, client_id)
186198
if key in self.connected_clients:
187-
self.connected_clients[key] = get_current_time(self.alpaca_config.timezone)
199+
# Only update last_seen, preserve connected_clients (start time)
200+
self.client_last_seen[key] = get_current_time(self.alpaca_config.timezone)
188201

189202
def _setup_mqtt(self):
190203
"""Setup and return MQTT client based on detect_config"""
@@ -334,7 +347,9 @@ def connect(self, client_ip: str, client_id: int):
334347
"""Connect a client to the device"""
335348
with self.connection_lock:
336349
key = (client_ip, client_id)
337-
self.connected_clients[key] = get_current_time(self.alpaca_config.timezone)
350+
current_time = get_current_time(self.alpaca_config.timezone)
351+
self.connected_clients[key] = current_time
352+
self.client_last_seen[key] = current_time
338353

339354
# Remove from disconnected clients if reconnecting
340355
if key in self.disconnected_clients:
@@ -358,6 +373,7 @@ def disconnect(self, client_ip: str = None, client_id: int = None):
358373
disc_time = get_current_time(self.alpaca_config.timezone)
359374
self.disconnected_clients[key] = (conn_time, disc_time)
360375
self.connected_clients.clear()
376+
self.client_last_seen.clear()
361377
self.disconnected_at = disc_time
362378
if self.connected_at:
363379
duration = (self.disconnected_at - self.connected_at).total_seconds()
@@ -372,6 +388,9 @@ def disconnect(self, client_ip: str = None, client_id: int = None):
372388
self.disconnected_clients[key] = (conn_time, disc_time)
373389

374390
del self.connected_clients[key]
391+
if key in self.client_last_seen:
392+
del self.client_last_seen[key]
393+
375394
logger.info(f"Client disconnected: {client_ip} (ID: {client_id}). Total clients: {len(self.connected_clients)}")
376395

377396
if len(self.connected_clients) == 0:

verify_config.py

Whitespace-only changes.

0 commit comments

Comments
 (0)