1package util
2
3import (
4	"fmt"
5	"net"
6	"net/url"
7	"strings"
8
9	"github.com/future-architect/vuls/config"
10)
11
12// GenWorkers generates goroutine
13// http://qiita.com/na-o-ys/items/65373132b1c5bc973cca
14func GenWorkers(num int) chan<- func() {
15	tasks := make(chan func())
16	for i := 0; i < num; i++ {
17		go func() {
18			defer func() {
19				if p := recover(); p != nil {
20					log := NewCustomLogger(config.ServerInfo{})
21					log.Errorf("run time panic: %v", p)
22				}
23			}()
24			for f := range tasks {
25				f()
26			}
27		}()
28	}
29	return tasks
30}
31
32// AppendIfMissing append to the slice if missing
33func AppendIfMissing(slice []string, s string) []string {
34	for _, ele := range slice {
35		if ele == s {
36			return slice
37		}
38	}
39	return append(slice, s)
40}
41
42// URLPathJoin make URL
43func URLPathJoin(baseURL string, paths ...string) (string, error) {
44	baseURL = strings.TrimSuffix(baseURL, "/")
45	trimmedPaths := []string{}
46	for _, path := range paths {
47		trimmed := strings.Trim(path, " /")
48		if len(trimmed) != 0 {
49			trimmedPaths = append(trimmedPaths, trimmed)
50		}
51	}
52	var url *url.URL
53	url, err := url.Parse(baseURL)
54	if err != nil {
55		return "", err
56	}
57	url.Path += "/" + strings.Join(trimmedPaths, "/")
58	return url.String(), nil
59}
60
61// URLPathParamJoin make URL
62func URLPathParamJoin(baseURL string, paths []string, params map[string]string) (string, error) {
63	urlPath, err := URLPathJoin(baseURL, paths...)
64	if err != nil {
65		return "", err
66	}
67	u, err := url.Parse(urlPath)
68	if err != nil {
69		return "", err
70	}
71
72	parameters := url.Values{}
73	for key := range params {
74		parameters.Add(key, params[key])
75	}
76	u.RawQuery = parameters.Encode()
77	return u.String(), nil
78}
79
80// IP returns scanner network ip addresses
81func IP() (ipv4Addrs []string, ipv6Addrs []string, err error) {
82	ifaces, err := net.Interfaces()
83	if err != nil {
84		return nil, nil, err
85	}
86	for _, i := range ifaces {
87		addrs, _ := i.Addrs()
88		for _, addr := range addrs {
89			var ip net.IP
90			switch v := addr.(type) {
91			case *net.IPNet:
92				ip = v.IP
93			case *net.IPAddr:
94				ip = v.IP
95			}
96
97			// only global unicast address
98			if !ip.IsGlobalUnicast() {
99				continue
100			}
101
102			if ok := ip.To4(); ok != nil {
103				ipv4Addrs = append(ipv4Addrs, ip.String())
104			} else {
105				ipv6Addrs = append(ipv6Addrs, ip.String())
106			}
107		}
108	}
109	return ipv4Addrs, ipv6Addrs, nil
110}
111
112// ProxyEnv returns shell environment variables to set proxy
113func ProxyEnv() string {
114	httpProxyEnv := ""
115	keys := []string{
116		"http_proxy",
117		"https_proxy",
118		"HTTP_PROXY",
119		"HTTPS_PROXY",
120	}
121	for _, key := range keys {
122		httpProxyEnv += fmt.Sprintf(
123			` %s="%s"`, key, config.Conf.HTTPProxy)
124	}
125	return httpProxyEnv
126}
127
128// PrependProxyEnv prepends proxy environment variable
129func PrependProxyEnv(cmd string) string {
130	if len(config.Conf.HTTPProxy) == 0 {
131		return cmd
132	}
133	return fmt.Sprintf("%s %s", ProxyEnv(), cmd)
134}
135
136//  func unixtime(s string) (time.Time, error) {
137//      i, err := strconv.ParseInt(s, 10, 64)
138//      if err != nil {
139//          return time.Time{}, err
140//      }
141//      return time.Unix(i, 0), nil
142//  }
143
144// Truncate truncates string to the length
145func Truncate(str string, length int) string {
146	if length < 0 {
147		return str
148	}
149	if length <= len(str) {
150		return str[:length]
151	}
152	return str
153}
154
155// Distinct a slice
156func Distinct(ss []string) (distincted []string) {
157	m := map[string]bool{}
158	for _, s := range ss {
159		if _, found := m[s]; !found {
160			m[s] = true
161			distincted = append(distincted, s)
162		}
163	}
164	return
165}
166