WebSocket 100 рдкрдВрдХреНрддрд┐рдпреЛрдВ рдореЗрдВ symfony2 рдкрд░ рдЪреИрдЯ рдХрд░рддрд╛ рд╣реИ

рд╣рд╛рдп рд╣рдорд░!
рдореИрдВрдиреЗ рд╣рд╛рд▓ рд╣реА рдореЗрдВ рдЕрдкрдиреА рд╕реЗрд╡рд╛ http://internetsms.org/chat рдХреЗ рд▓рд┐рдП рд╡реЗрдм рд╕реЙрдХреЗрдЯ рдкрд░ рдПрдХ рдЪреИрдЯ рд╡рд┐рдХрд╕рд┐рдд рдХреА рд╣реИред
рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдХреЗ рджреМрд░рд╛рди, рдореБрдЭреЗ рдЗрд╕ рддрдереНрдп рдХрд╛ рд╕рд╛рдордирд╛ рдХрд░рдирд╛ рдкрдбрд╝рд╛ рдХрд┐ рдЗрдВрдЯрд░рдиреЗрдЯ рдкрд░ рдЕрдзрд┐рдХрд╛рдВрд╢ рдЪреИрдЯ рдмрд╛рд░-рдмрд╛рд░ рдЕрдЬрд╛рдХреНрд╕ рдЕрдиреБрд░реЛрдзреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВ рдЬреЛ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдЕрд╡рдзрд┐ рдХреЗ рд▓рд┐рдП рдирдП рд╕рдВрджреЗрд╢реЛрдВ рдХреА рдЬрд╛рдВрдЪ рдХрд░рддреЗ рд╣реИрдВред рдпрд╣ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдореЗрд░реЗ рд▓рд┐рдП рдЕрд╕реНрд╡реАрдХрд╛рд░реНрдп рдерд╛, рдХреНрдпреЛрдВрдХрд┐ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреА рдЖрдордж рдХреЗ рд╕рд╛рде, рд╕рд░реНрд╡рд░ рдкрд░ рд▓реЛрдб рддреЗрдЬреА рд╕реЗ рдмрдврд╝реЗрдЧрд╛ред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдЕрдзрд┐рдХ рджрд┐рд▓рдЪрд╕реНрдк рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рд╡рд┐рдХрд▓реНрдк рд╣реИрдВ:
рд▓рдВрдмрд╛ рдорддрджрд╛рди
рдХреНрд▓рд╛рдЗрдВрдЯ рд╕рд░реНрд╡рд░ рдХреЛ "рд▓рдВрдмрд╛" рдЕрдиреБрд░реЛрдз рднреЗрдЬрддрд╛ рд╣реИ, рдФрд░ рдпрджрд┐ рдкрд░рд┐рд╡рд░реНрддрди рд╣реЛрддреЗ рд╣реИрдВ, рддреЛ рд╕рд░реНрд╡рд░ рдПрдХ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рднреЗрдЬрддрд╛ рд╣реИред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рдЕрдиреБрд░реЛрдзреЛрдВ рдХреА рд╕рдВрдЦреНрдпрд╛ рдХрдо рд╣реЛ рдЬрд╛рддреА рд╣реИред рд╡реИрд╕реЗ, рдЬреАрдореЗрд▓ рдореЗрдВ рдЗрд╕ рддрдХрдиреАрдХ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
рд╡реЗрдм рд╕реЙрдХреЗрдЯ
Html5 рдореЗрдВ WebSocket рдХрдиреЗрдХреНрд╢рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рдХреНрд╖рдорддрд╛ рд╣реИред рдпрд╣рд╛рдБ рдЕрдиреБрд░реЛрдз-рдкреНрд░рддрд┐рд╕рд╛рдж рдкреНрд░рддрд┐рдорд╛рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИред рдХреНрд▓рд╛рдЗрдВрдЯ рдФрд░ рд╕рд░реНрд╡рд░ рдХреЗ рдмреАрдЪ рдПрдХ рдмрд╛рд░ рдПрдХ рд╕рдВрдЪрд╛рд░ рдЪреИрдирд▓ рд╕реНрдерд╛рдкрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд╕рд░реНрд╡рд░ рдПрдХ рдПрдХрд▓ рдбреЗрдореЙрди рдЪрд▓рд╛рддрд╛ рд╣реИ рдЬреЛ рдЖрдиреЗ рд╡рд╛рд▓реЗ рдХрдиреЗрдХреНрд╢рди рдХреЛ рд╕рдВрд╕рд╛рдзрд┐рдд рдХрд░рддрд╛ рд╣реИред рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╕рд░реНрд╡рд░ рдкрд░ рд╡реНрдпрд╛рд╡рд╣рд╛рд░рд┐рдХ рд░реВрдк рд╕реЗ рдХреЛрдИ рд▓реЛрдб рдирд╣реАрдВ рд╣реИ, рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдмрдбрд╝реА рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдСрдирд▓рд╛рдЗрди рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рд╕рд╛рде рднреАред

