Skip to content

Commit 45e8dab

Browse files
merge: release v2.4.0 com compatibilidade de ping macOS Darwin, execucao silenciosa no Windows e UI ampliada
2 parents 9bfca05 + 18756b3 commit 45e8dab

7 files changed

Lines changed: 160 additions & 45 deletions

File tree

‎build/darwin/Info.plist‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
<key>CFBundleIdentifier</key>
1414
<string>com.ademartellecher.ipmonitorapp</string>
1515
<key>CFBundleVersion</key>
16-
<string>2.3.2</string>
16+
<string>2.4.0</string>
1717
<key>CFBundleShortVersionString</key>
18-
<string>2.3.2</string>
18+
<string>2.4.0</string>
1919
<key>CFBundleIconFile</key>
2020
<string>AppIcon</string>
2121
<key>LSMinimumSystemVersion</key>

‎frontend/index.html‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
</div>
4040
<div class="titlebar-actions">
4141
<button id="themeToggleBtn" class="theme-toggle-btn" title="Alternar entre tema escuro e claro">
42-
<svg class="sun-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>
42+
<svg class="sun-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>
4343
<span id="themeLabel">Tema</span>
4444
</button>
4545
</div>
@@ -52,7 +52,7 @@
5252
<ul class="nav-group top">
5353
<li class="nav-item" id="navFocusAdd" title="Adicionar Novo Host">
5454
<div class="nav-icon">
55-
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
55+
<svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
5656
<rect x="3" y="3" width="18" height="18" rx="3"/>
5757
<line x1="12" y1="8" x2="12" y2="16"/>
5858
<line x1="8" y1="12" x2="16" y2="12"/>
@@ -62,7 +62,7 @@
6262
</li>
6363
<li class="nav-item" id="navImport" title="Importar arquivo JSON de IPs">
6464
<div class="nav-icon">
65-
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
65+
<svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
6666
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
6767
<polyline points="7 10 12 15 17 10"/>
6868
<line x1="12" y1="15" x2="12" y2="3"/>
@@ -72,7 +72,7 @@
7272
</li>
7373
<li class="nav-item" id="navRefresh" title="Disparar Varredura Imediata">
7474
<div class="nav-icon">
75-
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
75+
<svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
7676
<path d="M23 4v6h-6M1 20v-6h6"/>
7777
<path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/>
7878
</svg>
@@ -84,7 +84,7 @@
8484
<ul class="nav-group bottom">
8585
<li class="nav-item disabled" id="navEdit" title="Editar Host Selecionado">
8686
<div class="nav-icon">
87-
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
87+
<svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
8888
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
8989
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
9090
</svg>
@@ -93,7 +93,7 @@
9393
</li>
9494
<li class="nav-item disabled" id="navRemove" title="Remover Host Selecionado">
9595
<div class="nav-icon">
96-
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
96+
<svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
9797
<polyline points="3 6 5 6 21 6"/>
9898
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
9999
</svg>
@@ -102,7 +102,7 @@
102102
</li>
103103
<li class="nav-item has-tooltip" id="navAbout">
104104
<div class="nav-icon">
105-
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
105+
<svg width="21" height="21" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
106106
<circle cx="12" cy="12" r="10"/>
107107
<line x1="12" y1="16" x2="12" y2="12"/>
108108
<line x1="12" y1="8" x2="12.01" y2="8"/>
@@ -111,7 +111,7 @@
111111
<span class="nav-label">Sobre</span>
112112
<div class="about-tooltip-popover" id="aboutPopover">
113113
<div class="tooltip-header">
114-
<div class="tooltip-badge">v2.3.2</div>
114+
<div class="tooltip-badge">v2.4.0</div>
115115
<span class="tooltip-title">IP Monitor App</span>
116116
</div>
117117
<p class="tooltip-text">Monitoramento de conectividade ICMP Ping em tempo real, ultra-leve e portátil.</p>

