webXMPP

Check-in [4dd13877ea]
Login

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

Overview
Comment:Bring up initial message notification get
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | master | trunk
Files: files | file ages | folders
SHA3-256:4dd13877ea645deff8f4183c4240cac34678829d799ebbc4855f4af1086eca53
User & Date: vandyswa@gmail.com 2017-06-28 21:00:25
Context
2017-06-29
18:09
Bringup, actual notification delivery check-in: 7ff7888f34 user: vandyswa@gmail.com tags: master, trunk
2017-06-28
21:00
Bring up initial message notification get check-in: 4dd13877ea user: vandyswa@gmail.com tags: master, trunk
2017-06-27
20:23
Bringup, get/notify check-in: c519c48b5b user: vandyswa@gmail.com tags: master, trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to notified.py.

15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
..
37
38
39
40
41
42
43


44
45
46
47
48
49
50
..
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
...
146
147
148
149
150
151
152




153
154
155
156
157
158
159
160
161
162
...
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
210
211
212
213
#
# The initial implementation is for Ubuntu Touch.  It plays
#  a sound and pushes a notification when receiving new
#  events.  It also turns on a blinking LED where it can,
#  and clears it only when the device is next unlocked.
#
# A client's request indicates the current event
#  serial seen (initially 0).  It specifies how many
#  event details it wants at most, along with whether its wants
#  subject and even body.  The server always indicates
#  the latest event serial, and considers the events delivered
#  regardless of how many bodies the client wanted to receie.
# Imagine the request is
#  {nextev: 100, detail: 2, nevent: 1}
# and that the server next event # is 103 (i.e., 100, 101 and
#  102 have arrived).  The server will respond:
#  {nextev: 103, events: [["xmpp", "Joe"]]}
# which tells the client to ask next for 103, and it can
................................................................................
#  Leve1 1 is just the event source type (XMPP, SMS, ...).
#  Level 2 is the sender.  Level 3 is the subject line,
#  level 4 is a message body.  In the above example the
#  client requested the first two items, thus seeing
#  that it's an XMPP message from Joe.  At detail 0, you
#  would only see that there were new events, but no other
#  detail.


#
import sys, json, time, os
import notify2
import pong
import pdb

# For DBus sniffing
................................................................................
from gi.repository import GLib

# Are LEDs available for notification indication?
LED = "/sys/class/leds/red"
blinking = leds = False

# Initial condition, no events ever seen
serial = 0

# Hook for logging
def log(s):
    sys.stderr.write(s)
    sys.stderr.write('\n')

# Quick/easy way to turn dict into an ob with those k/v as attrs
................................................................................

    # Get our configuration
    f = open(os.getenv("HOME") + "/.config/notify.json", "r")
    d = json.loads(f.read())
    f.close()
    cfg = DictOb(d)





# Endless execution, notification client
def run():
    global cfg

    # Get a wrapper for our pong network connection
    conn = pong.Client(cfg.server, cfg.port, cfg.user, cfg.password)

    # Prep LEDs for use if possible
    setup_leds()

................................................................................
        # Always yield for a second, so no matter
        #  what we never CPU spin hard.
        time.sleep(1)

        # Next round of notifications
        # Request events starting at this serial number
        pak = conn.msg("notify", "get", {
            "serial": serial,
            "detail": cfg.detail,
            "nmsg": cfg.nmsg})
        pak.who = dest
        resp = conn.ping_pong(pak, tmo*1.1)

        # Failure
        if resp is None:
            time.sleep(pong.WAITNET)
            continue

        # Nothing happened
        if resp["serial"] == serial:

            continue

        # New messages
        notify(resp)


if __name__ == "__main__":
    load_cfg()

    # No arg, just be a service daemon
    if len(sys.argv) == 1:
        run()







|


|







 







>
>







 







|







 







>
>
>
>


|







 







|











|
>




>







