рдореИрдВ рдЖрдкрдХреЗ рд▓рд┐рдП " рдЪреИрдирд▓ рдПрдкреАрдЖрдИ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдЪреИрдЯ " рдирд╛рдордХ рд▓реЗрдЦ рдХрд╛ рдореБрдлреНрдд рдЕрдиреБрд╡рд╛рдж рдкреНрд░рд╕реНрддреБрдд рдХрд░рддрд╛ рд╣реВрдВред рдореИрдВрдиреЗ рдЕрдкрдирд╛ рдХреЛрдб рдереЛрдбрд╝рд╛ рдЬреЛрдбрд╝рдиреЗ рдХрд╛ рднреА рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛редрдЖрдЬ рд╣рдо рдЖрдкрдХреЗ рд▓рд┐рдП рдЪреИрдирд▓ рдПрдкреАрдЖрдИ рдХреЗ рд▓рд┐рдП рд╕рдорд░реНрдкрд┐рдд
рдЧреВрдЧрд▓ рдРрдк рдЗрдВрдЬрди рдХреЗ рд▓рд┐рдП рдПрдХ рдирдпрд╛ рд▓реЗрдЦ рдкреНрд░рд╕реНрддреБрдд рдХрд░рддреЗ рд╣реИрдВ, рдЬреЛ рджрд┐рд╕рдВрдмрд░ 2010 рдореЗрдВ рд░рд┐рд▓реАрдЬ 1.4 рдореЗрдВ рджрд┐рдЦрд╛рдИ рджрд┐рдпрд╛ред рдЗрд╕ рдХреНрд╖рдг рд╕реЗ, рд╕рд░реНрд╡рд░ рд╕реЗ рдХреНрд▓рд╛рдЗрдВрдЯ рдФрд░ рдмреИрдХ рдкрд░ рдмрд┐рдирд╛
рдорддрджрд╛рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдП рд╕реАрдзреЗ рд╕рдВрджреЗрд╢ рднреЗрдЬрдирд╛ рд╕рдВрднрд╡ рд╣реЛ рдЧрдпрд╛ред
рдЗрд╕рд▓рд┐рдП, Google App Engine рдкрд░ рдЪреИрдЯ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдирд╛ рдХрд╛рдлреА рд╕рд░рд▓ рд╣реЛ рдЧрдпрд╛ред рдХрдЯреМрддреА рдХреЗ рддрд╣рдд рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдХрд╛ рд╡рд░реНрдгрди рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред
рдЖрдк
http://chat-channelapi.appspot.com/ рдкрд░
рдбреЗрдореЛ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВред
рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЛрдб рдпрд╣рд╛рдВ рдбрд╛рдЙрдирд▓реЛрдб рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛
рд╣реИ (рдореВрд▓ рд▓реЗрдЦ рд╕реЗ рдХреЛрдб
рдпрд╣рд╛рдВ рд╣реИ )ред
рд╣рдорд╛рд░реЗ рдЖрд╡реЗрджрди рдореЗрдВ, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдФрд░ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЗ рдмреАрдЪ рдПрдХ рдЪреИрдирд▓ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЪрд░рдгреЛрдВ рдХреЛ рд▓реЗрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЬреЛ рдЪрд┐рддреНрд░ рдореЗрдВ рдиреАрдЪреЗ рджрд┐рдЦрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИред

