@@ -45,15 +45,14 @@ class UserTokensUser(typing.TypedDict):
45
45
email : typing .Optional [str ]
46
46
47
47
48
+ UserTokensT = typing .TypeVar ("UserTokensT" , bound = "UserTokensBase" )
49
+
50
+
48
51
@dataclasses .dataclass
49
- class UserTokens :
52
+ class UserTokensBase :
50
53
redis : utils .RedisCache
51
54
owner_id : int
52
55
users : typing .List [UserTokensUser ]
53
- ttl : int = - 2
54
-
55
- RETENTION_SECONDS = 60 * 60 * 24 * 3 # 3 days
56
- VALIDITY_SECONDS = 3600
57
56
58
57
@staticmethod
59
58
async def select_users_for (
@@ -76,45 +75,64 @@ async def select_users_for(
76
75
users = sorted (users , key = lambda x : x ["login" ] != ctxt .pull ["user" ]["login" ])
77
76
return users
78
77
79
- @staticmethod
80
- def _cache_key (owner_id : int ) -> str :
81
- return f"user-tokens-cache-owner-{ owner_id } "
82
-
83
- @staticmethod
84
- def _get_users_from_config () -> typing .List [UserTokensUser ]:
85
- return [
86
- {
87
- "login" : github_types .GitHubLogin (login ),
88
- "oauth_access_token" : github_types .GitHubOAuthToken (oauth_access_token ),
89
- "email" : None ,
90
- "name" : None ,
91
- }
92
- for login , oauth_access_token in config .ACCOUNT_TOKENS .items ()
93
- ]
94
-
95
78
def get_token_for (
96
79
self , wanted_login : github_types .GitHubLogin
97
80
) -> typing .Optional [UserTokensUser ]:
98
81
wanted_login_lower = wanted_login .lower ()
99
- for user in self .users + self . _get_users_from_config () :
82
+ for user in self .users :
100
83
if user ["login" ].lower () == wanted_login_lower :
101
84
return user
102
85
return None
103
86
87
+ @classmethod
88
+ async def delete (
89
+ cls : typing .Type [UserTokensT ], redis : utils .RedisCache , owner_id : int
90
+ ) -> None :
91
+ raise NotImplementedError
92
+
93
+ @classmethod
94
+ async def get (
95
+ cls : typing .Type [UserTokensT ], redis : utils .RedisCache , owner_id : int
96
+ ) -> UserTokensT :
97
+ raise NotImplementedError
98
+
99
+
100
+ @dataclasses .dataclass
101
+ class UserTokensGitHubCom (UserTokensBase ):
102
+ ttl : int = - 2
103
+
104
+ RETENTION_SECONDS = 60 * 60 * 24 * 3 # 3 days
105
+ VALIDITY_SECONDS = 3600
106
+
107
+ @staticmethod
108
+ def _cache_key (owner_id : int ) -> str :
109
+ return f"user-tokens-cache-owner-{ owner_id } "
110
+
104
111
async def _has_expired (self ) -> bool :
105
112
if self .ttl < 0 : # not cached
106
113
return True
107
114
elapsed_since_stored = self .RETENTION_SECONDS - self .ttl
108
115
return elapsed_since_stored > self .VALIDITY_SECONDS
109
116
110
117
@classmethod
111
- async def delete (cls , redis : utils .RedisCache , owner_id : int ) -> None :
112
- await redis .delete (cls ._cache_key (owner_id ))
118
+ async def delete (
119
+ cls : typing .Type [UserTokensT ], redis : utils .RedisCache , owner_id : int
120
+ ) -> None :
121
+ await redis .delete (typing .cast (UserTokensGitHubCom , cls )._cache_key (owner_id ))
113
122
114
123
@classmethod
115
- async def get (cls , redis : utils .RedisCache , owner_id : int ) -> "UserTokens" :
116
- """Get a tokens."""
124
+ async def get (
125
+ cls : typing .Type [UserTokensT ], redis : utils .RedisCache , owner_id : int
126
+ ) -> UserTokensT :
127
+ return typing .cast (
128
+ UserTokensT ,
129
+ await typing .cast (UserTokensGitHubCom , cls )._get (redis , owner_id ),
130
+ )
117
131
132
+ @classmethod
133
+ async def _get (
134
+ cls , redis : utils .RedisCache , owner_id : int
135
+ ) -> "UserTokensGitHubCom" :
118
136
cached_tokens = await cls ._retrieve_from_cache (redis , owner_id )
119
137
if cached_tokens is None or await cached_tokens ._has_expired ():
120
138
try :
@@ -140,26 +158,10 @@ async def save_to_cache(self) -> None:
140
158
)
141
159
self .ttl = self .RETENTION_SECONDS
142
160
143
- @classmethod
144
- async def _retrieve_from_db (
145
- cls , redis : utils .RedisCache , owner_id : int
146
- ) -> "UserTokens" :
147
- async with http .AsyncClient () as client :
148
- try :
149
- resp = await client .get (
150
- f"{ config .SUBSCRIPTION_BASE_URL } /engine/user_tokens/{ owner_id } " ,
151
- auth = (config .OAUTH_CLIENT_ID , config .OAUTH_CLIENT_SECRET ),
152
- )
153
- except http .HTTPNotFound :
154
- return cls (redis , owner_id , [])
155
- else :
156
- tokens = resp .json ()
157
- return cls (redis , owner_id , tokens ["user_tokens" ])
158
-
159
161
@classmethod
160
162
async def _retrieve_from_cache (
161
163
cls , redis : utils .RedisCache , owner_id : int
162
- ) -> typing .Optional ["UserTokens " ]:
164
+ ) -> typing .Optional ["UserTokensGitHubCom " ]:
163
165
async with await redis .pipeline () as pipe :
164
166
await pipe .get (cls ._cache_key (owner_id ))
165
167
await pipe .ttl (cls ._cache_key (owner_id ))
@@ -177,3 +179,62 @@ async def _retrieve_from_cache(
177
179
178
180
return cls (redis , owner_id , decrypted_tokens ["user_tokens" ], ttl )
179
181
return None
182
+
183
+ @classmethod
184
+ async def _retrieve_from_db (
185
+ cls , redis : utils .RedisCache , owner_id : int
186
+ ) -> "UserTokensGitHubCom" :
187
+ async with http .AsyncClient () as client :
188
+ try :
189
+ resp = await client .get (
190
+ f"{ config .SUBSCRIPTION_BASE_URL } /engine/user_tokens/{ owner_id } " ,
191
+ auth = (config .OAUTH_CLIENT_ID , config .OAUTH_CLIENT_SECRET ),
192
+ )
193
+ except http .HTTPNotFound :
194
+ return cls (redis , owner_id , [])
195
+ else :
196
+ tokens = resp .json ()
197
+ return cls (redis , owner_id , tokens ["user_tokens" ])
198
+
199
+
200
+ @dataclasses .dataclass
201
+ class UserTokensOnPremise (UserTokensBase ):
202
+ @classmethod
203
+ async def delete (
204
+ cls : typing .Type [UserTokensT ], redis : utils .RedisCache , owner_id : int
205
+ ) -> None :
206
+ pass
207
+
208
+ @classmethod
209
+ async def get (
210
+ cls : typing .Type [UserTokensT ], redis : utils .RedisCache , owner_id : int
211
+ ) -> UserTokensT :
212
+ return cls (
213
+ redis ,
214
+ owner_id ,
215
+ [
216
+ {
217
+ "login" : github_types .GitHubLogin (login ),
218
+ "oauth_access_token" : github_types .GitHubOAuthToken (
219
+ oauth_access_token
220
+ ),
221
+ "email" : None ,
222
+ "name" : None ,
223
+ }
224
+ for login , oauth_access_token in config .ACCOUNT_TOKENS .items ()
225
+ ],
226
+ )
227
+
228
+
229
+ if config .SUBSCRIPTION_TOKEN is not None :
230
+
231
+ @dataclasses .dataclass
232
+ class UserTokens (UserTokensOnPremise ):
233
+ pass
234
+
235
+
236
+ else :
237
+
238
+ @dataclasses .dataclass
239
+ class UserTokens (UserTokensGitHubCom ): # type: ignore [no-redef]
240
+ pass
0 commit comments