From dfaa95e05a54008e83382edf8d69ff05747d56f9 Mon Sep 17 00:00:00 2001 From: ptrcnull Date: Thu, 10 Jun 2021 17:49:42 +0200 Subject: [PATCH] feat: Initial commit --- go.mod | 8 +++ go.sum | 25 ++++++++ main.go | 49 ++++++++++++++++ utils/html.go | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 236 insertions(+) create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go create mode 100644 utils/html.go diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2e0e820 --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module git.ddd.rip/ptrcnull/pkgs + +go 1.15 + +require ( + github.com/gofiber/fiber/v2 v2.12.0 + golang.org/x/net v0.0.0-20210510120150-4163338589ed +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..5f445ba --- /dev/null +++ b/go.sum @@ -0,0 +1,25 @@ +github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E= +github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/gofiber/fiber/v2 v2.12.0 h1:R7FVMs9mtMREjfCzCioh2j8RHwhz0/H+X0rH6BpBkJ4= +github.com/gofiber/fiber/v2 v2.12.0/go.mod h1:oZTLWqYnqpMMuF922SjGbsYZsdpE1MCfh416HNdweIM= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/klauspost/compress v1.12.2 h1:2KCfW3I9M7nSc5wOqXAlW2v2U6v+w6cbjvbfp+OykW8= +github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.26.0 h1:k5Tooi31zPG/g8yS6o2RffRO2C9B9Kah9SY8j/S7058= +github.com/valyala/fasthttp v1.26.0/go.mod h1:cmWIqlu99AO/RKcp1HWaViTqc57FswJOfYYdPJBl8BA= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I= +golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/main.go b/main.go new file mode 100644 index 0000000..22d96b1 --- /dev/null +++ b/main.go @@ -0,0 +1,49 @@ +package main + +import ( + "fmt" + "git.ddd.rip/ptrcnull/pkgs/utils" + "github.com/gofiber/fiber/v2" + "net/http" +) + +func main() { + app := fiber.New() + + app.Get("/:file", func(ctx *fiber.Ctx) error { + file := ctx.Params("file") + + res, err := http.Get("https://pkgs.alpinelinux.org/contents?file=" + file + "&path=&name=&branch=&arch=x86_64") + if err != nil { + return err + } + + node, err := utils.Parse(res.Body) + if err != nil { + return err + } + + tbody := node.QuerySelector("tbody") + if tbody == nil { + return fmt.Errorf("cannot find tbody") + } + + //log.Println(tbody.Render()) + + reply := "" + tbody.ForEach(func(row *utils.Node) { + cells := row.Children() + if len(cells) == 0 { + return + } + if len(cells) == 3 { + reply = "Not found :(" + } + reply += cells[1].Text() + "\n" + cells[0].Text() + "\n\n" + }) + + return ctx.SendString(reply) + }) + + panic(app.Listen(":8080")) +} diff --git a/utils/html.go b/utils/html.go new file mode 100644 index 0000000..be56539 --- /dev/null +++ b/utils/html.go @@ -0,0 +1,154 @@ +package utils + +import ( + "bytes" + "golang.org/x/net/html" + "io" + "strings" +) + +type Node struct { + *html.Node +} + +func Parse(r io.Reader) (*Node, error) { + n, err := html.Parse(r) + if err != nil { + return nil, err + } + return &Node{n}, nil +} + +func (n *Node) QuerySelector(selector string) *Node { + if strings.HasPrefix(selector, "#") { + return n.GetElementById(selector[1:]) + } + if strings.HasPrefix(selector, ".") { + return n.GetElementByClass(selector[1:]) + } + return n.GetElementByTagName(selector) +} + +func (n *Node) GetElementById(id string) *Node { + return n.FindOne(func(n *Node) bool { + return n.HasAttr("id", id) + }) +} + +func (n *Node) GetElementByClass(class string) *Node { + return n.FindOne(func(n *Node) bool { + return n.HasClass(class) + }) +} + +func (n *Node) GetElementByTagName(name string) *Node { + return n.FindOne(func (n *Node) bool { + return n.Type == html.ElementNode && n.Data == name + }) +} + +func (n *Node) HasClass(class string) bool { + return n.HasAttr("class", class) +} + +func (n *Node) GetAttr(key string) []string { + var res []string + for _, attr := range n.Attr { + if attr.Key == key { + res = append(res, attr.Val) + } + } + return res +} + +func (n *Node) HasAttr(key, value string) bool { + for _, attr := range n.Attr { + if attr.Key == key && attr.Val == value { + return true + } + } + return false +} + +func (n *Node) ForEach(cb func (n *Node)) { + for c := n.FirstChild; c != nil; c = c.NextSibling { + cb(&Node{c}) + } +} + +func (n *Node) ChildNodes() []*Node { + var res []*Node + n.ForEach(func(n *Node) { + res = append(res, n) + }) + return res +} + +func (n *Node) Children() []*Node { + var res []*Node + n.ForEach(func(n *Node) { + if n.Type == html.ElementNode { + res = append(res, n) + } + }) + return res +} + +func (n *Node) Traverse(cb func(n *Node)) { + var f func(*Node) + f = func(n *Node) { + cb(n) + n.ForEach(f) + } + f(n) +} + +func (n *Node) FindOne(cb func(n *Node) bool) *Node { + var res *Node + + var f func(*Node) + f = func(n *Node) { + if res != nil { + return + } + if cb(n) { + res = n + return + } + n.ForEach(f) + } + f(n) + + return res +} + +func (n *Node) FindMany(cb func(n *Node) bool) []*Node { + var res []*Node + + var f func(*Node) + f = func(n *Node) { + if cb(n) { + res = append(res, n) + } + n.ForEach(f) + } + f(n) + + return res +} + +func (n *Node) Text() string { + res := "" + n.Traverse(func(n *Node) { + if n.Type == html.TextNode { + res += n.Data + } + }) + return res +} + +func (n *Node) Render() (string, error) { + w := bytes.NewBuffer([]byte{}) + err := html.Render(w, n.Node) + return w.String(), err +}