рд╕рд░реНрд╡рд░ рд╕рд╛рдЗрдб


рдЕрдм рдореИрдВ рд╡рд┐рд╕реНрддрд╛рд░ рд╕реЗ рдмрддрд╛рдКрдВрдЧрд╛ рдХрд┐ рдпрд╣ рдЪреИрдЯ рдХреИрд╕реЗ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИред рдореИрдВрдиреЗ рд╢рд╛рдлрд╝реНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ - рдПрдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдЬреЛ рдЖрдкрдХреЛ рд╕рд░реНрд╡рд░ рдкрд░ рд╕реЙрдХреЗрдЯ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдбреЗрдЯрд╛рдмреЗрд╕ рдореМрдЬреВрджрд╛ рдЪреИрдЯ рд░реВрдо (рдЪреИрдЯ) рдФрд░ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ (рдЪреИрдЯрдпреВрдЬрд░) рдХреЛ рд╕реНрдЯреЛрд░ рдХрд░рддрд╛ рд╣реИред
рдЪрд╛рдЯ рд╕рдВрд╕реНрдерд╛
<?php namespace ISMS\ChatBundle\Entity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table */ class Chat { /** * @ORM\Id * @ORM\Column(type="bigint") * @ORM\GeneratedValue(strategy="AUTO") * * @var int */ private $id; /** * @var bool * * @ORM\Column(type="boolean") */ protected $isCompleted = false; /** * @ORM\OneToMany(targetEntity="ChatUser", mappedBy="Chat") * @var ArrayCollection */ private $users; /** * Constructor */ public function __construct() { $this->users = new ArrayCollection(); } /** * Get id * * @return integer */ public function getId() { return $this->id; } /** * Add users * * @param ChatUser $user * @return Chat */ public function addUser(ChatUser $user) { $this->users[] = $user; return $this; } /** * Remove users * * @param ChatUser $user */ public function removeUser(ChatUser $user) { $this->users->removeElement($user); } /** * Get users * * @return ArrayCollection|ChatUser[] */ public function getUsers() { return $this->users; } /** * @param boolean $isCompleted */ public function setIsCompleted($isCompleted) { $this->isCompleted = $isCompleted; } /** * @return boolean */ public function getIsCompleted() { return $this->isCompleted; } } 


ChatUser рдЗрдХрд╛рдИ
 <?php namespace ISMS\ChatBundle\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity * @ORM\Table */ class ChatUser { /** * @ORM\Id * @ORM\Column(type="bigint") * @ORM\GeneratedValue(strategy="AUTO") * * @var int */ private $id; /** * @ORM\Column(type="integer", unique=true) * * @var int */ private $rid; /** * @ORM\ManyToOne(targetEntity="Chat", inversedBy="users") * @ORM\JoinColumn(name="chat_id", referencedColumnName="id") * @var Chat */ private $Chat; /** * Get id * * @return integer */ public function getId() { return $this->id; } /** * Set rid * * @param integer $rid * @return ChatUser */ public function setRid($rid) { $this->rid = $rid; return $this; } /** * Get rid * * @return string */ public function getRid() { return $this->rid; } /** * Set Chat * * @param Chat $chat * @return ChatUser */ public function setChat(Chat $chat = null) { $this->Chat = $chat; $chat->addUser($this); return $this; } /** * Get Chat * * @return Chat */ public function getChat() { return $this->Chat; } } 



