Skip to content

Commit

Permalink
new comet works
Browse files Browse the repository at this point in the history
  • Loading branch information
limboy committed Oct 30, 2011
1 parent e774630 commit 0424d74
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 263 deletions.
15 changes: 0 additions & 15 deletions etc/supervisord.conf.in
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,6 @@ command=${buildout:directory}/bin/python ${buildout:directory}/src/app.py
stderr_logfile = ${buildout:directory}/log/supervisor/web-stderr.log
stdout_logfile = ${buildout:directory}/log/supervisor/web-stdout.log

[program:online_user]
command=${buildout:directory}/bin/python ${buildout:directory}/src/subscribers/online_user.py
stderr_logfile = ${buildout:directory}/log/supervisor/online_user-stderr.log
stdout_logfile = ${buildout:directory}/log/supervisor/online_user-stdout.log

[program:room_online_user]
command=${buildout:directory}/bin/python ${buildout:directory}/src/subscribers/room_online_user.py
stderr_logfile = ${buildout:directory}/log/supervisor/room_online_user-stderr.log
stdout_logfile = ${buildout:directory}/log/supervisor/room_online_user-stdout.log

[program:room]
command=${buildout:directory}/bin/python ${buildout:directory}/src/subscribers/room.py
stderr_logfile = ${buildout:directory}/log/supervisor/room-stderr.log
stdout_logfile = ${buildout:directory}/log/supervisor/room-stdout.log

[program:gc]
command=${buildout:directory}/bin/python ${buildout:directory}/src/gc.py
stderr_logfile = ${buildout:directory}/log/supervisor/gc-stderr.log
Expand Down
153 changes: 81 additions & 72 deletions src/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,31 +23,6 @@ def is_duplicate_name():
return True
return False

class Comet(object):
def _single(self, config_key, channel):
if config_key not in rc.hgetall(channel):
rc.hset(channel, config_key, rc.get(config_key))
channel_val = rc.hget(channel, config_key)
key_val = rc.get(config_key)

if channel_val != key_val:
rc.hset(channel, config_key, key_val)
if key_val:
return json.loads(key_val)

def online_users(self, channel):
return self._single(config.ONLINE_USER_KEY, channel)

def room_online_users(self, channel, room_id = 0, key = None):
if not key:
key = config.ROOM_ONLINE_USER_KEY.format(room=room_id)
return self._single(key, channel)

def room_content(self, channel, room_id = 0, key = None):
if not key:
key = config.ROOM_KEY.format(room=room_id)
return self._single(key, channel)

@app.route('/')
def index():
if session.get('user'):
Expand Down Expand Up @@ -90,12 +65,14 @@ def chat():
room_info_keys = config.ROOM_INFO_KEY.format(room='*')
for room_info_key in rc.keys(room_info_keys):
room_info = json.loads(rc.get(room_info_key))
users = rc.zrevrange(config.ROOM_ONLINE_USER_CHANNEL.format(room=room_info['room_id']), 0, -1)
rm_channel_placeholder(users)
rooms.append({
'id': room_info['room_id'],
'creator': room_info['user'],
'content': map(json.loads, reversed(rc.zrevrange(config.ROOM_CHANNEL.format(room=room_info['room_id']), 0, 4))),
'title': room_info['title'],
'users': rc.zrange(config.ROOM_ONLINE_USER_CHANNEL.format(room=room_info['room_id']), 0, -1),
'users': users,
})

return render_template('chat.html',
Expand Down Expand Up @@ -160,68 +137,100 @@ def post_content():
'id': rc.incr(config.ROOM_CONTENT_INCR_KEY),
}
rc.zadd(config.ROOM_CHANNEL.format(room=room_id), json.dumps(data), time.time())
rc.publish(config.ROOM_SIGNAL.format(room=room_id), json.dumps({
'type': 'add_content',
'data': data,
}))

return jsonify(**data)

