diff options
| author | Shulhan <ms@kilabit.info> | 2024-12-12 19:56:01 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2025-01-02 03:14:16 +0700 |
| commit | 29905485926706ca462c95a793d4312e86434357 (patch) | |
| tree | a4b1f340e355926f9d4b35b275da6c75f0b5a314 | |
| parent | 1797eb6cf1201013de7101651c41d43e409d26d2 (diff) | |
| download | kbbi-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.go | 138 |
1 files changed, 64 insertions, 74 deletions
@@ -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) } } |