15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
..
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
..
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
...
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
...
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
#
# The initial implementation is for Ubuntu Touch.  It plays
#  a sound and pushes a notification when receiving new
#  events.  It also turns on a blinking LED where it can,
#  and clears it only when the device is next unlocked.
#
# A client's request indicates the current event
#  generation seen (initially 0).  It specifies how many
#  event details it wants at most, along with whether its wants
#  subject and even body.  The server always indicates
#  the latest event generation, and considers the events delivered
#  regardless of how many bodies the client wanted to receie.
# Imagine the request is
#  {nextev: 100, detail: 2, nevent: 1}
# and that the server next event # is 103 (i.e., 100, 101 and
#  102 have arrived).  The server will respond:
#  {nextev: 103, events: [["xmpp", "Joe"]]}
# which tells the client to ask next for 103, and it can
................................................................................
#  Leve1 1 is just the event source type (XMPP, SMS, ...).
#  Level 2 is the sender.  Level 3 is the subject line,
#  level 4 is a message body.  In the above example the
#  client requested the first two items, thus seeing
#  that it's an XMPP message from Joe.  At detail 0, you
#  would only see that there were new events, but no other
#  detail.
#
# TBD: roster & presence.
#
import sys, json, time, os
import notify2
import pong
import pdb

# For DBus sniffing
................................................................................
from gi.repository import GLib

# Are LEDs available for notification indication?
LED = "/sys/class/leds/red"
blinking = leds = False

# Initial condition, no events ever seen
gen = 0

# Hook for logging
def log(s):
    sys.stderr.write(s)
    sys.stderr.write('\n')

# Quick/easy way to turn dict into an ob with those k/v as attrs
................................................................................

    # Get our configuration
    f = open(os.getenv("HOME") + "/.config/notify.json", "r")
    d = json.loads(f.read())
    f.close()
    cfg = DictOb(d)

# New notifications contained in this packet
def notify(pak):
    raise Exception("Notification: TBD")

# Endless execution, notification client
def run():
    global cfg, gen

    # Get a wrapper for our pong network connection
    conn = pong.Client(cfg.server, cfg.port, cfg.user, cfg.password)

    # Prep LEDs for use if possible
    setup_leds()

................................................................................
        # Always yield for a second, so no matter
        #  what we never CPU spin hard.
        time.sleep(1)

        # Next round of notifications
        # Request events starting at this serial number
        pak = conn.msg("notify", "get", {
            "gen": gen,
            "detail": cfg.detail,
            "nmsg": cfg.nmsg})
        pak.who = dest
        resp = conn.ping_pong(pak, tmo*1.1)

        # Failure
        if resp is None:
            time.sleep(pong.WAITNET)
            continue

        # Nothing happened
        pdb.set_trace()
        if resp.inner["gen"] == gen:
            continue

        # New messages
        notify(resp)
        gen = resp["gen"]

if __name__ == "__main__":
    load_cfg()

    # No arg, just be a service daemon
    if len(sys.argv) == 1:
        run()

Changes to put.py.

41
42
43
44
45
46
47

48
49
50
51
52
53
54
55
56
57
58
59
60
		if tup[2] == clientID:
		    tbd.add(tup)
		    u.pending.remove(tup)

	    # Now close their socket then let them exit()
	    for tup in tbd:
		handler = tup[3]

		sock = handler.connection
		handler.connection = None
		handler.close_connection = 0
		sys.stderr.write("Cancel %s %r\n" % (self.user, sock))
		sock.shutdown(socket.SHUT_RDWR)
		sock.close()

		# Let the thread wake up & exit
		tup[1].release()

	    # Register us for FCM messaging
	    u.pushkeys.add(self.vals["bg"])








>
|
|
|
|
|
|







41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
		if tup[2] == clientID:
		    tbd.add(tup)
		    u.pending.remove(tup)

	    # Now close their socket then let them exit()
	    for tup in tbd:
		handler = tup[3]
		if handler is not None:
		    sock = handler.connection
		    handler.connection = None
		    handler.close_connection = 0
		    sys.stderr.write("Cancel %s %r\n" % (self.user, sock))
		    sock.shutdown(socket.SHUT_RDWR)
		    sock.close()

		# Let the thread wake up & exit
		tup[1].release()

	    # Register us for FCM messaging
	    u.pushkeys.add(self.vals["bg"])

Changes to udp.py.

46
47
48
49
50
51
52
















53
54
55
56
57
58
59
..
76
77
78
79
80
81
82


































83
84
85
86
87
88
89
..
90
91
92
93
94
95
96

97
98
99
100

















101
102
103
104
105
106
107
	# Calculate hash
	hashedpw = pong.pwhash(pw)
	# Cache
	hashed[uname] = hashedpw
	# Return answer
	return hashedpw

















