summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2024-12-12 19:56:01 +0700
committerShulhan <ms@kilabit.info>2025-01-02 03:14:16 +0700
commit29905485926706ca462c95a793d4312e86434357 (patch)
treea4b1f340e355926f9d4b35b275da6c75f0b5a314
parent1797eb6cf1201013de7101651c41d43e409d26d2 (diff)
downloadkbbi-29905485926706ca462c95a793d4312e86434357.tar.xz
client: use libhttp.Client instead of standard http.Client
The libhttp.Client provides much simpler API, where we can define global headers once, like UserAgent and does not need to manually read the response body.
-rw-r--r--client.go138
1 files changed, 64 insertions, 74 deletions
diff --git a/client.go b/client.go
index d9781ab..a54f179 100644
--- a/client.go
+++ b/client.go
@@ -8,7 +8,6 @@ import (
"encoding/gob"
"errors"
"fmt"
- "io"
"log"
"net/http"
"net/http/cookiejar"
@@ -25,12 +24,14 @@ import (
)
const (
- kbbiUrlBase = "https://kbbi.kemdikbud.go.id"
- kbbiUrlLogin = kbbiUrlBase + "/Account/Login"
+ kbbiHost = `kbbi.kemdikbud.go.id`
+ kbbiUrlBase = `https://` + kbbiHost
+ kbbiUrlLogin = `/Account/Login`
kbbiPathEntri = "/entri/"
attrNameClass = "class"
attrNameHref = "href"
+ attrNameName = `name`
attrNameTitle = "title"
attrNameValue = "value"
@@ -64,7 +65,7 @@ const (
// Client for official KBBI web using HTTP.
type Client struct {
- httpc *http.Client
+ httpc *libhttp.Client
cookieURL *url.URL
baseDir string
cookies []*http.Cookie
@@ -87,14 +88,18 @@ func NewClient() (cl *Client, err error) {
return nil, fmt.Errorf("New: %w", err)
}
+ var clientOpts = libhttp.ClientOptions{
+ ServerURL: kbbiUrlBase,
+ Timeout: defTimeout,
+ }
+
cl = &Client{
cookieURL: cookieURL,
- httpc: &http.Client{
- Jar: jar,
- Timeout: defTimeout,
- },
+ httpc: libhttp.NewClient(clientOpts),
}
+ cl.httpc.Jar = jar
+
err = cl.loadCookies()
if err != nil {
return nil, fmt.Errorf("New: %w", err)
@@ -120,22 +125,17 @@ func (cl *Client) Lookup(ins []string) (res LookupResponse, err error) {
kata := &Word{}
res[in] = kata
- entriURL := kbbiUrlBase + kbbiPathEntri + in
- httpRes, err := cl.httpc.Get(entriURL)
- if err != nil {
- kata.err = err
- continue
+ var req = libhttp.ClientRequest{
+ Path: kbbiPathEntri + in,
}
-
- defer httpRes.Body.Close()
-
- body, err := io.ReadAll(httpRes.Body)
+ var resp *libhttp.ClientResponse
+ resp, err = cl.httpc.Get(req)
if err != nil {
kata.err = err
continue
}
- err = kata.parseHTMLEntri(in, body)
+ err = kata.parseHTMLEntri(in, resp.Body)
if err != nil {
kata.err = err
}
@@ -158,6 +158,7 @@ func (cl *Client) ListRootWords(pageStart, pageEnd int) (rootWords Words, err er
}
var (
+ logp = `ListRootWords`
params = url.Values{
paramNameMasukan: []string{paramValueDasar},
paramNameMasukanLengkap: []string{paramValueDasar},
@@ -167,39 +168,36 @@ func (cl *Client) ListRootWords(pageStart, pageEnd int) (rootWords Words, err er
n int
)
- urlPage := kbbiUrlBase + "/Cari/Jenis?"
+ urlPage := `/Cari/Jenis`
rootWords = make(Words)
for ; pageStart <= pageEnd; pageStart++ {
params.Set(paramNamePage, strconv.Itoa(pageStart))
- req, err := http.NewRequest(http.MethodGet, urlPage+params.Encode(), nil)
- if err != nil {
- return rootWords, err
+ var req = libhttp.ClientRequest{
+ Method: http.MethodGet,
+ Path: urlPage,
+ Params: params,
+ Type: libhttp.RequestTypeQuery,
}
-
- res, err := cl.httpc.Do(req)
- if err != nil {
- return rootWords, fmt.Errorf("ListRootWords: page %d: %w", pageStart, err)
- }
-
- defer res.Body.Close()
-
- body, err := io.ReadAll(res.Body)
+ var resp *libhttp.ClientResponse
+ resp, err = cl.httpc.Get(req)
if err != nil {
- return rootWords, fmt.Errorf("ListRootWords: page %d: %w", pageStart, err)
+ err = fmt.Errorf(`%s: halaman %d: %w`, logp, pageStart, err)
+ return rootWords, err
}
- got, err = cl.parseHTMLRootWords(body)
+ got, err = cl.parseHTMLRootWords(resp.Body)
if err != nil {
- return rootWords, fmt.Errorf("ListRootWords: page %d: %w", pageStart, err)
+ err = fmt.Errorf(`%s: halaman %d: %w`, logp, pageStart, err)
+ return rootWords, err
}
if len(got) == 0 {
break
}
- fmt.Printf("%d: got words: %v\n", pageStart, got)
+ log.Printf(`%s: halaman %d: daftar kata: %v`, logp, pageStart, got)
n = rootWords.merge(got)
if n == 0 {
@@ -207,8 +205,8 @@ func (cl *Client) ListRootWords(pageStart, pageEnd int) (rootWords Words, err er
break
}
- log.Printf("ListRootWords: halaman %d, jumlah kata %d, total kata %d",
- pageStart, len(got), len(rootWords))
+ log.Printf(`%s: halaman %d: jumlah kata %d, total kata %d`,
+ logp, pageStart, len(got), len(rootWords))
}
return rootWords, nil
@@ -222,9 +220,11 @@ func (cl *Client) IsAuthenticated() bool {
// Login authenticate the client using user email and password.
func (cl *Client) Login(email, pass string) (err error) {
+ var logp = `Login`
+
tokenLogin, err := cl.preLogin()
if err != nil {
- return fmt.Errorf("Login: %w", err)
+ return fmt.Errorf(`%s: %w`, logp, err)
}
params := url.Values{
@@ -234,29 +234,21 @@ func (cl *Client) Login(email, pass string) (err error) {
paramNameIngatSaya: []string{paramValueFalse},
}
- reqBody := strings.NewReader(params.Encode())
-
- req, err := http.NewRequest(http.MethodPost, kbbiUrlLogin, reqBody)
- if err != nil {
- return fmt.Errorf("Login: %w", err)
+ var req = libhttp.ClientRequest{
+ Method: http.MethodPost,
+ Path: kbbiUrlLogin,
+ Params: params,
+ Type: libhttp.RequestTypeForm,
}
-
- req.Header.Set(libhttp.HeaderContentType, libhttp.ContentTypeForm)
-
- res, err := cl.httpc.Do(req)
+ var resp *libhttp.ClientResponse
+ resp, err = cl.httpc.PostForm(req)
if err != nil {
- return fmt.Errorf("Login: %w", err)
+ return fmt.Errorf(`%s: %w`, logp, err)
}
- defer res.Body.Close()
-
- resBody, err := io.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)
+ if resp.HTTPResponse.StatusCode >= http.StatusBadRequest {
+ return fmt.Errorf(`%s: %d %s`, logp,
+ resp.HTTPResponse.StatusCode, resp.Body)
}
cl.cookies = cl.httpc.Jar.Cookies(cl.cookieURL)
@@ -316,35 +308,33 @@ func (cl *Client) parseHTMLLogin(htmlBody []byte) (
continue
}
+ var name = node.GetAttrValue(attrNameName)
+ if name != paramNameRequestVerificationToken {
+ continue
+ }
+
token := node.GetAttrValue(attrNameValue)
if len(token) > 0 {
return token, nil
}
}
- return "", fmt.Errorf("token login not found")
+ return ``, errors.New(`token login not found`)
}
// preLogin initialize the client to get the first cookie.
func (cl *Client) preLogin() (token string, err error) {
- req, err := http.NewRequest(http.MethodGet, kbbiUrlLogin, nil)
- if err != nil {
- return "", err
+ var req = libhttp.ClientRequest{
+ Method: http.MethodGet,
+ Path: kbbiUrlLogin,
}
-
- res, err := cl.httpc.Do(req)
- if err != nil {
- return "", err
- }
-
- defer res.Body.Close()
-
- body, err := io.ReadAll(res.Body)
+ var resp *libhttp.ClientResponse
+ resp, err = cl.httpc.Get(req)
if err != nil {
return "", err
}
- token, err = cl.parseHTMLLogin(body)
+ token, err = cl.parseHTMLLogin(resp.Body)
if err != nil {
return "", err
}
@@ -385,7 +375,7 @@ func (cl *Client) loadCookies() (err error) {
func (cl *Client) saveCookies() {
err := os.MkdirAll(filepath.Join(cl.baseDir, configDir), 0700)
if err != nil {
- log.Println("saveCookies:", err)
+ log.Println(`saveCookies:`, err)
}
f := filepath.Join(cl.baseDir, configDir, cookieFile)
@@ -394,11 +384,11 @@ func (cl *Client) saveCookies() {
enc := gob.NewEncoder(&buf)
err = enc.Encode(cl.cookies)
if err != nil {
- log.Println("saveCookies: ", err)
+ log.Println(`saveCookies:`, err)
}
err = os.WriteFile(f, buf.Bytes(), 0600)
if err != nil {
- log.Println("saveCookies: ", err)
+ log.Println(`saveCookies:`, err)
}
}