рдПрдХ рдЕрд▓рдЧ рдкреНрд░рдмрдВрдзрдХ рдореЗрдВ рдмрдирд╛рдИ рдЧрдИ рд╕рдВрд╕реНрдерд╛рдУрдВ рдХреЗ рд╕рд╛рде рддреБрдЪреНрдЫ рд╕рдВрдЪрд╛рд▓рди
 parameters: isms_chat.manager.class: ISMS\ChatBundle\Manager\ChatManager services: isms_chat.manager: class: %isms_chat.manager.class% arguments: [ @doctrine.orm.entity_manager ] 


ChatManager
 <?php namespace ISMS\ChatBundle\Manager; use Doctrine\Common\Persistence\ObjectManager; use ISMS\ChatBundle\Entity\Chat; use ISMS\ChatBundle\Entity\ChatUser; class ChatManager { /** @var ObjectManager */ private $em; public function __construct(ObjectManager $em) { $this->em = $em; } public function removeUserFromChat(ChatUser $user, Chat $chat) { if ($chat->getIsCompleted()) { $chat->removeUser($user); $chat->setIsCompleted(false); } else { $this->em->remove($chat); } $this->em->remove($user); $this->em->flush(); } public function findOrCreateChatForUser($rid) { $chat_user = new ChatUser(); $chat_user->setRid($rid); $chat = $this->getUncompletedChat(); if ($chat) { $chat->setIsCompleted(true); } else { $chat = new Chat(); } $chat_user->setChat($chat); $this->em->persist($chat); $this->em->persist($chat_user); $this->em->flush(); return $chat; } public function getChatByUser($rid) { $chat_user = $this->getUserByRid($rid); return $chat_user ? $chat_user->getChat() : null; } public function getUserByRid($rid) { return $this->em->getRepository('ISMSChatBundle:ChatUser')->findOneBy(['rid' => $rid]); } public function getUncompletedChat() { return $this->em->getRepository('ISMSChatBundle:Chat')->findOneBy(['isCompleted' => false]); } public function truncateChats() { /** @var \Doctrine\DBAL\Connection $conn */ $conn = $this->em->getConnection(); $platform = $conn->getDatabasePlatform(); $conn->query('SET FOREIGN_KEY_CHECKS=0'); $conn->executeUpdate($platform->getTruncateTableSQL('chat_user')); $conn->executeUpdate($platform->getTruncateTableSQL('chat')); $conn->query('SET FOREIGN_KEY_CHECKS=1'); } } 


рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛рдУрдВ рдХреЗ рдмреАрдЪ рдЖрдиреЗ рд╡рд╛рд▓реЗ рдХрдиреЗрдХреНрд╢рди рдФрд░ рд╕рдВрджреЗрд╢ рдЕрдЧреНрд░реЗрд╖рдг рдХреА рд╕рднреА рдкреНрд░рдХреНрд░рд┐рдпрд╛ рдЪреИрдЯ рд╡рд░реНрдЧ рдореЗрдВ рд╣реЛрддреА рд╣реИред
рдЪреИрдЯ
 <?php namespace ISMS\ChatBundle\Chat; use ISMS\ChatBundle\Manager\ChatManager; use Ratchet\ConnectionInterface; use Ratchet\MessageComponentInterface; use Ratchet\WebSocket\Version\RFC6455\Connection; class Chat implements MessageComponentInterface { /** @var ConnectionInterface[] */ protected $clients = []; /** @var ChatManager */ protected $chm; public function __construct(ChatManager $chm) { $this->chm = $chm; $this->chm->truncateChats(); } /** * @param ConnectionInterface|Connection $conn * @return string */ private function getRid(ConnectionInterface $conn) { return $conn->resourceId; } /** * @param ConnectionInterface|Connection $conn */ function onOpen(ConnectionInterface $conn) { $this->clients[$this->getRid($conn)] = $conn; } function onClose(ConnectionInterface $conn) { $rid = array_search($conn, $this->clients); if ($user = $this->chm->getUserByRid($rid)) { $chat = $user->getChat(); $this->chm->removeUserFromChat($user, $chat); foreach ($chat->getUsers() as $user) { $this->clients[$user->getRid()]->close(); } } unset($this->clients[$rid]); } function onError(ConnectionInterface $conn, \Exception $e) { $conn->close(); } function onMessage(ConnectionInterface $from, $msg) { $msg = json_decode($msg, true); $rid = array_search($from, $this->clients); switch ($msg['type']) { case 'request': $chat = $this->chm->findOrCreateChatForUser($rid); if ($chat->getIsCompleted()) { $msg = json_encode(['type' => 'response']); foreach ($chat->getUsers() as $user) { $conn = $this->clients[$user->getRid()]; $conn->send($msg); } } break; case 'message': if ($chat = $this->chm->getChatByUser($rid)) { foreach ($chat->getUsers() as $user) { $conn = $this->clients[$user->getRid()]; $msg['from'] = $conn === $from ? 'me' : 'guest'; $conn->send(json_encode($msg)); } } break; } } } 



