webXMPP

Check-in [81431ef981]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Some more work getting reconnect flying. Finally just bit the bullet and stop/start'ed prosody while testing various scenarios.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | master | trunk
Files: files | file ages | folders
SHA3-256: 81431ef98170216b70afb4155684ff767c51ca5c4a3947b17cb1443cabe8edd8
User & Date: web 2020-05-26 23:44:51
Context
2020-05-31
18:30
Continuing work on dealing with spurious server disconnects check-in: 4f3cfc408c user: web tags: master, trunk
2020-05-26
23:44
Some more work getting reconnect flying. Finally just bit the bullet and stop/start'ed prosody while testing various scenarios. check-in: 81431ef981 user: web tags: master, trunk
2020-05-18
23:04
Fiddle with some edge cases of trying to do XMPP before the connection is considered up. TBD, reconnect if it goes down. check-in: 1def2b208b user: web tags: master, trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to acct_xmpp.py.

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
...
140
141
142
143
144
145
146
147
148
149
150
151



152
153
154
155

156
157






158
159
160
161
162
163
164
165
166
167



168
169
170
171
172
173
174
175
176
177
178
179
180

181
182


183




184
185
186
187
188


189
190


191
192
193
194
195
196
197
...
204
205
206
207
208
209
210
211
212












213



214





215
216
217
218
219
220
221
222
223
224
225
226
227







#  together for purposes of viewing.
#
# user - Back-reference to User instance we're serving
# acct/pw - Account name and its password
# conn - XMPP Client instance
# stopping - Bool flag to tell us to wrap up our service loop
# status - String, latest "show" status from peer
# saw_roster - Flag that we've received our first roster
class Account(object):
    def __init__(self, user, acct, pw):
	self.user = user
	self.acct = acct
	self.pw = pw
	self.conn = None
	self.stopping = False
	self.saw_roster = False

    # Send a message
    # (User exclusion is held.)
    def send(self, towhom, msg):
	self.conn.send( xmpp.Message(towhom, msg) )

    # Callback from XMPP stack when we get a message
................................................................................
	    newstat = "available"
	    if newstat != user.status.get(who, "NEW"):
		sys.stderr.write("no show, updating to assume %s %d\n" %
		    (newstat, user.rgen))
		user.rgen += 1
		user.status[who] = newstat

	# Ok, we've now seen at least a part of our roster
	self.saw_roster = True

    # Establish the XMPP connection
    def reconnect(self):



	acct = self.acct
	self.saw_roster = False
	server = acct.split("@")[-1]
	jid = xmpp.JID(acct)

	self.conn = conn = xmpp.Client(server, debug=[])
	conn.connect()






	result = conn.auth(jid.getNode(),
	    self.pw, "webXMPP%d" % (os.getpid(),))
	if not result:
	    sys.stderr.write("Account %s XMPP start failed\n" % (self.acct,))
	    sys.exit(0)

	# Announce ourselves
	conn.RegisterHandler('message', self.message)
	conn.RegisterHandler('presence', self.presence)
	conn.sendInitPresence()




    # Update our presence
    def sendPresence(self, p):
	sys.stderr.write("Presence %s = %s\n" % (self.user, p))

	# Don't send presence until you see a roster (and thus,
	#  the presence of your buddies)
	if not self.saw_roster:
	    sys.stderr.write("presence before roster, hiding\n")
	    return

	while not hasattr(self.conn, "send"):
	    # You have to be kidding me.

	    sys.stderr.write("XMPP connection, no send method yet\n")
	    time.sleep(0.5)


	self.conn.send(xmpp.Presence(status=p, show=p))





    # This runs under a dedicated thread
    def start(self):
	# Connect to the actual XMPP account
	self.reconnect()



	# Fold in roster


	r = self.conn.getRoster()
	buds = set()
	nicks = self.user.approot.nicks
	for bud in r.getItems():
	    budstr = toascii(bud)
	    if '@' not in budstr:
		# Ignore aliases
................................................................................
		if n and (n != bud):
		    sys.stderr.write("Nickname %s -> %s\n" % (bud, n))
		    nicks[bud] = n
	self.buddies = frozenset(buds)
	user = self.user
	for bud in buds:
	    user.roster[bud] = self
	del buds













	# And dispatch incoming messages



	while self.conn.Process(10):





	    # No single XMPP destination will chew us up
	    time.sleep(0.2)

	    # Cleanly terminate if so flagged
	    if self.stopping:
		sys.stderr.write("Stopping.\n")
		for bud in self.buddies:
		    del user.roster[bud]
		try:
		    conn.disconnect()
		except:
		    pass
		sys.exit(0)














<







<







 