@app.route('/comet')
def comet():
uri = request.args.get('uri', '')
room_id = request.args.get('room_id', '')
comet = request.args.get('comet', '').split(',')
channel = config.CONN_CHANNEL_HASH.format(channel=request.args.get('channel'))

if room_id:
room_online_user_channel = config.ROOM_ONLINE_USER_CHANNEL.format(room=room_id)
rc.zadd(room_online_user_channel, session['user'], time.time())
rc.zadd(config.ONLINE_USER_CHANNEL, session['user'], time.time())
ts = request.args.get('ts', time.time())
channel = config.CONN_CHANNEL_SET.format(channel=request.args.get('channel'))

cmt = Comet()

if 'online_users' in comet:
result = cmt.online_users(channel)
if result:
return jsonify(result)

if 'room_online_users' in comet:
result = cmt.room_online_users(channel, room_id)
if result:
return jsonify(result)

if 'room_content' in comet:
result = cmt.room_content(channel, room_id)
if result:
return jsonify(result)

if 'room_online_users_count_all' in comet:
room_online_user_keys = config.ROOM_ONLINE_USER_KEY.format(room='*')
for user_key in rc.keys(room_online_user_keys):
result = cmt.room_online_users(channel, key = user_key)
if result:
return jsonify(result)

if 'room_content_all' in comet:
room_keys = config.ROOM_KEY.format(room='*')
for room_key in rc.keys(room_keys):
result = cmt.room_content(channel, key = room_key)
if result:
return jsonify(result)
result = cmt.check(channel, comet, ts, room_id)
if result:
return jsonify(**result)

passed_time = 0
while passed_time < config.COMET_TIMEOUT:
for key, val in rc.hgetall(channel).items():
current_val = rc.get(key)
if current_val and val != current_val:
data = json.loads(current_val)
rc.hset(channel, key, current_val)
return jsonify(**data)
comet = rc.smembers(config.CONN_CHANNEL_SET.format(channel=channel))
result = cmt.check(channel, comet, ts, room_id)
if result:
return jsonify(**result)
passed_time += config.COMET_POLL_TIME
gevent.sleep(config.COMET_POLL_TIME)

return jsonify([])
if room_id:
room_online_user_channel = config.ROOM_ONLINE_USER_CHANNEL.format(room=room_id)
rc.zadd(room_online_user_channel, session['user'], time.time())
rc.zadd(config.ONLINE_USER_CHANNEL, session['user'], time.time())

return jsonify(ts=time.time())

def rm_channel_placeholder(data):
for index, item in enumerate(data):
if item == config.CHANNEL_PLACEHOLDER:
data.pop(index)

class Comet(object):
def check(self, channel, comet, ts, room_id = 0):
conn_channel_set = config.CONN_CHANNEL_SET.format(channel=channel)
if 'online_users' in comet:
rc.sadd(conn_channel_set, 'online_users')
new_data = rc.zrangebyscore(config.ONLINE_USER_CHANNEL, ts, '+inf')
if new_data:
data=rc.zrevrange(config.ONLINE_USER_CHANNEL, 0, -1)
data.pop(0) if data[0] == config.CHANNEL_PLACEHOLDER else True
return dict(data=data,
ts=time.time(), type='online_users')

if 'room_online_users' in comet:
rc.sadd(conn_channel_set, 'room_online_users')
room_online_user_channel = config.ROOM_ONLINE_USER_CHANNEL.format(room=room_id)
new_data = rc.zrangebyscore(room_online_user_channel, ts, '+inf')
if new_data:
users=rc.zrevrange(room_online_user_channel, 0, -1)
rm_channel_placeholder(users)
data = {'room_id': room_id, 'users': users}
return dict(data=data,
ts=time.time(), type='room_online_users')

