1 module sockjs.server; 2 3 import std.stdio; 4 5 import vibe.d; 6 import sockjs.sockjs:SockJS; 7 import sockjs.connection; 8 import sockjs.sockjsSyntax; 9 10 /// 11 class SockJsException : Exception 12 { 13 /// 14 public this(string _s) 15 { 16 super(_s); 17 } 18 } 19 20 /// 21 public class Server 22 { 23 public: 24 25 /// 26 this(SockJS.Options _options) 27 { 28 m_options = _options; 29 } 30 31 /// 32 void handleRequest(HTTPServerRequest req, HTTPServerResponse res) 33 { 34 scope(failure) logCritical("handle request failed"); 35 36 auto url = req.requestURL; 37 38 if(url.length >= m_options.prefix.length) 39 { 40 if(url[0..m_options.prefix.length] == m_options.prefix) 41 { 42 munch(url, m_options.prefix); 43 44 string[] elements = url.split("/"); 45 46 string _body = cast(string)req.bodyReader.readAll(); 47 48 try handleSockJs(elements,_body,res,req.peer); 49 catch(SockJsException e) 50 { 51 logError("handleSockJs failed: %s",e); 52 53 res.statusCode = 404; 54 res.writeBody(""); 55 } 56 } 57 } 58 } 59 60 /// 61 alias void delegate(Connection) EventOnConnection; 62 63 /// 64 @property void onConnection(EventOnConnection _callback) { m_onConnection = _callback; } 65 66 /// 67 @property const(SockJS.Options)* options() const { return &m_options; } 68 69 private: 70 EventOnConnection m_onConnection; 71 SockJS.Options m_options; 72 Connection[string] m_connections; 73 74 /// 75 void handleSockJs(string[] _urlElements, string _body, HTTPServerResponse _res, string _remotePeer) 76 { 77 //writefln("handle: %s",_urlElements); 78 79 //TODO: cleanup 80 _res.headers["Access-Control-Allow-Origin"] = "http://localhost:8080"; 81 _res.headers["Access-Control-Allow-Credentials"] = "true"; 82 _res.headers["Connection"] = "keep-alive"; 83 _res.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0"; 84 85 if(_urlElements.length == 1 && _urlElements[0] == "info") 86 { 87 SockJsSyntax.writeInfo(_res); 88 } 89 else if(_urlElements.length == 3) 90 { 91 string serverId = _urlElements[0]; 92 string userId = _urlElements[1]; 93 string method = _urlElements[2]; 94 95 if(userId in m_connections) 96 { 97 auto conn = m_connections[userId]; 98 99 if(conn.isOpen) 100 conn.handleRequest(method == "xhr_send",_body,_res); 101 else 102 SockJsSyntax.writeClose(_res, conn.closeMsg); 103 } 104 else 105 { 106 if(method != "xhr") 107 throw new SockJsException("wrong connect method"); 108 else 109 { 110 auto newConn = new Connection(this, _remotePeer, userId); 111 112 m_onConnection(newConn); 113 114 m_connections[userId] = newConn; 115 116 //logInfo("[sockjs] new connection (count: %s)",m_connections.length); 117 118 SockJsSyntax.writeOpen(_res); 119 } 120 } 121 } 122 else 123 throw new SockJsException("wrong param count"); 124 } 125 126 /// 127 package void connectionClosed(Connection _conn) 128 { 129 130 if(_conn.userId in m_connections) 131 { 132 m_connections.remove(_conn.userId); 133 134 //logInfo("[sockjs] closed connection (count: %s)",m_connections.length); 135 } 136 137 _conn.destroy(); 138 } 139 }