<
<
<


>
>
>

|


>
|
|
>
>
>
>
>
>










>
>
>







<
<
<



>

|
>
>
|
>
>
>
>

<
<
<
<
>
>

|
>
>







 







<

>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
|
>
>
>
>
>
|
|

|
|
|
|
|
|
|
|
|
|
>
>
>
>
>
>
>
17
18
19
20
21
22
23

24
25
26
27
28
29
30

31
32
33
34
35
36
37
...
138
139
140
141
142
143
144



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182



183
184
185
186
187
188
189
190
191
192
193
194
195
196




197
198
199
200
201
202
203
204
205
206
207
208
209
...
216
217
218
219
220
221
222

223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
#  together for purposes of viewing.
#
# user - Back-reference to User instance we're serving
# acct/pw - Account name and its password
# conn - XMPP Client instance
# stopping - Bool flag to tell us to wrap up our service loop
# status - String, latest "show" status from peer

class Account(object):
    def __init__(self, user, acct, pw):
	self.user = user
	self.acct = acct
	self.pw = pw
	self.conn = None
	self.stopping = False


    # Send a message
    # (User exclusion is held.)
    def send(self, towhom, msg):
	self.conn.send( xmpp.Message(towhom, msg) )

    # Callback from XMPP stack when we get a message
................................................................................
	    newstat = "available"
	    if newstat != user.status.get(who, "NEW"):
		sys.stderr.write("no show, updating to assume %s %d\n" %
		    (newstat, user.rgen))
		user.rgen += 1
		user.status[who] = newstat




    # Establish the XMPP connection
    def reconnect(self):
	# Until we succeed
	self.conn = None

	acct = self.acct
	sys.stderr.write("Connection requested...\n")
	server = acct.split("@")[-1]
	jid = xmpp.JID(acct)
	while True:
	    conn = xmpp.Client(server, debug=[])
	    conn.connect()
	    if hasattr(conn, "Dispatcher"):
		break
	    sys.stderr.write("Waiting for Dispatcher on connect\n")
	    time.sleep(5)

	# Connected, now auth
	result = conn.auth(jid.getNode(),
	    self.pw, "webXMPP%d" % (os.getpid(),))
	if not result:
	    sys.stderr.write("Account %s XMPP start failed\n" % (self.acct,))
	    sys.exit(0)

	# Announce ourselves
	conn.RegisterHandler('message', self.message)
	conn.RegisterHandler('presence', self.presence)
	conn.sendInitPresence()

	# Ok, looks like we're good
	self.conn = conn

    # Update our presence
    def sendPresence(self, p):
	sys.stderr.write("Presence %s = %s\n" % (self.user, p))

	# Don't send presence until you see a roster (and thus,
	#  the presence of your buddies)




	while not hasattr(self.conn, "send"):
	    # You have to be kidding me.
	    # (This won't show up until the connection is established.)
	    sys.stderr.write("XMPP connection, no send method yet\n")
	    time.sleep(5.0)

	try:
	    self.conn.send(xmpp.Presence(status=p, show=p))
	    return
	except:
	    # Drop down to try and reconnect
	    pass





	sys.stderr.write("Lost XMPP server connection\n")
	return

    # Fold in roster
    def load_roster(self):
	sys.stderr.write("Loading roster...\n")
	r = self.conn.getRoster()
	buds = set()
	nicks = self.user.approot.nicks
	for bud in r.getItems():
	    budstr = toascii(bud)
	    if '@' not in budstr:
		# Ignore aliases
................................................................................
		if n and (n != bud):
		    sys.stderr.write("Nickname %s -> %s\n" % (bud, n))
		    nicks[bud] = n
	self.buddies = frozenset(buds)
	user = self.user
	for bud in buds:
	    user.roster[bud] = self


	# Ok, flag that we've seen it
	sys.stderr.write(" loaded\n")

    # This runs under a dedicated thread
    def start(self):

	while True:

	    # Connect to the actual XMPP account
	    self.reconnect()
	    self.load_roster()

	    # And dispatch incoming messages
	    while True:
		# Try to get work, catch an XMPP disconnect
		try:
		    res = self.conn.Process(2)
		except:
		    res = 0
		if not res:
		    break

		# No single XMPP destination will chew us up
		time.sleep(0.2)

		# Cleanly terminate if so flagged
		if self.stopping:
		    sys.stderr.write("Stopping.\n")
		    for bud in self.buddies:
			del user.roster[bud]
		    try:
			conn.disconnect()
		    except:
			pass
		    sys.exit(0)

	    # (Should be already disconnected from the Process
	    #  failure.)
	    try:
		self.conn.disconnect()
	    except:
		pass