wnox 0.3.0__py3-none-any.whl → 0.5.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 CHANGED
@@ -5,11 +5,22 @@ import logging
5
5
  from slixmpp import ClientXMPP
6
6
  import ssl
7
7
  import json
8
- from bson import ObjectId # If you need ObjectId validation
8
+ from bson import ObjectId
9
9
  import requests as r
10
10
 
11
+ import random
12
+ import string
13
+
11
14
  nest_asyncio.apply()
15
+ eventdatax = {}
16
+ eventsx = {}
12
17
  # logging.basicConfig(level=logging.DEBUG)
18
+
19
+ def serial_generator(length: int) -> str:
20
+ chars = string.digits + string.ascii_uppercase + string.ascii_lowercase
21
+ random_string = ''.join(random.choice(chars) for _ in range(length))
22
+ return random_string
23
+
13
24
  class EventEmitter:
14
25
  def __init__(self):
15
26
  self._events = {}
@@ -31,43 +42,41 @@ class EventEmitter:
31
42
  results.append(result)
32
43
  return results[0]
33
44
 
34
- class __WebSocketXMPP(ClientXMPP, EventEmitter):
35
- def __init__(self, jid, password):
45
+ class WSX(ClientXMPP, EventEmitter):
46
+ connected = False
47
+ def __init__(self, jid, password, app:str, uid:str, resource:str):
36
48
 
37
-
38
49
  ClientXMPP.__init__(self, jid, password)
39
50
  EventEmitter.__init__(self)
40
- print(f"connecting to {jid} - {password}")
41
- # self.jid = jid
51
+ self.app = app
52
+ self.uid = uid
53
+ self._resource = resource
42
54
  self.password = password
43
- # self.callback = callback # Store the callback function
44
55
  self.add_event_handler("session_start", self.start)
45
56
  self.add_event_handler("failed_auth", self.on_failed_auth)
46
57
  self.add_event_handler("disconnected", self.on_disconnect)
47
- self.add_event_handler("message", self.on_message) # Add event handler for incoming messages
58
+ self.add_event_handler("message", self.on_message)
48
59
 
49
60
  async def start(self, event):
50
61
  """Handle session start."""
51
62
  print("[bridge] connected.")
52
- self.send_presence()
63
+ self.send_presence(ptype="presence")
53
64
  await self.get_roster()
65
+ await self.emit("connect",{})
66
+ self.connected = True
54
67
 
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
68
 
59
69
  def on_failed_auth(self, event):
60
70
  """Handle authentication failure."""
61
- # print("[❌] Authentication failed. Check username/password.")
62
71
 
63
- def on_disconnect(self, event):
72
+ async def on_disconnect(self, event):
64
73
  """Handle disconnection and attempt reconnection."""
65
- # print("[❌] Disconnected from server. Attempting to reconnect...")
74
+ await self.emit("disconnect",{})
75
+ self.connected = False
66
76
  asyncio.create_task(self.reconnect())
67
77
 
68
78
  async def reconnect(self):
69
- await asyncio.sleep(5) # Wait before reconnecting
70
- print("[🔄] Reconnecting...")
79
+ await asyncio.sleep(5)
71
80
  self.connect(address=("direct.qepal.com", 5222), disable_starttls=False, force_starttls=True)
72
81
  self.process(forever=False)
73
82
 
@@ -78,14 +87,15 @@ class __WebSocketXMPP(ClientXMPP, EventEmitter):
78
87
  from_jid = str(stanza['from'])
79
88
  itsme = from_jid and f"{self.boundjid.bare.split('@')[0]}-{self.boundjid.bare.split('@')[1]}" in from_jid
80
89
  itsbro = not itsme and f"{self.boundjid.bare.split('@')[0]}-" in from_jid
90
+
91
+ if "conference.qepal.com" in from_jid:
92
+ itsme = f"{self.app}-{self.uid}-{self._resource}" in from_jid
93
+ itsbro = not itsme and f"{self.app}-{self.uid}-" in from_jid
94
+
81
95
  delayed = "urn:xmpp:delay" in str(stanza)
82
96
 
83
97
  if body and not delayed:
84
98
  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
99
 
90
100
  if body.startswith("{"):
91
101
  try:
@@ -103,43 +113,95 @@ class __WebSocketXMPP(ClientXMPP, EventEmitter):
103
113
  mbody=json.dumps({**result, "mid": json_data.get("mid")})
104
114
  )
105
115
  else:
106
- await self.emit("message", {"from": from_jid, "body": body, "itsme": itsme, "itsbro": itsbro, "is_app":is_app})
116
+ if "mid" in json_data:
117
+ data = {key: val for key, val in json_data.items() if key != "mid"}
118
+ eventdatax[json_data.get("mid")] = data
119
+ if json_data.get("mid") in eventsx:
120
+ eventsx.get(json_data.get("mid")).set()
121
+ else:
122
+ await self.emit("message", {"from": from_jid, "body": body, "itsme": itsme, "itsbro": itsbro})
123
+
107
124
  except json.JSONDecodeError:
108
125
  pass
109
126
  else:
110
- await self.emit("message", {"from": from_jid, "body": body, "itsme": itsme, "itsbro": itsbro, "is_app":is_app})
127
+ await self.emit("message", {"from": from_jid, "body": body, "itsme": itsme, "itsbro": itsbro})
111
128
 
112
129
 
113
130
 
114
131
  class App:
