metadata

Check-in [8a1cc96ebf]
Login

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

Overview
Comment:Idle shutdown of stream monitoring
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256:8a1cc96ebf99fb9cb6ed2a362b5984c422aec456753db8f9002a6efeadf0df12
User & Date: vashon 2018-06-18 22:40:57
Context
2018-06-18
22:58
Bringup check-in: 9e3a6abf61 user: vashon tags: trunk
22:40
Idle shutdown of stream monitoring check-in: 8a1cc96ebf user: vashon tags: trunk
22:31
Handle network errors w. cleanup check-in: 5d912ee6bc user: vashon tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to stream.py.

1
2
3
4
5



6
7
8
9
10
11
12
..
31
32
33
34
35
36
37



38
39
40
41
42
43
44
..
68
69
70
71
72
73
74

75
76
77
78
79
80
81
...
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
#
# stream.py
#	Code for serving metadata on a  given stream
#
import sys, threading, json, urlparse




# HTTP headers to get Icecast metadata
Args = """icy-metadata: 1\r
User-Agent: mplayer-metadata\r
"""


................................................................................
	self.json = None

	# Waiters for new self.gen value
	self.queue = []

	# Thread pulling on the stream
	self.thread = None




    # Pull a line from our socket
    # Not remendously efficient, but tolerable for HTTP headers
    #  (he said hopefully)
    def readline(self):
	s = self.sock
	res = ""
................................................................................
    # Pull from a stream with Icecast metadata.
    # Because Icecast metadata is kind of a hairball of legacy and
    #  modern, we just talk TCP to it ourselves.
    # This function only returns on errors like aborted streams.
    # On idle timeout, it simply exits after clearing itself
    #  from the stream state.
    def watch(self):


	# Request it
	s.send("GET %s HTTP/1.0\r\n%s\r\n" %
	    (self.path, Args))

	# Assemble the HTTP response headers.  We'll likely have
	#  more than that, which will be passed down to the loop
................................................................................
		continue

	    # Convert to a JSON string
	    res["err"] = None
	    res["gen"] = self.gen
	    self.gen += 1
	    self.json = json.dumps(res)

	    self.wakeups()









    # Our main worker is self.watch(), right above.  This wraps it,
    #  so that it can return here on network failure, and we can
    #  tear down this thread.
    def run_watch(self):
	try:
	    self.watch()
	except:
	    pass
	self.thread = None








	# Kick free any pending waiters
	res = {"gen": self.gen, "err": "closed"}
	self.gen += 1
	self.json = json.dumps(res)
	self.wakeups()





|
>
>
>







 







>
>
>







 







>







 







>

>
>
>
>
>
>
>
>










>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
..
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
..
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
...
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
210
211
212
213
214
215
216
217
218
219
220
221
#
# stream.py
#	Code for serving metadata on a  given stream
#
import sys, threading, json, urlparse, time

# How many seconds of non-use of a stream before we shut it down
IDLE=600.0

# HTTP headers to get Icecast metadata
Args = """icy-metadata: 1\r
User-Agent: mplayer-metadata\r
"""


................................................................................
	self.json = None

	# Waiters for new self.gen value
	self.queue = []

	# Thread pulling on the stream
	self.thread = None

	# Last time we served a user
	self.idle = time.time()

    # Pull a line from our socket
    # Not remendously efficient, but tolerable for HTTP headers
    #  (he said hopefully)
    def readline(self):
	s = self.sock
	res = ""
................................................................................
    # Pull from a stream with Icecast metadata.
    # Because Icecast metadata is kind of a hairball of legacy and
    #  modern, we just talk TCP to it ourselves.
    # This function only returns on errors like aborted streams.
    # On idle timeout, it simply exits after clearing itself
    #  from the stream state.
    def watch(self):
	global IDLE

	# Request it
	s.send("GET %s HTTP/1.0\r\n%s\r\n" %
	    (self.path, Args))

	# Assemble the HTTP response headers.  We'll likely have
	#  more than that, which will be passed down to the loop
................................................................................
		continue

	    # Convert to a JSON string
	    res["err"] = None
	    res["gen"] = self.gen
	    self.gen += 1
	    self.json = json.dumps(res)
	    waiters = bool(self.waiters)
	    self.wakeups()

	    # Keep track of idleness
	    tm = time.time()
	    if waiters:
		self.idle = tm
	    elif (tm - self.idle) > IDLE:
		sys.stderr.write("idle reached for %s\n" % (self.host,))
		return

    # Our main worker is self.watch(), right above.  This wraps it,
    #  so that it can return here on network failure, and we can
    #  tear down this thread.
    def run_watch(self):
	try:
	    self.watch()
	except:
	    pass
	self.thread = None

	# Shut off the stream
	try:
	    self.sock.close()
	except:
	    pass
	self.sock = None

	# Kick free any pending waiters
	res = {"gen": self.gen, "err": "closed"}
	self.gen += 1
	self.json = json.dumps(res)
	self.wakeups()