mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-29 15:37:57 +00:00
Fixed chat server to work with new api fixes #4
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -11,3 +11,6 @@
|
||||
|
||||
objs_shared/
|
||||
objs_static/
|
||||
|
||||
examples/chat_server/chat_server
|
||||
examples/echo_server/echo_server
|
||||
@@ -0,0 +1,23 @@
|
||||
CFLAGS = -O2
|
||||
LDFLAGS =
|
||||
|
||||
CXX ?= c++
|
||||
SHARED ?= "1"
|
||||
|
||||
ifeq ($(SHARED), 1)
|
||||
LDFLAGS := $(LDFLAGS) -lboost_system -lwebsocketpp
|
||||
else
|
||||
LDFLAGS := $(LDFLAGS) -lboost_system ../../libwebsocketpp.a
|
||||
endif
|
||||
|
||||
chat_server: chat_server.o chat.o
|
||||
$(CXX) $(CFLAGS) $^ -o $@ $(LDFLAGS)
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) -c $(CFLAGS) -o $@ $^
|
||||
|
||||
# cleanup by removing generated files
|
||||
#
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f *.o chat_server
|
||||
|
||||
@@ -27,31 +27,154 @@
|
||||
|
||||
#include "chat.hpp"
|
||||
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
|
||||
using websocketchat::chat_handler;
|
||||
using websocketpp::session_ptr;
|
||||
|
||||
|
||||
void chat_handler::validate(websocketpp::session_ptr client) {
|
||||
void chat_handler::validate(session_ptr client) {
|
||||
std::stringstream err;
|
||||
|
||||
// We only know about the chat resource
|
||||
if (client->get_request() != "/chat") {
|
||||
err << "Request for unknown resource " << client->get_request();
|
||||
throw(handshake_error(err.str(),404));
|
||||
throw(websocketpp::handshake_error(err.str(),404));
|
||||
}
|
||||
|
||||
// Require specific origin example
|
||||
if (client->get_origin() != "http://zaphoyd.com") {
|
||||
err << "Request from unrecognized origin: " << client->get_origin();
|
||||
throw(handshake_error(err.str(),403));
|
||||
throw(websocketpp::handshake_error(err.str(),403));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void connect(session_ptr client) {
|
||||
void chat_handler::connect(session_ptr client) {
|
||||
std::cout << "client " << client << " joined the lobby." << std::endl;
|
||||
m_connections.insert(client);
|
||||
|
||||
// send user list to all clients
|
||||
// send signon message from server to all other clients.
|
||||
m_connections.insert(std::pair<session_ptr,std::string>(client,get_con_id(client)));
|
||||
|
||||
// send user list and signon message to all clients
|
||||
send_to_all(serialize_state());
|
||||
client->send(encode_message("server","Welcome, use the /alias command to set a name, /help for a list of other commands."));
|
||||
send_to_all(encode_message("server",m_connections[client]+" has joined the chat."));
|
||||
}
|
||||
|
||||
void chat_handler::disconnect(session_ptr client,uint16_t status,const std::string &reason) {
|
||||
std::map<session_ptr,std::string>::iterator it = m_connections.find(client);
|
||||
|
||||
if (it == m_connections.end()) {
|
||||
// this client has already disconnected, we can ignore this.
|
||||
// this happens during certain types of disconnect where there is a
|
||||
// deliberate "soft" disconnection preceeding the "hard" socket read
|
||||
// fail or disconnect ack message.
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "client " << client << " left the lobby." << std::endl;
|
||||
|
||||
m_connections.erase(it);
|
||||
|
||||
// send user list and signoff message to all clients
|
||||
send_to_all(serialize_state());
|
||||
send_to_all(encode_message("server",m_connections[client]+" has left the chat."));
|
||||
}
|
||||
|
||||
void chat_handler::message(session_ptr client,const std::string &msg) {
|
||||
std::cout << "message from client " << client << ": " << msg << std::endl;
|
||||
|
||||
|
||||
|
||||
// check for special command messages
|
||||
if (msg == "/help") {
|
||||
// print command list
|
||||
client->send(encode_message("server","avaliable commands:<br /> /help - show this help<br /> /alias foo - set alias to foo",false));
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg.substr(0,7) == "/alias ") {
|
||||
std::string response;
|
||||
std::string alias;
|
||||
|
||||
if (msg.size() == 7) {
|
||||
response = "You must enter an alias.";
|
||||
client->send(encode_message("server",response));
|
||||
return;
|
||||
} else {
|
||||
alias = msg.substr(7);
|
||||
}
|
||||
|
||||
// store alias
|
||||
response = m_connections[client] + " is now known as "+alias;
|
||||
|
||||
m_connections[client] = alias;
|
||||
|
||||
// set alias
|
||||
send_to_all(serialize_state());
|
||||
send_to_all(encode_message("server",response));
|
||||
return;
|
||||
}
|
||||
|
||||
// catch other slash commands
|
||||
if (msg[0] == '/') {
|
||||
client->send(encode_message("server","unrecognized command"));
|
||||
return;
|
||||
}
|
||||
|
||||
// create JSON message to send based on msg
|
||||
send_to_all(encode_message(m_connections[client],msg));
|
||||
}
|
||||
|
||||
// {"type":"participants","value":[<participant>,...]}
|
||||
std::string chat_handler::serialize_state() {
|
||||
std::stringstream s;
|
||||
|
||||
s << "{\"type\":\"participants\",\"value\":[";
|
||||
|
||||
std::map<session_ptr,std::string>::iterator it;
|
||||
|
||||
for (it = m_connections.begin(); it != m_connections.end(); it++) {
|
||||
s << "\"" << (*it).second << "\"";
|
||||
if (++it != m_connections.end()) {
|
||||
s << ",";
|
||||
}
|
||||
it--;
|
||||
}
|
||||
|
||||
s << "]}";
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
// {"type":"msg","sender":"<sender>","value":"<msg>" }
|
||||
std::string chat_handler::encode_message(std::string sender,std::string msg,bool escape) {
|
||||
std::stringstream s;
|
||||
|
||||
// escape JSON characters
|
||||
boost::algorithm::replace_all(msg,"\\","\\\\");
|
||||
boost::algorithm::replace_all(msg,"\"","\\\"");
|
||||
|
||||
// escape HTML characters
|
||||
if (escape) {
|
||||
boost::algorithm::replace_all(msg,"&","&");
|
||||
boost::algorithm::replace_all(msg,"<","<");
|
||||
boost::algorithm::replace_all(msg,">",">");
|
||||
}
|
||||
|
||||
s << "{\"type\":\"msg\",\"sender\":\"" << sender
|
||||
<< "\",\"value\":\"" << msg << "\"}";
|
||||
|
||||
return s.str();
|
||||
}
|
||||
|
||||
std::string chat_handler::get_con_id(session_ptr s) {
|
||||
std::stringstream endpoint;
|
||||
endpoint << s->socket().remote_endpoint();
|
||||
return endpoint.str();
|
||||
}
|
||||
|
||||
void chat_handler::send_to_all(std::string data) {
|
||||
std::map<session_ptr,std::string>::iterator it;
|
||||
for (it = m_connections.begin(); it != m_connections.end(); it++) {
|
||||
(*it).first->send(data);
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,7 @@
|
||||
// com.zaphoyd.websocketpp.chat protocol
|
||||
//
|
||||
// client messages:
|
||||
// alias [UTF8 text, 16 characters max]
|
||||
// msg [UTF8 text]
|
||||
//
|
||||
// server messages:
|
||||
@@ -39,9 +40,8 @@
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <websocketpp/websocket_connection_handler.hpp>
|
||||
#include "../../src/websocket_connection_handler.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -56,54 +56,25 @@ public:
|
||||
void validate(websocketpp::session_ptr client);
|
||||
|
||||
// add new connection to the lobby
|
||||
void connect(session_ptr client) {
|
||||
std::cout << "client " << client << " joined the lobby." << std::endl;
|
||||
m_connections.insert(client);
|
||||
|
||||
// send user list to all clients
|
||||
// send signon message from server to all other clients.
|
||||
|
||||
}
|
||||
void connect(websocketpp::session_ptr client);
|
||||
|
||||
// someone disconnected from the lobby, remove them
|
||||
void disconnect(websocketpp::session_ptr client,uint16_t status,const std::string &reason) {
|
||||
std::set<session_ptr>::iterator it = m_connections.find(client);
|
||||
|
||||
if (it == m_connections.end()) {
|
||||
// this client has already disconnected, we can ignore this.
|
||||
// this happens during certain types of disconnect where there is a
|
||||
// deliberate "soft" disconnection preceeding the "hard" socket read
|
||||
// fail or disconnect ack message.
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "client " << client << " left the lobby." << std::endl;
|
||||
|
||||
m_connections.erase(it);
|
||||
|
||||
// send signoff message from server to all clients
|
||||
// send user list to all remaining clients
|
||||
}
|
||||
void disconnect(websocketpp::session_ptr client,uint16_t status,const std::string &reason);
|
||||
|
||||
void message(websocketpp::session_ptr client,const std::string &msg) {
|
||||
std::cout << "message from client " << client << ": " << msg << std::endl;
|
||||
|
||||
// create JSON message to send based on msg
|
||||
|
||||
for (std::set<session_ptr>::iterator it = m_connections.begin();
|
||||
it != m_connections.end(); it++) {
|
||||
(*it)->send(msg);
|
||||
}
|
||||
}
|
||||
void message(websocketpp::session_ptr client,const std::string &msg);
|
||||
|
||||
// lobby will ignore binary messages
|
||||
void message(websocketpp::session_ptr client,
|
||||
const std::vector<unsigned char> &data) {}
|
||||
private:
|
||||
std::string serialize_state();
|
||||
|
||||
std::string encode_message(std::string sender,std::string msg,bool escape = true);
|
||||
std::string get_con_id(websocketpp::session_ptr s);
|
||||
|
||||
void send_to_all(std::string data);
|
||||
|
||||
// list of outstanding connections
|
||||
std::set<session_ptr> m_connections;
|
||||
std::map<websocketpp::session_ptr,std::string> m_connections;
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<chat_handler> chat_handler_ptr;
|
||||
|
||||
177
examples/chat_server/chat_client.html
Normal file
177
examples/chat_server/chat_client.html
Normal file
@@ -0,0 +1,177 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript" src="jquery-1.6.3.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="text/javascript">
|
||||
var ws;
|
||||
var url;
|
||||
|
||||
$(document).ready(init);
|
||||
|
||||
function init() {
|
||||
$(document).keypress(function(event) {
|
||||
if ( event.which == 13 ) {
|
||||
event.preventDefault();
|
||||
send();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function connect() {
|
||||
url = $("#server_url").val();
|
||||
console.log(url);
|
||||
|
||||
if ("WebSocket" in window) {
|
||||
ws = new WebSocket(url);
|
||||
} else if ("MozWebSocket" in window) {
|
||||
ws = new MozWebSocket(url);
|
||||
} else {
|
||||
chat_message("This Browser does not support WebSockets");
|
||||
return;
|
||||
}
|
||||
ws.onopen = function(e) {
|
||||
chat_message("A connection to "+url+" has been opened.");
|
||||
|
||||
$("#server_url").attr("disabled",true);
|
||||
$("#toggle_connect").html("Disconnect");
|
||||
};
|
||||
|
||||
ws.onerror = function(e) {
|
||||
chat_message("An error occured, see console log for more details.");
|
||||
console.log(e);
|
||||
};
|
||||
|
||||
ws.onclose = function(e) {
|
||||
chat_message("The connection to "+url+" was closed.");
|
||||
};
|
||||
|
||||
ws.onmessage = function(e) {
|
||||
var message = JSON.parse(e.data);
|
||||
|
||||
if (message.type == "msg") {
|
||||
chat_message(message.value,message.sender);
|
||||
} else if (message.type == "participants") {
|
||||
var o = "<ul>";
|
||||
for (var p in message.value) {
|
||||
o += "<li>"+message.value[p]+"</li>";
|
||||
}
|
||||
o += "</ul>";
|
||||
$("#participants").html(o);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function chat_message(message,sender) {
|
||||
if (arguments.length == 1) {
|
||||
sender = "";
|
||||
}
|
||||
|
||||
var style;
|
||||
|
||||
if (sender == "") {
|
||||
style = "client";
|
||||
} else if (sender == "server") {
|
||||
style = "server";
|
||||
sender = "["+sender+"]";
|
||||
} else {
|
||||
style = "message";
|
||||
sender = "["+sender+"]";
|
||||
}
|
||||
|
||||
$("#messages").append("<span class='"+style+"'><span class='sender'>"+sender+"</span> <span class='msg'>"+message+"</span></span><br />");
|
||||
$("#messages").prop({ scrollTop: $("#messages").prop("scrollHeight") });
|
||||
}
|
||||
|
||||
function disconnect() {
|
||||
ws.close();
|
||||
$("#server_url").removeAttr("disabled");
|
||||
$("#toggle_connect").html("Connect");
|
||||
$("#participants").html("");
|
||||
}
|
||||
|
||||
function toggle_connect() {
|
||||
if ($("#server_url").attr("disabled") != "disabled") {
|
||||
connect();
|
||||
} else {
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
function send() {
|
||||
if (ws === undefined || ws.readyState != 1) {
|
||||
chat_message("Websocket is not avaliable for writing");
|
||||
return;
|
||||
}
|
||||
|
||||
ws.send($("#msg").val());
|
||||
$("#msg").val("");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style>
|
||||
body,html {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
height: 100%;
|
||||
background-color: #999;
|
||||
font-family: sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
|
||||
}
|
||||
|
||||
#controls {
|
||||
padding: 4px;
|
||||
float:right;
|
||||
width: 300px;
|
||||
|
||||
}
|
||||
|
||||
input {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
#messages {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
#messages .client {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
#messages .server {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
#messages .message {
|
||||
color: white;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<div id="controls">
|
||||
<div id="server">
|
||||
<input type="text" name="server_url" id="server_url" value="ws://thor-websocket.zaphoyd.net:9000/chat" />
|
||||
<button id="toggle_connect" onclick="toggle_connect();">Connect</button>
|
||||
</div>
|
||||
|
||||
<div id="message_input"><input type="text" name="msg" id="msg" value="Hello World!" />
|
||||
<button onclick="send();">Send</button></div>
|
||||
<h3>Chat Participants</h3>
|
||||
<div id="participants"></div>
|
||||
</div>
|
||||
<div id="messages"></div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -35,8 +35,8 @@
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
std::string host = "localhost:5000";
|
||||
short port = 5000;
|
||||
std::string host = "localhost:9000";
|
||||
short port = 9000;
|
||||
|
||||
if (argc == 3) {
|
||||
// TODO: input validation?
|
||||
@@ -56,7 +56,7 @@ int main(int argc, char* argv[]) {
|
||||
tcp::endpoint endpoint(tcp::v6(), port);
|
||||
|
||||
websocketpp::server_ptr server(
|
||||
new websocketpp::server(io_service,endpoint,host,chat_handler)
|
||||
new websocketpp::server(io_service,endpoint,chat_handler)
|
||||
);
|
||||
|
||||
// setup server settings
|
||||
|
||||
4
examples/chat_server/jquery-1.6.3.min.js
vendored
Normal file
4
examples/chat_server/jquery-1.6.3.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user