Implement webchat and badge notifications

This commit is contained in:
Trever Fischer
2012-10-23 13:10:06 -04:00
parent c5d644371d
commit 6b8239eb3f
7 changed files with 137 additions and 8 deletions

View File

@@ -1,4 +1,5 @@
from django.conf import settings
from django.core.cache import cache
from minecraft.models import Server
from json import dumps, JSONEncoder
import beanstalkc
@@ -16,6 +17,19 @@ class Event(object):
self.type = type
self.data = data
class ChatEvent(Event):
def __init__(self, sender, message):
super(ChatEvent, self).__init__(type='chat', data={'sender': sender,
'message': message})
class QuitEvent(Event):
def __init__(self, player):
super(QuitEvent, self).__init__(type='quit', data={'player': player})
class JoinEvent(Event):
def __init__(self, player):
super(JoinEvent, self).__init__(type='join', data={'player': player})
class BroadcastEvent(Event):
def __init__(self, message):
super(BroadcastEvent, self).__init__(type='broadcast', data={'message':
@@ -58,3 +72,33 @@ def player_message(playername, message, *args):
for server in Server.objects.all():
event = PlayerMessageEvent(playername, message)
send_server_event(server, event)
def web_queue(id):
queueName = 'caminus-web-%s'%id
queue = beanstalkc.Connection(host=settings.CAMINUS_BEANSTALKD_HOST,
port = settings.CAMINUS_BEANSTALKD_PORT)
queue.use(queueName)
queue.watch(queueName)
return queue
def send_web_event(event):
latest = cache.get('minecraft-web-events')
if latest is None:
latest = []
latest.append(dumps(event, cls=EventEncoder))
while len(latest) > 10:
latest.pop(0)
cache.set('minecraft-web-events', latest, 86400);
print 'cache:', latest
if settings.CAMINUS_USE_BEANSTALKD:
queue = beanstalkc.Connection(host=settings.CAMINUS_BEANSTALKD_HOST,
port = settings.CAMINUS_BEANSTALKD_PORT)
json = dumps(event, cls=EventEncoder)
for tube in queue.tubes():
if tube.startswith("caminus-web-"):
queue.use(tube)
queue.put(json)
def chat(playername, message):
evt = ChatEvent(playername, message)
send_web_event(evt)

View File

@@ -1,4 +1,7 @@
from piston.handler import AnonymousBaseHandler, BaseHandler
import time
from django.core.cache import cache
from django.conf import settings
from django.core.cache import cache
import appversion
from minecraft.models import MinecraftProfile
@@ -10,7 +13,7 @@ from urllib2 import urlopen
import json
from datetime import datetime
from models import cachePlayerList
from events import server_queue
from events import server_queue, web_queue, chat, server_broadcast, send_web_event, QuitEvent, JoinEvent
class MOTDHandler(AnonymousBaseHandler):
allowed_methods = ('GET',)
@@ -40,6 +43,7 @@ class NewPlayerSessionHandler(BaseHandler):
server = request.server
profile = MinecraftProfile.objects.get(mc_username__exact=playername)
session = PlayerSession.objects.create(server=server, player=profile, ip=ip)
send_web_event(JoinEvent(playername))
return {'success': True, 'error': '', 'permissions': profile.serverPermissions(), 'sessionId': session.id}
else:
return {'success': False, 'error': 'Your account is inactive.', 'permissions': []}
@@ -52,6 +56,7 @@ class ClosePlayerSessionHandler(BaseHandler):
for session in sessions:
session.end = datetime.now()
session.save()
send_web_event(QuitEvent(playername))
return {'valid': True}
class EconomyHandler(BaseHandler):
@@ -79,7 +84,7 @@ class ServerPingHandler(BaseHandler):
return {'identity': request.server, 'api-version': 2, 'server-version': appversion.version()}
class ServerEventHandler(BaseHandler):
allowed_methods = ('GET', 'POST')
allowed_methods = ('GET', 'POST', 'PUT')
def read(self, request):
queue = server_queue(request.server)
@@ -95,6 +100,22 @@ class ServerEventHandler(BaseHandler):
queue.delete(int(request.POST['job']))
return {'result': 'success'}
def update(self, request):
events = json.loads(request.POST['events'])['events']
for evt in events:
print repr(evt)
if evt['type'] == 'chat':
chat(evt['payload']['sender'], evt['payload']['message'])
return {'result': 'success'}
class ChatHandler(BaseHandler):
allowed_methods = ('POST',)
def create(self, request):
chat(request.user.minecraftprofile.mc_username, request.POST['message'])
server_broadcast("<%s> %s"%(request.user.minecraftprofile.mc_username,
request.POST['message']))
class PollHandler(BaseHandler):
allowed_methods = ('GET',)
@@ -106,4 +127,19 @@ class PollHandler(BaseHandler):
pollData['server-info'] = cache.get('caminus-server-info')
if not request.user.is_anonymous():
pollData['user-info']['balance'] = request.user.minecraftprofile.currencyaccount.balance
pollData['events'] = []
pollData['poll-id'] = timestamp
if timestamp == "0" and settings.CAMINUS_USE_BEANSTALKD:
pollData['poll-id'] = time.time()
latestEvents = cache.get('minecraft-web-events')
if not latestEvents:
latestEvents = []
for e in latestEvents:
pollData['events'].append(json.loads(e))
else:
eventQueue = web_queue(timestamp)
event = eventQueue.reserve(timeout=30)
if event:
pollData['events'].append(json.loads(event.body))
event.delete()
return pollData

View File

@@ -1,6 +1,8 @@
from django.db.models.signals import post_save
from minecraft.models import PlayerSession, Server
from django.core.cache import cache
import badges.api
import events
def cachePlayerList():
serverInfo = {}
@@ -15,3 +17,9 @@ def update_player_lists(sender, instance, created, **kwargs):
cachePlayerList()
post_save.connect(update_player_lists, sender=PlayerSession)
def notify_badge(sender, award, *args, **kwargs):
player = award.user.minecraftprofile.mc_username
events.server_broadcast("%s was awarded the %s badge!"%(player, award.badge.name))
badges.api.badge_awarded.connect(notify_badge)

View File

@@ -38,6 +38,11 @@ class ServerResource(Resource):
super(ServerResource, self).__init__(handler, ServerAuther())
self.csrf_exempt = getattr(self.handler, 'csrf_exempt', True)
class SimpleResource(Resource):
def __init__(self, handler):
super(SimpleResource, self).__init__(handler)
self.csrf_exempt = getattr(self.handler, 'csrf_exempt', True)
urlpatterns = patterns('api',
url(r'^motd/(?P<username>.*)$', motdHandler),
url(r'^server/whoami$', ServerResource(handlers.ServerPingHandler)),
@@ -45,5 +50,6 @@ urlpatterns = patterns('api',
url(r'^server/economy/(?P<playername>.*)$', ServerResource(handlers.EconomyHandler)),
url(r'^server/session/(?P<playername>.*)/new$', ServerResource(handlers.NewPlayerSessionHandler)),
url(r'^server/session/(?P<playername>.*)/close$', ServerResource(handlers.ClosePlayerSessionHandler)),
url(r'^poll/(?P<timestamp>[0-9]+)$', Resource(handlers.PollHandler)),
url(r'^poll/(?P<timestamp>.+)$', SimpleResource(handlers.PollHandler)),
url(r'^chat$', SimpleResource(handlers.ChatHandler)),
)

View File

@@ -1,8 +1,21 @@
function sendChat(message) {
$.post('/api/chat', {'message': message}, function(data) {
$('#chat-line').val('');
$('#chat-line').disabled = false;
});
}
$(document).ready(function() {
$('#server-interaction .drawer').each(function() {
var canvas = $(this).children('.canvas');
$(this, '.drawer-label').click(function() {
$(this).children('.drawer-label').click(function() {
canvas.slideToggle("blind");
});
});
$('#chat-line').keypress(function(evt) {
if (evt.charCode == 13) {
$('#chat-line').disabled = true;
sendChat($('#chat-line').val());
}
});
});

View File

@@ -1,12 +1,23 @@
function pollMessages() {
$.get('/api/poll/0', function(data) {
function pollMessages(id) {
$.get('/api/poll/'+id, function(data) {
if (id == 0)
$('#chat-display').html('');
$('#balance-display').html(data['user-info']['balance']);
$(data['events']).each(function(idx, evt) {
if (evt['type'] == "chat") {
$('#chat-display').append("<li>"+evt['payload']['sender']+": "+evt['payload']['message']);
} else if (evt['type'] == 'join') {
$('#chat-display').append("<li><em>"+evt['payload']['player']+" has joined</em></li>");
} else if (evt['type'] == 'quit') {
$('#chat-display').append("<li><em>"+evt['payload']['player']+" has quit</em></li>");
}
});
window.setTimeout(function() {pollMessages(data['poll-id'])}, 1);
});
}
function poll() {
pollMessages();
window.setTimeout(pollMessages, 3000);
pollMessages(0);
}
$(document).ready(function () {

View File

@@ -169,6 +169,17 @@ s.parentNode.insertBefore(po, s);
{% endif %}
</div>
<div id="server-interaction">
<div class="drawer">
<div class="drawer-label">
Chat
</div>
<div class="canvas">
<ul id="chat-display">
<li>Loading...</li>
</ul>
<input type="text" id="chat-line"/>
</div>
</div>
<div class="drawer">
<div class="drawer-label">
Online Players