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
200202func (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"
0 commit comments