рд╕рд░реНрд╡рд░ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдбреЗрдореЙрди рдХрдорд╛рдВрдб рдмрдирд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдПрдХ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рд╡реИрд╕реЗ, рдпрд╣ рд╡рд░реНрдгрди рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдорд╛рдирдХ рдЙрдкрд╕реНрдЯрд╛рд░реНрдЯ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдбреЗрдорди рдХреЛ рдХреИрд╕реЗ рд╢реБрд░реВ рдХрд┐рдпрд╛ рдЬрд╛рдП ред рдЗрд╕рд╕реЗ рдЖрдк рдЪреИрдЯ рдкреНрд░рдХреНрд░рд┐рдпрд╛ рд╢реБрд░реВ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдФрд░ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдХрд┐ рдпрд╣ рдЧрд┐рд░ рди рдЬрд╛рдПред

DaemonCommand
 <?php namespace ISMS\ChatBundle\Command; use ISMS\ChatBundle\Chat\Chat; use Ratchet\Http\HttpServer; use Ratchet\Server\IoServer; use Ratchet\WebSocket\WsServer; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Wrep\Daemonizable\Command\EndlessCommand; class DaemonCommand extends EndlessCommand implements ContainerAwareInterface { /** @var ContainerInterface */ private $container; public function setContainer(ContainerInterface $container = null) { $this->container = $container; } protected function configure() { $this->setName('isms:chat:daemon'); } protected function execute(InputInterface $input, OutputInterface $output) { $chm = $this->container->get('isms_chat.manager'); $server = IoServer::factory( new HttpServer( new WsServer( new Chat($chm) ) ), 8080 ); $server->run(); } } 



рдЧреНрд░рд╛рд╣рдХ рднрд╛рдЧ


рдЪреИрдЯ рдЗрдВрдЬрди рдХреЛ рдПрдХ рд░рд╛рдЬреНрдп рдорд╢реАрди рдХреЗ рд░реВрдк рдореЗрдВ рдбрд┐рдЬрд╝рд╛рдЗрди рдХрд┐рдпрд╛ рдЧрдпрд╛ рд╣реИ, рдЬрд┐рд╕реЗ рд░рд╛рдЬреНрдпреЛрдВ рдФрд░ рд╕рдВрдХреНрд░рдордгреЛрдВ рдХреЗ рдПрдХ рд╕рдореВрд╣ рджреНрд╡рд╛рд░рд╛ рджрд░реНрд╢рд╛рдпрд╛ рдЧрдпрд╛ рд╣реИред рдЗрд╕рдХреЗ рд▓рд┐рдП, рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдлрд╝рд┐рдирд╛рдЗрдЯ рд╕реНрдЯреЗрдЯ рдорд╢реАрди рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЧрдпрд╛ рдерд╛ред рдХрд┐рд╕реА рднреА рд╕рдВрдХреНрд░рдордг рдХреА рд╕реНрдерд┐рддрд┐ рдореЗрдВ рдЖрдк рдлрд╝рдВрдХреНрд╢рди рд╣реИрдВрдбрд▓рд░ рд╕реЗрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдЖрдк рд╡реНрдпрд╛рдкрд╛рд░ рддрд░реНрдХ рдХреЛ рд╣реИрдВрдбрд▓рд░ рдкрд░ рд▓рдЯрдХрд╛ рд╕рдХрддреЗ рд╣реИрдВред