if 'room_content' in comet:
rc.sadd(conn_channel_set, 'room_content')
room_channel = config.ROOM_CHANNEL.format(room=room_id)
new_data = rc.zrangebyscore(room_channel, ts, '+inf')
if new_data:
data = {'room_id': room_id, 'content':[]}
for item in new_data:
data['content'].append(json.loads(item))
return dict(data=data, ts=time.time(), type='add_content')

if 'room_online_users_count_all' in comet:
rc.sadd(conn_channel_set, 'room_online_users_count_all')
room_online_user_channels = config.ROOM_ONLINE_USER_CHANNEL.format(room='*')
for room_online_user_channel in rc.keys(room_online_user_channels):
new_data = rc.zrangebyscore(room_online_user_channel, ts, '+inf')
if new_data:
users=rc.zrevrange(room_online_user_channel, 0, -1)
rm_channel_placeholder(users)
room_id = room_online_user_channel.split('_')[-1]
data = {'room_id': room_id, 'users': users}
return dict(data=data, ts=time.time(), type='room_online_users')

if 'room_content_all' in comet:
rc.sadd(conn_channel_set, 'room_content_all')
room_channels = config.ROOM_CHANNEL.format(room='*')
for room_channel in rc.keys(room_channels):
new_data = rc.zrangebyscore(room_channel, ts, '+inf')
if new_data:
room_id = room_channel.split('_')[-1]
data = {'room_id': room_id, 'content':[]}
for item in new_data:
data['content'].append(json.loads(item))
return dict(data=data, ts=time.time(), type='add_content')


def run():
http_server = WSGIServer(('', config.PORT), app)
Expand Down
7 changes: 3 additions & 4 deletions src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@
ROOM_INCR_KEY = 'room_incr_key'
ROOM_CONTENT_INCR_KEY = 'room_content_incr_key'
ROOM_INFO_KEY = 'room_info_key_{room}'
ONLINE_USER_KEY = 'online_user_key'
ROOM_ONLINE_USER_KEY = 'room_online_user_key_{room}'
ROOM_KEY = 'room_key_{room}'

ONLINE_USER_SIGNAL = ONLINE_USER_CHANNEL
ROOM_ONLINE_USER_SIGNAL = ROOM_ONLINE_USER_CHANNEL
ROOM_SIGNAL = ROOM_CHANNEL

CONN_CHANNEL_HASH = 'conn_channel_hash_{channel}'
CONN_CHANNEL_SET = 'conn_channel_set_{channel}'

COMET_TIMEOUT = 30
COMET_POLL_TIME = 2

CHANNEL_PLACEHOLDER = 'jwdlh'
6 changes: 2 additions & 4 deletions src/gc.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,12 @@ def clear():
current_time = time.time()
affcted_num = rc.zremrangebyscore(config.ONLINE_USER_CHANNEL, '-inf', current_time - 60)
if affcted_num:
rc.publish(config.ONLINE_USER_SIGNAL, '')
rc.zadd(config.ONLINE_USER_CHANNEL, config.CHANNEL_PLACEHOLDER, time.time())

# cause channel == signal, so publish channel is ok
for key in rc.keys(config.ROOM_ONLINE_USER_CHANNEL.format(room='*')):
affcted_num = rc.zremrangebyscore(key, '-inf', current_time - 60)
room_id = key.split('_')[-1]
if affcted_num:
rc.publish(key, json.dumps({'room_id': room_id}))
rc.zadd(key, config.CHANNEL_PLACEHOLDER, time.time())

sched.add_cron_job(clear, minute='*')

Expand Down
81 changes: 38 additions & 43 deletions src/static/script/main.coffee
Original file line number Diff line number Diff line change
@@ -1,67 +1,62 @@
channel = Math.floor(Math.random()*1000000)

