ElectronRA 1.0.1__tar.gz

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.
@@ -0,0 +1,12 @@
1
+ Metadata-Version: 2.4
2
+ Name: Electron
3
+ Version: 1.0.0
4
+ Summary: A powerful Python library for Rubika bots
5
+ Author: Your Name
6
+ Requires-Python: >=3.7
7
+ Requires-Dist: aiohttp>=3.8.0
8
+ Requires-Dist: requests>=2.28.0
9
+ Dynamic: author
10
+ Dynamic: requires-dist
11
+ Dynamic: requires-python
12
+ Dynamic: summary
@@ -0,0 +1,16 @@
1
+ README.md
2
+ pyproject.toml
3
+ setup.py
4
+ Electron.egg-info/PKG-INFO
5
+ Electron.egg-info/SOURCES.txt
6
+ Electron.egg-info/dependency_links.txt
7
+ Electron.egg-info/requires.txt
8
+ Electron.egg-info/top_level.txt
9
+ electron/__init__.py
10
+ electron/bot.py
11
+ electron/client.py
12
+ electron/filters.py
13
+ electron/handlers.py
14
+ electron/real_client.py
15
+ electron/types.py
16
+ electron/methods/__init__.py
@@ -0,0 +1,2 @@
1
+ aiohttp>=3.8.0
2
+ requests>=2.28.0
@@ -0,0 +1 @@
1
+ electron
@@ -0,0 +1,12 @@
1
+ Metadata-Version: 2.4
2
+ Name: Electron
3
+ Version: 1.0.0
4
+ Summary: A powerful Python library for Rubika bots
5
+ Author: Your Name
6
+ Requires-Python: >=3.7
7
+ Requires-Dist: aiohttp>=3.8.0
8
+ Requires-Dist: requests>=2.28.0
9
+ Dynamic: author
10
+ Dynamic: requires-dist
11
+ Dynamic: requires-python
12
+ Dynamic: summary
@@ -0,0 +1,59 @@
1
+ # Electron
2
+
3
+ Powerful Python library for Rubika bots - Dual Mode (Bot + Self)
4
+
5
+ ## Features
6
+
7
+ - Dual Mode - Bot Token & Self Session
8
+ - Async/Await - High performance
9
+ - Simple decorator-based API
10
+ - Advanced handler system
11
+ - Fully independent
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ pip install Electron
17
+ from electron import Bot
18
+
19
+ # Bot mode
20
+ bot = Bot(token="YOUR_TOKEN")
21
+ # OR Self mode
22
+ bot = Bot(session="my_account")
23
+
24
+ @bot.on_command("start")
25
+ async def start(message):
26
+ await message.reply("Hello!")
27
+
28
+ bot.run()
29
+
30
+ ### ۲. آپدیت setup.py:
31
+
32
+ ```bash
33
+ cat > setup.py << 'ENDOFFILE'
34
+ from setuptools import setup, find_packages
35
+
36
+ with open("README.md", "r", encoding="utf-8") as fh:
37
+ long_description = fh.read()
38
+
39
+ setup(
40
+ name="Electron",
41
+ version="1.0.0",
42
+ author="Your Name",
43
+ author_email="your@email.com",
44
+ description="Powerful Python library for Rubika bots - Dual Mode",
45
+ long_description=long_description,
46
+ long_description_content_type="text/markdown",
47
+ url="https://github.com/yourusername/Electron",
48
+ packages=find_packages(),
49
+ classifiers=[
50
+ "Programming Language :: Python :: 3",
51
+ "License :: OSI Approved :: MIT License",
52
+ "Operating System :: OS Independent",
53
+ ],
54
+ python_requires=">=3.7",
55
+ install_requires=[
56
+ "aiohttp>=3.8.0",
57
+ "requests>=2.28.0",
58
+ ],
59
+ )
@@ -0,0 +1,16 @@
1
+ """
2
+ Electron - کتابخونه قدرتمند پایتون برای ساخت ربات‌های روبیکا
3
+ پشتیبانی از Bot Token و Self Session
4
+ """
5
+
6
+ __version__ = "1.0.0"
7
+ __author__ = "Your Name"
8
+
9
+ from .bot import Bot
10
+ from .types import Message, Chat, User, MessageType
11
+ from .handlers import (
12
+ Handler, MessageHandler, CommandHandler,
13
+ PhotoHandler, VideoHandler, VoiceHandler
14
+ )
15
+ from .filters import Filters
16
+ from .client import create_client, BotClient, SelfClient
@@ -0,0 +1,171 @@
1
+ import asyncio
2
+ import logging
3
+ from typing import Optional, Callable, List, Dict, Any, Union
4
+ from .client import create_client, BotClient, SelfClient, BaseClient
5
+ from .types import Message, Chat, User, MessageType
6
+ from .handlers import (
7
+ Handler, MessageHandler, CommandHandler,
8
+ PhotoHandler, VideoHandler, VoiceHandler, DocumentHandler
9
+ )
10
+
11
+ logging.basicConfig(level=logging.INFO)
12
+ logger = logging.getLogger(__name__)
13
+
14
+ class Bot:
15
+ def __init__(self, token: str = None, session: str = None, parse_mode: str = None):
16
+ if not token and not session:
17
+ raise ValueError("Either 'token' or 'session' must be provided!")
18
+
19
+ self.client: BaseClient = create_client(token=token, session=session)
20
+ self.token = token
21
+ self.session_name = session
22
+ self.handlers: List[Handler] = []
23
+ self._running = False
24
+ self._me = None
25
+ self.parse_mode = parse_mode
26
+
27
+ self.is_bot = token is not None
28
+ self.is_self = session is not None
29
+
30
+ if self.is_bot:
31
+ logger.info("Bot mode: Ready")
32
+ else:
33
+ logger.info("Self mode: Ready")
34
+
35
+ @property
36
+ async def me(self) -> Dict:
37
+ if not self._me:
38
+ self._me = await self.client.get_me()
39
+ return self._me
40
+
41
+ @property
42
+ def mode(self) -> str:
43
+ return "bot" if self.is_bot else "self"
44
+
45
+ def on_message(self, callback: Callable = None):
46
+ def decorator(func):
47
+ handler = MessageHandler(func)
48
+ self.handlers.append(handler)
49
+ return func
50
+ if callback:
51
+ return decorator(callback)
52
+ return decorator
53
+
54
+ def on_command(self, command: str, prefix: str = "/"):
55
+ def decorator(func):
56
+ handler = CommandHandler(command, func, prefix)
57
+ self.handlers.append(handler)
58
+ return func
59
+ return decorator
60
+
61
+ def on_photo(self, callback: Callable = None):
62
+ def decorator(func):
63
+ handler = PhotoHandler(func)
64
+ self.handlers.append(handler)
65
+ return func
66
+ if callback:
67
+ return decorator(callback)
68
+ return decorator
69
+
70
+ def on_video(self, callback: Callable = None):
71
+ def decorator(func):
72
+ handler = VideoHandler(func)
73
+ self.handlers.append(handler)
74
+ return func
75
+ if callback:
76
+ return decorator(callback)
77
+ return decorator
78
+
79
+ def on_voice(self, callback: Callable = None):
80
+ def decorator(func):
81
+ handler = VoiceHandler(func)
82
+ self.handlers.append(handler)
83
+ return func
84
+ if callback:
85
+ return decorator(callback)
86
+ return decorator
87
+
88
+ def on_document(self, callback: Callable = None):
89
+ def decorator(func):
90
+ handler = DocumentHandler(func)
91
+ self.handlers.append(handler)
92
+ return func
93
+ if callback:
94
+ return decorator(callback)
95
+ return decorator
96
+
97
+ async def _process_update(self, update: Dict):
98
+ try:
99
+ message = Message(
100
+ message_id=update.get("message_id", ""),
101
+ chat=Chat(**update.get("chat", {})),
102
+ from_user=User(**update.get("from", {})) if update.get("from") else None,
103
+ text=update.get("text"),
104
+ message_type=MessageType(update.get("message_type", "text")),
105
+ date=update.get("date"),
106
+ _client=self.client
107
+ )
108
+
109
+ for handler in self.handlers:
110
+ try:
111
+ if await handler.check(message):
112
+ await handler.execute(message)
113
+ except Exception as e:
114
+ logger.error(f"Handler error: {e}")
115
+
116
+ except Exception as e:
117
+ logger.error(f"Update error: {e}")
118
+
119
+ async def start(self, poll_interval: float = 1.0):
120
+ self._running = True
121
+ logger.info(f"Electron starting in {self.mode} mode...")
122
+
123
+ try:
124
+ await self.client.connect()
125
+ me = await self.me
126
+ logger.info(f"Connected as: {me}")
127
+ except Exception as e:
128
+ logger.error(f"Connection failed: {e}")
129
+ return
130
+
131
+ logger.info(f"Listening for updates...")
132
+
133
+ while self._running:
134
+ try:
135
+ updates = await self.client.get_updates()
136
+ for update in updates:
137
+ await self._process_update(update)
138
+ await asyncio.sleep(poll_interval)
139
+ except Exception as e:
140
+ logger.error(f"Polling error: {e}")
141
+ await asyncio.sleep(5)
142
+
143
+ def stop(self):
144
+ self._running = False
145
+ asyncio.create_task(self.client.close())
146
+ logger.info("Bot stopped")
147
+
148
+ def run(self):
149
+ try:
150
+ print("=" * 40)
151
+ print(f" Electron v1.0.0 - {self.mode.upper()}")
152
+ print("=" * 40)
153
+ asyncio.run(self.start())
154
+ except KeyboardInterrupt:
155
+ logger.info("Goodbye!")
156
+
157
+ async def send_message(self, chat_id: str, text: str, reply_to: str = None, **kwargs):
158
+ return await self.client.send_message(chat_id, text, reply_to)
159
+
160
+ async def reply_to(self, message: Message, text: str):
161
+ return await self.send_message(
162
+ chat_id=message.chat.chat_id,
163
+ text=text,
164
+ reply_to=message.message_id
165
+ )
166
+
167
+ def add_handler(self, handler: Handler):
168
+ self.handlers.append(handler)
169
+
170
+ def clear_handlers(self):
171
+ self.handlers.clear()
@@ -0,0 +1,225 @@
1
+ """
2
+ کلاینت اصلی Electron
3
+ پشتیبانی از دو حالت: Bot Token و User Session
4
+ """
5
+ import asyncio
6
+ import aiohttp
7
+ import json
8
+ import logging
9
+ from typing import Optional, Dict, Any, List, Union
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ class BaseClient:
14
+ """کلاس پایه برای هر دو نوع کلاینت"""
15
+
16
+ HEADERS = {
17
+ "user-agent": "okhttp/3.12.1",
18
+ "content-type": "application/json",
19
+ }
20
+
21
+ def __init__(self):
22
+ self.session = None
23
+ self.api_url = None
24
+ self.connected = False
25
+ self.auth_token = None
26
+ self.is_bot = False
27
+ self.is_self = False
28
+
29
+ async def _get_dcs(self) -> str:
30
+ """دریافت آدرس سرور روبیکا"""
31
+ urls = [
32
+ "https://getdcs.rubika.ir/",
33
+ "https://d3.im/",
34
+ ]
35
+
36
+ for url in urls:
37
+ try:
38
+ connector = aiohttp.TCPConnector(ssl=False)
39
+ async with aiohttp.ClientSession(connector=connector, headers=self.HEADERS) as session:
40
+ async with session.post(url, json={
41
+ "api_version": "5",
42
+ "method": "getDcs"
43
+ }, ssl=False, timeout=10) as resp:
44
+ data = await resp.json()
45
+ if data and "data" in data:
46
+ dcs = data["data"]
47
+ api_url = (dcs.get("messenger_url") or
48
+ dcs.get("api_url") or
49
+ dcs.get("url"))
50
+ if api_url:
51
+ return api_url.rstrip("/")
52
+ except:
53
+ continue
54
+
55
+ return "https://messengerg2c31.iranlms.ir"
56
+
57
+ async def connect(self) -> bool:
58
+ """اتصال به روبیکا"""
59
+ self.api_url = await self._get_dcs()
60
+
61
+ connector = aiohttp.TCPConnector(ssl=False)
62
+ self.session = aiohttp.ClientSession(
63
+ connector=connector,
64
+ headers=self.HEADERS,
65
+ timeout=aiohttp.ClientTimeout(total=30)
66
+ )
67
+
68
+ self.connected = True
69
+ logger.info(f"✅ Connected to: {self.api_url}")
70
+ return True
71
+
72
+ async def send_request(self, method: str, data: dict = None) -> dict:
73
+ """ارسال درخواست به API"""
74
+ if not self.connected:
75
+ await self.connect()
76
+
77
+ payload = {
78
+ "api_version": "5",
79
+ "method": method,
80
+ "data": data or {}
81
+ }
82
+
83
+ # اضافه کردن auth_token اگه bot باشه
84
+ if self.is_bot and self.auth_token:
85
+ payload["auth"] = self.auth_token
86
+
87
+ try:
88
+ async with self.session.post(self.api_url, json=payload, ssl=False) as resp:
89
+ text = await resp.text()
90
+ try:
91
+ return json.loads(text)
92
+ except:
93
+ return {}
94
+ except Exception as e:
95
+ logger.error(f"Request error: {e}")
96
+ return {}
97
+
98
+ async def close(self):
99
+ if self.session:
100
+ await self.session.close()
101
+ self.connected = False
102
+
103
+
104
+ class BotClient(BaseClient):
105
+ """کلاینت ربات (Bot Token)"""
106
+
107
+ def __init__(self, token: str):
108
+ super().__init__()
109
+ self.auth_token = token
110
+ self.is_bot = True
111
+ self.is_self = False
112
+
113
+ async def get_me(self) -> dict:
114
+ result = await self.send_request("getUserInfo", {})
115
+ return result.get("data", {})
116
+
117
+ async def send_message(self, chat_id: str, text: str, reply_to: str = None) -> dict:
118
+ data = {
119
+ "object_guid": chat_id,
120
+ "text": text,
121
+ "rnd": str(int(asyncio.get_event_loop().time() * 1000))
122
+ }
123
+ if reply_to:
124
+ data["reply_to_message_id"] = reply_to
125
+ return await self.send_request("sendMessage", data)
126
+
127
+ async def get_updates(self) -> list:
128
+ result = await self.send_request("getChatsUpdates", {"state": 0})
129
+ return result.get("data", []) if isinstance(result, dict) else []
130
+
131
+
132
+ class SelfClient(BaseClient):
133
+ """کلاینت سلف (User Session)"""
134
+
135
+ def __init__(self, session_name: str = "self_bot"):
136
+ super().__init__()
137
+ self.session_name = session_name
138
+ self.is_bot = False
139
+ self.is_self = True
140
+ self.auth_info = None # auth, guid, private_key
141
+
142
+ def load_session(self) -> bool:
143
+ """لود کردن سشن از فایل"""
144
+ try:
145
+ with open(f"{self.session_name}.session", "r") as f:
146
+ data = json.load(f)
147
+ self.auth_info = data
148
+ return True
149
+ except FileNotFoundError:
150
+ logger.warning(f"Session {self.session_name}.session not found")
151
+ return False
152
+
153
+ def save_session(self):
154
+ """ذخیره سشن تو فایل"""
155
+ if self.auth_info:
156
+ with open(f"{self.session_name}.session", "w") as f:
157
+ json.dump(self.auth_info, f)
158
+ logger.info(f"Session saved: {self.session_name}.session")
159
+
160
+ async def login(self, phone: str = None, code: str = None) -> bool:
161
+ """ورود با شماره موبایل"""
162
+ if phone and not code:
163
+ # ارسال کد
164
+ result = await self.send_request("sendCode", {
165
+ "phone_number": phone
166
+ })
167
+ logger.info(f"Code sent: {result}")
168
+ return True
169
+
170
+ elif phone and code:
171
+ # تایید کد
172
+ result = await self.send_request("signIn", {
173
+ "phone_number": phone,
174
+ "phone_code_hash": "",
175
+ "phone_code": code
176
+ })
177
+ if result and "data" in result:
178
+ self.auth_info = result["data"]
179
+ self.save_session()
180
+ return True
181
+
182
+ return False
183
+
184
+ async def get_me(self) -> dict:
185
+ result = await self.send_request("getUserInfo", {})
186
+ return result.get("data", {})
187
+
188
+ async def send_message(self, chat_id: str, text: str, reply_to: str = None) -> dict:
189
+ data = {
190
+ "object_guid": chat_id,
191
+ "text": text,
192
+ "rnd": str(int(asyncio.get_event_loop().time() * 1000))
193
+ }
194
+ if reply_to:
195
+ data["reply_to_message_id"] = reply_to
196
+ return await self.send_request("sendMessage", data)
197
+
198
+ async def get_updates(self) -> list:
199
+ result = await self.send_request("getChatsUpdates", {"state": 0})
200
+ return result.get("data", []) if isinstance(result, dict) else []
201
+
202
+
203
+ def create_client(token: str = None, session: str = None) -> BaseClient:
204
+ """
205
+ ساخت کلاینت مناسب بر اساس نوع ورودی
206
+
207
+ Args:
208
+ token: توکن ربات
209
+ session: نام فایل سشن
210
+
211
+ Returns:
212
+ BotClient یا SelfClient
213
+ """
214
+ if token:
215
+ logger.info("??? Bot mode activated")
216
+ return BotClient(token)
217
+ elif session:
218
+ client = SelfClient(session)
219
+ if client.load_session():
220
+ logger.info("??? Self mode activated (session loaded)")
221
+ else:
222
+ logger.info("??? Self mode activated (new session)")
223
+ return client
224
+ else:
225
+ raise ValueError("Either token or session must be provided")
@@ -0,0 +1,32 @@
1
+ from typing import List, Callable
2
+ from .types import Message, MessageType
3
+
4
+ class Filters:
5
+ @staticmethod
6
+ def text(message: Message) -> bool:
7
+ return message.message_type == MessageType.TEXT
8
+
9
+ @staticmethod
10
+ def photo(message: Message) -> bool:
11
+ return message.message_type == MessageType.PHOTO
12
+
13
+ @staticmethod
14
+ def video(message: Message) -> bool:
15
+ return message.message_type == MessageType.VIDEO
16
+
17
+ @staticmethod
18
+ def voice(message: Message) -> bool:
19
+ return message.message_type == MessageType.VOICE
20
+
21
+ @staticmethod
22
+ def reply(message: Message) -> bool:
23
+ return message.reply_to_message is not None
24
+
25
+ @staticmethod
26
+ def command(commands: List[str]) -> Callable:
27
+ def filter_func(message: Message) -> bool:
28
+ if not message.text or not message.text.startswith('/'):
29
+ return False
30
+ cmd = message.text.split()[0][1:]
31
+ return cmd in commands
32
+ return filter_func
@@ -0,0 +1,62 @@
1
+ from typing import Callable, Any
2
+ from .types import Message, MessageType
3
+ import re
4
+ import asyncio
5
+
6
+ class Handler:
7
+ def __init__(self, callback: Callable, **filters):
8
+ self.callback = callback
9
+ self.filters = filters
10
+
11
+ async def check(self, message: Message) -> bool:
12
+ return True
13
+
14
+ async def execute(self, message: Message) -> Any:
15
+ if asyncio.iscoroutinefunction(self.callback):
16
+ return await self.callback(message)
17
+ return self.callback(message)
18
+
19
+ class MessageHandler(Handler):
20
+ async def check(self, message: Message) -> bool:
21
+ return message.message_type == MessageType.TEXT and message.text is not None
22
+
23
+ class CommandHandler(Handler):
24
+ def __init__(self, command: str, callback: Callable, prefix: str = "/"):
25
+ super().__init__(callback)
26
+ self.command = command
27
+ self.prefix = prefix
28
+
29
+ async def check(self, message: Message) -> bool:
30
+ if message.text and message.text.startswith(self.prefix):
31
+ command_part = message.text.split()[0][len(self.prefix):]
32
+ return command_part.lower() == self.command.lower()
33
+ return False
34
+
35
+ class RegexHandler(Handler):
36
+ def __init__(self, pattern: str, callback: Callable):
37
+ super().__init__(callback)
38
+ self.pattern = re.compile(pattern)
39
+
40
+ async def check(self, message: Message) -> bool:
41
+ return bool(message.text and self.pattern.search(message.text))
42
+
43
+ async def execute(self, message: Message) -> Any:
44
+ match = self.pattern.search(message.text)
45
+ message.match = match
46
+ return await super().execute(message)
47
+
48
+ class PhotoHandler(Handler):
49
+ async def check(self, message: Message) -> bool:
50
+ return message.message_type == MessageType.PHOTO
51
+
52
+ class VideoHandler(Handler):
53
+ async def check(self, message: Message) -> bool:
54
+ return message.message_type == MessageType.VIDEO
55
+
56
+ class VoiceHandler(Handler):
57
+ async def check(self, message: Message) -> bool:
58
+ return message.message_type == MessageType.VOICE
59
+
60
+ class DocumentHandler(Handler):
61
+ async def check(self, message: Message) -> bool:
62
+ return message.message_type == MessageType.DOCUMENT
File without changes
@@ -0,0 +1,121 @@
1
+ """
2
+ کلاینت واقعی Electron با استفاده از aiohttp
3
+ مستقل و قدرتمند - بدون وابستگی به rubpy
4
+ """
5
+ import asyncio
6
+ import aiohttp
7
+ import json
8
+ import logging
9
+ from typing import Optional, Dict, Any, List
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+ class RealRubikaClient:
14
+ """کلاینت واقعی روبیکا با aiohttp"""
15
+
16
+ HEADERS = {
17
+ "origin": "https://m.rubika.ir",
18
+ "referer": "https://m.rubika.ir/",
19
+ "content-type": "application/json",
20
+ "connection": "keep-alive",
21
+ "user-agent": "okhttp/3.12.1"
22
+ }
23
+
24
+ def __init__(self, auth_token: str):
25
+ self.auth_token = auth_token
26
+ self.session = None
27
+ self.api_url = "https://messenger.rubika.ir/"
28
+ self.connected = False
29
+
30
+ async def connect(self):
31
+ """اتصال به روبیکا"""
32
+ connector = aiohttp.TCPConnector(verify_ssl=False)
33
+ self.session = aiohttp.ClientSession(
34
+ connector=connector,
35
+ headers=self.HEADERS,
36
+ timeout=aiohttp.ClientTimeout(total=30)
37
+ )
38
+
39
+ # تست اتصال
40
+ try:
41
+ async with self.session.get(
42
+ "https://messenger.rubika.ir/",
43
+ ssl=False
44
+ ) as resp:
45
+ if resp.status == 200:
46
+ self.connected = True
47
+ logger.info("✅ به روبیکا متصل شد!")
48
+ return True
49
+ except Exception as e:
50
+ logger.error(f"❌ خطای اتصال: {e}")
51
+
52
+ return False
53
+
54
+ async def send_request(self, method: str, data: dict) -> dict:
55
+ """ارسال درخواست به API"""
56
+ if not self.connected:
57
+ await self.connect()
58
+
59
+ url = f"{self.api_url}api/{method}"
60
+
61
+ payload = {
62
+ "api_version": "5",
63
+ "auth": self.auth_token,
64
+ "data": data,
65
+ "method": method
66
+ }
67
+
68
+ try:
69
+ async with self.session.post(url, json=payload, ssl=False) as resp:
70
+ result = await resp.json()
71
+ return result.get("data", {})
72
+ except Exception as e:
73
+ logger.error(f"Request error: {e}")
74
+ return {}
75
+
76
+ async def get_me(self) -> dict:
77
+ return await self.send_request("getUserInfo", {})
78
+
79
+ async def send_message(self, chat_id: str, text: str, reply_to: str = None) -> dict:
80
+ data = {
81
+ "object_guid": chat_id,
82
+ "text": text
83
+ }
84
+ if reply_to:
85
+ data["reply_to_message_id"] = reply_to
86
+
87
+ return await self.send_request("sendMessage", data)
88
+
89
+ async def get_updates(self, limit: int = 10) -> list:
90
+ result = await self.send_request("getChatsUpdates", {
91
+ "state": 0
92
+ })
93
+ return result if isinstance(result, list) else []
94
+
95
+ async def close(self):
96
+ if self.session:
97
+ await self.session.close()
98
+ self.connected = False
99
+
100
+ # تست
101
+ async def test():
102
+ TOKEN = "BHBAHF0PYXRCYQWUDIGELJPUNRCEXXBUYLMQHJFILWKMEOYWXACICRLKKZZRIMVB"
103
+
104
+ client = RealRubikaClient(TOKEN)
105
+
106
+ print("??? Connecting...")
107
+ if await client.connect():
108
+ print("✅ Connected!")
109
+
110
+ print("\n??? Testing get_me...")
111
+ me = await client.get_me()
112
+ print(f"Result: {me}")
113
+
114
+ print("\n??? Testing get_updates...")
115
+ updates = await client.get_updates()
116
+ print(f"Updates: {len(updates)} found")
117
+
118
+ await client.close()
119
+
120
+ if __name__ == "__main__":
121
+ asyncio.run(test())
@@ -0,0 +1,74 @@
1
+ from dataclasses import dataclass, field
2
+ from typing import Optional, List, Dict, Any
3
+ from enum import Enum
4
+
5
+ class MessageType(Enum):
6
+ TEXT = "text"
7
+ PHOTO = "photo"
8
+ VIDEO = "video"
9
+ VOICE = "voice"
10
+ DOCUMENT = "document"
11
+ STICKER = "sticker"
12
+
13
+ @dataclass
14
+ class User:
15
+ user_id: str
16
+ username: Optional[str] = None
17
+ first_name: Optional[str] = None
18
+ last_name: Optional[str] = None
19
+ phone: Optional[str] = None
20
+ bio: Optional[str] = None
21
+
22
+ @property
23
+ def full_name(self) -> str:
24
+ if self.first_name and self.last_name:
25
+ return f"{self.first_name} {self.last_name}"
26
+ return self.first_name or self.username or "Unknown"
27
+
28
+ @dataclass
29
+ class Chat:
30
+ chat_id: str
31
+ type: str = "private"
32
+ title: Optional[str] = None
33
+ username: Optional[str] = None
34
+ members_count: Optional[int] = None
35
+
36
+ @dataclass
37
+ class Message:
38
+ message_id: str
39
+ chat: Chat
40
+ from_user: Optional[User] = None
41
+ text: Optional[str] = None
42
+ message_type: MessageType = MessageType.TEXT
43
+ reply_to_message: Optional['Message'] = None
44
+ file_id: Optional[str] = None
45
+ caption: Optional[str] = None
46
+ date: Optional[int] = None
47
+ _client: Any = None
48
+
49
+ def reply(self, text: str, **kwargs):
50
+ if self._client:
51
+ return self._client.send_message(
52
+ chat_id=self.chat.chat_id,
53
+ text=text,
54
+ reply_to_message_id=self.message_id,
55
+ **kwargs
56
+ )
57
+ raise ValueError("Client not set")
58
+
59
+ def delete(self):
60
+ if self._client:
61
+ return self._client.delete_message(
62
+ chat_id=self.chat.chat_id,
63
+ message_id=self.message_id
64
+ )
65
+ raise ValueError("Client not set")
66
+
67
+ def edit(self, new_text: str):
68
+ if self._client:
69
+ return self._client.edit_message(
70
+ chat_id=self.chat.chat_id,
71
+ message_id=self.message_id,
72
+ text=new_text
73
+ )
74
+ raise ValueError("Client not set")
@@ -0,0 +1,3 @@
1
+ [build-system]
2
+ requires = ["setuptools>=64", "wheel"]
3
+ build-backend = "setuptools.backends._legacy:_Backend"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,14 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="Electron",
5
+ version="1.0.0",
6
+ author="Your Name",
7
+ description="A powerful Python library for Rubika bots",
8
+ packages=find_packages(),
9
+ install_requires=[
10
+ "aiohttp>=3.8.0",
11
+ "requests>=2.28.0",
12
+ ],
13
+ python_requires=">=3.7",
14
+ )