-
Notifications
You must be signed in to change notification settings - Fork 55
extract token load and save to token manager #179
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
481a7d6 to
ef51dba
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #179 +/- ##
==========================================
+ Coverage 63.41% 64.97% +1.55%
==========================================
Files 14 20 +6
Lines 1170 1359 +189
Branches 98 117 +19
==========================================
+ Hits 742 883 +141
- Misses 388 430 +42
- Partials 40 46 +6 ☔ View full report in Codecov by Sentry. |
|
first the good news : it worked "out of the box" I did have a look at the device_token_manager.py, but that does not seem to be used. I only see that FileTokenManager and TokenManagerInterface are used. The TokenManagerInterface.py looks more like a placeholder. The In http.py, the comment lines 155- 163 needs update to reflect the new situation. I'll start spending time on the device_token_manager.py approach. |
|
update on device_token_manager.py. On saving and loading different locks : what happens is LOCK_SH is busy loading and LOCK_EX is requested by saving ? I was not able to find out how to pass a different token_manager. I only got it work with hard coding load_pending_device_data() in combination with has_pending_device_data() will cause exception if NO data, but should return false or empty In case of a single household there is not an issue, but what it the same PyTado-instance is used for different houses. each of them have a different user/login. now there could be a race condition where a authorisation is pending for house-A, now a house-B want to login with actually a different a user/passwd, but it gets the device-ID for house-A ? |
The The The So one could either use our implementations ( I will describe the use case in the description and create an example. |
|
Just so you know, I created a testcase, but I need to work on it a bit more, is is not working currently |
|
Thanks Wolfgang. changed EDIT : |
|
@paulvha I did fix all tests and made some modifications to device token manager. It now works in my test scenario, which I updated in the description. @erwindouna do mind having a look at this PR? |
|
I have just tried it, but it does not work for me. First feedback Setting OAUTH_DATA_KEY = "oauth_data" is causing all the previous stored refresh-tokens to fail first time as these are stored with "refresh_token" and as such can not be found. Then in load_token() only the refresh_token it self is passed on, but _set_oauth_data(), expects the "refresh_token" header is part of the oauth_data that is passed on. |
1902edc to
38ef2a2
Compare
|
I could not login but after sometime the login prompt showed : Why is there a time.sleep(50) in _login_device_flow()? |
|
Still I could not login. In the function _check_device_activation(), it fails the test In the _tokenmanager interface.py this always returns false and thus always fails |
Sure in a bit. I've been rather occupied with Home Assistant to get the needed fix in and deliver support. :) |
Ok, missed that. I will convert old format to new style!
Yes, that is the idea. We only need the refresh_token in http.py, but handle the full response inside the token_manager implementation.
Sorry, Debug-Code. Removed it!
I don't know why I missed that!!! I'll fix it now. |
|
@paulvha I did change the implementation. I did mix too much functionality and separated it now into a token_manager and device_manager functionality. I also added backward compatibility to the token_manager, so it loads a previous saved single refresh token |
|
I had the first look to the updated code this afternoon, and found a couple of issues and it failed (issue 3 below):
doing: will not work correctly as _set_oauth_data(), in token_manager_interface.py, will also look for "expires_in", which not passed.
doing will not work correctly as _set_oauth_data(), in token_manager_interface.py, will also look for "expires_in", which not passed.
doing : fails as the DummyDeviceManager.py. has_pending_device_data() returns false I have commented the check out and then it reads the "old" refresh- and writes the new oauth-content to the file and works.
|
|
I wonder whether the correct "expires_in" is used for the access-code. This code is only valid for 10 minutes When http() is called from init() it will try to load the saved information with self._token_manager.get_token(). Now the FileContent.OAUTH_DATA is send to _set_oauth_data() where "expires in" is taken from the earlier saved data At the first start there should ALWAYS be an updated triggered to obtain the new access code and to set the "_refresh_at" moment. Hence I think that saving the refresh-code only, as was done before, is enough. |
|
@paulvha you might also comment directly in the code, that way you can presicely point to the questionable code.
Ohh I missed that!
Yes you are right, I tried to make it simpler by just sending the data to the "manager" and it should do whatever it has to. And for the The change to the expiration should make your 1. and 2. obsolete. I will take a look into 3. and 4. asap. For 5. my main language is C# and I use abstraction, interfaces and polymorphism a lot 😄 , so I brought it over to python. Maybe it is a bit too much, I will check if I can simply it. |
@wmalgadey : one person making changes in the code is enough :-).. But this one was a bit harder to explain indeed ... |
ba6ee6e to
c589f76
Compare
- do not fail_fast, we want to have all checks done on commit
fb01b7b to
875df73
Compare
Description
Add an abstract token manager interface (
TokenManagerInterface) as a base class for newTokenManagers. With this solution, it is possible to create a different mechanism to store the refresh token, without the introduction of a callback method.This has the advantage of further abstraction and testability, while maintaining a flexible library.
To save, load or pass an external saved token, I created the
FileTokenManager. This will be used as a default fortoken_managerand mimics the current functionality of passing a refresh token via init-parameter and/or saving and loading the refresh token to a file.The
Tadoclass ininterface.pyhas been modified to pass a new class implementing theTokenManagerInterface. For instance theDeviceTokenManager. You cannot provide both atoken_managerandtoken_file_pathorsaved_refresh_token.The
DeviceTokenManageris a new implementation, which (currently) cannot be configured from the outside. I did this because I wanted to make sure that, when you use it, the loading and saving will be done to a central file with proper locking for loading and saving. It didn't make sense to me, if you use theDeviceTokenManagerthat you would like to save to different files in the same "automation"-environment (and create different device ids!). That's what this class tries to solve!This example should start 3 Tado-instances in parallel and the first 2 should nearly in the same time present the same URL to authenticate the device. The 3rd instance should not display anything, if you activate the device within 30 seconds. Even if you create different
DeviceTokenManagerinstances, they always use the same file to sync.ToDos
Related Issues
Type of Changes
Mark the type of changes included in this pull request:
Checklist
Additional Notes
Add any additional comments, screenshots, or context for the reviewer(s).
Thank you for your contribution to PyTado! 🎉