wnox 0.1.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- wnox/__init__.py +145 -0
- wnox-0.1.0.dist-info/LICENSE.txt +0 -0
- wnox-0.1.0.dist-info/METADATA +27 -0
- wnox-0.1.0.dist-info/RECORD +6 -0
- wnox-0.1.0.dist-info/WHEEL +5 -0
- wnox-0.1.0.dist-info/top_level.txt +1 -0
wnox/__init__.py
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
#%%
|
2
|
+
import asyncio
|
3
|
+
import nest_asyncio
|
4
|
+
import logging
|
5
|
+
from slixmpp import ClientXMPP
|
6
|
+
import ssl
|
7
|
+
import json
|
8
|
+
from bson import ObjectId # If you need ObjectId validation
|
9
|
+
import requests as r
|
10
|
+
|
11
|
+
nest_asyncio.apply()
|
12
|
+
# logging.basicConfig(level=logging.DEBUG)
|
13
|
+
class EventEmitter:
|
14
|
+
def __init__(self):
|
15
|
+
self._events = {}
|
16
|
+
|
17
|
+
def on(self, event_name, callback):
|
18
|
+
if event_name not in self._events:
|
19
|
+
self._events[event_name] = []
|
20
|
+
self._events[event_name].append(callback)
|
21
|
+
|
22
|
+
async def emit(self, event_name, *args, **kwargs):
|
23
|
+
if event_name in self._events:
|
24
|
+
# Collect the results of all event handlers
|
25
|
+
results = []
|
26
|
+
for callback in self._events[event_name]:
|
27
|
+
result = callback(*args, **kwargs)
|
28
|
+
if asyncio.iscoroutinefunction(callback): # If callback is async
|
29
|
+
results.append(await result)
|
30
|
+
else: # If callback is sync
|
31
|
+
results.append(result)
|
32
|
+
return results[0]
|
33
|
+
|
34
|
+
class __WebSocketXMPP(ClientXMPP, EventEmitter):
|
35
|
+
def __init__(self, jid, password):
|
36
|
+
|
37
|
+
|
38
|
+
ClientXMPP.__init__(self, jid, password)
|
39
|
+
EventEmitter.__init__(self)
|
40
|
+
print(f"connecting to {jid} - {password}")
|
41
|
+
# self.jid = jid
|
42
|
+
self.password = password
|
43
|
+
# self.callback = callback # Store the callback function
|
44
|
+
self.add_event_handler("session_start", self.start)
|
45
|
+
self.add_event_handler("failed_auth", self.on_failed_auth)
|
46
|
+
self.add_event_handler("disconnected", self.on_disconnect)
|
47
|
+
self.add_event_handler("message", self.on_message) # Add event handler for incoming messages
|
48
|
+
|
49
|
+
async def start(self, event):
|
50
|
+
"""Handle session start."""
|
51
|
+
print("[bridge] connected.")
|
52
|
+
self.send_presence()
|
53
|
+
await self.get_roster()
|
54
|
+
|
55
|
+
# Send a test message
|
56
|
+
self.send_message(mto="ethan@qepal.com", mbody="Hello via WebSocket!")
|
57
|
+
print("[📩] Message sent to ethan@qepal.com")
|
58
|
+
|
59
|
+
def on_failed_auth(self, event):
|
60
|
+
"""Handle authentication failure."""
|
61
|
+
# print("[❌] Authentication failed. Check username/password.")
|
62
|
+
|
63
|
+
def on_disconnect(self, event):
|
64
|
+
"""Handle disconnection and attempt reconnection."""
|
65
|
+
# print("[❌] Disconnected from server. Attempting to reconnect...")
|
66
|
+
asyncio.create_task(self.reconnect())
|
67
|
+
|
68
|
+
async def reconnect(self):
|
69
|
+
await asyncio.sleep(5) # Wait before reconnecting
|
70
|
+
print("[🔄] Reconnecting...")
|
71
|
+
self.connect(address=("direct.qepal.com", 5222), disable_starttls=False, force_starttls=True)
|
72
|
+
self.process(forever=False)
|
73
|
+
|
74
|
+
async def on_message(self, stanza):
|
75
|
+
"""Handle incoming messages."""
|
76
|
+
if stanza.tag == "{jabber:client}message":
|
77
|
+
body = str(stanza['body'])
|
78
|
+
from_jid = str(stanza['from'])
|
79
|
+
itsme = from_jid and f"{self.boundjid.bare.split('@')[0]}-{self.boundjid.bare.split('@')[1]}" in from_jid
|
80
|
+
itsbro = not itsme and f"{self.boundjid.bare.split('@')[0]}-" in from_jid
|
81
|
+
delayed = "urn:xmpp:delay" in str(stanza)
|
82
|
+
|
83
|
+
if body and not delayed:
|
84
|
+
user_uid = from_jid.split('@')[0]
|
85
|
+
is_app = False
|
86
|
+
if len(user_uid) != 24 or not ObjectId.is_valid(user_uid):
|
87
|
+
user_uid = user_uid.split("-")[-1]
|
88
|
+
is_app = True
|
89
|
+
|
90
|
+
if body.startswith("{"):
|
91
|
+
try:
|
92
|
+
json_data = json.loads(body)
|
93
|
+
if "api" in json_data:
|
94
|
+
data = {key: val for key, val in json_data.items() if key != "api"}
|
95
|
+
data = {key: val for key, val in data.items() if key != "mid"}
|
96
|
+
|
97
|
+
if True or len(user_uid) == 24 and ObjectId.is_valid(user_uid):
|
98
|
+
result = await self.emit(json_data["api"], data)
|
99
|
+
if result == None:
|
100
|
+
result = {}
|
101
|
+
self.send_message(
|
102
|
+
mto=from_jid,
|
103
|
+
mbody=json.dumps({**result, "mid": json_data.get("mid")})
|
104
|
+
)
|
105
|
+
else:
|
106
|
+
await self.emit("message", {"from": from_jid, "body": body, "itsme": itsme, "itsbro": itsbro, "is_app":is_app})
|
107
|
+
except json.JSONDecodeError:
|
108
|
+
pass
|
109
|
+
else:
|
110
|
+
await self.emit("message", {"from": from_jid, "body": body, "itsme": itsme, "itsbro": itsbro, "is_app":is_app})
|
111
|
+
|
112
|
+
|
113
|
+
|
114
|
+
class App:
|
115
|
+
def __init__(self, *, app:str, resource:str, securekey:str, image:str, public:bool=False):
|
116
|
+
self.app = app
|
117
|
+
self.resource = resource
|
118
|
+
self.securekey = securekey
|
119
|
+
self.image = image
|
120
|
+
self.public = public
|
121
|
+
|
122
|
+
json = r.post("https://qepal.com/api/bridge/worker/init", json={
|
123
|
+
"app":app, "resource":resource, "securekey":securekey, "image":image, "public":public}).json()
|
124
|
+
|
125
|
+
self.uid = json["uid"]
|
126
|
+
self.myjid = self.app + "-" + str(self.uid) + "@qepal.com/" + self.resource
|
127
|
+
self.password = json["password"]
|
128
|
+
self.xmpp = __WebSocketXMPP(self.myjid, self.password)
|
129
|
+
|
130
|
+
def on(self, api:str, cb:callable):
|
131
|
+
self.xmpp.on(api, cb)
|
132
|
+
|
133
|
+
|
134
|
+
async def loop(self):
|
135
|
+
# print("[🔄] Initializing connection...")
|
136
|
+
ssl_ctx = ssl.create_default_context()
|
137
|
+
ssl_ctx.check_hostname = False # Disable hostname verification
|
138
|
+
ssl_ctx.verify_mode = ssl.CERT_NONE # Ignore SSL certificate validation
|
139
|
+
self.xmpp.ssl_context = ssl_ctx
|
140
|
+
|
141
|
+
self.xmpp.connect(address=("direct.qepal.com", 5222), disable_starttls=False, force_starttls=True)
|
142
|
+
self.xmpp.process(forever=True) # Keep the connection alive
|
143
|
+
|
144
|
+
|
145
|
+
|
File without changes
|
@@ -0,0 +1,27 @@
|
|
1
|
+
Metadata-Version: 2.2
|
2
|
+
Name: wnox
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: A short description of your package
|
5
|
+
Home-page: https://github.com/arminkardan/pywnox
|
6
|
+
Author: Ethan (Armin) Cardan
|
7
|
+
Author-email: "Ethan (Armin) Cardan" <armin.fire@gmail.com>
|
8
|
+
Project-URL: homepage, https://github.com/arminkardan/pywnox
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
11
|
+
Classifier: Operating System :: OS Independent
|
12
|
+
Requires-Python: >=3.6
|
13
|
+
Description-Content-Type: text/markdown
|
14
|
+
License-File: LICENSE.txt
|
15
|
+
Requires-Dist: asyncio
|
16
|
+
Requires-Dist: nest_asyncio
|
17
|
+
Requires-Dist: logging
|
18
|
+
Requires-Dist: slixmpp
|
19
|
+
Requires-Dist: ssl
|
20
|
+
Requires-Dist: bson
|
21
|
+
Requires-Dist: json
|
22
|
+
Requires-Dist: requests
|
23
|
+
Dynamic: author
|
24
|
+
Dynamic: home-page
|
25
|
+
Dynamic: requires-python
|
26
|
+
|
27
|
+
QE nexus client.
|
@@ -0,0 +1,6 @@
|
|
1
|
+
wnox/__init__.py,sha256=j7NZA4FZiwhE4EAUumAR-8pWweC7Fw-Dt2QHbPCgJu4,6128
|
2
|
+
wnox-0.1.0.dist-info/LICENSE.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
3
|
+
wnox-0.1.0.dist-info/METADATA,sha256=xCsnfct854waMtW1yW5vfrWwWcBQzEChG7QC5vFv8mg,812
|
4
|
+
wnox-0.1.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
5
|
+
wnox-0.1.0.dist-info/top_level.txt,sha256=Xm9SC1bx_o6zjvo2FI-3QiZX2PZ_0UBQkGlvfYsnkwc,5
|
6
|
+
wnox-0.1.0.dist-info/RECORD,,
|
@@ -0,0 +1 @@
|
|
1
|
+
wnox
|