рд░рд╛рдЬреНрдп рдФрд░ рдПрдХ рдкрд░рд┐рдорд┐рдд рд░рд╛рдЬреНрдп рдорд╢реАрди рдХреЗ рд╕рдВрдХреНрд░рдордг


рдПрдЪрдЯреАрдПрдордПрд▓
  <div id="chat_wrapper"> <div id="template_idle" class="template"> <div class="row text-center"> <div> <h3>    !</h3> <p>  ,   " "  ,     </p> <p>   ,   " "    " ".</p> <p>   . !</p> </div> <a class="btn btn-large btn-primary begin-chat"> </a> </div> </div> <div id="template_wait" class="template"> <div class="row text-center"> <h3><i class="fa fa-spin fa-refresh"></i> </h3> <span class="state"></span> </div> </div> <div id="template_chat" class="template"> <div class="row"> <div class="message_box" id="message_box"></div> </div> <div class="row well"> <form id="send-msg-form"> <div class="input-append"> <textarea id="message" rows="2" placeholder="  (  Ctrl + Enter)" required="required" class="span6"></textarea> <button id="send-btn" type="submit" class="btn btn-primary btn-large has-spinner"><span class="spinner"><i class="fa fa-spin fa-refresh"></i></span></button> </div> <div class="text-center"> <div class="show-chat"><a href="#" class="btn btn-danger close-chat"> </a></div> <div class="show-closed"> . <a href="#" class="btn btn-primary begin-chat"> </a></div> </div> </form> </div> </div> </div> <script type="text/javascript" src="{{ asset('bundles/ismschat/js/chat-widget.js') }}"></script> <script type="text/javascript"> $(document).ready(function(){ $('#chat_wrapper').chatWidget(); }); </script> 



