From 897ca83ad8cbeaed4c5eeb6ca446909b09117ee7 Mon Sep 17 00:00:00 2001 From: Sergey Melnikov Date: Thu, 18 Jan 2024 15:52:30 +0300 Subject: [PATCH] init --- .gitignore | 1 + go.mod | 24 +++++ go.sum | 57 +++++++++++ internals/app/conc/conc.go | 183 +++++++++++++++++++++++++++++++++++ internals/app/dbs/pg.go | 65 +++++++++++++ internals/app/trace/trace.go | 16 +++ main.go | 72 ++++++++++++++ 7 files changed, 418 insertions(+) create mode 100644 .gitignore create mode 100644 go.mod create mode 100644 go.sum create mode 100644 internals/app/conc/conc.go create mode 100644 internals/app/dbs/pg.go create mode 100644 internals/app/trace/trace.go create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a725465 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +vendor/ \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..037911a --- /dev/null +++ b/go.mod @@ -0,0 +1,24 @@ +module models + +go 1.21.6 + +require ( + github.com/antchfx/htmlquery v1.2.3 + github.com/lib/pq v1.6.0 + golang.org/x/net v0.0.0-20200602114024-627f9648deb9 +) + +require ( + github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 // indirect + github.com/antchfx/xpath v1.1.6 // indirect + github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect + github.com/hashicorp/go-uuid v1.0.2 // indirect + github.com/jcmturner/aescts/v2 v2.0.0 // indirect + github.com/jcmturner/dnsutils/v2 v2.0.0 // indirect + github.com/jcmturner/gofork v1.0.0 // indirect + github.com/jcmturner/goidentity/v6 v6.0.1 // indirect + github.com/jcmturner/gokrb5/v8 v8.2.0 // indirect + github.com/jcmturner/rpc/v2 v2.0.2 // indirect + golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4 // indirect + golang.org/x/text v0.3.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..23efbf3 --- /dev/null +++ b/go.sum @@ -0,0 +1,57 @@ +github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 h1:P5U+E4x5OkVEKQDklVPmzs71WM56RTTRqV4OrDC//Y4= +github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5/go.mod h1:976q2ETgjT2snVCf2ZaBnyBbVoPERGjUz+0sofzEfro= +github.com/antchfx/htmlquery v1.2.3 h1:sP3NFDneHx2stfNXCKbhHFo8XgNjCACnU/4AO5gWz6M= +github.com/antchfx/htmlquery v1.2.3/go.mod h1:B0ABL+F5irhhMWg54ymEZinzMSi0Kt3I2if0BLYa3V0= +github.com/antchfx/xpath v1.1.6 h1:6sVh6hB5T6phw1pFpHRQ+C4bd8sNI+O58flqtg7h0R0= +github.com/antchfx/xpath v1.1.6/go.mod h1:Yee4kTMuNiPYJ7nSNorELQMr1J33uOpXDMByNYhvtNk= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= +github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= +github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= +github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= +github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= +github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= +github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= +github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8= +github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= +github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= +github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= +github.com/jcmturner/gokrb5/v8 v8.2.0 h1:lzPl/30ZLkTveYsYZPKMcgXc8MbnE6RsTd4F9KgiLtk= +github.com/jcmturner/gokrb5/v8 v8.2.0/go.mod h1:T1hnNppQsBtxW0tCHMHTkAt8n/sABdzZgZdoFrZaZNM= +github.com/jcmturner/rpc/v2 v2.0.2 h1:gMB4IwRXYsWw4Bc6o/az2HJgFUA1ffSh90i26ZJ6Xl0= +github.com/jcmturner/rpc/v2 v2.0.2/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= +github.com/lib/pq v1.6.0 h1:I5DPxhYJChW9KYc66se+oKFFQX6VuQrKiprsX6ivRZc= +github.com/lib/pq v1.6.0/go.mod h1:4vXEAYvW1fRQ2/FhZ78H73A60MHw1geSm145z2mdY1g= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4 h1:QmwruyY+bKbDDL0BaglrbZABEali68eoMFhTZpCjYVA= +golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200421231249-e086a090c8fd/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= +golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= +gopkg.in/jcmturner/dnsutils.v1 v1.0.1/go.mod h1:m3v+5svpVOhtFAP/wSz+yzh4Mc0Fg7eRhxkJMWSIz9Q= +gopkg.in/jcmturner/goidentity.v3 v3.0.0/go.mod h1:oG2kH0IvSYNIu80dVAyu/yoefjq1mNfM5bm88whjWx4= +gopkg.in/jcmturner/gokrb5.v7 v7.5.0/go.mod h1:l8VISx+WGYp+Fp7KRbsiUuXTTOnxIc3Tuvyavf11/WM= +gopkg.in/jcmturner/rpc.v1 v1.1.0/go.mod h1:YIdkC4XfD6GXbzje11McwsDuOlZQSb9W4vfLvuNnlv8= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internals/app/conc/conc.go b/internals/app/conc/conc.go new file mode 100644 index 0000000..9b0b348 --- /dev/null +++ b/internals/app/conc/conc.go @@ -0,0 +1,183 @@ +package conc + +import ( + "crypto/tls" + "models/internals/app/trace" + "net/http" + "reflect" + "strings" + + "github.com/antchfx/htmlquery" + "golang.org/x/net/html" + "golang.org/x/net/html/charset" +) + +const ( + totalChan = 10 +) + +var tr = &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, +} +var client = &http.Client{Transport: tr} + +// Item struct for html answer +type Item struct { + ID int64 + IP string + YeaLinkLink string + CiscoLink string + Error error + Model string + Firmware string + Lang string + Statuscode int +} + +func (i *Item) getURL() *Item { + resp, err := client.Get(i.YeaLinkLink) + if err != nil { + i.Error = err + return i + } + if resp == nil { + return i + } + if resp.StatusCode == 404 { + resp, err = client.Get(i.CiscoLink) + if err != nil { + i.Error = err + return i + } + if resp == nil { + return i + } + } + defer resp.Body.Close() + + r, err := charset.NewReader(resp.Body, resp.Header.Get("Content-Type")) + if err != nil { + i.Error = err + return i + } + doc, err := html.Parse(r) + if err != nil { + i.Error = err + return i + } + nodes, err := htmlquery.Query(doc, "//title") + if err != nil { + i.Error = err + return i + } + if nodes == nil { + return i + } + // check T26 phone + t26 := false + td, _ := htmlquery.Query(doc, "//td[@contains(@id,'loginPhoneModel')]") + if td != nil { + if strings.Contains(htmlquery.InnerText(td), "T26P") { + t26 = true + } + } + i.Statuscode = resp.StatusCode + model := handlerTitle(htmlquery.InnerText(nodes), t26) + i.Model = model + i.Lang = "ru" + + if model != "SPA303" { + fnd, _ := htmlquery.Query(doc, "//script[contains(@src, '/Russian')]") + if fnd == nil { + fnd, _ = htmlquery.Query(doc, "//script[contains(@src, '11.Russian')]") + } + + frm, _ := htmlquery.Query(doc, "//script[contains(@src, 'utility')]") + if frm == nil { + frm, _ = htmlquery.Query(doc, "//script[contains(@src, 'commonjs')]") + } + if frm != nil { + src := htmlquery.SelectAttr(frm, "src") + arrs := strings.Split(src, "?") + if len(arrs) == 2 { + i.Firmware = strings.TrimSpace(arrs[1]) + } + } else { + + frm, _ = htmlquery.Query(doc, "//script[contains(@src, '11.Russian')]") + if frm != nil { + src := htmlquery.SelectAttr(frm, "src") + arrs := strings.Split(src, "?") + if len(arrs) == 2 { + i.Firmware = strings.TrimSpace(arrs[1]) + } + } + } + if fnd == nil { + i.Lang = "en" + } + } + return i +} + +// Producer chan Item +type Producer struct { + out [totalChan]chan *Item +} + +func (p *Producer) produce(i int, item *Item) { + channel := i % totalChan + p.out[channel] <- item.getURL() +} + +// Concurency call goroutines +func Concurency(items []*Item) []*Item { + + defer trace.UndoTrace(trace.MyTrace()) + var handleItems []*Item + + m := [totalChan]chan *Item{} + for i := range m { + m[i] = make(chan *Item) + } + prod := Producer{out: m} + + for i, item := range items { + go prod.produce(i, item) + } + + cases := make([]reflect.SelectCase, len(prod.out)) + for i, ch := range prod.out { + cases[i] = reflect.SelectCase{Dir: reflect.SelectRecv, Chan: reflect.ValueOf(ch)} + } + +ForLoop: + for { + _, value, _ := reflect.Select(cases) + i := value.Elem().Interface().(Item) + handleItems = append(handleItems, &i) + if len(items) == len(handleItems) { + break ForLoop + } + } + + return handleItems +} + +func handlerTitle(title string, t26 bool) string { + title = strings.Replace(title, "_", " ", -1) + if strings.Contains(title, "502") { + title = "" + } + if strings.Contains(title, "SPA303") { + title = "SPA303" + } + if title == "Yealink Phone" { + if t26 { + title = "Yealink T26P Phone" + } else { + title = "Yealink T19 Phone" + } + } + return title +} diff --git a/internals/app/dbs/pg.go b/internals/app/dbs/pg.go new file mode 100644 index 0000000..a3c3d9a --- /dev/null +++ b/internals/app/dbs/pg.go @@ -0,0 +1,65 @@ +package dbs + +import ( + "database/sql" + "database/sql/driver" + "encoding/json" + "errors" + "log" + + // import for postgres + _ "github.com/lib/pq" +) + +// PHONE struct pg table +type PHONE struct { + ID int64 `json:"id" db:"id"` + MAC string `json:"mac" db:"mac"` + IP string `json:"ip,omitempty" db:"ip"` + INVENTORY string `json:"inventory,omitempty" db:"inventory"` + MODEL string `json:"model,omitempty" db:"model"` + LANG string `json:"lang,omitempty" db:"lang"` + FIRMWARE string `json:"firmware,omitempty" db:"firmware"` + TYPECONN int64 `json:"typeconn" db:"typeconn"` + EXTS *ExtSlice `json:"exts" db:"exts"` + STATUS int `json:"busy" db:"busy"` +} + +// ExtSlice slice of extension +type ExtSlice []*EXTS + +// Value return jsonb to json +func (e ExtSlice) Value() (driver.Value, error) { + return json.Marshal(e) +} + +// Scan return json to jsonb +func (e *ExtSlice) Scan(src interface{}) error { + switch v := src.(type) { + case []byte: + return json.Unmarshal(v, &e) + case string: + return json.Unmarshal([]byte(v), &e) + } + return errors.New("type assertion failed") +} + +// EXTS struct extension +type EXTS struct { + NUM int64 `json:"num"` + PASSWORD string `json:"password,omitempty"` + NAME string `json:"name,omitempty"` +} + +// GetPG return pg sql.db +func GetPG() *sql.DB { + pgconn, err := sql.Open("postgres", "postgres://<>?sslmode=disable") + if err != nil { + log.Fatal(err) + } + if err := pgconn.Ping(); err != nil { + log.Fatal(err) + } + + return pgconn +} diff --git a/internals/app/trace/trace.go b/internals/app/trace/trace.go new file mode 100644 index 0000000..ed4196c --- /dev/null +++ b/internals/app/trace/trace.go @@ -0,0 +1,16 @@ +package trace + +import ( + "fmt" + "time" +) + +func MyTrace() time.Time { + fmt.Println("START TRACE") + return time.Now() +} + +func UndoTrace(startTime time.Time) { + endTime := time.Now() + fmt.Println("END ElapsedTime in seconds: ", endTime.Sub(startTime)) +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..8992849 --- /dev/null +++ b/main.go @@ -0,0 +1,72 @@ +package main + +import ( + "fmt" + "log" + "models/internals/app/conc" + "models/internals/app/dbs" + "os" +) + +const ( + yealinkLink = "http://%s/servlet?m=mod_listener&p=login&q=loginForm&jumpto=status" + ciscoLink = "http://%s/admin/spacfg.xml" +) + +func main() { + db := dbs.GetPG() + defer db.Close() + mac := "" + if len(os.Args) > 1 { + mac = os.Args[1] + } + + sql := "" + + if mac != "" { + sql = fmt.Sprintf("SELECT id,ip FROM phones WHERE mac = '%s' AND status = 0", mac) + } else { + sql = "SELECT id,ip FROM phones WHERE status = 0 AND ip !='0.0.0.0'" + } + + rows, err := db.Query(sql) + if err != nil { + log.Println(err) + return + } + + var results []*dbs.PHONE + + for rows.Next() { + phone := &dbs.PHONE{} + err := rows.Scan( + &phone.ID, + &phone.IP, + ) + if err != nil { + log.Println(err) + } + + results = append(results, phone) + } + var items []*conc.Item + for _, row := range results { + item := &conc.Item{ + ID: row.ID, + YeaLinkLink: fmt.Sprintf(yealinkLink, row.IP), + CiscoLink: fmt.Sprintf(ciscoLink, row.IP), + } + items = append(items, item) + } + + items = conc.Concurency(items) + log.Println(len(items)) + for _, item := range items { + if item.Model != "" && item.Firmware != "" { + _, err := db.Exec(`UPDATE phones SET model = $1, firmware = $2, lang = $3 WHERE id = $4`, item.Model, item.Firmware, item.Lang, item.ID) + if err != nil { + log.Println(err) + } + } + } +}