package models import ( "errors" "fmt" "strings" "github.com/qdm12/gluetun/internal/constants/providers" "github.com/qdm12/gluetun/internal/constants/vpn" ) func boolToMarkdown(b bool) string { if b { return "✅" } return "❌" } func markdownTableHeading(legendFields ...string) (markdown string) { return "| " + strings.Join(legendFields, " | ") + " |\n" + "|" + strings.Repeat(" --- |", len(legendFields)) } const ( categoriesHeader = "Categories" cityHeader = "City" countryHeader = "Country" freeHeader = "Free" hostnameHeader = "Hostname" ispHeader = "ISP" multiHopHeader = "MultiHop" nameHeader = "Name" numberHeader = "Number" ownedHeader = "Owned" portForwardHeader = "Port forwarding" premiumHeader = "Premium" regionHeader = "Region" secureHeader = "Secure" streamHeader = "Stream" tcpHeader = "TCP" torHeader = "Tor" udpHeader = "UDP" vpnHeader = "VPN" ) func (s *Server) ToMarkdown(headers ...string) (markdown string) { if len(headers) == 0 { return "" } fields := make([]string, len(headers)) for i, header := range headers { switch header { case cityHeader: fields[i] = s.City case countryHeader: fields[i] = s.Country case categoriesHeader: fields[i] = strings.Join(s.Categories, ", ") case freeHeader: fields[i] = boolToMarkdown(s.Free) case hostnameHeader: fields[i] = fmt.Sprintf("`%s`", s.Hostname) case ispHeader: fields[i] = s.ISP case multiHopHeader: fields[i] = boolToMarkdown(s.MultiHop) case nameHeader: fields[i] = s.ServerName case numberHeader: fields[i] = fmt.Sprint(s.Number) case ownedHeader: fields[i] = boolToMarkdown(s.Owned) case portForwardHeader: fields[i] = boolToMarkdown(s.PortForward) case premiumHeader: fields[i] = boolToMarkdown(s.Premium) case regionHeader: fields[i] = s.Region case streamHeader: fields[i] = boolToMarkdown(s.Stream) case tcpHeader: fields[i] = boolToMarkdown(s.TCP) case udpHeader: fields[i] = boolToMarkdown(s.UDP || s.VPN == vpn.Wireguard) case vpnHeader: fields[i] = s.VPN } } return "| " + strings.Join(fields, " | ") + " |" } func (s *Servers) toMarkdown(vpnProvider string) (formatted string, err error) { headers, err := getMarkdownHeaders(vpnProvider) if err != nil { return "", fmt.Errorf("getting markdown headers: %w", err) } legend := markdownTableHeading(headers...) entries := make([]string, len(s.Servers)) for i, server := range s.Servers { entries[i] = server.ToMarkdown(headers...) } formatted = legend + "\n" + strings.Join(entries, "\n") + "\n" return formatted, nil } var ErrMarkdownHeadersNotDefined = errors.New("markdown headers not defined") func getMarkdownHeaders(vpnProvider string) (headers []string, err error) { switch vpnProvider { case providers.Airvpn: return []string{ regionHeader, countryHeader, cityHeader, vpnHeader, udpHeader, tcpHeader, hostnameHeader, nameHeader, }, nil case providers.Cyberghost: return []string{countryHeader, hostnameHeader, tcpHeader, udpHeader}, nil case providers.Expressvpn: return []string{countryHeader, cityHeader, hostnameHeader, tcpHeader, udpHeader}, nil case providers.Fastestvpn: return []string{countryHeader, hostnameHeader, vpnHeader, tcpHeader, udpHeader}, nil case providers.Giganews: return []string{regionHeader, hostnameHeader, tcpHeader, udpHeader}, nil case providers.HideMyAss: return []string{countryHeader, regionHeader, cityHeader, hostnameHeader, tcpHeader, udpHeader}, nil case providers.Ipvanish: return []string{countryHeader, cityHeader, hostnameHeader, tcpHeader, udpHeader}, nil case providers.Ivpn: return []string{countryHeader, cityHeader, ispHeader, hostnameHeader, vpnHeader, tcpHeader, udpHeader}, nil case providers.Mullvad: return []string{countryHeader, cityHeader, ispHeader, ownedHeader, hostnameHeader, vpnHeader}, nil case providers.Nordvpn: return []string{countryHeader, regionHeader, cityHeader, hostnameHeader, vpnHeader, categoriesHeader}, nil case providers.Perfectprivacy: return []string{cityHeader, tcpHeader, udpHeader}, nil case providers.Privado: return []string{countryHeader, regionHeader, cityHeader, hostnameHeader}, nil case providers.PrivateInternetAccess: return []string{regionHeader, hostnameHeader, nameHeader, tcpHeader, udpHeader, portForwardHeader}, nil case providers.Privatevpn: return []string{countryHeader, cityHeader, hostnameHeader}, nil case providers.Protonvpn: return []string{ countryHeader, regionHeader, cityHeader, hostnameHeader, vpnHeader, freeHeader, portForwardHeader, secureHeader, torHeader, }, nil case providers.Purevpn: return []string{countryHeader, regionHeader, cityHeader, hostnameHeader, tcpHeader, udpHeader}, nil case providers.SlickVPN: return []string{regionHeader, countryHeader, cityHeader, hostnameHeader}, nil case providers.Surfshark: return []string{ regionHeader, countryHeader, cityHeader, hostnameHeader, vpnHeader, multiHopHeader, tcpHeader, udpHeader, }, nil case providers.Torguard: return []string{countryHeader, cityHeader, hostnameHeader, tcpHeader, udpHeader}, nil case providers.VPNSecure: return []string{regionHeader, cityHeader, hostnameHeader, premiumHeader}, nil case providers.VPNUnlimited: return []string{countryHeader, cityHeader, hostnameHeader, freeHeader, streamHeader, tcpHeader, udpHeader}, nil case providers.Vyprvpn: return []string{regionHeader, hostnameHeader, tcpHeader, udpHeader}, nil case providers.Wevpn: return []string{cityHeader, hostnameHeader, tcpHeader, udpHeader}, nil case providers.Windscribe: return []string{regionHeader, cityHeader, hostnameHeader, vpnHeader}, nil default: return nil, fmt.Errorf("%w: for %s", ErrMarkdownHeadersNotDefined, vpnProvider) } }