github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/cmd/cli/commands/server/server.go (about) 1 // This file is part of the Smart Home 2 // Program complex distribution https://github.com/e154/smart-home 3 // Copyright (C) 2016-2023, Filippov Alex 4 // 5 // This library is free software: you can redistribute it and/or 6 // modify it under the terms of the GNU Lesser General Public 7 // License as published by the Free Software Foundation; either 8 // version 3 of the License, or (at your option) any later version. 9 // 10 // This library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 // Library General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public 16 // License along with this library. If not, see 17 // <https://www.gnu.org/licenses/>. 18 19 // The following commands will run pingmq as a server, pinging the 8.8.8.0/28 CIDR 20 // block, and publishing the results to /ping/success/{ip} and /ping/failure/{ip} 21 // topics every 30 seconds. `sudo` is needed because we are using RAW sockets and 22 // that requires root privilege. 23 // 24 // $ go build 25 // $ sudo ./pingmq server -p 8.8.8.0/28 -i 30 26 package server 27 28 import ( 29 "fmt" 30 "log" 31 "net" 32 "strings" 33 "time" 34 35 "github.com/DrmagicE/gmqtt" 36 "github.com/DrmagicE/gmqtt/server" 37 "github.com/e154/smart-home/system/mqtt" 38 "github.com/koron/netx" 39 "github.com/spf13/cobra" 40 ) 41 42 var ( 43 // Server ... 44 Server = &cobra.Command{ 45 Use: "server", 46 Short: "server starts a SurgeMQ server and publishes to it all the ping results", 47 } 48 49 serverURI string 50 serverQuiet bool 51 serverIPs strlist 52 pingInterval int 53 54 s mqtt.GMqttServer 55 56 p *netx.Pinger 57 ) 58 59 type strlist []string 60 61 // String ... 62 func (s *strlist) String() string { 63 return fmt.Sprint(*s) 64 } 65 66 // Type ... 67 func (s *strlist) Type() string { 68 return "strlist" 69 } 70 71 // Set ... 72 func (s *strlist) Set(value string) error { 73 for _, ip := range strings.Split(value, ",") { 74 *s = append(*s, ip) 75 } 76 77 return nil 78 } 79 80 func init() { 81 Server.Flags().StringVarP(&serverURI, "uri", "u", "0.0.0.0:1883", "URI to run the server on") 82 Server.Flags().BoolVarP(&serverQuiet, "quiet", "q", false, "print out ping results") 83 Server.Flags().VarP(&serverIPs, "ping", "p", "Comma separated list of IPv4 addresses to ping") 84 Server.Flags().IntVarP(&pingInterval, "interval", "i", 60, "ping interval in seconds") 85 Server.Run = serv 86 87 } 88 89 func serv(cmd *cobra.Command, args []string) { 90 91 log.Printf("Starting server...") 92 go func() { 93 ln, err := net.Listen("tcp", serverURI) 94 if err != nil { 95 log.Fatal(err.Error()) 96 return 97 } 98 99 options := []server.Options{ 100 server.WithTCPListener(ln), 101 } 102 103 // Create a new server 104 s = server.New(options...) 105 106 if err = s.Run(); err != nil { 107 log.Println(err.Error()) 108 } 109 110 }() 111 time.Sleep(300 * time.Millisecond) 112 113 log.Printf("Starting pinger...") 114 115 pinger() 116 } 117 118 func pinger() { 119 120 p = &netx.Pinger{} 121 if err := p.AddIPs(serverIPs); err != nil { 122 log.Fatal(err) 123 } 124 125 cnt := 0 126 tick := time.NewTicker(time.Duration(pingInterval) * time.Second) 127 128 for { 129 if cnt != 0 { 130 <-tick.C 131 } 132 133 res, err := p.Start() 134 if err != nil { 135 log.Fatal(err) 136 } 137 138 for pr := range res { 139 if !serverQuiet { 140 log.Println(pr) 141 } 142 143 var topic string 144 145 // Creates a new PUBLISH message with the appropriate contents for publishing 146 if pr.Err != nil { 147 topic = fmt.Sprintf("/ping/failure/%s", pr.Src) 148 } else { 149 topic = fmt.Sprintf("/ping/success/%s", pr.Src) 150 } 151 152 payload, err := pr.GobEncode() 153 if err != nil { 154 log.Printf("pinger: Error from GobEncode: %v\n", err) 155 continue 156 } 157 158 // Publishes to the server 159 s.Publisher().Publish(&gmqtt.Message{ 160 Topic: topic, 161 Payload: payload, 162 QoS: 0, 163 Retained: true, 164 }) 165 } 166 167 p.Stop() 168 cnt++ 169 } 170 }