From 2d823c8f8557f0a49e4307717e99a90b24052e9c Mon Sep 17 00:00:00 2001 From: lassulus Date: Fri, 8 Nov 2013 13:15:52 +0100 Subject: webchat: refactored code --- webchat/public/client.js | 58 +++------------------- webchat/public/commands.js | 25 ++++++++++ webchat/public/functions.js | 117 ++++++++++++++++++++++++++++++++++++++++++++ webchat/public/krebs.png | Bin 956 -> 2583 bytes webchat/public/reset.css | 6 +-- 5 files changed, 152 insertions(+), 54 deletions(-) create mode 100644 webchat/public/commands.js create mode 100644 webchat/public/functions.js (limited to 'webchat/public') diff --git a/webchat/public/client.js b/webchat/public/client.js index ca71b537..4842d9c2 100644 --- a/webchat/public/client.js +++ b/webchat/public/client.js @@ -1,34 +1,4 @@ -function replaceURLWithHTMLLinks (text) { - var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; - return text.replace(exp,"$1"); -} -function setMaybeNick (input) { - var match = /^\/nick\s+(.+)$/.exec(input); - if (match) { - nick = match[1]; - $('#nick').html(nick); - } -} - -function getCurTime () { - date = new Date; - h = date.getHours(); - if(h<10) - { - h = "0"+h; - } - m = date.getMinutes(); - if(m<10) - { - m = "0"+m; - } - s = date.getSeconds(); - if(s<10) - { - s = "0"+s; - } - return ''+h+':'+m+':'+s; -}; +var settings = {} $(function updateTime () { $('#time').html(getCurTime()); @@ -36,8 +6,6 @@ $(function updateTime () { return true; }); -var nick; - $(function connect() { sock = new SockJS('/echo'); @@ -50,16 +18,11 @@ $(function connect() { try { var object = JSON.parse(e.data); console.log(object.message); - var safe_message = $('
').text(object.message).html(); - safe_message = replaceURLWithHTMLLinks(safe_message); - var safe_from = $('
').text(object.from).html(); - $(''+getCurTime()+''+safe_from+''+safe_message+'').insertBefore('#foot'); - - var elem = document.getElementById('chatter'); - elem.scrollTop = elem.scrollHeight; + clientParser(object); } catch (error) { console.log(error); + throw error; } }; sock.onclose = function(event) { @@ -77,18 +40,11 @@ $(function() { e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); - setMaybeNick($('#input').val()); - var sendObj = { - message: $('#input').val(), - }; - - if (typeof nick === 'string') { - sendObj.nick = nick; - }; - - sock.send(JSON.stringify(sendObj)); + var input = ($('#input').val()); $('#input').val(''); - return; + + var command = inputParser(input) + return (commands[command.method] || commands.badcommand)(settings, command.params) } }); diff --git a/webchat/public/commands.js b/webchat/public/commands.js new file mode 100644 index 00000000..8cd3bba1 --- /dev/null +++ b/webchat/public/commands.js @@ -0,0 +1,25 @@ +var commands = {} + +commands.say = function (settings, params) { + var sendObj = { + method: 'say', + params: { message: params }, + }; + sock.send(JSON.stringify(sendObj)) +} + +commands.nick = function (settings, params) { + settings.nick = params + var sendObj = { + method: 'nick', + params: { nick: params }, + } + sock.send(JSON.stringify(sendObj)) +} + +commands.badcommand = function (settings, params) { + console.log("error"); + chatboxAppend( 'error', 'command not found' ) + + +} diff --git a/webchat/public/functions.js b/webchat/public/functions.js new file mode 100644 index 00000000..ddd3aad6 --- /dev/null +++ b/webchat/public/functions.js @@ -0,0 +1,117 @@ +function inputParser (str) { + var match = /^\/([a-z]+)(?:\s+(.*\S))?\s*$/.exec(str) + if (match) { + return { method: match[1], params: match[2] } + } else { + return { method: 'say', params: str } + } +} + + +function clientParser(object) { + console.log(object) + switch (object.type) { + case 'message': + return printMessage(object); + case 'join': + return handleJoin(object); + case 'quit': + return handleQuit(object); + case 'nicklist': + return handleNicklist(object); + case 'nickchange': + return handleNickchange(object); + } +}; + +function handleJoin(object) { + var safe_from = $('
').text(object.from).html(); + $(''+getCurTime()+''+safe_from+'joined').insertBefore('#foot'); + $('#nicklist').append('
' + safe_from + '
') ; +}; + +function handleQuit(object) { + var safe_from = $('
').text(object.from).html(); + $(''+getCurTime()+''+safe_from+'quit').insertBefore('#foot'); + console.log('removing', safe_from); + $(getNicklistElement(safe_from)).remove(); +}; + +function handleNicklist(object) { + Object.keys(object.message).forEach(function (nick) { +// console.log('nick',nick); + var hash_from = btoa(nick).replace(/=/g,'_'); +// $('.name').each(function (i,e) { console.log(i,e); if (e.innerHTML === 'kweb') { $(e).attr("style", "color:green") } }) + $('#nicklist').append('
' + nick + '
') ; + }); +}; + +function handleNickchange(object) { + var safe_from = $('
').text(object.nick).html(); + var safe_newnick = $('
').text(object.newnick).html(); + $(''+getCurTime()+''+safe_from+'is now known as '+object.newnick+'').insertBefore('#foot'); + $(getNicklistElement(safe_from)).remove(); + $('#nicklist').append('
' + safe_from + '
') ; +}; + +function replaceURLWithHTMLLinks (text) { + var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; + return text.replace(exp,"$1"); +} + +function setMaybeNick (input) { + if (match) { + nick = match[1]; + $('#nick').html(nick); + } +} +function sortNicklist () { +}; + +function getNicklistElement(name) { + var el; + $('.name').each(function (i,e) { + if (e.innerHTML === name) { + if (typeof el !== 'undefined') { + throw new Error('duplicate name: ' + name); + }; + el = e; + }; + }); + return el; +} + +function chatboxAppend (chat_from, chat_msg, type) { + type = type||'chat' + $(''+getCurTime()+''+chat_from+''+chat_msg+'').insertBefore('#foot'); + + var elem = document.getElementById('chatter'); + elem.scrollTop = elem.scrollHeight; +}; + +function printMessage(object) { + var safe_message = $('
').text(object.message).html(); + safe_message = replaceURLWithHTMLLinks(safe_message); + var safe_from = $('
').text(object.nick).html(); + return chatboxAppend(safe_from, safe_message) +}; + +function getCurTime () { + date = new Date; + h = date.getHours(); + if(h<10) + { + h = "0"+h; + } + m = date.getMinutes(); + if(m<10) + { + m = "0"+m; + } + s = date.getSeconds(); + if(s<10) + { + s = "0"+s; + } + return ''+h+':'+m+':'+s; +}; diff --git a/webchat/public/krebs.png b/webchat/public/krebs.png index 263d5b1c..5762e7f4 100644 Binary files a/webchat/public/krebs.png and b/webchat/public/krebs.png differ diff --git a/webchat/public/reset.css b/webchat/public/reset.css index 65f68058..4139aca5 100644 --- a/webchat/public/reset.css +++ b/webchat/public/reset.css @@ -21,7 +21,6 @@ time, mark, audio, video { border: 0; font-size: 100%; font: inherit; - font-family: monospace; vertical-align: baseline; } /* HTML5 display-role reset for older browsers */ @@ -33,6 +32,7 @@ body { line-height: 1; background-color: black; color: white; + font-family: monospace; } ol, ul { list-style: none; @@ -54,7 +54,7 @@ q:before, q:after { } #input{ width: 100%; - background-color: #555555; + background-color: #221111; border: 1px solid black; color: white; } @@ -116,4 +116,4 @@ a { font-size: 14px; position: absolute; bottom: 5px; -} \ No newline at end of file +} -- cgit v1.2.3 From 24efdc59cb58c5bbfa49516088fe124bc9f431c1 Mon Sep 17 00:00:00 2001 From: lassulus Date: Mon, 11 Nov 2013 17:46:27 +0100 Subject: webchat: still refactoring --- webchat/public/client.js | 2 +- webchat/public/commands.js | 2 +- webchat/public/functions.js | 63 ++++++++++----------------------------------- webchat/public/reset.css | 1 + 4 files changed, 17 insertions(+), 51 deletions(-) (limited to 'webchat/public') diff --git a/webchat/public/client.js b/webchat/public/client.js index 4842d9c2..5e0202a1 100644 --- a/webchat/public/client.js +++ b/webchat/public/client.js @@ -17,7 +17,7 @@ $(function connect() { console.log('message', e.data); try { var object = JSON.parse(e.data); - console.log(object.message); + console.log(object); clientParser(object); } catch (error) { diff --git a/webchat/public/commands.js b/webchat/public/commands.js index 8cd3bba1..20197fbb 100644 --- a/webchat/public/commands.js +++ b/webchat/public/commands.js @@ -3,7 +3,7 @@ var commands = {} commands.say = function (settings, params) { var sendObj = { method: 'say', - params: { message: params }, + params: { msg: params }, }; sock.send(JSON.stringify(sendObj)) } diff --git a/webchat/public/functions.js b/webchat/public/functions.js index ddd3aad6..adcf3169 100644 --- a/webchat/public/functions.js +++ b/webchat/public/functions.js @@ -9,50 +9,22 @@ function inputParser (str) { function clientParser(object) { - console.log(object) - switch (object.type) { - case 'message': - return printMessage(object); - case 'join': - return handleJoin(object); - case 'quit': - return handleQuit(object); - case 'nicklist': - return handleNicklist(object); - case 'nickchange': - return handleNickchange(object); - } -}; - -function handleJoin(object) { - var safe_from = $('
').text(object.from).html(); - $(''+getCurTime()+''+safe_from+'joined').insertBefore('#foot'); - $('#nicklist').append('
' + safe_from + '
') ; + console.log('parser: ',object) + return (handler[object.method] || console.log)(object.params) +//switch (object.method) { +// case 'message': +// return handler.message(object.params); +// case 'join': +// return handler.join(object.params); +// case 'quit': +// return handler.quit(object.params); +// case 'nicklist': +// return handler.nicklist(object.params); +// case 'nickchange': +// return handler.nickchange(object.params); +//} }; -function handleQuit(object) { - var safe_from = $('
').text(object.from).html(); - $(''+getCurTime()+''+safe_from+'quit').insertBefore('#foot'); - console.log('removing', safe_from); - $(getNicklistElement(safe_from)).remove(); -}; - -function handleNicklist(object) { - Object.keys(object.message).forEach(function (nick) { -// console.log('nick',nick); - var hash_from = btoa(nick).replace(/=/g,'_'); -// $('.name').each(function (i,e) { console.log(i,e); if (e.innerHTML === 'kweb') { $(e).attr("style", "color:green") } }) - $('#nicklist').append('
' + nick + '
') ; - }); -}; - -function handleNickchange(object) { - var safe_from = $('
').text(object.nick).html(); - var safe_newnick = $('
').text(object.newnick).html(); - $(''+getCurTime()+''+safe_from+'is now known as '+object.newnick+'').insertBefore('#foot'); - $(getNicklistElement(safe_from)).remove(); - $('#nicklist').append('
' + safe_from + '
') ; -}; function replaceURLWithHTMLLinks (text) { var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; @@ -89,13 +61,6 @@ function chatboxAppend (chat_from, chat_msg, type) { elem.scrollTop = elem.scrollHeight; }; -function printMessage(object) { - var safe_message = $('
').text(object.message).html(); - safe_message = replaceURLWithHTMLLinks(safe_message); - var safe_from = $('
').text(object.nick).html(); - return chatboxAppend(safe_from, safe_message) -}; - function getCurTime () { date = new Date; h = date.getHours(); diff --git a/webchat/public/reset.css b/webchat/public/reset.css index 4139aca5..64ba963e 100644 --- a/webchat/public/reset.css +++ b/webchat/public/reset.css @@ -63,6 +63,7 @@ q:before, q:after { font-weight: bold; text-align: right; font-size:12px; + white-space: nowrap; } .chat_from:after { content: ":"; -- cgit v1.2.3 From d577b700aa39c6dba270cbc9c11f3777866d4a69 Mon Sep 17 00:00:00 2001 From: lassulus Date: Mon, 11 Nov 2013 17:57:19 +0100 Subject: webchat: refactor into handler.js --- webchat/public/handler.js | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 webchat/public/handler.js (limited to 'webchat/public') diff --git a/webchat/public/handler.js b/webchat/public/handler.js new file mode 100644 index 00000000..2f9eb2a7 --- /dev/null +++ b/webchat/public/handler.js @@ -0,0 +1,38 @@ +var handler = {} + +handler.message = function(object) { + var safe_message = $('
').text(object.msg).html(); + safe_message = replaceURLWithHTMLLinks(safe_message); + var safe_from = $('
').text(object.nick).html(); + return chatboxAppend(safe_from, safe_message) +}; + +handler.join = function(object) { + var safe_from = $('
').text(object.from).html(); + $(''+getCurTime()+''+safe_from+'joined').insertBefore('#foot'); + $('#nicklist').append('
' + safe_from + '
') ; +}; + +handler.quit = function(object) { + var safe_from = $('
').text(object.from).html(); + $(''+getCurTime()+''+safe_from+'quit').insertBefore('#foot'); + console.log('removing', safe_from); + $(getNicklistElement(safe_from)).remove(); +}; + +handler.nicklist = function(object) { + Object.keys(object.nicklist).forEach(function (nick) { +// console.log('nick',nick); + var hash_from = btoa(nick).replace(/=/g,'_'); +// $('.name').each(function (i,e) { console.log(i,e); if (e.innerHTML === 'kweb') { $(e).attr("style", "color:green") } }) + $('#nicklist').append('
' + nick + '
') ; + }); +}; + +handler.nickchange = function(object) { + var safe_from = $('
').text(object.nick).html(); + var safe_newnick = $('
').text(object.newnick).html(); + $(''+getCurTime()+''+safe_from+'is now known as '+object.newnick+'').insertBefore('#foot'); + $(getNicklistElement(safe_from)).remove(); + $('#nicklist').append('
' + safe_newnick + '
') ; +}; -- cgit v1.2.3 From 2197882bc5a131ed7c877505ac66cbfa02679273 Mon Sep 17 00:00:00 2001 From: lassulus Date: Mon, 11 Nov 2013 18:28:25 +0100 Subject: webchat: join and quit color via css --- webchat/public/functions.js | 4 ++-- webchat/public/handler.js | 11 ++++------- webchat/public/reset.css | 16 +++++++++++----- 3 files changed, 17 insertions(+), 14 deletions(-) (limited to 'webchat/public') diff --git a/webchat/public/functions.js b/webchat/public/functions.js index adcf3169..0b8f2d49 100644 --- a/webchat/public/functions.js +++ b/webchat/public/functions.js @@ -54,8 +54,8 @@ function getNicklistElement(name) { } function chatboxAppend (chat_from, chat_msg, type) { - type = type||'chat' - $(''+getCurTime()+''+chat_from+''+chat_msg+'').insertBefore('#foot'); + type = type||'msg' + $(''+getCurTime()+''+chat_from+''+chat_msg+'').insertBefore('#foot'); var elem = document.getElementById('chatter'); elem.scrollTop = elem.scrollHeight; diff --git a/webchat/public/handler.js b/webchat/public/handler.js index 2f9eb2a7..4c13ba80 100644 --- a/webchat/public/handler.js +++ b/webchat/public/handler.js @@ -4,27 +4,24 @@ handler.message = function(object) { var safe_message = $('
').text(object.msg).html(); safe_message = replaceURLWithHTMLLinks(safe_message); var safe_from = $('
').text(object.nick).html(); - return chatboxAppend(safe_from, safe_message) + return chatboxAppend(safe_from, safe_message, 'msg') }; handler.join = function(object) { var safe_from = $('
').text(object.from).html(); - $(''+getCurTime()+''+safe_from+'joined').insertBefore('#foot'); $('#nicklist').append('
' + safe_from + '
') ; + return chatboxAppend(safe_from, 'joined', 'join') }; handler.quit = function(object) { var safe_from = $('
').text(object.from).html(); - $(''+getCurTime()+''+safe_from+'quit').insertBefore('#foot'); - console.log('removing', safe_from); $(getNicklistElement(safe_from)).remove(); + return chatboxAppend(safe_from, 'quit', 'quit') }; handler.nicklist = function(object) { Object.keys(object.nicklist).forEach(function (nick) { -// console.log('nick',nick); var hash_from = btoa(nick).replace(/=/g,'_'); -// $('.name').each(function (i,e) { console.log(i,e); if (e.innerHTML === 'kweb') { $(e).attr("style", "color:green") } }) $('#nicklist').append('
' + nick + '
') ; }); }; @@ -32,7 +29,7 @@ handler.nicklist = function(object) { handler.nickchange = function(object) { var safe_from = $('
').text(object.nick).html(); var safe_newnick = $('
').text(object.newnick).html(); - $(''+getCurTime()+''+safe_from+'is now known as '+object.newnick+'').insertBefore('#foot'); $(getNicklistElement(safe_from)).remove(); $('#nicklist').append('
' + safe_newnick + '
') ; + return chatboxAppend(safe_from, 'is now known as ' + safe_newnick, 'nick'); }; diff --git a/webchat/public/reset.css b/webchat/public/reset.css index 64ba963e..d369bc86 100644 --- a/webchat/public/reset.css +++ b/webchat/public/reset.css @@ -58,14 +58,14 @@ q:before, q:after { border: 1px solid black; color: white; } -.chat_from { +.from { color:grey; font-weight: bold; text-align: right; font-size:12px; white-space: nowrap; } -.chat_from:after { +.from:after { content: ":"; padding-right: 6px; } @@ -88,16 +88,16 @@ q:before, q:after { } .chat_date,.chat_from,.chat_msg{ } -.chat_msg{ +.msg{ width: 100%; } a { color: red; } -.chat_date { +.date { color: green; } -.chat_date:after { +.date:after { content: ""; padding-right: 4px; } @@ -118,3 +118,9 @@ a { position: absolute; bottom: 5px; } +.join_msg { + color: #00FF00; +} +.quit_msg { + color: #FF0000; +} -- cgit v1.2.3 From 2be3c286f5151ca319700dd4bd7c6d16cec6c2c4 Mon Sep 17 00:00:00 2001 From: lassulus Date: Mon, 11 Nov 2013 18:31:04 +0100 Subject: webchat: cleanup code --- webchat/public/functions.js | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'webchat/public') diff --git a/webchat/public/functions.js b/webchat/public/functions.js index 0b8f2d49..b669a928 100644 --- a/webchat/public/functions.js +++ b/webchat/public/functions.js @@ -11,18 +11,6 @@ function inputParser (str) { function clientParser(object) { console.log('parser: ',object) return (handler[object.method] || console.log)(object.params) -//switch (object.method) { -// case 'message': -// return handler.message(object.params); -// case 'join': -// return handler.join(object.params); -// case 'quit': -// return handler.quit(object.params); -// case 'nicklist': -// return handler.nicklist(object.params); -// case 'nickchange': -// return handler.nickchange(object.params); -//} }; -- cgit v1.2.3 From c6a7cd9027150fca42500b3bbc78be01993856f6 Mon Sep 17 00:00:00 2001 From: lassulus Date: Mon, 11 Nov 2013 20:16:45 +0100 Subject: webchat: request handling --- webchat/public/client.js | 42 +++++++++++++++++++++++++++++++++++------- webchat/public/commands.js | 5 ++--- webchat/public/functions.js | 13 +++++++++++-- webchat/public/handler.js | 10 +++++----- 4 files changed, 53 insertions(+), 17 deletions(-) (limited to 'webchat/public') diff --git a/webchat/public/client.js b/webchat/public/client.js index 5e0202a1..8f7becb7 100644 --- a/webchat/public/client.js +++ b/webchat/public/client.js @@ -6,26 +6,54 @@ $(function updateTime () { return true; }); +var gensym = (function () { + var i = 0 + return function () { + return ++i; + } +})() + +settings.waiting_callbacks = {} + +function request (settings, method, params, callback) { + var id = gensym() + settings.waiting_callbacks[id] = callback + settings.sock.send({method: method, params: params, id: id}); +} + $(function connect() { - sock = new SockJS('/echo'); + settings.sock = new SockJS('/echo'); - sock.onopen = function() { + settings.sock.onopen = function() { console.log('open'); - sock.send('open'); + request(settings, 'coi', {}, function (error, result) { + if (error) { + console.log('coi error', error) + } else { + settings.nick = result.nick //TODO: write to display + settings.addr = result.addr //TODO: write to display + } + }) }; - sock.onmessage = function(e) { + settings.sock.onmessage = function(e) { console.log('message', e.data); try { var object = JSON.parse(e.data); console.log(object); - clientParser(object); } catch (error) { console.log(error); throw error; } - }; - sock.onclose = function(event) { + if (typeof object.method === 'string') { + return methodDispatcher(settings, object); + } else if (typeof object.result === 'string') { + return resultDispatcher(settings, object); + } else { + console.log('bad message:', object) + } + } + settings.sock.onclose = function(event) { console.log('close'); switch (event.code) { case 1006: //abnormal closure diff --git a/webchat/public/commands.js b/webchat/public/commands.js index 20197fbb..5a570556 100644 --- a/webchat/public/commands.js +++ b/webchat/public/commands.js @@ -5,16 +5,15 @@ commands.say = function (settings, params) { method: 'say', params: { msg: params }, }; - sock.send(JSON.stringify(sendObj)) + settings.sock.send(JSON.stringify(sendObj)) } commands.nick = function (settings, params) { - settings.nick = params var sendObj = { method: 'nick', params: { nick: params }, } - sock.send(JSON.stringify(sendObj)) + settings.sock.send(JSON.stringify(sendObj)) } commands.badcommand = function (settings, params) { diff --git a/webchat/public/functions.js b/webchat/public/functions.js index b669a928..45c8ad3f 100644 --- a/webchat/public/functions.js +++ b/webchat/public/functions.js @@ -8,9 +8,18 @@ function inputParser (str) { } -function clientParser(object) { +function methodDispatcher (settings, object) { console.log('parser: ',object) - return (handler[object.method] || console.log)(object.params) + return (handler[object.method] || console.log)(settings, object.params) +}; + +function resultDispatcher (settings, object) { + console.log('parser: ',object) + var callback = settings.waiting_callbacks[object.id] + delete settings.waiting_callbacks[object.id] + if (typeof callback === 'function') { + callback(object.error, object.result) + } }; diff --git a/webchat/public/handler.js b/webchat/public/handler.js index 4c13ba80..0930646d 100644 --- a/webchat/public/handler.js +++ b/webchat/public/handler.js @@ -1,32 +1,32 @@ var handler = {} -handler.message = function(object) { +handler.message = function(settings, object) { var safe_message = $('
').text(object.msg).html(); safe_message = replaceURLWithHTMLLinks(safe_message); var safe_from = $('
').text(object.nick).html(); return chatboxAppend(safe_from, safe_message, 'msg') }; -handler.join = function(object) { +handler.join = function(settings, object) { var safe_from = $('
').text(object.from).html(); $('#nicklist').append('
' + safe_from + '
') ; return chatboxAppend(safe_from, 'joined', 'join') }; -handler.quit = function(object) { +handler.quit = function(settings, object) { var safe_from = $('
').text(object.from).html(); $(getNicklistElement(safe_from)).remove(); return chatboxAppend(safe_from, 'quit', 'quit') }; -handler.nicklist = function(object) { +handler.nicklist = function(settings, object) { Object.keys(object.nicklist).forEach(function (nick) { var hash_from = btoa(nick).replace(/=/g,'_'); $('#nicklist').append('
' + nick + '
') ; }); }; -handler.nickchange = function(object) { +handler.nickchange = function(settings, object) { var safe_from = $('
').text(object.nick).html(); var safe_newnick = $('
').text(object.newnick).html(); $(getNicklistElement(safe_from)).remove(); -- cgit v1.2.3 From 3531d46cc3644a64b990f904e40e4846b8242a07 Mon Sep 17 00:00:00 2001 From: lassulus Date: Tue, 12 Nov 2013 02:01:29 +0100 Subject: webchat: refactor to rpc --- webchat/public/client.js | 75 ++++++++++++----------- webchat/public/commands.js | 11 ++-- webchat/public/functions.js | 20 +------ webchat/public/handler.js | 35 ----------- webchat/public/rpc.js | 99 +++++++++++++++++++++++++++++++ webchat/public/sockjs_client_transport.js | 27 +++++++++ 6 files changed, 172 insertions(+), 95 deletions(-) delete mode 100644 webchat/public/handler.js create mode 100644 webchat/public/rpc.js create mode 100644 webchat/public/sockjs_client_transport.js (limited to 'webchat/public') diff --git a/webchat/public/client.js b/webchat/public/client.js index 8f7becb7..8865fcc0 100644 --- a/webchat/public/client.js +++ b/webchat/public/client.js @@ -23,44 +23,43 @@ function request (settings, method, params, callback) { $(function connect() { settings.sock = new SockJS('/echo'); - - settings.sock.onopen = function() { - console.log('open'); - request(settings, 'coi', {}, function (error, result) { - if (error) { - console.log('coi error', error) - } else { - settings.nick = result.nick //TODO: write to display - settings.addr = result.addr //TODO: write to display - } - }) - }; - settings.sock.onmessage = function(e) { - console.log('message', e.data); - try { - var object = JSON.parse(e.data); - console.log(object); - - } catch (error) { - console.log(error); - throw error; - } - if (typeof object.method === 'string') { - return methodDispatcher(settings, object); - } else if (typeof object.result === 'string') { - return resultDispatcher(settings, object); - } else { - console.log('bad message:', object) - } - } - settings.sock.onclose = function(event) { - console.log('close'); - switch (event.code) { - case 1006: //abnormal closure - return setTimeout(connect, 1000); - }; - }; - + var transport = make_sockjs_client_transport(settings.sock) + var rpc = new RPC(transport) + rpc.register('msg', {type: 'string', nick: 'string', msg: 'string'}, function(params, callback) { + var safe_message = $('
').text(params.msg).html(); + safe_message = replaceURLWithHTMLLinks(safe_message); + var safe_from = $('
').text(params.nick).html(); + chatboxAppend(safe_from, safe_message, 'web_msg') + return callback(null) + }) + rpc.register('nick', {type: 'string', newnick: 'string', oldnick: 'string'}, function(params, callback) { + var safe_oldnick = $('
').text(params.oldnick).html(); + var safe_newnick = $('
').text(params.newnick).html(); + var safe_type = $('
').text(params.type).html(); + $(getNicklistElement(safe_oldnick,safe_type)).remove(); + $('#nicklist').append('
' + safe_newnick + '
') ; + chatboxAppend(safe_oldnick, 'is now known as ' + safe_newnick, 'nick'); + return callback(null) + }) + rpc.register('your_nick', {nick: 'string'}, function(params, callback) { + var safe_nick = $('
').text(params.nick).html(); + settings.nick = safe_nick + return callback(null) + }) + rpc.register('join', {type: 'string', nick: 'string'}, function(params, callback) { + var safe_nick = $('
').text(params.nick).html(); + var safe_type = $('
').text(params.type).html(); + $('#nicklist').append('
' + safe_nick + '
') ; + chatboxAppend(safe_nick, 'has joined'); + return callback(null) + }) + rpc.register('part', {type: 'string', nick: 'string'}, function(params, callback) { + var safe_nick = $('
').text(params.nick).html(); + var safe_type = $('
').text(params.type).html(); + $(getNicklistElement(safe_nick,safe_type)).remove(); + chatboxAppend(safe_nick, 'has parted'); + return callback(null) + }) }); $(function() { $('#input').keydown(function(e) { diff --git a/webchat/public/commands.js b/webchat/public/commands.js index 5a570556..d4408c4c 100644 --- a/webchat/public/commands.js +++ b/webchat/public/commands.js @@ -1,14 +1,15 @@ var commands = {} -commands.say = function (settings, params) { +commands.msg = function (settings, params) { var sendObj = { - method: 'say', - params: { msg: params }, - }; + method: 'msg', + params: { msg: params } + } settings.sock.send(JSON.stringify(sendObj)) } commands.nick = function (settings, params) { + settings.nick = params var sendObj = { method: 'nick', params: { nick: params }, @@ -17,7 +18,7 @@ commands.nick = function (settings, params) { } commands.badcommand = function (settings, params) { - console.log("error"); + console.log("error", params); chatboxAppend( 'error', 'command not found' ) diff --git a/webchat/public/functions.js b/webchat/public/functions.js index 45c8ad3f..244af67b 100644 --- a/webchat/public/functions.js +++ b/webchat/public/functions.js @@ -3,25 +3,11 @@ function inputParser (str) { if (match) { return { method: match[1], params: match[2] } } else { - return { method: 'say', params: str } + return { method: 'msg', params: str } } } -function methodDispatcher (settings, object) { - console.log('parser: ',object) - return (handler[object.method] || console.log)(settings, object.params) -}; - -function resultDispatcher (settings, object) { - console.log('parser: ',object) - var callback = settings.waiting_callbacks[object.id] - delete settings.waiting_callbacks[object.id] - if (typeof callback === 'function') { - callback(object.error, object.result) - } -}; - function replaceURLWithHTMLLinks (text) { var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; @@ -37,9 +23,9 @@ function setMaybeNick (input) { function sortNicklist () { }; -function getNicklistElement(name) { +function getNicklistElement(name, type) { var el; - $('.name').each(function (i,e) { + $('.'+type+'_name').each(function (i,e) { if (e.innerHTML === name) { if (typeof el !== 'undefined') { throw new Error('duplicate name: ' + name); diff --git a/webchat/public/handler.js b/webchat/public/handler.js deleted file mode 100644 index 0930646d..00000000 --- a/webchat/public/handler.js +++ /dev/null @@ -1,35 +0,0 @@ -var handler = {} - -handler.message = function(settings, object) { - var safe_message = $('
').text(object.msg).html(); - safe_message = replaceURLWithHTMLLinks(safe_message); - var safe_from = $('
').text(object.nick).html(); - return chatboxAppend(safe_from, safe_message, 'msg') -}; - -handler.join = function(settings, object) { - var safe_from = $('
').text(object.from).html(); - $('#nicklist').append('
' + safe_from + '
') ; - return chatboxAppend(safe_from, 'joined', 'join') -}; - -handler.quit = function(settings, object) { - var safe_from = $('
').text(object.from).html(); - $(getNicklistElement(safe_from)).remove(); - return chatboxAppend(safe_from, 'quit', 'quit') -}; - -handler.nicklist = function(settings, object) { - Object.keys(object.nicklist).forEach(function (nick) { - var hash_from = btoa(nick).replace(/=/g,'_'); - $('#nicklist').append('
' + nick + '
') ; - }); -}; - -handler.nickchange = function(settings, object) { - var safe_from = $('
').text(object.nick).html(); - var safe_newnick = $('
').text(object.newnick).html(); - $(getNicklistElement(safe_from)).remove(); - $('#nicklist').append('
' + safe_newnick + '
') ; - return chatboxAppend(safe_from, 'is now known as ' + safe_newnick, 'nick'); -}; diff --git a/webchat/public/rpc.js b/webchat/public/rpc.js new file mode 100644 index 00000000..8e911e1d --- /dev/null +++ b/webchat/public/rpc.js @@ -0,0 +1,99 @@ +try { + module.exports = RPC +} +catch(e){ +} + +function RPC (transport) { + this._id = 0 + this._waiting_callbacks = {} + this._methods = {} + this._transport = transport + + transport.onmessage = this.onmessage.bind(this) +} + +RPC.prototype.register = function (method, params, callback) { + this._methods[method] = callback +} + +RPC.prototype.send = function (method, params, callback) { + var message = { + method: method, + params: params, + } + if (callback) { + var id = ++this._id + this._waiting_callbacks[id] = callback + message.id = id + } + return this._transport.send(message) +} + +function _is_request (message) { + return typeof message.method === 'string' +} + +function _is_response (message) { + return message.hasOwnProperty('result') + || message.hasOwnProperty('error') +} + +RPC.prototype.onmessage = function (message) { + console.log('RPC message:', message) + if (_is_request(message)) { + return this._on_request(message) + } + if (_is_response(message)) { + return this._on_response(message) + } + return this._on_bad_message(message) +} + +RPC.prototype._on_request = function (request) { + var method = this._methods[request.method] || function(){ + console.log('method not found', request.method) + } + var params = request.params + var id = request.id + + var transport = this._transport + + if (typeof id === 'string' || typeof id === 'number' || id === null) { + return method(params, function (error, result) { + var response = { + id: id, + } + if (error) { + response.error = error + } else { + response.result = result + } + console.log('request:', request, '->', response) + return transport.send(response) + }) + } else { + return method(params, function (error, result) { + var response = { + id: id, + } + if (error) { + response.error = error + } else { + response.result = result + } + console.log('notification:', request, '->', response) + }) + } +} + +RPC.prototype._on_response = function (response) { + var result = response.result + var error = response.error + var id = response.id + + var callback = this._waiting_callbacks[id] + delete this._waiting_callbacks[id] + + return callback(result, error) +} diff --git a/webchat/public/sockjs_client_transport.js b/webchat/public/sockjs_client_transport.js new file mode 100644 index 00000000..4e525d0d --- /dev/null +++ b/webchat/public/sockjs_client_transport.js @@ -0,0 +1,27 @@ + +function make_sockjs_client_transport (sock) { + var transport = {} + + sock.onmessage = function (data) { + console.log('sockjs parse', data) + try { + var message = JSON.parse(data.data) + } catch (error) { + return console.log('error', error) + } + transport.onmessage(message) + } + + transport.send = function (message) { + try { + var data = JSON.stringify(message) + } catch (error) { + return console.log('sockjs transport send error:', error) + } + sock.send(data) + } + + return transport +} + + -- cgit v1.2.3 From fc72fda5fc46daea25a991ba6b907a793e52ed06 Mon Sep 17 00:00:00 2001 From: lassulus Date: Tue, 12 Nov 2013 02:06:24 +0100 Subject: webchat: remove cruft --- webchat/public/client.js | 13 ------------- webchat/public/functions.js | 11 ----------- 2 files changed, 24 deletions(-) (limited to 'webchat/public') diff --git a/webchat/public/client.js b/webchat/public/client.js index 8865fcc0..a90cf8d6 100644 --- a/webchat/public/client.js +++ b/webchat/public/client.js @@ -6,21 +6,8 @@ $(function updateTime () { return true; }); -var gensym = (function () { - var i = 0 - return function () { - return ++i; - } -})() - settings.waiting_callbacks = {} -function request (settings, method, params, callback) { - var id = gensym() - settings.waiting_callbacks[id] = callback - settings.sock.send({method: method, params: params, id: id}); -} - $(function connect() { settings.sock = new SockJS('/echo'); var transport = make_sockjs_client_transport(settings.sock) diff --git a/webchat/public/functions.js b/webchat/public/functions.js index 244af67b..781fafce 100644 --- a/webchat/public/functions.js +++ b/webchat/public/functions.js @@ -7,22 +7,11 @@ function inputParser (str) { } } - - function replaceURLWithHTMLLinks (text) { var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; return text.replace(exp,"$1"); } -function setMaybeNick (input) { - if (match) { - nick = match[1]; - $('#nick').html(nick); - } -} -function sortNicklist () { -}; - function getNicklistElement(name, type) { var el; $('.'+type+'_name').each(function (i,e) { -- cgit v1.2.3 From a170673b55215137b5e7fe19e587767c2ef57453 Mon Sep 17 00:00:00 2001 From: lassulus Date: Tue, 12 Nov 2013 02:48:45 +0100 Subject: webchat: refactor code --- webchat/public/client.js | 5 +++++ webchat/public/commands.js | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'webchat/public') diff --git a/webchat/public/client.js b/webchat/public/client.js index a90cf8d6..58002f78 100644 --- a/webchat/public/client.js +++ b/webchat/public/client.js @@ -23,6 +23,10 @@ $(function connect() { var safe_oldnick = $('
').text(params.oldnick).html(); var safe_newnick = $('
').text(params.newnick).html(); var safe_type = $('
').text(params.type).html(); + if (safe_oldnick === settings.nick){ + settings.nick = safe_newnick + $('#nick').html(settings.nick) + } $(getNicklistElement(safe_oldnick,safe_type)).remove(); $('#nicklist').append('
' + safe_newnick + '
') ; chatboxAppend(safe_oldnick, 'is now known as ' + safe_newnick, 'nick'); @@ -31,6 +35,7 @@ $(function connect() { rpc.register('your_nick', {nick: 'string'}, function(params, callback) { var safe_nick = $('
').text(params.nick).html(); settings.nick = safe_nick + $('#nick').html(settings.nick) return callback(null) }) rpc.register('join', {type: 'string', nick: 'string'}, function(params, callback) { diff --git a/webchat/public/commands.js b/webchat/public/commands.js index d4408c4c..f19c78dc 100644 --- a/webchat/public/commands.js +++ b/webchat/public/commands.js @@ -9,7 +9,6 @@ commands.msg = function (settings, params) { } commands.nick = function (settings, params) { - settings.nick = params var sendObj = { method: 'nick', params: { nick: params }, -- cgit v1.2.3 From 721b4fb1b32ee47f158fb3b9a1ad0747ff579044 Mon Sep 17 00:00:00 2001 From: lassulus Date: Tue, 12 Nov 2013 02:59:28 +0100 Subject: webchat: remove input parser --- webchat/public/client.js | 100 ++++++++++++++++-------------- webchat/public/commands.js | 24 ------- webchat/public/functions.js | 8 --- webchat/public/sockjs_client_transport.js | 2 - 4 files changed, 52 insertions(+), 82 deletions(-) delete mode 100644 webchat/public/commands.js (limited to 'webchat/public') diff --git a/webchat/public/client.js b/webchat/public/client.js index 58002f78..d7a5ecab 100644 --- a/webchat/public/client.js +++ b/webchat/public/client.js @@ -1,4 +1,50 @@ var settings = {} +settings.sock = new SockJS('/echo'); +settings.waiting_callbacks = {} + +var transport = make_sockjs_client_transport(settings.sock) +var rpc = new RPC(transport) + +rpc.register('msg', {type: 'string', nick: 'string', msg: 'string'}, function(params, callback) { + var safe_message = $('
').text(params.msg).html(); + safe_message = replaceURLWithHTMLLinks(safe_message); + var safe_from = $('
').text(params.nick).html(); + chatboxAppend(safe_from, safe_message, 'web_msg') + return callback(null) +}) +rpc.register('nick', {type: 'string', newnick: 'string', oldnick: 'string'}, function(params, callback) { + var safe_oldnick = $('
').text(params.oldnick).html(); + var safe_newnick = $('
').text(params.newnick).html(); + var safe_type = $('
').text(params.type).html(); + if (safe_oldnick === settings.nick){ + settings.nick = safe_newnick + $('#nick').html(settings.nick) + } + $(getNicklistElement(safe_oldnick,safe_type)).remove(); + $('#nicklist').append('
' + safe_newnick + '
') ; + chatboxAppend(safe_oldnick, 'is now known as ' + safe_newnick, 'nick'); + return callback(null) +}) +rpc.register('your_nick', {nick: 'string'}, function(params, callback) { + var safe_nick = $('
').text(params.nick).html(); + settings.nick = safe_nick + $('#nick').html(settings.nick) + return callback(null) +}) +rpc.register('join', {type: 'string', nick: 'string'}, function(params, callback) { + var safe_nick = $('
').text(params.nick).html(); + var safe_type = $('
').text(params.type).html(); + $('#nicklist').append('
' + safe_nick + '
') ; + chatboxAppend(safe_nick, 'has joined'); + return callback(null) +}) +rpc.register('part', {type: 'string', nick: 'string'}, function(params, callback) { + var safe_nick = $('
').text(params.nick).html(); + var safe_type = $('
').text(params.type).html(); + $(getNicklistElement(safe_nick,safe_type)).remove(); + chatboxAppend(safe_nick, 'has parted'); + return callback(null) +}) $(function updateTime () { $('#time').html(getCurTime()); @@ -6,53 +52,7 @@ $(function updateTime () { return true; }); -settings.waiting_callbacks = {} -$(function connect() { - settings.sock = new SockJS('/echo'); - var transport = make_sockjs_client_transport(settings.sock) - var rpc = new RPC(transport) - rpc.register('msg', {type: 'string', nick: 'string', msg: 'string'}, function(params, callback) { - var safe_message = $('
').text(params.msg).html(); - safe_message = replaceURLWithHTMLLinks(safe_message); - var safe_from = $('
').text(params.nick).html(); - chatboxAppend(safe_from, safe_message, 'web_msg') - return callback(null) - }) - rpc.register('nick', {type: 'string', newnick: 'string', oldnick: 'string'}, function(params, callback) { - var safe_oldnick = $('
').text(params.oldnick).html(); - var safe_newnick = $('
').text(params.newnick).html(); - var safe_type = $('
').text(params.type).html(); - if (safe_oldnick === settings.nick){ - settings.nick = safe_newnick - $('#nick').html(settings.nick) - } - $(getNicklistElement(safe_oldnick,safe_type)).remove(); - $('#nicklist').append('
' + safe_newnick + '
') ; - chatboxAppend(safe_oldnick, 'is now known as ' + safe_newnick, 'nick'); - return callback(null) - }) - rpc.register('your_nick', {nick: 'string'}, function(params, callback) { - var safe_nick = $('
').text(params.nick).html(); - settings.nick = safe_nick - $('#nick').html(settings.nick) - return callback(null) - }) - rpc.register('join', {type: 'string', nick: 'string'}, function(params, callback) { - var safe_nick = $('
').text(params.nick).html(); - var safe_type = $('
').text(params.type).html(); - $('#nicklist').append('
' + safe_nick + '
') ; - chatboxAppend(safe_nick, 'has joined'); - return callback(null) - }) - rpc.register('part', {type: 'string', nick: 'string'}, function(params, callback) { - var safe_nick = $('
').text(params.nick).html(); - var safe_type = $('
').text(params.type).html(); - $(getNicklistElement(safe_nick,safe_type)).remove(); - chatboxAppend(safe_nick, 'has parted'); - return callback(null) - }) -}); $(function() { $('#input').keydown(function(e) { if (e.keyCode === 13) { @@ -62,8 +62,12 @@ $(function() { var input = ($('#input').val()); $('#input').val(''); - var command = inputParser(input) - return (commands[command.method] || commands.badcommand)(settings, command.params) + var match = /^\/([a-z]+)(?:\s+(.*\S))?\s*$/.exec(input) + if (match) { + return rpc.send(match[1], match[2]) + } else { + return rpc.send('msg', input) + } } }); diff --git a/webchat/public/commands.js b/webchat/public/commands.js deleted file mode 100644 index f19c78dc..00000000 --- a/webchat/public/commands.js +++ /dev/null @@ -1,24 +0,0 @@ -var commands = {} - -commands.msg = function (settings, params) { - var sendObj = { - method: 'msg', - params: { msg: params } - } - settings.sock.send(JSON.stringify(sendObj)) -} - -commands.nick = function (settings, params) { - var sendObj = { - method: 'nick', - params: { nick: params }, - } - settings.sock.send(JSON.stringify(sendObj)) -} - -commands.badcommand = function (settings, params) { - console.log("error", params); - chatboxAppend( 'error', 'command not found' ) - - -} diff --git a/webchat/public/functions.js b/webchat/public/functions.js index 781fafce..318d0865 100644 --- a/webchat/public/functions.js +++ b/webchat/public/functions.js @@ -1,11 +1,3 @@ -function inputParser (str) { - var match = /^\/([a-z]+)(?:\s+(.*\S))?\s*$/.exec(str) - if (match) { - return { method: match[1], params: match[2] } - } else { - return { method: 'msg', params: str } - } -} function replaceURLWithHTMLLinks (text) { var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; diff --git a/webchat/public/sockjs_client_transport.js b/webchat/public/sockjs_client_transport.js index 4e525d0d..a7b76af3 100644 --- a/webchat/public/sockjs_client_transport.js +++ b/webchat/public/sockjs_client_transport.js @@ -23,5 +23,3 @@ function make_sockjs_client_transport (sock) { return transport } - - -- cgit v1.2.3 From b749c216ae84f02330da7396135be11259ec12d9 Mon Sep 17 00:00:00 2001 From: lassulus Date: Tue, 12 Nov 2013 04:08:38 +0100 Subject: webchat: fix nicklist --- webchat/public/client.js | 22 +++++++++------------- webchat/public/functions.js | 8 ++++++++ 2 files changed, 17 insertions(+), 13 deletions(-) (limited to 'webchat/public') diff --git a/webchat/public/client.js b/webchat/public/client.js index d7a5ecab..54ccfe34 100644 --- a/webchat/public/client.js +++ b/webchat/public/client.js @@ -3,16 +3,16 @@ settings.sock = new SockJS('/echo'); settings.waiting_callbacks = {} var transport = make_sockjs_client_transport(settings.sock) -var rpc = new RPC(transport) +settings.rpc = new RPC(transport) -rpc.register('msg', {type: 'string', nick: 'string', msg: 'string'}, function(params, callback) { +settings.rpc.register('msg', {type: 'string', nick: 'string', msg: 'string'}, function(params, callback) { var safe_message = $('
').text(params.msg).html(); safe_message = replaceURLWithHTMLLinks(safe_message); var safe_from = $('
').text(params.nick).html(); chatboxAppend(safe_from, safe_message, 'web_msg') return callback(null) }) -rpc.register('nick', {type: 'string', newnick: 'string', oldnick: 'string'}, function(params, callback) { +settings.rpc.register('nick', {type: 'string', newnick: 'string', oldnick: 'string'}, function(params, callback) { var safe_oldnick = $('
').text(params.oldnick).html(); var safe_newnick = $('
').text(params.newnick).html(); var safe_type = $('
').text(params.type).html(); @@ -25,20 +25,20 @@ rpc.register('nick', {type: 'string', newnick: 'string', oldnick: 'string'}, fun chatboxAppend(safe_oldnick, 'is now known as ' + safe_newnick, 'nick'); return callback(null) }) -rpc.register('your_nick', {nick: 'string'}, function(params, callback) { +settings.rpc.register('your_nick', {nick: 'string'}, function(params, callback) { var safe_nick = $('
').text(params.nick).html(); settings.nick = safe_nick $('#nick').html(settings.nick) return callback(null) }) -rpc.register('join', {type: 'string', nick: 'string'}, function(params, callback) { +settings.rpc.register('join', {type: 'string', nick: 'string'}, function(params, callback) { var safe_nick = $('
').text(params.nick).html(); var safe_type = $('
').text(params.type).html(); $('#nicklist').append('
' + safe_nick + '
') ; chatboxAppend(safe_nick, 'has joined'); return callback(null) }) -rpc.register('part', {type: 'string', nick: 'string'}, function(params, callback) { +settings.rpc.register('part', {type: 'string', nick: 'string'}, function(params, callback) { var safe_nick = $('
').text(params.nick).html(); var safe_type = $('
').text(params.type).html(); $(getNicklistElement(safe_nick,safe_type)).remove(); @@ -60,14 +60,10 @@ $(function() { e.stopPropagation(); e.stopImmediatePropagation(); var input = ($('#input').val()); - $('#input').val(''); + $('#input').val('') - var match = /^\/([a-z]+)(?:\s+(.*\S))?\s*$/.exec(input) - if (match) { - return rpc.send(match[1], match[2]) - } else { - return rpc.send('msg', input) - } + var command = inputParser(input) + return (commands[command.method] || commands.badcommand)(settings, command.params) } }); diff --git a/webchat/public/functions.js b/webchat/public/functions.js index 318d0865..781fafce 100644 --- a/webchat/public/functions.js +++ b/webchat/public/functions.js @@ -1,3 +1,11 @@ +function inputParser (str) { + var match = /^\/([a-z]+)(?:\s+(.*\S))?\s*$/.exec(str) + if (match) { + return { method: match[1], params: match[2] } + } else { + return { method: 'msg', params: str } + } +} function replaceURLWithHTMLLinks (text) { var exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; -- cgit v1.2.3