kleinkram 0.38.1.dev20241119134715__py3-none-any.whl → 0.38.1.dev20241125112529__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of kleinkram might be problematic. Click here for more details.

kleinkram/api/client.py CHANGED
@@ -1,10 +1,15 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import logging
4
+ from threading import Lock
5
+ from typing import Any
6
+
3
7
  import httpx
4
8
  from kleinkram.auth import Config
5
9
  from kleinkram.config import Credentials
6
- from kleinkram.errors import LOGIN_MESSAGE
7
- from kleinkram.errors import NotAuthenticatedException
10
+ from kleinkram.errors import NotAuthenticated
11
+
12
+ logger = logging.getLogger(__name__)
8
13
 
9
14
 
10
15
  COOKIE_AUTH_TOKEN = "authtoken"
@@ -12,54 +17,87 @@ COOKIE_REFRESH_TOKEN = "refreshtoken"
12
17
  COOKIE_CLI_KEY = "clikey"
13
18
 
14
19
 
20
+ class NotLoggedInException(Exception): ...
21
+
22
+
15
23
  class AuthenticatedClient(httpx.Client):
16
- def __init__(self, *args, **kwargs) -> None:
24
+ _config: Config
25
+ _config_lock: Lock
26
+
27
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
17
28
  super().__init__(*args, **kwargs)
18
- self.config = Config()
19
29
 
20
- if self.config.has_cli_key:
21
- assert self.config.cli_key, "unreachable"
22
- self.cookies.set(COOKIE_CLI_KEY, self.config.cli_key)
30
+ self._config = Config()
31
+ self._config_lock = Lock()
32
+
33
+ if self._config.has_cli_key:
34
+ assert self._config.cli_key, "unreachable"
35
+ logger.info("using cli key...")
36
+ self.cookies.set(COOKIE_CLI_KEY, self._config.cli_key)
23
37
 
24
- elif self.config.has_refresh_token:
25
- assert self.config.auth_token is not None, "unreachable"
26
- self.cookies.set(COOKIE_AUTH_TOKEN, self.config.auth_token)
38
+ elif self._config.has_refresh_token:
39
+ logger.info("using refresh token...")
40
+ assert self._config.auth_token is not None, "unreachable"
41
+ self.cookies.set(COOKIE_AUTH_TOKEN, self._config.auth_token)
27
42
  else:
28
- raise NotAuthenticatedException(self.config.endpoint)
43
+ logger.info("not authenticated...")
44
+ raise NotAuthenticated
29
45
 
30
46
  def _refresh_token(self) -> None:
31
- if self.config.has_cli_key:
32
- raise RuntimeError
33
-
34
- refresh_token = self.config.refresh_token
35
- if not refresh_token:
36
- raise RuntimeError
47
+ if self._config.has_cli_key:
48
+ raise RuntimeError("cannot refresh token when using cli key auth")
37
49
 
50
+ refresh_token = self._config.refresh_token
51
+ if refresh_token is None:
52
+ raise RuntimeError("no refresh token found")
38
53
  self.cookies.set(COOKIE_REFRESH_TOKEN, refresh_token)
39
54
 
55
+ logger.info("refreshing token...")
40
56
  response = self.post(
41
57
  "/auth/refresh-token",
42
58
  )
43
59
  response.raise_for_status()
44
-
45
60
  new_access_token = response.cookies[COOKIE_AUTH_TOKEN]
46
61
  creds = Credentials(auth_token=new_access_token, refresh_token=refresh_token)
47
62
 
48
- self.config.save_credentials(creds)
63
+ logger.info("saving new tokens...")
64
+
65
+ with self._config_lock:
66
+ self._config.save_credentials(creds)
67
+
49
68
  self.cookies.set(COOKIE_AUTH_TOKEN, new_access_token)
50
69
 
51
- def request(self, method, url, *args, **kwargs):
52
- full_url = f"{self.config.endpoint}{url}"
70
+ def request(
71
+ self, method: str, url: str | httpx.URL, *args: Any, **kwargs: Any
72
+ ) -> httpx.Response:
73
+ if isinstance(url, httpx.URL):
74
+ raise NotImplementedError(f"`httpx.URL` is not supported {url!r}")
75
+ if not url.startswith("/"):
76
+ url = f"/{url}"
77
+
78
+ # try to do a request
79
+ full_url = f"{self._config.endpoint}{url}"
80
+ logger.info(f"requesting {method} {full_url}")
53
81
  response = super().request(method, full_url, *args, **kwargs)
54
82
 
83
+ logger.info(f"got response {response}")
84
+
85
+ # if the requesting a refresh token fails, we are not logged in
55
86
  if (url == "/auth/refresh-token") and response.status_code == 401:
56
- raise RuntimeError(LOGIN_MESSAGE)
87
+ logger.info("got 401, not logged in...")
88
+ raise NotAuthenticated
57
89
 
90
+ # otherwise we try to refresh the token
58
91
  if response.status_code == 401:
92
+ logger.info("got 401, trying to refresh token...")
59
93
  try:
60
94
  self._refresh_token()
61
95
  except Exception:
62
- raise RuntimeError(LOGIN_MESSAGE)
63
- return super().request(method, full_url, *args, **kwargs)
96
+ raise NotAuthenticated
97
+
98
+ logger.info(f"retrying request {method} {full_url}")
99
+ resp = super().request(method, full_url, *args, **kwargs)
100
+ logger.info(f"got response {resp}")
101
+ return resp
64
102
  else:
65
103
  return response