132
+
115
133
  def __init__(self, *, app:str, resource:str, securekey:str, image:str, public:bool=False):
116
134
  self.app = app
135
+ self.channels = set()
117
136
  self.resource = resource
118
137
  self.securekey = securekey
119
138
  self.image = image
120
139
  self.public = public
121
140
 
122
- json = r.post("https://qepal.com/api/bridge/worker/init", json={
141
+ _json = r.post("https://qepal.com/api/bridge/worker/init", json={
123
142
  "app":app, "resource":resource, "securekey":securekey, "image":image, "public":public}).json()
124
143
 
125
- self.uid = json["uid"]
144
+ self.uid = _json["uid"]
126
145
  self.myjid = self.app + "-" + str(self.uid) + "@qepal.com/" + self.resource
127
- self.password = json["password"]
128
- self.xmpp = __WebSocketXMPP(self.myjid, self.password)
146
+ self.password = _json["password"]
147
+ self.xmpp = WSX(self.myjid, self.password, self.app, self.uid, self.resource)
129
148
 
130
149
  def on(self, api:str, cb:callable):
131
150
  self.xmpp.on(api, cb)
132
151
 
152
+ def sendtojid(self, jid:str, body:str):
153
+ self.xmpp.send_message(mto=jid, mbody=body)
154
+
155
+ def connected(self):
156
+ return self.xmpp.connected
157
+
158
+ async def api(self, app:str, cmd:str, body:dict, jid:str = None, prioritize_public:bool = False):
159
+ if jid == None:
160
+ res:dict = r.post("https://qepal.com/api/bridge/worker/findfreeresource", json={ "app":app, "securekey": self.securekey }).json()
161
+ jids = list(res.get("jids",[]))
162
+ if len(jids) > 0:
163
+ if prioritize_public:
164
+ jid = jids[-1]
165
+ else:
166
+ jid = jids[0]
167
+ if jid == None:
168
+ print("unable to send api (-1)")
169
+ return
170
+
171
+ mid = serial_generator(10)
172
+ msg = {"mid":mid, "api":cmd, **body }
173
+ eventsx[mid] = asyncio.Event()
174
+ self.sendtojid(jid, json.dumps(msg))
175
+ await eventsx[mid].wait()
176
+ data = eventdatax.get(mid)
177
+ return data
178
+
179
+
180
+
181
+ def subscribe(self, channelname:str):
182
+ self.xmpp.send_presence(pto=channelname+ "@conference.qepal.com/"+ self.app + "-" + self.uid + "-" + self.resource , ptype="presence")
183
+ self.xmpp.get_roster()
184
+ self.channels.add(channelname)
185
+
186
+ def unsubscribe(self, channelname:str):
187
+ self.xmpp.send_presence(pto=channelname+ "@conference.qepal.com" , ptype="unavailable")
188
+ self.xmpp.get_roster()
189
+ self.channels.remove(channelname)
190
+
191
+ def sendtochannel(self, channelname:str, body:str):
192
+ if channelname not in self.channels:
193
+ self.subscribe(channelname)
194
+ self.xmpp.send_message(mto=f"{channelname}@conference.qepal.com", mbody=body, mtype='groupchat')
133
195
 
134
196
  async def loop(self):
135
- # print("[🔄] Initializing connection...")
197
+
136
198
  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
199
+ ssl_ctx.check_hostname = False
200
+ ssl_ctx.verify_mode = ssl.CERT_NONE
139
201
  self.xmpp.ssl_context = ssl_ctx
140
202
 
141
203
  self.xmpp.connect(address=("direct.qepal.com", 5222), disable_starttls=False, force_starttls=True)
142
- self.xmpp.process(forever=True) # Keep the connection alive
204
+ self.xmpp.process(forever=True)
143
205
 
144
206
 
145
207
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: wnox
3
- Version: 0.3.0
3
+ Version: 0.5.0
4
4
  Summary: A short description of your package
5
5
  Home-page: https://github.com/arminkardan/pywnox
6
6
  Author: Ethan (Armin) Cardan
@@ -0,0 +1,6 @@
1
+ wnox/__init__.py,sha256=_M92Wza8dl4QeQWdM0ckRtphgyfZs9g4DqwwvgSvOKI,8234
2
+ wnox-0.5.0.dist-info/LICENSE.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ wnox-0.5.0.dist-info/METADATA,sha256=JK1RXI-Ep2tmgbAmGiIkbCCwBMWwyjGrBZ6oXYWrfZE,670
4
+ wnox-0.5.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
5
+ wnox-0.5.0.dist-info/top_level.txt,sha256=Xm9SC1bx_o6zjvo2FI-3QiZX2PZ_0UBQkGlvfYsnkwc,5
6
+ wnox-0.5.0.dist-info/RECORD,,
@@ -1,6 +0,0 @@
1
- wnox/__init__.py,sha256=j7NZA4FZiwhE4EAUumAR-8pWweC7Fw-Dt2QHbPCgJu4,6128
2
- wnox-0.3.0.dist-info/LICENSE.txt,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- wnox-0.3.0.dist-info/METADATA,sha256=4jzCO_HyB0cIHeSrEg4MvYuVibx0goO1S_Hgqk2yyJI,670
4
- wnox-0.3.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
5
- wnox-0.3.0.dist-info/top_level.txt,sha256=Xm9SC1bx_o6zjvo2FI-3QiZX2PZ_0UBQkGlvfYsnkwc,5
6
- wnox-0.3.0.dist-info/RECORD,,
File without changes