Skip to content

Commit 0d5b5f0

Browse files
authored
Merge pull request #16 from DarkCat09/device-id
Accept custom device_id so it can be persistently stored
2 parents 805c56a + 9d4373b commit 0d5b5f0

3 files changed

Lines changed: 69 additions & 52 deletions

File tree

README.md

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,24 @@ The package is [available on PyPI](https://pypi.org/project/vkmax/)
1717
More in [examples](examples/)
1818
```python
1919
import asyncio
20-
import logging
20+
from pathlib import Path
2121

22-
import requests
23-
import sys
22+
import aiohttp
2423

2524
from vkmax.client import MaxClient
2625
from vkmax.functions.messages import edit_message
2726

28-
from pathlib import Path
27+
28+
# global aiohttp session
29+
http = None
2930

3031

3132
async def get_weather(city: str) -> str:
32-
response = requests.get(f"https://ru.wttr.in/{city}?Q&T&format=3")
33-
return response.text
33+
global http
34+
if not http:
35+
http = aiohttp.ClientSession()
36+
response = await http.get(f"https://ru.wttr.in/{city}?Q&T&format=3")
37+
return await response.text()
3438

3539

3640
async def packet_callback(client: MaxClient, packet: dict):
@@ -56,26 +60,29 @@ async def packet_callback(client: MaxClient, packet: dict):
5660

5761
async def main():
5862
client = MaxClient()
59-
6063
await client.connect()
6164

62-
login_token_file = Path('login_token.txt')
63-
64-
if login_token_file.exists():
65-
login_token_from_file = login_token_file.read_text(encoding='utf-8').strip()
66-
try:
67-
await client.login_by_token(login_token_from_file)
68-
except:
69-
print("Couldn't login by token. Falling back to SMS login")
65+
session_file = Path('max_session.txt')
7066

71-
else:
67+
if not session_file.exists():
7268
phone_number = input('Enter your phone number: ')
73-
sms_login_token = await client.send_code(phone_number)
69+
sms_token = await client.send_code(phone_number)
7470
sms_code = int(input('Enter SMS code: '))
75-
account_data = await client.sign_in(sms_login_token, sms_code)
71+
account_data = await client.sign_in(sms_token, sms_code)
7672

73+
device_id = client.device_id
7774
login_token = account_data['payload']['tokenAttrs']['LOGIN']['token']
78-
login_token_file.write_text(login_token, encoding='utf-8')
75+
76+
# save device uuid and auth token delimited by newline
77+
session_file.write_text(f'{device_id}\n{login_token}')
78+
79+
else:
80+
contents = session_file.read_text()
81+
device_id, login_token = contents.split('\n', maxsplit=1)
82+
try:
83+
await client.login_by_token(login_token, device_id)
84+
except:
85+
print("Couldn't login by token")
7986

8087
await client.set_callback(packet_callback)
8188

example.py

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,32 @@
11
import asyncio
22
import logging
3-
4-
import requests
53
import sys
4+
from pathlib import Path
5+
6+
import aiohttp
67

78
from vkmax.client import MaxClient
89
from vkmax.functions.messages import edit_message
910

10-
from pathlib import Path
11-
12-
date_format = '%d.%m.%Y %H:%M:%S'
13-
logging_format = '[%(asctime)s] [%(name)s] [%(levelname)s] %(message)s'
14-
15-
handlers = [
16-
logging.StreamHandler(sys.stdout)
17-
]
1811

12+
# setup logging with custom format and level `info`
1913
logging.basicConfig(
20-
format=logging_format,
21-
datefmt=date_format,
22-
handlers=handlers,
14+
format='[%(asctime)s] [%(name)s] [%(levelname)s] %(message)s',
15+
datefmt='%d.%m.%Y %H:%M:%S',
16+
handlers=[logging.StreamHandler(sys.stdout)],
2317
level=logging.INFO
2418
)
2519

20+
# global aiohttp session
21+
http = None
22+
23+
2624
async def get_weather(city: str) -> str:
27-
response = requests.get(f"https://ru.wttr.in/{city}?Q&T&format=3")
28-
return response.text
25+
global http
26+
if not http:
27+
http = aiohttp.ClientSession()
28+
response = await http.get(f"https://ru.wttr.in/{city}?Q&T&format=3")
29+
return await response.text()
2930

3031

3132
async def packet_callback(client: MaxClient, packet: dict):
@@ -51,26 +52,29 @@ async def packet_callback(client: MaxClient, packet: dict):
5152

5253
async def main():
5354
client = MaxClient()
54-
5555
await client.connect()
5656

57-
login_token_file = Path('login_token.txt')
57+
session_file = Path('max_session.txt')
5858

59-
if login_token_file.exists():
60-
login_token_from_file = login_token_file.read_text(encoding='utf-8').strip()
61-
try:
62-
await client.login_by_token(login_token_from_file)
63-
except:
64-
print("Couldn't login by token. Falling back to SMS login")
65-
66-
else:
67-
phone_number = input('Your phone number: ')
68-
sms_login_token = await client.send_code(phone_number)
59+
if not session_file.exists():
60+
phone_number = input('Enter your phone number: ')
61+
sms_token = await client.send_code(phone_number)
6962
sms_code = int(input('Enter SMS code: '))
70-
account_data = await client.sign_in(sms_login_token, sms_code)
63+
account_data = await client.sign_in(sms_token, sms_code)
7164

65+
device_id = client.device_id
7266
login_token = account_data['payload']['tokenAttrs']['LOGIN']['token']
73-
login_token_file.write_text(login_token, encoding='utf-8')
67+
68+
# save device uuid and auth token delimited by newline
69+
session_file.write_text(f'{device_id}\n{login_token}')
70+
71+
else:
72+
contents = session_file.read_text()
73+
device_id, login_token = contents.split('\n', maxsplit=1)
74+
try:
75+
await client.login_by_token(login_token, device_id)
76+
except:
77+
print("Couldn't login by token")
7478

7579
await client.set_callback(packet_callback)
7680

vkmax/client.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def __init__(self):
3434
self._connection: Optional[ClientConnection] = None
3535
self._http_pool: Optional[aiohttp.ClientSession] = None
3636
self._is_logged_in: bool = False
37+
self._device_id: Optional[str] = None
3738
self._seq = itertools.count(1)
3839
self._keepalive_task: Optional[asyncio.Task] = None
3940
self._recv_task: Optional[asyncio.Task] = None
@@ -166,7 +167,8 @@ async def _stop_keepalive_task(self):
166167
# --- Authentication ---
167168

168169
@ensure_connected
169-
async def _send_hello_packet(self):
170+
async def _send_hello_packet(self, device_id: Optional[str] = None):
171+
self._device_id = device_id or f'{uuid.uuid4()}'
170172
return await self.invoke_method(
171173
opcode=6,
172174
payload={
@@ -181,7 +183,7 @@ async def _send_hello_packet(self):
181183
"screen": "956x1470 2.0x",
182184
"timezone": "Asia/Vladivostok"
183185
},
184-
"deviceId": str(uuid.uuid4())
186+
"deviceId": self._device_id,
185187
}
186188
)
187189

@@ -230,8 +232,8 @@ async def sign_in(self, sms_token: str, sms_code: int):
230232
return verification_response
231233

232234
@ensure_connected
233-
async def login_by_token(self, token: str):
234-
await self._send_hello_packet()
235+
async def login_by_token(self, token: str, device_id: Optional[str] = None):
236+
await self._send_hello_packet(device_id)
235237
_logger.info("using session")
236238
login_response = await self.invoke_method(
237239
opcode=19,
@@ -260,3 +262,7 @@ async def login_by_token(self, token: str):
260262
await self._start_keepalive_task()
261263

262264
return login_response
265+
266+
@property
267+
def device_id(self) -> Optional[str]:
268+
return self._device_id

0 commit comments

Comments
 (0)