create_chat_comet = ->
arg = "comet=room_online_users_count_all,room_content_all&channel=#{channel}"
create_chat_comet = (ts = '') ->
arg = "comet=room_online_users_count_all,room_content_all&channel=#{channel}&ts=#{ts}"
$.getJSON "/comet?uri=#{window.uri}&#{arg}", (result) ->
if result.type == 'room_online_users'
room_online_users_count_all result.data
else if result.type == 'add_content'
room_content_all result.data
create_chat_comet()
create_chat_comet(result.ts)

create_room_comet = ->
arg = "comet=online_users,room_online_users,room_content&channel=#{channel}&room_id=#{window.room_id}"
create_room_comet = (ts = '') ->
arg = "comet=room_online_users,room_content&channel=#{channel}&room_id=#{window.room_id}&ts=#{ts}"
$.getJSON "/comet?uri=#{window.uri}&#{arg}", (result) ->
if result.type == 'online_users'
online_users result.data
else if result.type == 'room_online_users'
room_online_users result.data
else if result.type == 'add_content'
room_content result.data
create_room_comet()
create_room_comet(result.ts)

room_online_users_count_all = (content) ->
for room_id, users of content
$("#room-#{room_id} .header span").text("(#{users.length}人在线)")
room_online_users_count_all = (data) ->
$("#room-#{data.room_id} .header span").text("(#{data.users.length}人在线)")

room_content_all = (content) ->
$body = $("#room-#{content.room_id} .body")
$body.find('ul').append("<li class='new' title='#{content.user} #{content.created}'>#{content.content}</li>")
if $body.find('ul li').length > 5
room_content_all = (data) ->
$body = $("#room-#{data.room_id} .body")
for content in data.content
$body.find('ul').append("<li class='new' title='#{content.user} #{content.created}'>#{content.content}</li>")
while $body.find('ul li').length > 5
$body.find('ul li:first-child').remove()

online_users = (content) ->
room_online_users = (data) ->
html = ''
for val in content
html += "<span>#{val}</span>"
$('#global_online_user .user_list').html(html)

room_online_users = (content) ->
html = ''
for room_id, val of content
for item in val
html += "<span>#{item}</span>"
for item in data.users
html += "<span>#{item}</span>"
$('#room_online_user .user_list').html(html)

room_content = (content) ->
$msg = $("#msg-#{content.id}")
if not $msg.length
html = "<tr id='msg-#{content.id}'>
<td>#{content.user}</td>
<td>#{content.content}</td>
<td>#{content.created}</td>
</tr>
"
$('#chat_content table tbody').append(html)
$("#chat_content table tbody tr:last-child").get(0).scrollIntoView()
if not window.entering_content
if document.title.substr(0, 1) != '('
document.title = "(1) #{document.title}"
else
current_title = document.title
current_count = parseInt(current_title.slice(current_title.indexOf('(')+1, current_title.indexOf(')')))
new_count = current_count + 1
document.title = current_title.replace("(#{current_count})", "(#{new_count})")
room_content = (data) ->
console.log data
for content in data.content
$msg = $("#msg-#{content.id}")
if not $msg.length
html = "<tr id='msg-#{content.id}'>
<td>#{content.user}</td>
<td>#{content.content}</td>
<td>#{content.created}</td>
</tr>
"
$('#chat_content table tbody').append(html)
$("#chat_content table tbody tr:last-child").get(0).scrollIntoView()
if not window.entering_content
if document.title.substr(0, 1) != '('
document.title = "(1) #{document.title}"
else
current_title = document.title
current_count = parseInt(current_title.slice(current_title.indexOf('(')+1, current_title.indexOf(')')))
new_count = current_count + 1
document.title = current_title.replace("(#{current_count})", "(#{new_count})")

$ ->
if $('#chat_content tbody tr').length
Expand All @@ -80,7 +75,7 @@ $ ->
$('#post_content input[name="content"]').val('')
window.entering_content = true
document.title = document.title.replace(/\([0-9]+\) /, '')
room_content result
room_content {'content': [result]}
'json'
)

Expand Down
Loading

0 comments on commit 0424d74

Please sign in to comment.