diff options
Diffstat (limited to 'direct_client.go')
| -rw-r--r-- | direct_client.go | 120 |
1 files changed, 97 insertions, 23 deletions
diff --git a/direct_client.go b/direct_client.go index 75f1404..aa296b5 100644 --- a/direct_client.go +++ b/direct_client.go @@ -6,12 +6,16 @@ package kbbi import ( "bytes" + "encoding/gob" + "errors" "fmt" "io/ioutil" "log" "net/http" "net/http/cookiejar" "net/url" + "os" + "path/filepath" "strconv" "strings" @@ -21,6 +25,8 @@ import ( ) const ( + cookieFile = "cookie" + configDir = "kbbi" maxPageNumber = 501 ) @@ -28,7 +34,9 @@ const ( // directClient for KBBI web using HTTP. // type directClient struct { + baseDir string cookieURL *url.URL + cookies []*http.Cookie httpc *http.Client } @@ -36,7 +44,7 @@ type directClient struct { // newDirectClient create and initialize new client that connect directly to // KBBI official website. // -func newDirectClient(cookies []*http.Cookie) (cl *directClient, err error) { +func newDirectClient() (cl *directClient, err error) { cookieURL, err := url.Parse(baseURL) if err != nil { return nil, fmt.Errorf("newDirectClient: %w", err) @@ -48,11 +56,7 @@ func newDirectClient(cookies []*http.Cookie) (cl *directClient, err error) { jar, err := cookiejar.New(jarOpt) if err != nil { - return nil, err - } - - if cookies != nil { - jar.SetCookies(cookieURL, cookies) + return nil, fmt.Errorf("newDirectClient: %w", err) } cl = &directClient{ @@ -63,6 +67,15 @@ func newDirectClient(cookies []*http.Cookie) (cl *directClient, err error) { }, } + 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 } @@ -169,20 +182,26 @@ func (cl *directClient) ListKataDasar() (kataDasar DaftarKata, err error) { } // -// Login authenticate the client using username and password. +// isAuthenticated will return true if the client already login; otherwise it +// will return false. // -func (cl *directClient) login(user, pass string) ( - cookies []*http.Cookie, err error, -) { +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 nil, fmt.Errorf("Login: %w", err) + return fmt.Errorf("Login: %w", err) } params := url.Values{ paramNameRequestVerificationToken: []string{tokenLogin}, - paramNamePosel: []string{user}, - paramNameKataSandi: []string{pass}, + paramNamePosel: []string{surel}, + paramNameKataSandi: []string{sandi}, paramNameIngatSaya: []string{paramValueFalse}, } @@ -190,39 +209,39 @@ func (cl *directClient) login(user, pass string) ( req, err := http.NewRequest(http.MethodPost, loginURL, reqBody) if err != nil { - return nil, fmt.Errorf("Login: %w", err) + return fmt.Errorf("Login: %w", err) } req.Header.Set(headerNameContentType, headerValueContentType) res, err := cl.httpc.Do(req) if err != nil { - return nil, fmt.Errorf("Login: %w", err) + return fmt.Errorf("Login: %w", err) } defer res.Body.Close() resBody, err := ioutil.ReadAll(res.Body) if err != nil { - return nil, fmt.Errorf("Login: %w", err) + return fmt.Errorf("Login: %w", err) } if res.StatusCode >= http.StatusBadRequest { - return nil, fmt.Errorf("Login: %d %s", res.StatusCode, resBody) + return fmt.Errorf("login: %d %s", res.StatusCode, resBody) } - cookies = cl.httpc.Jar.Cookies(cl.cookieURL) + cl.cookies = cl.httpc.Jar.Cookies(cl.cookieURL) + cl.setCookies() + cl.saveCookies() - return cookies, nil + return nil } // // setCookies for HTTP request that need an authentication. // -func (cl *directClient) setCookies(cookies []*http.Cookie) { - if len(cookies) > 0 { - cl.httpc.Jar.SetCookies(cl.cookieURL, cookies) - } +func (cl *directClient) setCookies() { + cl.httpc.Jar.SetCookies(cl.cookieURL, cl.cookies) } func (cl *directClient) parseHTMLKataDasar(htmlBody []byte) ( @@ -309,3 +328,58 @@ func (cl *directClient) preLogin() (token string, err error) { 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) + } +} |
