aboutsummaryrefslogtreecommitdiff
path: root/direct_client.go
diff options
context:
space:
mode:
Diffstat (limited to 'direct_client.go')
-rw-r--r--direct_client.go120
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)
+ }
+}