aboutsummaryrefslogtreecommitdiff
path: root/direct_client.go
diff options
context:
space:
mode:
Diffstat (limited to 'direct_client.go')
-rw-r--r--direct_client.go386
1 files changed, 0 insertions, 386 deletions
diff --git a/direct_client.go b/direct_client.go
deleted file mode 100644
index 61824b1..0000000
--- a/direct_client.go
+++ /dev/null
@@ -1,386 +0,0 @@
-// Copyright 2020, Shulhan <m.shulhan@gmail.com>. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package kamusku
-
-import (
- "bytes"
- "encoding/gob"
- "errors"
- "fmt"
- "io/ioutil"
- "log"
- "net/http"
- "net/http/cookiejar"
- "net/url"
- "os"
- "path/filepath"
- "strconv"
- "strings"
-
- "github.com/shuLhan/share/lib/debug"
- libhttp "github.com/shuLhan/share/lib/http"
- "github.com/shuLhan/share/lib/net/html"
- "golang.org/x/net/publicsuffix"
-)
-
-const (
- cookieFile = "cookie"
- configDir = "kbbi"
- maxPageNumber = 501
-)
-
-//
-// directClient for KBBI web using HTTP.
-//
-type directClient struct {
- baseDir string
- cookieURL *url.URL
- cookies []*http.Cookie
- httpc *http.Client
-}
-
-//
-// newDirectClient create and initialize new client that connect directly to
-// KBBI official website.
-//
-func newDirectClient() (cl *directClient, err error) {
- cookieURL, err := url.Parse(baseURL)
- if err != nil {
- return nil, fmt.Errorf("newDirectClient: %w", err)
- }
-
- jarOpt := &cookiejar.Options{
- PublicSuffixList: publicsuffix.List,
- }
-
- jar, err := cookiejar.New(jarOpt)
- if err != nil {
- return nil, fmt.Errorf("newDirectClient: %w", err)
- }
-
- cl = &directClient{
- cookieURL: cookieURL,
- httpc: &http.Client{
- Jar: jar,
- Timeout: defTimeout,
- },
- }
-
- err = cl.loadCookies()
- if err != nil {
- return nil, fmt.Errorf("newDirectClient: %w", err)
- }
-
- if cl.cookies != nil {
- jar.SetCookies(cookieURL, cl.cookies)
- }
-
- return cl, nil
-}
-
-//
-// CariDefinisi dari daftar kata.
-//
-func (cl *directClient) CariDefinisi(ins []string) (
- res DefinisiResponse, err error,
-) {
- res = make(DefinisiResponse, len(ins))
-
- for _, in := range ins {
- _, ok := res[in]
- if ok {
- continue
- }
-
- kata := &Kata{}
- res[in] = kata
-
- entriURL := baseURL + entriPath + in
- httpRes, err := cl.httpc.Get(entriURL)
- if err != nil {
- kata.err = err
- continue
- }
-
- defer httpRes.Body.Close()
-
- body, err := ioutil.ReadAll(httpRes.Body)
- if err != nil {
- kata.err = err
- continue
- }
-
- if debug.Value >= 2 {
- fmt.Printf(">>> HTML body for %s:\n%s", entriURL, body)
- }
-
- err = kata.parseHTMLEntri(in, body)
- if err != nil {
- kata.err = err
- }
-
- if len(kata.Definisi) == 0 && len(kata.Pesan) == 0 {
- kata.Pesan = "Entri tidak ditemukan"
- }
- }
-
- return res, nil
-}
-
-//
-// ListKataDasar list all of the root words in dictionary.
-//
-func (cl *directClient) ListKataDasar() (kataDasar DaftarKata, err error) {
- params := url.Values{
- paramNameMasukan: []string{paramValueDasar},
- paramNameMasukanLengkap: []string{paramValueDasar},
- }
-
- urlPage := baseURL + "/Cari/Jenis?"
-
- kataDasar = make(DaftarKata)
-
- for pageNumber := 1; pageNumber <= maxPageNumber; pageNumber++ {
- params.Set(paramNamePage, strconv.Itoa(pageNumber))
-
- req, err := http.NewRequest(http.MethodGet, urlPage+params.Encode(), nil)
- if err != nil {
- return kataDasar, err
- }
-
- res, err := cl.httpc.Do(req)
- if err != nil {
- return kataDasar, fmt.Errorf("ListKataDasar: page %d: %w",
- pageNumber, err)
- }
-
- defer res.Body.Close()
-
- body, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return kataDasar, fmt.Errorf("ListKataDasar: page %d: %w",
- pageNumber, err)
- }
-
- got, err := cl.parseHTMLKataDasar(body)
- if err != nil {
- return kataDasar, fmt.Errorf("ListKataDasar: page %d: %w",
- pageNumber, err)
- }
- if len(got) == 0 {
- break
- }
-
- kataDasar.merge(got)
-
- log.Printf("ListKataDasar: halaman %d, jumlah kata %d, total kata %d",
- pageNumber, len(got), len(kataDasar))
- }
-
- return kataDasar, nil
-}
-
-//
-// isAuthenticated will return true if the client already login; otherwise it
-// will return false.
-//
-func (cl *directClient) isAuthenticated() bool {
- return len(cl.cookies) > 0
-}
-
-//
-// login authenticate the client using username and password.
-//
-func (cl *directClient) login(surel, sandi string) (err error) {
- tokenLogin, err := cl.preLogin()
- if err != nil {
- return fmt.Errorf("Login: %w", err)
- }
-
- params := url.Values{
- paramNameRequestVerificationToken: []string{tokenLogin},
- paramNamePosel: []string{surel},
- paramNameKataSandi: []string{sandi},
- paramNameIngatSaya: []string{paramValueFalse},
- }
-
- reqBody := strings.NewReader(params.Encode())
-
- req, err := http.NewRequest(http.MethodPost, loginURL, reqBody)
- if err != nil {
- return fmt.Errorf("Login: %w", err)
- }
-
- req.Header.Set(libhttp.HeaderContentType, libhttp.ContentTypeForm)
-
- res, err := cl.httpc.Do(req)
- if err != nil {
- return fmt.Errorf("Login: %w", err)
- }
-
- defer res.Body.Close()
-
- resBody, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return fmt.Errorf("Login: %w", err)
- }
-
- if res.StatusCode >= http.StatusBadRequest {
- return fmt.Errorf("login: %d %s", res.StatusCode, resBody)
- }
-
- cl.cookies = cl.httpc.Jar.Cookies(cl.cookieURL)
- cl.setCookies()
- cl.saveCookies()
-
- return nil
-}
-
-//
-// setCookies for HTTP request that need an authentication.
-//
-func (cl *directClient) setCookies() {
- cl.httpc.Jar.SetCookies(cl.cookieURL, cl.cookies)
-}
-
-func (cl *directClient) parseHTMLKataDasar(htmlBody []byte) (
- kataDasar DaftarKata, err error,
-) {
- iter, err := html.Parse(bytes.NewReader(htmlBody))
- if err != nil {
- return nil, err
- }
-
- kataDasar = make(DaftarKata)
-
- for node := iter.Next(); node != nil; node = iter.Next() {
- if !node.IsElement() {
- continue
- }
- if node.Data != tagNameAnchor {
- continue
- }
- hrefValue := node.GetAttrValue(attrNameHref)
- if !strings.HasPrefix(hrefValue, entriPath) {
- continue
- }
- k := strings.TrimSpace(node.FirstChild.Data)
- kataDasar[k] = struct{}{}
- }
-
- return kataDasar, nil
-}
-
-//
-// parseHTMLLogin get the token at the form login.
-//
-func (cl *directClient) parseHTMLLogin(htmlBody []byte) (
- token string, err error,
-) {
- iter, err := html.Parse(bytes.NewReader(htmlBody))
- if err != nil {
- return "", err
- }
-
- for node := iter.Next(); node != nil; node = iter.Next() {
- if !node.IsElement() {
- continue
- }
- if node.Data != tagNameInput {
- continue
- }
-
- token := node.GetAttrValue(attrNameValue)
- if len(token) > 0 {
- return token, nil
- }
- }
-
- return "", fmt.Errorf("token login not found")
-}
-
-//
-// preLogin initialize the client to get the first cookie.
-//
-func (cl *directClient) preLogin() (token string, err error) {
- req, err := http.NewRequest(http.MethodGet, loginURL, nil)
- if err != nil {
- return "", err
- }
-
- res, err := cl.httpc.Do(req)
- if err != nil {
- return "", err
- }
-
- defer res.Body.Close()
-
- body, err := ioutil.ReadAll(res.Body)
- if err != nil {
- return "", err
- }
-
- token, err = cl.parseHTMLLogin(body)
- if err != nil {
- return "", err
- }
-
- return token, nil
-}
-
-//
-// loadCookies load the KBBI cookies from file.
-//
-func (cl *directClient) loadCookies() (err error) {
- cl.baseDir, err = os.UserConfigDir()
- if err != nil {
- return fmt.Errorf("loadCookies: %w", err)
- }
-
- f := filepath.Join(cl.baseDir, configDir, cookieFile)
-
- _, err = os.Stat(f)
- if errors.Is(err, os.ErrNotExist) {
- return nil
- }
-
- body, err := ioutil.ReadFile(f)
- if err != nil {
- return fmt.Errorf("loadCookies: %w", err)
- }
-
- dec := gob.NewDecoder(bytes.NewReader(body))
-
- err = dec.Decode(&cl.cookies)
- if err != nil {
- return fmt.Errorf("loadCookies: %w", err)
- }
-
- return nil
-}
-
-//
-// saveCookies store the client cookies to the file for future use.
-//
-func (cl *directClient) saveCookies() {
- err := os.MkdirAll(filepath.Join(cl.baseDir, configDir), 0700)
- if err != nil {
- log.Println("saveCookies:", err)
- }
-
- f := filepath.Join(cl.baseDir, configDir, cookieFile)
-
- var buf bytes.Buffer
- enc := gob.NewEncoder(&buf)
- err = enc.Encode(cl.cookies)
- if err != nil {
- log.Println("saveCookies: ", err)
- }
-
- err = ioutil.WriteFile(f, buf.Bytes(), 0600)
- if err != nil {
- log.Println("saveCookies: ", err)
- }
-}