نگاهی مختصر به ساختار چت روم کلوب از دید Client - بخش اول
ساختار کلی :
در واقع اکثر و میشه گفت تمام سیستم های گفتگوی متنی آنلاین گروهی یک ساختار واحدی رو دنبال میکنند که شامل :
- محیطی که کاربر متن خودش رو در اون وارد میکنه (تحت کلاینت)
- تکه کدی که یک سری پردازش روی این متن انجام میشه (تحت کلاینت)
- فایل و یا کدی که این پردازش حاصل شده رو به سرور ارسال میکنه (تحت کلاینت)
- سرور که اطلاعات رو گرفته آنلایز و پاسخ میده (تحت سرور)
- کدی که اطلاعات دریافتی از سرور رو میگیره و برای چاپ آماده میکنه (تحت کلاینت)
- محیطی که کاربر متن های گفتگو شده رو میبینه (تحت کلاینت)
ما با بخش سرور کاری نداریم چون در حالت عادی اصلا دسترسی نداریم بهش !
ولی 5 بخش در سیستم کاربر یا همون سیستم ماها پردازش و اجرا میشه ، پس اگه بتونیم سیستم و ساختار اون رو بشناسیم می تونیم یه کارایی باهاش بکنیم !!!!
خوب من این بخش هارو که گفتم رو یکی میرم جلو ببینیم چی میشه :|
• محیطی که کاربر متن خودش رو در اون وارد میکنه
این بخش در محیط گفتگوی کلوب یک جعبه متن هست (textarea) که متن رو دریافت میکنه
کد HTML مربوط به کادر متن :
<textarea class="chatPageV2_containerChatForm_textbox" id="chat_body" onkeyup="base_check_composing()" onkeypress="base_checkEnterKey(event)" style="direction: ltr; height: 48px; overflow: hidden;"></textarea>
اگه دقت کرده باشین این تکه کد یک پارمتر داره به نام onkeypress که وقتی دکمه ای فشار داده بشه تابعی با نام base_checkEnterKey شروع به فعالیت میکنه که این تابع درون فایل جاوااسکریپتی هست به نام base_lib.js که در آدرس زیر میتونید کد های مربوط به اون رو ببینید :
http://static.cloob.com//public/scripts/jabber_new/base_lib.js
از طریق Inspect Element نیز می تونید به کد این صفحه دسترسی داشته باشید و حتی به صورت آنلاین اون رو ویرایش کنید و دوباره اجراش کنید. (این نکته مهمیه ! چون با همین روش خیلی کار ها میشه کرد)
اما کد اون تابع که گفتیم وقتی onkeypress میشه اجرا میشه به این صورته :
function base_checkEnterKey(e){
var key;
var shiftKey=false;
if(window.event){
key = window.event.keyCode; //IE
shiftKey=window.event.shiftKey;
}else{
key = e.which; //firefox
shiftKey=e.shiftKey;
}
if(!shiftKey && key == 13){
base_send_message();
}
}
در کد بالا چند شرط ساده رو میشه دید ! ولی چیزی که به درد ما میخوره شرط آخر هست .
شرط به این ترتیبه که میگه وقتی دکمه 13 کیبورد (کد اسکی) فشار داده شد تابع جدیدی به نام base_send_message رو اجرا کن ، که خوشبختانه این تابع تویه همین صفحه base_lib.js هستش.
خوب تا اینجا یه مروری میکنیم > وقتی شما دارین تویه کادر متن تایپ میکنید تابع اولی (onkeypress) بررسی میشه و تا وقتی دکمه اینتر (کد 13) زده نشه هیچ اتفاقی نمی افته تا اینکه شما اینتر رو بزنید و تابع دوم اجرا میشه که این تابع هست : base_send_message
کد این تابع به شکل زیر هست
function base_send_message(){ var msg_out = c_$('chat_body').value; msg_out = strGetTrim(msg_out); msg_out = base_limitText(msg_out); if(msg_out=='buzz'){ if(!other_alarmreq[base_active_Receiver_name] && !c_$('chat_body').disabled && base_active_Receiver_type=='chat'){ other_setBuzz(); } else{ c_$('chat_body').value=''; return false; } } if(base_active_Receiver_name!='' && msg_out!='' && (base_active_Receiver_type=='chat' || msg_out!='buzz')){ c_$('chat_body').value = ''; var content = new Array(); // msg_out = msg_out.replace("\n",_msg_break_line_split) ; msg_out = msg_out.split("\t").join(_msg_break_tab_split); msg_out = msg_out.split("\n").join(_msg_break_line_split); content['body']= persianUrl.encode(msg_out); var rec_type = ''; var rec_Nickname = '/'+jabber_resource; var chatType = 'chat'; if(base_active_Receiver_type!='chat'){ var rec_type = base_active_Receiver_type+'.'; rec_Nickname = ''; chatType = 'groupchat'; } else{ content['offline']= true; } var base_rec = base_active_Receiver_name+'@'+rec_type+jabber_serverName+rec_Nickname ; var sender = jabber_username+'@'+jabber_serverName+'/'+jabber_resource ; var msgid = ''; var objName = base_active_Receiver_type+__base_split_Type_Name+base_active_Receiver_name; if(base_active_Receiver_type=='chat'){ msgid = chatType + "_" + base_getrandid(); base_fill_chatbox(sender,base_rec,msg_out,jabber_firstname,jabber_fullname,jabber_userphotoPath,'',msgid); } else{ if(!base_clubroom_sendMessage_timer[objName]){ base_clubroom_sendMessage_timer[objName]=setTimeout(function(){ if(base_chatData_Arr_Write[objName]){ base_chatData_Arr_Write[objName] = null ; c_$('chat_body').disabled = 1; base_clubroom_sendMessage_timer[objName]= null; } },1000); } } this_key = base_chatData_Arr_Msg_Key[objName] ; base_chatData_composing[objName] = false; jabber_SendMessage(base_rec, chatType, msgid, content, '','',this_key); } c_$('chat_body').value = ''; setTimeout(function () { c_$('chat_body').value = ''; c_$('chat_body').focus(); }, 20); //c_$('chat_body').focus(); return false; }
چند نکته مهم و جالب اینجا هست که فقط به بررسی اونها می پردازم و بقیه کد هایی که اینجا نوشته عملا به درد ما نمیخوره
یکی از این تکه کد ها c_$('chat_body').value این هست ! این تیکه کد در واقع مقداری که شما تویه اون کادر متن تو صفحه نوشتین رو نشون میده ، و چند جا ازش استفاده شده مثلا :
در آخر اون رو خالی کرده (یعنی وقتی متن شما ارسال میشه میبینید که متن تویه کادر پاک میشه) :
c_$('chat_body').value = '';
در بخش های بالاتر هم کد مربوط به بررسی و ارسال این متن نوشته شده (که بعدا در مورد شرح کامل این بخش تو آنالیز های بعدی خواهم پرداخت) ولی مهمترین بخش این کدها دستور زیر هست که متن نوشته شده رو به یک تابع دیگه به نام jabber_SendMessage ارسال میکنه
jabber_SendMessage(base_rec, chatType, msgid, content, '','',this_key);
شناسه روم@clubroom.jabber.cloob.com
msgid : پارامتر بعدی یک رشته و عدد ساخته شده توسط خود کلوب هست که به متن شما یک شناسه میده ! که اگه این شناسه رو تکراری هم بزنید مشکلی بوجود نمیاد (این یعنی ضعف امنیتی)
content : مهمترین پارامتر میشه گفت همیه ، که یک آرایه هست (یعنی یه مقدار نیست بلکه چندین مقدار توش قرار داره) که متن اصلی که میخوایم ارسال کنیم به سرور تا به همه نشون بده از درون این آرایه به تابع بعدی (jabber_SendMessage) ارسال میشه
'' ,'' : این پارمتر ها خالی ارسال میشن و تویه چت گروهی استفاده ای نداره ، ولی تویه چت خصوصی دیلوری یا همون تیک سبز کچولو که کنار متن میاد با این ها ارسال میشن
this_key : پارامتر آخر هم یکی از مهم ترین پارمتر های ارسالی هست ، این پارامتر هم کلید روم هست، منظور از کلید در واقع میشه گفت پسورد روم ، که شما در حال عادی نمی بینید اینجوری در نظر بگیرید که پارمتر اولی یوزر و پارمتر آخر پسورد روم هست که به کمک اونا کلوب میفهمه متن باید کدوم روم بره نمایش داده بشه ، برای مثلا یک کلید روم این هست : e94786029126289353dba4aa826f0d59
خوب همه این موارد که پر شدن (که اکثر پارامتر ها توسط خود کلوب پر میشن که قابل ویرایش توسط ما هم هستن ، و یکی که متن ما هست content) آماده ارسال به تابع jabber_SendMessage میشه
این تابع (jabber_SendMessage) کدهاش مثلا از دید ما پنهان شده اند و در یک فایل جاوااسکریپت دیگه به نام g.chatroom.new.v4.js قرار داره که این فایل توسط یک سری ساختار کدگذاری شده که نشه فهمید درون این فایل چه اتفاقی می افته ، و من به حق برنامه نویس کلوب احترام میزارم و کل فایل رو دیکود شده اینجا نمی نویسم فقط یه تیکه هاییش رو مینویسم (که اگه خودتون یکم زرنگ باشین دی کودرش رو پیدا میکنید)
آدرس فایل :
http://static.cloob.com//public/scripts/jabber_new/g.chatroom.new.v4.js
خوب حالا این پارمتر ها که از تابع قبلی به داخل jabber_SendMessage که کد شده هست ارسال کردیم چه اتفاقی می افته ؟
کد مربوط به این تابع که من دیکود کردم به شکل زیر است
function jabber_SendMessage(to,type,id,content,payload,composing,cloobkey){ if(to){ if(!id){ id=type+"_"+base_getrandid() } xml="<message to='"+to+"' type='"+type+"' id='"+id+"'>\n"; if(content['subject']){ xml+="<subject>"+content['subject']+"</subject>\n" } if(content['thread']){ xml+="<thread>"+content['thread']+"</thread>\n" } if(composing){ xml+="<composing>"+composing+"</composing>\n" } else if(content['body']){ xml+="<body> "+base_codeSpChars(content['body'])+"</body>\n" } if(content['offline']){ xml+="<x xmlns='jabber:x:event'><delivered/></x>\n" } xml+="<cloobkey>"+cloobkey+"</cloobkey>\n"; xml+="<firstname>"+jabber_firstname+"</firstname>\n"; xml+="<fullname>"+jabber_fullname+"</fullname>\n"; xml+="<photopath>"+jabber_userphotoPath+"</photopath>\n"; xml+=payload; xml+="</message>\n"; Jabber_AddToLog('send msg : '+xml); jabber_sendPacket(xml) } }
اگه یکم دقیق نگاه کنید کاملا مشخص هست چی به چیه ! اون پارمترها رو که پاس کردیم اینور رو میگره و یک رشته XML تولید میکنه !
خوب الان به یک نکته ای میرسیم ! متن و مشخصات ما قبل از ارسال به سرور و نمایش تویه روم به XML تبدیل میشن ! و این خیلی خوبه از نظر کد نویسی و من به برنامه نویسی که اینو نوشته تبریک میگم که XML رو برای ساختار جابجای متن ها انتخاب کرده ، (اگر بخواید بدونید XML چیه ! یه توضیح کوتاه تو همین وبلاگ نوشتم)
خوب برگردیم سر موضوع اصلی بعد از ساخته شدن یه رشته XML ، این رشته به داخل یک تابع دیگه ارسال میشه به نام jabber_sendPacket !!
برای مثال یک رشته XML ایجاد شده توسط کلوب به شکل زیر میشه »
<message to='room_26760@clubroom.jabber.cloob.com' type='groupchat' id='groupchat_6033876b3937314a'>
<body> متن تست</body>
<cloobkey>e9a62906886a5adca7e21287d0fbac11</cloobkey>
<firstname>اربابــــــ</firstname>
<fullname>اربابــــــ</fullname>
<photopath>/public/user_data/user_photo/715/2545741.jpg</photopath>
</message>
http://www.cloob.com/public/public/images/flashjsproxy/JsSocketProxy_chat_443?84821248
System.security.loadPolicyFile("xmlsocket://chat.cloob.com:443");
var = new JSP();
// Action script... // [Initial MovieClip Action of sprite 1] #initclip 1 class JSP { var _eventHandler, _socket; function JSP() { flash.external.ExternalInterface.addCallback("connect", this, connect); flash.external.ExternalInterface.addCallback("sendMessage", this, sendMessage); flash.external.ExternalInterface.addCallback("disconnect", this, disconnect); flash.external.ExternalInterface.addCallback("setEventHandlers", this, setEventHandlers); _eventHandler = new Object(); _socket = new XMLSocket(); _root.jsP = this; _socket.onConnect = function (success) { _root.jsP.raiseEvent(_root.jsP._eventHandler.on_connect, [success]); }; _socket.onClose = function () { _root.jsP.raiseEvent(_root.jsP._eventHandler.on_disconnect, []); }; _socket.onData = function (msg) { _root.jsP.raiseEvent(_root.jsP._eventHandler.on_message, [msg]); }; } // End of the function function connect(host, port) { var _loc3 = _socket.connect(host, port); if (!_loc3) { var _loc2 = new Object(); _loc2.type = "connectError"; this.raiseEvent(_eventHandler.on_error, [_loc2]); } // end if } // End of the function function sendMessage(msg) { _socket.send(msg); } // End of the function function disconnect() { _socket.close(); } // End of the function function setEventHandlers(eventHandlers) { for (var _loc2 = 0; _loc2 < eventHandlers.length; ++_loc2) { _eventHandler["on_" + eventHandlers[_loc2].name] = eventHandlers[_loc2].handler; } // end of for } // End of the function function raiseEvent(handlerName, args) { flash.external.ExternalInterface.call(handlerName, args); } // End of the function } // End of Class #endinitclip
خوب ! فعلا تا اینجا بسه ، بخش بعدی آنالیز مربوط به این هست که متنی که ارسال شده چطوری وارد صفحه روم ما میشه !
چیزهایی که الان گفتم میشه خیلی کارا کرد ، ولی این مطالب برای استفاده های سودمند تهیه شده (مثل تغییر فونت ، تغییر شکل ظاهری صفحه ، آشنایی و پیدا کردن راه حل های جدید برای مبارزه با برخی مثائل بوجود اومده در روم ها و ...) و مسئولیت استفاده آن به هر نحوی به عهده شخص می باشد.
• یه پلاگین هم به زودی با استفاده از همین ها ارائه خواهم داد که می تونید به کمک اون هر کسی رو که دوست نداشتید متنش رو تویه روم ببینید تمام متن هاش رو بلاک کنید و تویه روم برای شما دیده نشه.
با تشکر از توجه شما اگه غلط املایی یا هر چی بوده ببخشید دیگه :|
- ۹۲/۰۲/۲۱