package internet import ( "fmt" "io" "log" "os" "os/exec" "strings" "github.com/CGSG-2021-AE4/modem-test/api/modem/at" ) var apns = map[string]string{ "tinkoff": "m.tinkoff", } const pppConfigName = "annalistnet" const pppConfig = ` # Annalist project custom internet connection # APN: connect "/usr/sbin/chat -v -f /etc/chatscripts/gprs -T %s" # Port: %s # Baudrate: %d noipdefault usepeerdns defaultroute persist noauth nocrtscts local ` type conn struct { logger *log.Logger port at.Port } type Conn interface { Init() error ConfigurePPP() error Ping() bool // Is connected io.Closer } func New(logger *log.Logger, port at.Port) Conn { return &conn{ logger: logger, port: port, } } func (c *conn) checkPackageExist(pname string) bool { resp, err := exec.Command("sudo", "apt-mark", "showmanual", pname).Output() if err != nil { c.logger.Println("CHECK PACKAGE ERROR: ", err.Error()) return false } return string(resp) == pname } func (c *conn) ensurePackage(pname string) error { if c.checkPackageExist(pname) { return nil } c.logger.Println("Installing", pname, "package...") resp, err := exec.Command("sudo", "apt-get", "install", pname).Output() if err != nil { return fmt.Errorf("execute install cmd: %w", err) } c.logger.Println(resp) c.logger.Println("\x1b[38;2;255;0;0mComplete\x1b[38;2;255;255;255m") return nil } // Check requirenments func (c *conn) checkReqs() error { // Check AT port for sure if c.port == nil || !c.port.IsConnected() { return fmt.Errorf("AT port is not connect or nil") } // Ensure all necessary packages installed if err := c.ensurePackage("ppp"); err != nil { return fmt.Errorf("ensure ppp package: %w", err) } if err := c.ensurePackage("net-tools"); err != nil { return fmt.Errorf("ensure net-tools package: %w", err) } // Check SIM is valid // AT+CPIN? and just check resp, err := c.port.Send("AT+CPIN?") if err != nil { return fmt.Errorf("AT+CPIN? request: %w", err) } if !resp.Check() { return fmt.Errorf("SIM card is not inserted") } return nil } func (c *conn) ConfigurePPP() error { // Get provider name and its APN // AT+CSPN provider := "" apn := apns[provider] if apn == "" { return fmt.Errorf("no apn for provider: %s", provider) } config := fmt.Sprintf(pppConfig, apn, c.port.GetName(), c.port.GetBaudrate()) f, err := os.OpenFile("etc/ppp/pears/"+pppConfigName, os.O_CREATE, 0666) if err != nil { return fmt.Errorf("open ppp config file %w", err) } defer f.Close() if _, err := f.Write([]byte(config)); err != nil { return fmt.Errorf("write to ppp config file: %w", err) } return nil } func (c *conn) setup() error { c.logger.Println("Check requirenments...") if err := c.checkReqs(); err != nil { return fmt.Errorf("check requirenments: %w", err) } // DEBUG show networks and signal resp, err := c.port.Send("AT+COPS?") if err != nil { return fmt.Errorf("AT+COPS? request: %w", err) } c.logger.Println("DEBUG networks:", resp) resp, err = c.port.Send("AT+CSQ") if err != nil { return fmt.Errorf("AT+CSQ request: %w", err) } c.logger.Println("DEBUG signal quality:", resp) // Configure ppp // what is better ASK If /etc/ppp/peers/annalistnet not exists c.logger.Println("Configure ppp...") if err := c.ConfigurePPP(); err != nil { return fmt.Errorf("configure ppp: %w", err) } return nil } func (c *conn) connect() error { resp, err := exec.Command("sudo", "pon", pppConfigName).Output() if err != nil { return fmt.Errorf("execute connect cmd: %w", err) } c.logger.Println("DEBUG pon response:", resp) return nil } func (c *conn) diconnect() error { resp, err := exec.Command("sudo", "poff", pppConfigName).Output() if err != nil { return fmt.Errorf("execute disconnect cmd: %w", err) } c.logger.Println("DEBUG poff response:", resp) return nil } func (c *conn) Init() error { // Setup c.logger.Println("Setup...") if err := c.setup(); err != nil { return fmt.Errorf("setup: %w", err) } // Connect c.logger.Println("Connect...") if err := c.connect(); err != nil { return fmt.Errorf("connect: %w", err) } //DEBUG resp, err := exec.Command("ifconfig").Output() if err != nil { return fmt.Errorf("execute ifconfig cmd: %w", err) } c.logger.Println("DEBUG ifconfig resp:", resp) // Test connectin using Ping c.logger.Println("Test...") if !c.Ping() { return fmt.Errorf("ping failed") } return nil } func (c *conn) Ping() bool { // Test - try to connect to Google DNS // ping -I ppp0 8.8.8.8 resp, err := exec.Command("ping", "-I", "ppp0", "8.8.8.8").Output() if err != nil { c.logger.Println("Ping cmd error:", err) } c.logger.Println("Ping resp:", resp) return !strings.Contains(string(resp), "Destination Host Unreachable") // tmp solution } func (c *conn) Close() error { if err := c.diconnect(); err != nil { return fmt.Errorf("diconnect: %w", err) } return nil }