рдХрджрдо:
1) рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдЪреИрдирд▓ рдЖрдИрдбреА (рдЪреИрдирд▓ рдЖрдИрдбреА) рдФрд░ рдЯреЛрдХрди рдмрдирд╛рддрд╛ рд╣реИ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рднреЗрдЬрддрд╛ рд╣реИ
2) рдХреНрд▓рд╛рдЗрдВрдЯ рдПрдХ рд╕реЙрдХреЗрдЯ рдЦреЛрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдЯреЛрдХрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИ рдЬреЛ рдЪреИрдирд▓ рдХреЛ рд╕реБрдиреЗрдЧрд╛
3) рдХреНрд▓рд╛рдЗрдВрдЯ 2 рдЕрдкрдиреА рдЕрдиреВрдареА рдЪреИрдирд▓ рдЖрдИрдбреА рдХреЗ рд╕рд╛рде, рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдХреЛ рдПрдХ рдЪреИрдЯ рд╕рдВрджреЗрд╢ рднреЗрдЬрддрд╛ рд╣реИ
4) рдПрдкреНрд▓рд┐рдХреЗрд╢рди рд╕рднреА рдЧреНрд░рд╛рд╣рдХреЛрдВ рдХреЛ рд╕рдВрджреЗрд╢ рднреЗрдЬрддрд╛ рд╣реИ рдЬреЛ рд╕реЙрдХреЗрдЯ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЪреИрдирд▓ рд╕реБрдирддреЗ рд╣реИрдВред рдЗрд╕рдХреЗ рд▓рд┐рдП, рдкреНрд░рддреНрдпреЗрдХ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреА рдЪреИрдирд▓ рдЖрдИрдбреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
рд╕рднреА рдЪрд░рдгреЛрдВ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдиреЗ рд╕реЗ рдкрд╣рд▓реЗ, рдпрд╣ рдзреНрдпрд╛рди рджрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдП рдХрд┐ рд╣рдордиреЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреА рдЗрдХрд╛рдИ рдХреЛ рдпрдерд╛рд╕рдВрднрд╡ рд╕рд░рд▓ рдмрдирд╛ рджрд┐рдпрд╛ рд╣реИ рдЬреЛ рдХрд╛рд░реНрдпрдХреНрд░рдо рдореЗрдВ рднрд╛рдЧ рд▓реЗрдВрдЧреЗред рд╣рдордиреЗ рджреЛ рдмрдирд╛рдП - рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдореЙрдбрд▓ рдФрд░ рд╕рдВрджреЗрд╢ред
class OnlineUser (db . Model):
nick = db . StringProperty(default = "" )
channel_id = db . StringProperty(default = "" )
class Message (db . Model):
text = db . StringProperty(default = "" )
user = db . ReferenceProperty(User)
рдХреЛрдб
рдЬреАрдПрдИ рдЙрдкрдпреЛрдЧрд┐рддрд╛рдУрдВ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдореЗрдВ рд▓рд╛рдЧреВ рд╕рддреНрд░ рддрдВрддреНрд░ рдХрд╛ рднреА рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рд╕рддреНрд░ рдкрд░ рдЬреНрдпрд╛рджрд╛ рдзреНрдпрд╛рди рди рджреЗрдВред
рдЪрд░рдг 1рдЗрд╕ рдЪрд░рдг рдореЗрдВ, рд╣рдорд╛рд░рд╛ рдЪреИрдЯ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдЪреИрдирд▓ рдЖрдИрдбреА рдФрд░ рдЯреЛрдХрди рдмрдирд╛рддрд╛ рд╣реИ рдФрд░ рдЙрдиреНрд╣реЗрдВ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреЛ рднреЗрдЬрддрд╛ рд╣реИред рдЗрд╕ рдЪрд░рдг рдХреЗ рд▓рд┐рдП рдХреЛрдб рдХрд╛рдлреА рд╕рд░рд▓ рд╣реИред рдмрд╕ рдЪреИрдирд▓ рдПрдкреАрдЖрдИ рдЖрдпрд╛рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдпрд╛рдж рд░рдЦреЗрдВ:
from google.appengine.api import channel
рдЙрд╕рдХреЗ рдмрд╛рдж, рдПрдХ рд╣реИрдВрдбрд▓рд░ рдмрдирд╛рдПрдВ рдЬреЛ рдкреНрд░рддреНрдпреЗрдХ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрджреНрд╡рд┐рддреАрдп рдЖрдИрдбреА рдмрдирд╛рддрд╛ рд╣реИ (рд╣рдо uuid4 () рдлрд╝рдВрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ uuid рдореЙрдбреНрдпреВрд▓ рд╕реЗ рдХрд░реЗрдВрдЧреЗ)ред рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╣реИрдВрдбрд▓рд░ рдмрд╕ рдпрд╣реА рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЧреНрд░рд╛рд╣рдХ рдХреЛ рдбреЗрдЯрд╛ рдЯреЗрдореНрдкрд▓реЗрдЯ рдореЗрдВ рднреЗрдЬрддрд╛ рд╣реИ:
class ChatHandler (webapp . RequestHandler):
def get ( self ):
self . redirect( '/' )
def post ( self ):
# http://gaeutilities.appspot.com/
self . session = Session()
#
nick = self . request . get( 'nick' )
if not nick:
self . redirect( '/' )
# ,
user = OnlineUser . all() . filter( 'nick =' , nick) . get()
if user:
self . session[ 'error' ] = 'That nickname is taken'
self . redirect( '/' )
return
else :
self . session[ 'error' ] = ''
# id Channel API
channel_id = str (uuid . uuid4())
chat_token = channel . create_channel(channel_id)
#
user = OnlineUser(nick = nick,channel_id = channel_id)
user . put()
# 100
messages = Message . all() . order( 'date' ) . fetch( 1000 )
#
template_vars = { 'nick' :nick, 'messages' :messages, 'channel_id' :channel_id, 'chat_token' :chat_token}
temp = os . path . join(os . path . dirname(__file__), 'templates/chat.html' )
outstr = template . render(temp, template_vars)
self . response . out . write(outstr)
рдЗрд╕ рд▓реЗрдЦ рдХреЛ рдЕрдзрд┐рднрд╛рд░ рдирд╣реАрдВ рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВ рдпрд╣рд╛рдВ рдЯреЗрдореНрдкреНрд▓реЗрдЯ рдХреЛрдб рдкреНрд░рджрд╛рди рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реВрдВред рдЖрдк рдЗрд╕реЗ рдЧрд┐рддреБрдм рдкрд░ рджреЗрдЦ рд╕рдХрддреЗ рд╣реИрдВред
рдЪрд░рдг 2рдЕрдм рдХреНрд▓рд╛рдЗрдВрдЯ рдЯреЛрдХрди рдирд┐рдХрд╛рд▓рдиреЗ рдФрд░ рд╕реЙрдХреЗрдЯ рдЦреЛрд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдЬрд┐рдореНрдореЗрджрд╛рд░ рд╣реИред рд╣рдо рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЛрдб рдХреЛ рдХрдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП jQuery рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рдиреАрдЪреЗ рд╣рдорд╛рд░рд╛ рдХреЛрдб рд╣реИ:
var chat_token = $( '#channel_api_params' ).attr( 'chat_token' );
var channel = new goog.appengine.Channel(chat_token);
var socket = channel.open();
socket.onopen = function (){
};
socket.onmessage = function (m){
var data = $.parseJSON(m.data);
$( '#center' ).append(data[ 'html' ]);
$( '#center' ).animate({scrollTop : $( "#center" ).attr( "scrollHeight" )}, 500 );
};
socket.onerror = function (err){
alert( "Error => " + err.description);
};
socket.onclose = function (){
alert( "channel closed" );
};
рдЪрд░рдг 3рдЗрд╕ рдЪрд░рдг рдкрд░, рдХреНрд▓рд╛рдЗрдВрдЯ 2 рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рд╣рдорд╛рд░реА рдЪреИрдЯ рдкрд░ рдПрдХ рд╕рдВрджреЗрд╢ рднреЗрдЬрддрд╛ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдПрдХ рд╕рдВрджреЗрд╢ рднреЗрдЬрдиреЗ рдХреЗ рд▓рд┐рдП рдмрд╕ рдПрдХ рдЯреЗрдХреНрд╕реНрдЯ рдмреЙрдХреНрд╕ рдФрд░ рдПрдХ рдмрдЯрди рдмрдирд╛рдПрдВред рд╕рдВрджреЗрд╢ рдХреЛ рдПрдХ рд╕рд░рд▓ рд╢реНрд░реЛрддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЛрдб рдореЗрдВ рднреЗрдЬрд╛ рдЬрд╛рдПрдЧрд╛, рдЬрд┐рд╕реЗ рд╣рдо jQuery рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд▓рд╛рдЧреВ рдХрд░рддреЗ рд╣реИрдВред рдЖрдк рдЗрд╕рдХреЗ рдмрдЬрд╛рдп рдпрд╛ рдХреЗрд╡рд▓ XMLHttpRequest рдСрдмреНрдЬреЗрдХреНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд┐рд╕реА рднреА javsctipt рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдмрд╕ рдзреНрдпрд╛рди рд░рдЦреЗрдВ рдХрд┐ рдЖрдкрдХреЛ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдореЗрдВ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреА рд╕рд╣реА рдкрд╣рдЪрд╛рди рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рдЕрджреНрд╡рд┐рддреАрдп рдХреНрд▓рд╛рдЗрдВрдЯ рдЪреИрдирд▓ рдЖрдИрдбреА рднреЗрдЬрдирд╛ рд╣реЛрдЧрд╛ред
$( '#send' ).click( function (){
var text = $( '#text' ).val();
var nick = $( '#nick' ).attr( 'value' );
var channel_id = $( '#channel_api_params' ).attr( 'channel_id' );
$.ajax({
url : '/newMessage/' ,
type : 'POST' ,
data : {
text : text,
nick : nick,
channel_id : channel_id,
},
success : function (data){
},
complete : function (){
}
});
});
рдЪрд░рдг 4рдЧреНрд░рд╛рд╣рдХреЛрдВ рд╕реЗ рд╕рдВрджреЗрд╢ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдПрдХ рдирдпрд╛ рд╣реИрдВрдбрд▓рд░ рд▓рд╛рдЧреВ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЬреЛ рд╕рднреА рдЧреНрд░рд╛рд╣рдХреЛрдВ рдХреЛ рдПрдХ рд╕рдВрджреЗрд╢ рднреА рднреЗрдЬреЗрдЧрд╛ред
class NewMessageHandler (webapp . RequestHandler):
def post ( self ):
#
text = self . request . get( 'text' )
channel_id = self . request . get( 'channel_id' )
q = db . GqlQuery( "SELECT * FROM OnlineUser WHERE channel_id = :1" , channel_id)
nick = q . fetch( 1 )[ 0 ] . nick
date = datetime . datetime . now()
#
message = Message(user = nick,text = strip_tags(text), date = date, date_string = date . strftime( "%H:%M:%S" ))
message . put()
#
messages = [message]
template_vars = { 'messages' :messages}
temp = os . path . join(os . path . dirname(__file__), 'templates/messages.html' )
outstr = template . render(temp, template_vars)
channel_msg = json . dumps({ 'success' : True , "html" :outstr})
#
users = OnlineUser . all() . fetch( 100 )
for user in users:
channel . send_message(user . channel_id, channel_msg)
рд╡реИрдХрд▓реНрдкрд┐рдХ рдХрджрдордЗрд╕ рд╕реНрддрд░ рдкрд░, рдореВрд▓ рд▓реЗрдЦ рд╕рдорд╛рдкреНрдд рд╣реЛ рдЬрд╛рддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдореИрдВ рдЕрдЧрд▓реЗ рдХрд╛рд░реНрдп рд╕реЗ рд╕рдВрдмрдВрдзрд┐рдд рдХреЛрдб рдореЗрдВ рдХреБрдЫ рдмрджрд▓рд╛рд╡ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛ред рдореВрд▓ рд▓реЗрдЦ рдореЗрдВ, рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдирд╛рдо рдЪреИрдЯ рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж рдмреНрд▓реЙрдХ рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВ рдФрд░ рдЖрдк рдЗрд╕ рдЙрдкрдирд╛рдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд▓реЙрдЧ рдЗрди рдирд╣реАрдВ рдХрд░ рд╕рдХрддреЗред рд╣рдо рдЗрд╕ рдкреНрд░рддрд┐рдмрдВрдз рдХреЛ рд╣рдЯрд╛рддреЗ рд╣реИрдВред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдХреБрдВрдЬреА рд╕рдорд╛рдкреНрдд рд╣реЛрдиреЗ рдХреЗ рдмрд╛рдж рдбреЗрдЯрд╛рдмреЗрд╕ рд╕реЗ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдбреЗрдЯрд╛ рд╣рдЯрд╛рдПрдВред рдХреБрдВрдЬреА рддрдм рддрдХ рд╕рдорд╛рдкреНрдд рд╣реЛ рдЬрд╛рддреА рд╣реИ рдЬрдм рддрдХ рдХрд┐ рджреЛ рдШрдВрдЯреЗ рдмреАрдд рдЪреБрдХреЗ рд╣реЛрддреЗ рд╣реИрдВ, рдпрд╛ рдЬрдм рддрдХ рдЧреНрд░рд╛рд╣рдХ рд╕реЙрдХреЗрдЯ рдкрд░ рдмрдВрдж () рдлрд╝рдВрдХреНрд╢рди рдХреЛ рдХреЙрд▓ рдирд╣реАрдВ рдХрд░рддрд╛ред рддрдм / _ah / рдЪреИрдирд▓ / рдбрд┐рд╕реНрдХрдиреЗрдХреНрдЯ / рдореЗрдВ рдкрдВрдЬреАрдХреГрдд рд╣реИрдВрдбрд▓рд░ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рд╣рдо рдРрд╕реЗ рд╣реИрдВрдбрд▓рд░ рд▓рд┐рдЦреЗрдВрдЧреЗред
class ChannelDisconnectHandler (webapp . RequestHandler):
def post ( self ):
channel_id = self . request . get( 'from' )
q = OnlineUser . all() . filter( 'channel_id =' , channel_id)
users = q . fetch( 1000 )
db . delete(users)
рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЛрдб рдореЗрдВ, рдЙрд╕ рдШрдЯрдирд╛ рдХрд╛ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдЬреЛрдбрд╝реЗрдВ рдЬреЛ рддрдм рд╣реЛрддрд╛ рд╣реИ рдЬрдм рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдЗрд╕ рдкреГрд╖реНрда рдХреЛ рдЫреЛрдбрд╝рддрд╛ рд╣реИ:
$( window ).unload( function (){
socket.close();
});
рдпрд╣ рдирд┐рдореНрди рд╕реНрдерд┐рддрд┐ рдХреЛ рд╕рдВрднрд╛рд▓рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдиреА рд╣реБрдИ рд╣реИред рдпрджрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдиреЗ рдЪреИрдЯ рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд┐рдпрд╛, рд▓реЗрдХрд┐рди рдЬрд▓реНрджреА рд╕реЗ рдЦрд┐рдбрд╝рдХреА рдмрдВрдж рдХрд░ рджреА, рддреЛ рдЪреИрдирд▓ рдирд╣реАрдВ рдЦреБрд▓рд╛ред рдпрд╣ рдЙрд╕ рд╕реНрдерд┐рддрд┐ рдХреА рдУрд░ рдЬрд╛рддрд╛ рд╣реИ рдЬрдм рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рд░рд┐рдХреЙрд░реНрдб рдбреЗрдЯрд╛рдмреЗрд╕ рдореЗрдВ рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рдЗрд╕ рддрдереНрдп рдХреЗ рдХрд╛рд░рдг рд╣рдЯрд╛рдпрд╛ рдирд╣реАрдВ рдЬрд╛рддрд╛ рд╣реИ рдХрд┐ рдЪреИрдирд▓ рдмрдВрдж рдирд╣реАрдВ рд╣реЛ рд░рд╣рд╛ рд╣реИред рд╣рдорд╛рд░рд╛ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдбреЗрдЯрд╛ рдореЙрдбрд▓ рдмрджрд▓реЗрдВ:
class OnlineUser (db . Model):
nick = db . StringProperty(default = "" )
channel_id = db . StringProperty(default = "" )
creation_date = db . DateTimeProperty(auto_now_add = True )
opened_socket = db . BooleanProperty(default = False )
рдЕрдм рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рд░рд┐рдХреЙрд░реНрдб (рдирд┐рд░реНрдорд╛рдг_рдбреЗрдЯ) рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рдордп рд╣реИ рдФрд░ рдЪреИрдирд▓ рдХреЗ рдЦреБрд▓рдиреЗ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдХреНрд▓рд╛рдЗрдВрдЯ рд╕реЗ рдкреБрд╖реНрдЯрд┐ (рдУрдкрди_рд╕реЛрдХреЗрдЯ) рдЖ рдЧрдИ рд╣реИред рдЬрдм рдЪреИрдирд▓ рдХреА рдУрд░ рд╕реЗ рдЪреИрдирд▓.рдУрдкрди () рдХреЙрд▓ рдХрд░рдХреЗ рдХреНрд▓рд╛рдЗрдВрдЯ рдХреА рддрд░рдл рд╕реЗ рдПрдХ рдЪреИрдирд▓ рдЦреЛрд▓рд╛ рдЬрд╛рддрд╛ рд╣реИ, рддреЛ / _ah / рдЪреИрдирд▓ / рдХрдиреЗрдХреНрдЯ / рд╕реЗ рдкрдВрдЬреАрдХреГрдд рд╣реИрдВрдбрд▓рд░ рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣ рд╣реИрдВрдбрд▓рд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛ рдЪреИрдирд▓ рдЦреЛрд▓рдиреЗ рдХреА рдкреБрд╖реНрдЯрд┐ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЙрдЬрд╛рдЧрд░ рдХрд░реЗрдЧрд╛:
class ChannelConnectHandler (webapp . RequestHandler):
def post ( self ):
channel_id = self . request . get( 'from' )
q = OnlineUser . all() . filter( 'channel_id =' , channel_id)
user = q . fetch( 1 )[ 0 ]
user . opened_socket = True
user . put()
рдпрд╣ рдХреЛрдб рдкрд╣рдЪрд╛рди рдХреЗ рд▓рд┐рдП рдЪреИрдирд▓ рдЖрдИрдбреА рдХреЛ рд╕рд░реНрд╡рд░ рдкрд░ рднреЗрдЬрддрд╛ рд╣реИред рд╣реИрдВрдбрд▓рд░ рдиреАрдЪреЗ рдкреНрд░рд╕реНрддреБрдд рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ:
class RegisterOpenSocketHandler (webapp . RequestHandler):
def post ( self ):
channel_id = self . request . get( 'channel_id' )
q = OnlineUser . all() . filter( 'channel_id =' , channel_id)
user = q . fetch( 1 )[ 0 ]
user . opened_socket = True
user . put()
рдЕрдВрддрд┐рдо рдЪрд░рдг рдХреНрд░реЛрди рд╣реИрдВрдбрд▓рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╣реЛрдЧрд╛, рдЬреЛ OnlineUser рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдореЙрдбрд▓ рд╕реЗ рд╕рднреА рдкреНрд░рд╡рд┐рд╖реНрдЯрд┐рдпреЛрдВ рдХрд╛ рдЪрдпрди рдХрд░реЗрдЧрд╛, рдЬрд┐рд╕рдореЗрдВ рдЪреИрдирд▓ рдХреЗ рдЦреБрд▓рдиреЗ рдХреА рдкреБрд╖реНрдЯрд┐ рд╣реЛрдЧреА рдФрд░ рд╡рд░реНрддрдорд╛рди рд╕реЗ рдирд┐рд░реНрдорд╛рдг рдХрд╛ рд╕рдордп 120 рд╕реЗрдХрдВрдб рд╕реЗ рдЕрдзрд┐рдХ рд╣реЛрдЧрд╛:
class ClearDBHandler (webapp . RequestHandler):
def get ( self ):
q = OnlineUser . all() . filter( 'opened_socket =' , False )
users = q . fetch( 1000 )
for user in users:
if ((datetime . datetime . now() - user . creation_date) . seconds > 120 ):
db . delete(user)
рдЕрдВрдд рдореЗрдВрд╣рдо рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдЪреИрдЯ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмрдирд╛рдиреЗ рдореЗрдВ рдХрд╛рдордпрд╛рдм рд░рд╣реЗред рдореВрд▓ рд▓реЗрдЦ рдХреЗ рдЪрд╛рд░ рдЪрд░рдг рдЪреИрдирд▓ рдПрдкреАрдЖрдИ рдХреЛ рджрд┐рдЦрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реИрдВ, рдХреЛрдб рдХреЛ рдЬреЛрдбрд╝рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ рддрд╛рдХрд┐ рдЖрд╡реЗрджрди рдХреЛ рджреЗрдЦрдиреЗ рдХреЗ рд▓рд┐рдП, рдореЗрд░реА рд░рд╛рдп рдореЗрдВ, рдЕрдзрд┐рдХ рдкреВрд░реНрдг рд╣реЛ рд╕рдХреЗред
PS рдЕрдиреБрдкреНрд░рдпреЛрдЧ рдХреЗ рд╡рд╛рд╕реНрддрд╡рд┐рдХ рдХрд╛рд░реНрдп рд╕реЗ рдкрддрд╛ рдЪрд▓рд╛ рдХрд┐ рд╕рдВрджреЗрд╢реЛрдВ рдХреЛ рдлрд╝рд┐рд▓реНрдЯрд░ рдХрд░рдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИ, рдЙрдирдореЗрдВ рд╕реЗ html рдЯреИрдЧ рдХреЛ рдЫреЛрдбрд╝рдХрд░ред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, django рдврд╛рдВрдЪреЗ рд╕реЗ strip_tags рдлрд╝рдВрдХреНрд╢рди рдЖрдпрд╛рдд рдХрд░реЗрдВ:
from django.utils.html import strip_tags
рдирдП рд╕рдВрджреЗрд╢ рд╣реИрдВрдбрд▓рд░ (NewMessageHandler) рдореЗрдВ, рд╣рдо рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреЗ рд╕рд╛рде рдПрдХ рдирдпрд╛ рд╕рдВрджреЗрд╢ рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдХреЛрдб рдХреЛ рдкреНрд░рддрд┐рд╕реНрдерд╛рдкрд┐рдд рдХрд░рддреЗ рд╣реИрдВ:
message = Message(user = nick,text = strip_tags(text), date = date, date_string = date . strftime( "%H:%M:%S" ))