‎frontend/style.css‎

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -93,12 +93,12 @@ body {
9393
Barra de Título (Titlebar)
9494
-------------------------------------------------------------------------- */
9595
.titlebar {
96-
height: 38px;
96+
height: 42px;
9797
background: var(--bg-titlebar);
9898
display: flex;
9999
align-items: center;
100100
justify-content: space-between;
101-
padding: 0 14px;
101+
padding: 0 16px;
102102
border-bottom: 1px solid var(--border-subtle);
103103
flex-shrink: 0;
104104
-webkit-app-region: drag;
@@ -107,12 +107,12 @@ body {
107107
.brand {
108108
display: flex;
109109
align-items: center;
110-
gap: 8px;
110+
gap: 9px;
111111
}
112112

113113
.brand-logo {
114-
width: 22px;
115-
height: 22px;
114+
width: 25px;
115+
height: 25px;
116116
display: flex;
117117
align-items: center;
118118
justify-content: center;
@@ -124,15 +124,15 @@ body {
124124
}
125125

126126
.brand-title {
127-
font-size: 14px;
127+
font-size: 15.5px;
128128
font-weight: 600;
129129
letter-spacing: 0.2px;
130130
}
131131

132132
.brand-tag {
133-
font-size: 11.5px;
133+
font-size: 12px;
134134
color: var(--text-dim);
135-
margin-left: 2px;
135+
margin-left: 3px;
136136
font-weight: 500;
137137
}
138138

@@ -143,13 +143,13 @@ body {
143143
.theme-toggle-btn {
144144
display: inline-flex;
145145
align-items: center;
146-
gap: 5px;
146+
gap: 6px;
147147
background: transparent;
148148
border: 1px solid var(--border-subtle);
149149
border-radius: var(--radius-sm);
150150
color: var(--text-secondary);
151-
padding: 4px 10px;
152-
font-size: 12px;
151+
padding: 5px 11px;
152+
font-size: 13px;
153153
font-weight: 500;
154154
cursor: pointer;
155155
transition: all 0.15s ease;
@@ -174,13 +174,13 @@ body {
174174
Barra Lateral (Sidebar)
175175
-------------------------------------------------------------------------- */
176176
.sidebar {
177-
width: 66px;
177+
width: 76px;
178178
background: var(--bg-sidebar);
179179
border-right: 1px solid var(--border-subtle);
180180
display: flex;
181181
flex-direction: column;
182182
justify-content: space-between;
183-
padding: 10px 0;
183+
padding: 12px 0;
184184
flex-shrink: 0;
185185
position: relative;
186186
z-index: 100;
@@ -190,22 +190,22 @@ body {
190190
list-style: none;
191191
display: flex;
192192
flex-direction: column;
193-
gap: 6px;
194-
padding: 0 6px;
193+
gap: 8px;
194+
padding: 0 7px;
195195
}
196196

197197
.nav-item {
198198
display: flex;
199199
flex-direction: column;
200200
align-items: center;
201201
justify-content: center;
202-
padding: 8px 4px 6px;
202+
padding: 10px 4px 8px;
203203
border-radius: var(--radius-md);
204204
cursor: pointer;
205205
color: var(--text-secondary);
206206
transition: all 0.16s ease;
207207
position: relative;
208-
gap: 4px;
208+
gap: 5px;
209209
}
210210

211211
.nav-item:hover {
@@ -393,18 +393,19 @@ body.light-theme #navRefresh:hover:not(.disabled) {
393393
}
394394

395395
.nav-icon {
396-
width: 18px;
397-
height: 18px;
396+
width: 22px;
397+
height: 22px;
398398
display: flex;
399399
align-items: center;
400400
justify-content: center;
401401
}
402402

403403
.nav-label {
404-
font-size: 11px;
405-
font-weight: 500;
404+
font-size: 12.5px;
405+
font-weight: 600;
406406
text-align: center;
407407
white-space: nowrap;
408+
letter-spacing: 0.1px;
408409
}
409410

410411
/* --------------------------------------------------------------------------
@@ -1228,30 +1229,30 @@ body.light-theme .detail-tag {
12281229
Rodapé do Sistema
12291230
-------------------------------------------------------------------------- */
12301231
.system-footer {
1231-
height: 30px;
1232+
height: 34px;
12321233
background: var(--bg-titlebar);
12331234
border-top: 1px solid var(--border-subtle);
12341235
display: flex;
12351236
align-items: center;
12361237
justify-content: space-between;
1237-
padding: 0 14px;
1238-
font-size: 11.5px;
1238+
padding: 0 16px;
1239+
font-size: 12.5px;
12391240
color: var(--text-dim);
12401241
flex-shrink: 0;
12411242
}
12421243

12431244
.footer-indicator {
12441245
display: flex;
12451246
align-items: center;
1246-
gap: 6px;
1247+
gap: 7px;
12471248
}
12481249

12491250
.pulse-beacon {
1250-
width: 6px;
1251-
height: 6px;
1251+
width: 8px;
1252+
height: 8px;
12521253
border-radius: 50%;
12531254
background: var(--accent-green);
1254-
box-shadow: 0 0 6px var(--accent-green);
1255+
box-shadow: 0 0 8px var(--accent-green);
12551256
}
12561257

12571258
/* --------------------------------------------------------------------------

‎internal/service/monitor_service.go‎

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ import (
77
"net"
88
"net/http"
99
"net/url"
10+
"runtime"
1011
"strings"
12+
"sync"
1113
"time"
1214

1315
"github.com/AdemarTellecher/ipmonitorapp/internal/model"
@@ -196,16 +198,42 @@ func (s *MonitorService) EditIPWithDetails(id int, newIP, name, method string, t
196198
return Result{Success: true, Message: "Host atualizado com sucesso"}
197199
}
198200

199-
// UpdateAllStatuses executa o ping em todos os IPs cadastrados e retorna a lista atualizada
201+
// UpdateAllStatuses executa a verificação em paralelo em todos os IPs cadastrados e retorna a lista atualizada
200202
func (s *MonitorService) UpdateAllStatuses() ([]model.IPDevice, error) {
201203
devices, err := s.Repo.List()
202204
if err != nil {
203205
return nil, err
204206
}
207+
208+
type statusUpdate struct {
209+
id int
210+
status string
211+
}
212+
213+
// Executa as checagens com concorrência controlada para respostas ultrarrápidas
214+
updatesChan := make(chan statusUpdate, len(devices))
215+
sem := make(chan struct{}, 20) // limite de 20 conexões simultâneas
216+
217+
var wg sync.WaitGroup
205218
for _, d := range devices {
206-
status := checkIPOnline(d.IP)
207-
_ = s.Repo.UpdateStatus(d.ID, status)
219+
wg.Add(1)
220+
go func(dev model.IPDevice) {
221+
defer wg.Done()
222+
sem <- struct{}{}
223+
defer func() { <-sem }()
224+
225+
st := checkIPOnline(dev.IP)
226+
updatesChan <- statusUpdate{id: dev.ID, status: st}
227+
}(d)
228+
}
229+
230+
wg.Wait()
231+
close(updatesChan)
232+
233+
for up := range updatesChan {
234+
_ = s.Repo.UpdateStatus(up.id, up.status)
208235
}
236+
209237
return s.Repo.List()
210238
}
211239

@@ -390,11 +418,19 @@ func checkIPOnline(target string) string {
390418
return "Offline"
391419
}
392420

421+
// 1. Tentativa via go-ping (ICMP direto)
393422
pinger, err := ping.NewPinger(target)
394423
if err == nil {
395424
pinger.Count = 1
396-
pinger.Timeout = 2 * time.Second
397-
pinger.SetPrivileged(true)
425+
pinger.Timeout = 1500 * time.Millisecond
426+
// No Windows é obrigatório Privileged = true para sockets ICMP.
427+
// No macOS (Darwin) e Linux sem root, Privileged deve ser false (usa sockets UDP ICMP unprivileged).
428+
if runtime.GOOS == "windows" {
429+
pinger.SetPrivileged(true)
430+
} else {
431+
pinger.SetPrivileged(false)
432+
}
433+
398434
runErr := pinger.Run()
399435
if runErr == nil {
400436
stats := pinger.Statistics()
@@ -404,8 +440,15 @@ func checkIPOnline(target string) string {
404440
}
405441
}
406442

407-
for _, port := range []string{"443", "80"} {
408-
conn, dialErr := net.DialTimeout("tcp", net.JoinHostPort(target, port), 1500*time.Millisecond)
443+
// 2. Fallback para ping nativo do sistema operacional (macOS / Linux / Windows)
444+
// Essencial no macOS onde o utilitário `/sbin/ping` possui setuid-root e sempre tem permissão ICMP
445+
if pingSystemCommand(target) {
446+
return "Online"
447+
}
448+
449+
// 3. Fallback para portas TCP comuns de serviços (80, 443, 8080, 22)
450+
for _, port := range []string{"443", "80", "8080", "22"} {
451+
conn, dialErr := net.DialTimeout("tcp", net.JoinHostPort(target, port), 1000*time.Millisecond)
409452
if dialErr == nil {
410453
_ = conn.Close()
411454
return "Online"

‎internal/service/ping_other.go‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//go:build !windows
2+
3+
package service
4+
5+
import (
6+
"os/exec"
7+
"runtime"
8+
)
9+
10+
// pingSystemCommand executa o ping nativo em sistemas Unix-like (macOS / Linux)
11+
func pingSystemCommand(target string) bool {
12+
var cmd *exec.Cmd
13+
switch runtime.GOOS {
14+
case "darwin":
15+
// No macOS: -c 1 (1 pacote), -t 2 (timeout de 2s)
16+
cmd = exec.Command("ping", "-c", "1", "-t", "2", target)
17+
case "linux":
18+
// No Linux: -c 1 (1 pacote), -W 2 (timeout de 2s)
19+
cmd = exec.Command("ping", "-c", "1", "-W", "2", target)
20+
default:
21+
cmd = exec.Command("ping", "-c", "1", target)
22+
}
23+
24+
err := cmd.Run()
25+
return err == nil
26+
}

‎internal/service/ping_windows.go‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//go:build windows
2+
3+
package service
4+
5+
import (
6+
"os/exec"
7+
"syscall"
8+
)
9+
10+
// pingSystemCommand executa o ping.exe nativo do Windows sem abrir janela de prompt (cmd/conhost)
11+
func pingSystemCommand(target string) bool {
12+
cmd := exec.Command("ping", "-n", "1", "-w", "1500", target)
13+
cmd.SysProcAttr = &syscall.SysProcAttr{
14+
HideWindow: true,
15+
CreationFlags: 0x08000000, // CREATE_NO_WINDOW
16+
}
17+
err := cmd.Run()
18+
return err == nil
19+
}

0 commit comments

Comments
 (0)