рдЪреИрдЯ-widget.js
 (function($) { $.fn.extend({chatWidget: function(options){ var o = jQuery.extend({ wsUri: 'ws://'+location.host+':8080', tmplClass: '.template', tmplIdle: '#template_idle', tmplWait: '#template_wait', tmplChat: '#template_chat', btnBeginChat: '.begin-chat', labelWaitState: '.state', messageBox: '#message_box', formSend: '#send-msg-form', textMessage: '#message', btnCloseChat: '.close-chat' },options); var websocket, fsm; var windowNotifier = function(){ var window_active = true, new_message = false; $(window).blur(function(){ window_active = false; }); $(window).focus(function(){ window_active = true; new_message = false; }); var original = document.title; window.setInterval(function() { if (new_message && window_active == false) { document.title = '******'; setTimeout(function(){ document.title = original; }, 750); } }, 1500); return { setNewMessage: function() { new_message = true; } }; } (); var initSocket = function() { websocket = new WebSocket(o.wsUri); websocket.onopen = function(e) { fsm.request(); }; websocket.onclose = function(e){ fsm.close(); }; websocket.onerror = function(e){ console.log(e); if (websocket.readyState == 1) { websocket.close(); } }; websocket.onmessage = function(e) { var msg = JSON.parse(e.data); switch (msg.type) { case 'response': fsm.response(); windowNotifier.setNewMessage(); break; case 'message': chatController.addMessage(msg); if (msg.from == 'me') { chatController.unspinChat(); } else { windowNotifier.setNewMessage(); } $(o.textMessage).focus(); break; } } }; var setView = function(tmpl) { $(o.tmplClass).removeClass('active'); $(tmpl).addClass('active'); }; var idleController = function() { $(o.btnBeginChat).click(function() { fsm.open(); }); return { show: function() { setView(o.tmplIdle); } }; } (); var waitController = function() { return { show: function(label) { $(o.labelWaitState).text(label); setView(o.tmplWait); } }; } (); var chatController = function() { $(o.textMessage).keydown(function (e) { if (e.ctrlKey && e.keyCode == 13) { $(o.formSend).trigger('submit'); } }); $(document).on('submit', o.formSend, function(e) { e.preventDefault(); var text = $(o.textMessage).val(); text = $.trim(text); if (!text) { return; } var msg = { type: 'message', message: text }; websocket.send(JSON.stringify(msg)); $(o.textMessage).val(''); chatController.spinChat(); }); $(o.btnCloseChat).click(function(e) { websocket.close(); }); var htmlForTextWithEmbeddedNewlines = function(text) { var htmls = []; var lines = text.split(/\n/); var tmpDiv = jQuery(document.createElement('div')); for (var i = 0 ; i < lines.length ; i++) { htmls.push(tmpDiv.text(lines[i]).html()); } return htmls.join("<br>"); }; return { clear: function() { $(o.messageBox).empty(); }, lockChat: function() { $(o.formSend).find(':input').attr('disabled', 'disabled'); }, unlockChat: function() { $(o.formSend).find(':input').removeAttr('disabled'); }, spinChat: function() { chatController.lockChat(); $(o.formSend).find('.btn').addClass('active'); }, unspinChat: function() { $(o.formSend).find('.btn').removeClass('active'); chatController.unlockChat(); }, showChat: function() { chatController.unlockChat(); $('.show-closed').hide(); $('.show-chat').show(); setView(o.tmplChat); }, showClosed: function() { chatController.lockChat(); $('.show-chat').hide(); $('.show-closed').show(); setView(o.tmplChat); }, addMessage: function(msg) { var d = new Date(); var text = htmlForTextWithEmbeddedNewlines(msg.message); $(o.messageBox).append( '<div>' + '<span class="user_name">'+msg.from+'</span> : <span class="user_message">'+text + '</span>' + '<span class="pull-right">'+d.toLocaleTimeString()+'</span>' + '</div>' ); $(o.messageBox).scrollTop($(o.messageBox)[0].scrollHeight); }, addSystemMessage: function(msg) { $(o.messageBox).append('<div class="system_msg">'+msg+'</div>'); } }; } (); fsm = StateMachine.create({ initial: 'idle', events: [ { name: 'open', from: ['idle', 'closed'], to: 'connecting' }, { name: 'request', from: 'connecting', to: 'waiting' }, { name: 'response', from: 'waiting', to: 'chat' }, { name: 'close', from: ['connecting', 'waiting'], to: 'idle' }, { name: 'close', from: 'chat', to: 'closed' } ], callbacks: { onidle: function(event, from, to) { idleController.show(); }, onconnecting: function(event, from, to) { waitController.show('  '); }, onwaiting: function(event, from, to) { waitController.show(' '); }, onchat: function(event, from, to) { chatController.showChat(); }, onclosed: function(event, from, to) { chatController.showClosed(); }, onopen: function(event, from, to) { initSocket(); }, onrequest: function (event, from, to) { var msg = { type: 'request' }; websocket.send(JSON.stringify(msg)); }, onresponse: function (event, from, to) { chatController.clear(); chatController.addSystemMessage('  - '); }, onclose: function (event, from, to) { chatController.addSystemMessage(' '); } } }); }}) })(jQuery); 



рдкрд░рд┐рдгрд╛рдо


рдЪреИрдЯ рд▓рдЧрднрдЧ рджреЛ рд╕рдкреНрддрд╛рд╣ рд╕реЗ рд╕реНрдерд┐рд░ рд╣реИред рдбреЗрдорди 50MB рдореЗрдореЛрд░реА рдФрд░ 0.2% рдкреНрд░реЛрд╕реЗрд╕рд░ рдХрд╛ рдЙрдкрднреЛрдЧ рдХрд░рддрд╛ рд╣реИред
рд▓реЛрдЧ рд╕рд╛рдЗрдЯ рдкрд░ рдЕрдзрд┐рдХ рд╕рдордп рддрдХ рд░рд╣рддреЗ рд╣реИрдВ, рд╕рдВрд╡рд╛рдж рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рдкрд╕рдВрдж рдХрд░рддреЗ рд╣реИрдВред рдореИрдВ рдЖрдкрдХреЛ рдЪреИрдЯ рдХреЗ рд▓рд┐рдП рдЖрдордВрддреНрд░рд┐рдд рдХрд░рддрд╛ рд╣реВрдВ!

рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж!

Source: https://habr.com/ru/post/In205934/


All Articles