class UDP(object):
    def __init__(self, cfg, approot):
	global TIMEOUT, accounts

	self.approot = approot
	TIMEOUT = approot.config["poll1"]
	port = self.port = cfg["port"]
................................................................................
	    resp = self.conn.msg(uname, inner["pakseq"],
		"params", "got", { "timeout": TIMEOUT, })
	    self.conn.reply(pak, resp)
	    return

	log(" param unknown subop: " + subop)



































    # Notification operations
    def handle_notify(self, pak):
	inner = pak.inner
	subop = inner["subop"]

	# Look up account state for this user
	approot = self.approot
................................................................................
	uname = pak.outer["user"]
	user = approot.users.get(uname)
	if user is None:
	    # Start user on first use
	    if not approot.start_user(uname):
		log(" can't start user " + uname)
		return


	# Get next notification(s)
	if subop == "get":
	    pdb.set_trace()


















	log(" notify unknown subop: " + subop)

    # Dispatch the latest request
    def handle(self, pak):
	inner = pak.inner
	op = inner["op"]







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>



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







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
..
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
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
	# Calculate hash
	hashedpw = pong.pwhash(pw)
	# Cache
	hashed[uname] = hashedpw
	# Return answer
	return hashedpw

# Pack up the latest notifications (if any) and send
#  back a reply to this packet.
class Notify_Reply(object):
    def __init__(self, handler, user, pak):
	self.handler = handler
	self.user = user
	self.pak = pak

    # We've been kicked awake, either from timeout or due
    #  to new notifications.  Send back a response.
    def release(self):
	log(" resolve PONG to " + self.user.name)
	self.handler.notifications(self.user, self.pak)
	# We're all done
	self.handler = self.user = self.pak = None

class UDP(object):
    def __init__(self, cfg, approot):
	global TIMEOUT, accounts

	self.approot = approot
	TIMEOUT = approot.config["poll1"]
	port = self.port = cfg["port"]
................................................................................
	    resp = self.conn.msg(uname, inner["pakseq"],
		"params", "got", { "timeout": TIMEOUT, })
	    self.conn.reply(pak, resp)
	    return

	log(" param unknown subop: " + subop)

    # Generate an answer packet with any new notifications
    def _notifications(self, user, inpak):
	det = inpak.inner["detail"]
	nmsg = inpak.inner["nmsg"]
	msgs = []
	resp = {"gen": user.gen, "msgs": msgs}
	for tup in user.msgs:
	    if len(msgs) > nmsg:
		break

	    # Assemble specified amount of detail
	    body = []
	    if det > 0:
		# Direction
		body.append(tup[1])
	    if det > 1:
		# Who
		body.append(tup[2])
	    if det > 2:
		body.append(tup[3])
	    msgs.append(body)

	# Build reply packet around this inner message,
	#  and send
	pdb.set_trace()
	outpak = self.conn.pong(inpak, "got", resp)
	self.conn.reply(inpak, outpak)

    def notifications(self, user, pak):
	try:
	    self._notifications(user, pak)
	except:
	    log("Response assembly to %s failed" % (user.name,))

    # Notification operations
    def handle_notify(self, pak):
	inner = pak.inner
	subop = inner["subop"]

	# Look up account state for this user
	approot = self.approot
................................................................................
	uname = pak.outer["user"]
	user = approot.users.get(uname)
	if user is None:
	    # Start user on first use
	    if not approot.start_user(uname):
		log(" can't start user " + uname)
		return
	    user = approot.users[uname]

	# Get next notification(s)
	if subop == "get":
	    gen = inner["gen"]

	    # We already have something for them
	    if gen < user.gen:
		self.notifications(user, pak)
		return

	    # Hold off on answering until timeout or
	    #  something arrives
	    # Unlike HTTP, we haven't spun up a thread for this
	    #  request, nor would it make sense to do so now.
	    # Instead, we create an instance with a "release"
	    #  method, and will directly answer the request
	    #  from that.
	    log(" queue for reply")
	    replier = Notify_Reply(self, user, pak)
	    user.await(TIMEOUT, replier, None, None)
	    return

	log(" notify unknown subop: " + subop)

    # Dispatch the latest request
    def handle(self, pak):
	inner = pak.inner
	op = inner["op"]