├── TODO ├── .gitignore ├── samples ├── jetty │ ├── src │ │ ├── assemble │ │ │ └── distribution.xml │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── codeminders │ │ │ └── socketio │ │ │ └── sample │ │ │ └── jetty │ │ │ └── ChatServer.java │ └── pom.xml ├── tomcat │ ├── src │ │ ├── assemble │ │ │ └── distribution.xml │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── codeminders │ │ │ └── socketio │ │ │ └── sample │ │ │ └── tomcat │ │ │ └── ChatServer.java │ └── pom.xml ├── pom.xml └── chat │ ├── src │ └── main │ │ ├── webapp │ │ ├── META-INF │ │ │ └── context.xml │ │ ├── json.js │ │ ├── WEB-INF │ │ │ └── web.xml │ │ └── chat.html │ │ ├── resources │ │ └── log4j.xml │ │ └── java │ │ └── com │ │ └── codeminders │ │ └── socketio │ │ └── sample │ │ └── chat │ │ └── ChatSocketServlet.java │ └── pom.xml ├── licenses └── MIT ├── socket-io ├── src │ ├── main │ │ └── java │ │ │ └── com │ │ │ └── codeminders │ │ │ └── socketio │ │ │ ├── server │ │ │ ├── ACKListener.java │ │ │ ├── DisconnectListener.java │ │ │ ├── UnsupportedTransportException.java │ │ │ ├── SocketIOProtocolException.java │ │ │ ├── EventListener.java │ │ │ ├── transport │ │ │ │ ├── XHRPollingTransport.java │ │ │ │ ├── websocket │ │ │ │ │ ├── WebsocketTransportProvider.java │ │ │ │ │ ├── WebsocketConfigurator.java │ │ │ │ │ ├── ServletConfigHolder.java │ │ │ │ │ ├── SynchronizedWebsocketIO.java │ │ │ │ │ ├── WebsocketIOServlet.java │ │ │ │ │ ├── WebsocketIO.java │ │ │ │ │ ├── WebsocketTransport.java │ │ │ │ │ └── WebsocketTransportConnection.java │ │ │ │ ├── AbstractTransportProvider.java │ │ │ │ ├── AbstractTransport.java │ │ │ │ ├── JSONPPollingTransport.java │ │ │ │ ├── AbstractHttpTransport.java │ │ │ │ ├── AbstractTransportConnection.java │ │ │ │ └── XHRTransportConnection.java │ │ │ ├── ConnectionListener.java │ │ │ ├── SocketIOClosedException.java │ │ │ ├── ConnectionException.java │ │ │ ├── Outbound.java │ │ │ ├── TransportType.java │ │ │ ├── Config.java │ │ │ ├── TransportProvider.java │ │ │ ├── Transport.java │ │ │ ├── Room.java │ │ │ ├── TransportConnection.java │ │ │ ├── ServletBasedConfig.java │ │ │ ├── Namespace.java │ │ │ ├── SocketIOManager.java │ │ │ ├── Socket.java │ │ │ └── SocketIOServlet.java │ │ │ ├── common │ │ │ ├── SocketIOException.java │ │ │ ├── ConnectionState.java │ │ │ └── DisconnectReason.java │ │ │ └── protocol │ │ │ ├── BinaryPacket.java │ │ │ ├── ACKPacket.java │ │ │ ├── EventPacket.java │ │ │ ├── BinaryACKPacket.java │ │ │ ├── SocketIOPacket.java │ │ │ ├── BinaryEventPacket.java │ │ │ ├── EngineIOPacket.java │ │ │ └── EngineIOProtocol.java │ └── test │ │ └── java │ │ └── com │ │ └── codeminders │ │ └── socketio │ │ └── protocol │ │ └── EngineIOProtocolTest.java └── pom.xml ├── README.md └── pom.xml /TODO: -------------------------------------------------------------------------------- 1 | * handle b64 flag 2 | * JSONP polling transport (not sure how to test it) 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | syntax: glob 2 | *.cert 3 | *.crt 4 | *.key 5 | *.orig 6 | *.iml 7 | *.ipr 8 | *.iws 9 | *.swp 10 | bin 11 | build 12 | dist 13 | .git 14 | *~ 15 | .DS_Store 16 | .idea 17 | .settings 18 | .project 19 | .classpath 20 | war 21 | build.properties 22 | target 23 | com.codeminders.socketio.sample.gwtchat.GWTChat 24 | samples/chat-gwt/src/main/gwt-unitCache/ -------------------------------------------------------------------------------- /samples/jetty/src/assemble/distribution.xml: -------------------------------------------------------------------------------- 1 | 4 | standalone 5 | 6 | jar 7 | 8 | 9 | 10 | 11 | true 12 | 13 | 14 | -------------------------------------------------------------------------------- /samples/tomcat/src/assemble/distribution.xml: -------------------------------------------------------------------------------- 1 | 4 | standalone 5 | 6 | jar 7 | 8 | 9 | 10 | 11 | true 12 | 13 | 14 | -------------------------------------------------------------------------------- /samples/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 4.0.0 6 | 7 | 8 | com.codeminders.socketio 9 | socketio-parent 10 | 1.0.10 11 | 12 | 13 | socketio-sample 14 | pom 15 | 16 | Socket.IO Samples 17 | Socket.IO Java Samples 18 | 19 | 20 | chat 21 | jetty 22 | tomcat 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /licenses/MIT: -------------------------------------------------------------------------------- 1 | The MIT License 2 | Copyright (c) ${year} ${owner} 3 | 4 | Contributors: ${contributors} 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /samples/chat/src/main/webapp/META-INF/context.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /samples/chat/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 4.0.0 6 | 7 | 8 | com.codeminders.socketio 9 | socketio-sample 10 | 1.0.10 11 | 12 | 13 | socketio-sample-chat 14 | war 15 | 16 | Socket.IO Sample Chat 17 | ${project.name} 18 | 19 | 20 | 21 | com.codeminders.socketio 22 | socket-io 23 | 1.0.10 24 | 25 | 26 | 27 | 28 | 29 | 30 | org.apache.maven.plugins 31 | maven-war-plugin 32 | 2.1.1 33 | 34 | true 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/ACKListener.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.server; 24 | 25 | /** 26 | * @author Alexander Sova (bird@codeminders.com) 27 | */ 28 | public interface ACKListener 29 | { 30 | void onACK(Object[] args); 31 | } 32 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/DisconnectListener.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.server; 24 | 25 | import com.codeminders.socketio.common.DisconnectReason; 26 | 27 | /** 28 | * @author Alexander Sova (bird@codeminders.com) 29 | */ 30 | public interface DisconnectListener 31 | { 32 | void onDisconnect(Socket socket, DisconnectReason reason, String errorMessage); 33 | } 34 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/UnsupportedTransportException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.server; 24 | 25 | /** 26 | * @author Alexander Sova (bird@codeminders.com) 27 | */ 28 | public class UnsupportedTransportException extends Exception { 29 | 30 | public UnsupportedTransportException(String name) { 31 | super("Unsupported transport " + name); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/SocketIOProtocolException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.server; 24 | 25 | import com.codeminders.socketio.common.SocketIOException; 26 | 27 | /** 28 | * @author Alexander Sova (bird@codeminders.com) 29 | */ 30 | public class SocketIOProtocolException extends SocketIOException 31 | { 32 | 33 | public SocketIOProtocolException(String message) 34 | { 35 | super(message); 36 | } 37 | 38 | public SocketIOProtocolException(String message, Throwable cause) 39 | { 40 | super(message, cause); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/common/SocketIOException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2010 Tad Glines 4 | * 5 | * Contributors: Ovea.com, Mycila.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | package com.codeminders.socketio.common; 26 | 27 | import java.io.IOException; 28 | 29 | public class SocketIOException extends IOException { 30 | private static final long serialVersionUID = 1L; 31 | 32 | public SocketIOException() { 33 | super(); 34 | } 35 | 36 | public SocketIOException(String message) { 37 | super(message); 38 | } 39 | 40 | public SocketIOException(Throwable cause) { 41 | super(cause); 42 | } 43 | 44 | public SocketIOException(String message, Throwable cause) { super(message, cause); } 45 | } 46 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/EventListener.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.server; 24 | 25 | /** 26 | * @author Alexander Sova (bird@codeminders.com) 27 | */ 28 | public interface EventListener 29 | { 30 | /** 31 | * Called upon incoming event 32 | * 33 | * @param ackRequested true if client requested an acknowledgement 34 | * @param name event name 35 | * @param args event arguments 36 | * @return Object to send back to the caller as an acknowledgement, null if no ack to be sent 37 | */ 38 | Object onEvent(String name, Object[] args, boolean ackRequested); 39 | } 40 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/transport/XHRPollingTransport.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2010 Tad Glines 4 | * 5 | * Contributors: Ovea.com, Mycila.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | package com.codeminders.socketio.server.transport; 26 | 27 | import com.codeminders.socketio.server.TransportConnection; 28 | import com.codeminders.socketio.server.TransportType; 29 | 30 | public class XHRPollingTransport extends AbstractHttpTransport 31 | { 32 | @Override 33 | public TransportType getType() 34 | { 35 | return TransportType.XHR_POLLING; 36 | } 37 | 38 | @Override 39 | public TransportConnection createConnection() 40 | { 41 | return new XHRTransportConnection(this); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/transport/websocket/WebsocketTransportProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.server.transport.websocket; 24 | 25 | import com.codeminders.socketio.server.Transport; 26 | import com.codeminders.socketio.server.transport.AbstractTransportProvider; 27 | 28 | /** 29 | * @author Alexander Sova (bird@codeminders.com) 30 | */ 31 | public class WebsocketTransportProvider extends AbstractTransportProvider 32 | { 33 | static final Transport websocket = new WebsocketTransport(); 34 | 35 | @Override 36 | protected Transport createWebSocketTransport() 37 | { 38 | return websocket; 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/ConnectionListener.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.server; 24 | 25 | /** 26 | * @author Alexander Sova (bird@codeminders.com) 27 | */ 28 | public interface ConnectionListener 29 | { 30 | /** 31 | * Callback to be called on new connection 32 | * 33 | * @param socket new socket 34 | * @throws ConnectionException thrown if caller want to fail the connection 35 | * for some reason (e.g. authentication error). 36 | * The error message will be sent to the client 37 | */ 38 | void onConnect(Socket socket) throws ConnectionException; 39 | } 40 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/SocketIOClosedException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2010 Tad Glines 4 | * 5 | * Contributors: Ovea.com, Mycila.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | package com.codeminders.socketio.server; 26 | 27 | import com.codeminders.socketio.common.SocketIOException; 28 | 29 | public class SocketIOClosedException extends SocketIOException { 30 | private static final long serialVersionUID = 1L; 31 | 32 | public SocketIOClosedException() { 33 | 34 | } 35 | 36 | public SocketIOClosedException(String message) { 37 | super(message); 38 | } 39 | 40 | public SocketIOClosedException(String message, Throwable cause) { 41 | super(message, cause); 42 | } 43 | 44 | public SocketIOClosedException(Throwable cause) { 45 | super(cause); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /samples/chat/src/main/webapp/json.js: -------------------------------------------------------------------------------- 1 | if(!this.JSON){JSON=function(){function f(n){return n<10?'0'+n:n;} 2 | Date.prototype.toJSON=function(){return this.getUTCFullYear()+'-'+ 3 | f(this.getUTCMonth()+1)+'-'+ 4 | f(this.getUTCDate())+'T'+ 5 | f(this.getUTCHours())+':'+ 6 | f(this.getUTCMinutes())+':'+ 7 | f(this.getUTCSeconds())+'Z';};var m={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'};function stringify(value,whitelist){var a,i,k,l,r=/["\\\x00-\x1f\x7f-\x9f]/g,v;switch(typeof value){case'string':return r.test(value)?'"'+value.replace(r,function(a){var c=m[a];if(c){return c;} 8 | c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+ 9 | (c%16).toString(16);})+'"':'"'+value+'"';case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';} 10 | if(typeof value.toJSON==='function'){return stringify(value.toJSON());} 11 | a=[];if(typeof value.length==='number'&&!(value.propertyIsEnumerable('length'))){l=value.length;for(i=0;i 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.server; 24 | 25 | /** 26 | * @author Alexander Sova (bird@codeminders.com) 27 | */ 28 | public class ConnectionException extends Exception 29 | { 30 | private Object args; 31 | 32 | public Object getArgs() 33 | { 34 | return args; 35 | } 36 | 37 | public ConnectionException(String message, Throwable cause, Object args) 38 | { 39 | super(message, cause); 40 | this.args = args; 41 | } 42 | 43 | public ConnectionException(Throwable cause, Object args) 44 | { 45 | super(cause); 46 | this.args = args; 47 | } 48 | 49 | public ConnectionException(Object args) 50 | { 51 | this.args = args; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/transport/websocket/WebsocketConfigurator.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.server.transport.websocket; 24 | 25 | import javax.websocket.HandshakeResponse; 26 | import javax.websocket.server.HandshakeRequest; 27 | import javax.websocket.server.ServerEndpointConfig; 28 | 29 | /** 30 | * Adds handshake request information to user properties 31 | */ 32 | public class WebsocketConfigurator extends ServerEndpointConfig.Configurator 33 | { 34 | @Override 35 | public void modifyHandshake(ServerEndpointConfig config, 36 | HandshakeRequest request, 37 | HandshakeResponse response) 38 | { 39 | config.getUserProperties().put(HandshakeRequest.class.getName(), request); 40 | } 41 | } -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/Outbound.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.server; 24 | 25 | import com.codeminders.socketio.common.SocketIOException; 26 | 27 | public interface Outbound 28 | { 29 | /** 30 | * Emits an event to the socket identified by the string name. 31 | * 32 | * @param name event name 33 | * @param args list of arguments. Arguments can contain any type of field that can result of JSON decoding, 34 | * including objects and arrays of arbitrary size. If last argument is {@code ACKListener} 35 | * then this listener to be called upon ACK arriving 36 | * @throws SocketIOException if IO or protocol error happens 37 | */ 38 | 39 | void emit(String name, Object... args) throws SocketIOException; 40 | } 41 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/transport/websocket/ServletConfigHolder.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.server.transport.websocket; 24 | 25 | import javax.servlet.ServletConfig; 26 | 27 | /** 28 | * @author Alex Saveliev (lyolik@codeminders.com) 29 | */ 30 | public final class ServletConfigHolder 31 | { 32 | private ServletConfig config; 33 | 34 | private static ServletConfigHolder instance = new ServletConfigHolder(); 35 | 36 | private ServletConfigHolder() { 37 | } 38 | 39 | public static ServletConfigHolder getInstance() { 40 | return instance; 41 | } 42 | 43 | public void setConfig(ServletConfig config) { 44 | this.config = config; 45 | } 46 | 47 | public ServletConfig getConfig() { 48 | return this.config; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/protocol/BinaryPacket.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.protocol; 24 | 25 | import java.io.InputStream; 26 | import java.util.Collection; 27 | 28 | /** 29 | * @author Alexander Sova (bird@codeminders.com) 30 | */ 31 | public interface BinaryPacket 32 | { 33 | Collection getAttachments(); 34 | 35 | /** 36 | * @return true when all expected attachment arrived, false otherwise 37 | */ 38 | boolean isComplete(); 39 | 40 | /** 41 | * This method to be called when new attachement arrives to the socket 42 | * 43 | * @param attachment new attachment 44 | */ 45 | void addAttachment(InputStream attachment); 46 | 47 | SocketIOPacket.Type getType(); 48 | 49 | Object[] getArgs(); 50 | 51 | void setArgs(Object[] args); 52 | } 53 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/transport/websocket/SynchronizedWebsocketIO.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2018 Alex Saveliev (lyolik@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.server.transport.websocket; 24 | 25 | import java.io.IOException; 26 | 27 | /** 28 | * @author Alex Saveliev (lyolik@codeminders.com) 29 | */ 30 | public class SynchronizedWebsocketIO extends WebsocketIO { 31 | 32 | public SynchronizedWebsocketIO(javax.websocket.Session remoteEndpoint) { 33 | super(remoteEndpoint); 34 | } 35 | 36 | public synchronized void sendString(String data) throws IOException { 37 | super.sendString(data); 38 | } 39 | 40 | public synchronized void sendBinary(byte[] data) throws IOException { 41 | super.sendBinary(data); 42 | } 43 | 44 | public void disconnect() throws IOException { 45 | remoteEndpoint.close(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /samples/chat/src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 31 | 32 | 33 | ChatSocketServlet 34 | com.codeminders.socketio.sample.chat.ChatSocketServlet 35 | 36 | 37 | 38 | ChatSocketServlet 39 | /socket.io/* 40 | 41 | 42 | 43 | chat.html 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/protocol/ACKPacket.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.protocol; 24 | 25 | import com.codeminders.socketio.server.SocketIOProtocolException; 26 | 27 | /** 28 | * @author Alexander Sova (bird@codeminders.com) 29 | */ 30 | public abstract class ACKPacket extends SocketIOPacket 31 | { 32 | private Object[] args; 33 | 34 | public ACKPacket(Type type, int id, String ns, Object[] args) 35 | { 36 | super(type, id, ns); 37 | this.args = args; 38 | } 39 | 40 | @Override 41 | protected String encodeArgs() throws SocketIOProtocolException 42 | { 43 | return SocketIOProtocol.toJSON(args); 44 | } 45 | 46 | public Object[] getArgs() 47 | { 48 | return args; 49 | } 50 | 51 | public void setArgs(Object[] args) 52 | { 53 | this.args = args; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/TransportType.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2010 Tad Glines 4 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 5 | * 6 | * Contributors: Ovea.com, Mycila.com 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.codeminders.socketio.server; 27 | 28 | public enum TransportType 29 | { 30 | 31 | WEB_SOCKET("websocket"), 32 | FLASH_SOCKET("flashsocket"), 33 | JSONP_POLLING("jsonp-polling"), 34 | XHR_POLLING("xhr-polling"), 35 | UNKNOWN(""); 36 | 37 | private final String name; 38 | 39 | TransportType(String name) 40 | { 41 | this.name = name; 42 | } 43 | 44 | @Override 45 | public String toString() 46 | { 47 | return name; 48 | } 49 | 50 | public static TransportType from(String name) 51 | { 52 | for (TransportType type : values()) 53 | { 54 | if (type.name.equals(name)) 55 | return type; 56 | } 57 | return UNKNOWN; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/transport/websocket/WebsocketIOServlet.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.server.transport.websocket; 24 | 25 | import com.codeminders.socketio.server.SocketIOServlet; 26 | import com.codeminders.socketio.server.TransportProvider; 27 | 28 | import javax.servlet.ServletConfig; 29 | import javax.servlet.ServletException; 30 | 31 | /** 32 | * @author Alexander Sova (bird@codeminders.com) 33 | */ 34 | public abstract class WebsocketIOServlet extends SocketIOServlet 35 | { 36 | @Override 37 | public void init(ServletConfig config) throws ServletException 38 | { 39 | super.init(config); 40 | ServletConfigHolder.getInstance().setConfig(config); 41 | TransportProvider transportProvider = new WebsocketTransportProvider(); 42 | transportProvider.init(config, getServletContext()); 43 | setTransportProvider(transportProvider); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /socket-io/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 4.0.0 6 | 7 | 8 | 9 | org.apache.maven.plugins 10 | maven-compiler-plugin 11 | 12 | 1.7 13 | 1.7 14 | 15 | 16 | 17 | 18 | 19 | 20 | com.codeminders.socketio 21 | socketio-parent 22 | 1.0.10 23 | 24 | 25 | socket-io 26 | jar 27 | 28 | Socket.IO Java 29 | Socket.IO server classes 30 | 31 | 32 | 33 | com.fasterxml.jackson.core 34 | jackson-core 35 | 2.9.1 36 | 37 | 38 | com.fasterxml.jackson.core 39 | jackson-databind 40 | 2.9.1 41 | 42 | 43 | javax.websocket 44 | javax.websocket-api 45 | 1.1 46 | provided 47 | 48 | 49 | junit 50 | junit 51 | 4.10 52 | test 53 | 54 | 55 | org.assertj 56 | assertj-core 57 | 3.10.0 58 | test 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/transport/websocket/WebsocketIO.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2018 Alex Saveliev (lyolik@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.server.transport.websocket; 24 | 25 | import java.io.IOException; 26 | import java.nio.ByteBuffer; 27 | 28 | /** 29 | * @author Alex Saveliev (lyolik@codeminders.com) 30 | */ 31 | public class WebsocketIO { 32 | 33 | protected javax.websocket.Session remoteEndpoint; 34 | 35 | public WebsocketIO(javax.websocket.Session remoteEndpoint) { 36 | this.remoteEndpoint = remoteEndpoint; 37 | } 38 | 39 | public void sendString(String data) throws IOException { 40 | remoteEndpoint.getBasicRemote().sendText(data); 41 | } 42 | 43 | //TODO: implement streaming. right now it is all in memory. 44 | //TODO: read and send in chunks using sendPartialBytes() 45 | public void sendBinary(byte[] data) throws IOException { 46 | remoteEndpoint.getBasicRemote().sendBinary(ByteBuffer.wrap(data)); 47 | } 48 | 49 | public void disconnect() throws IOException { 50 | remoteEndpoint.close(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/Config.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2010 Tad Glines 4 | * 5 | * Contributors: Ovea.com, Mycila.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | package com.codeminders.socketio.server; 26 | 27 | /** 28 | * @author Mathieu Carbou 29 | */ 30 | public interface Config 31 | { 32 | String MAX_TEXT_MESSAGE_SIZE = "maxTextMessageSize"; 33 | String PING_INTERVAL = "pingInterval"; 34 | String TIMEOUT = "timeout"; 35 | 36 | String BUFFER_SIZE = "bufferSize"; 37 | String MAX_IDLE = "maxIdleTime"; 38 | 39 | int DEFAULT_BUFFER_SIZE = 8192; 40 | int DEFAULT_MAX_IDLE = 300 * 1000; 41 | 42 | int DEFAULT_PING_INTERVAL = 25 * 1000; // 25s 43 | int DEFAULT_PING_TIMEOUT = 60 * 1000; // 60s 44 | 45 | long getPingInterval(long def); 46 | 47 | long getTimeout(long def); 48 | 49 | int getBufferSize(); 50 | 51 | int getMaxIdle(); 52 | 53 | String getString(String key); 54 | 55 | String getString(String key, String def); 56 | 57 | int getInt(String key, int def); 58 | 59 | long getLong(String key, long def); 60 | 61 | boolean getBoolean(String key, boolean def); 62 | 63 | String getNamespace(); 64 | } 65 | -------------------------------------------------------------------------------- /socket-io/src/test/java/com/codeminders/socketio/protocol/EngineIOProtocolTest.java: -------------------------------------------------------------------------------- 1 | package com.codeminders.socketio.protocol; 2 | 3 | import com.codeminders.socketio.server.SocketIOProtocolException; 4 | import org.junit.Test; 5 | 6 | import java.io.ByteArrayInputStream; 7 | import java.io.ByteArrayOutputStream; 8 | import java.io.IOException; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | import static org.assertj.core.api.Assertions.assertThat; 13 | 14 | public class EngineIOProtocolTest { 15 | @Test 16 | public void decodeMultiPayload() 17 | throws SocketIOProtocolException, StringIndexOutOfBoundsException 18 | { 19 | String payload = "10:40/stream,1:227:42/stream,[\"SET_STREAM_ID\"]1:1"; 20 | List expected = new ArrayList<>(); 21 | expected.add(new EngineIOPacket(EngineIOPacket.Type.MESSAGE, "0/stream,")); 22 | expected.add(new EngineIOPacket(EngineIOPacket.Type.PING, "")); 23 | expected.add(new EngineIOPacket(EngineIOPacket.Type.MESSAGE, "2/stream,[\"SET_STREAM_ID\"]")); 24 | expected.add(new EngineIOPacket(EngineIOPacket.Type.CLOSE, "")); 25 | 26 | List result = EngineIOProtocol.decodePayload(payload); 27 | assertThat(result).isEqualTo(expected); 28 | } 29 | 30 | @Test 31 | public void decodeSimplePayload() 32 | throws SocketIOProtocolException 33 | { 34 | String payload = "10:40/stream,"; 35 | List expected = new ArrayList<>(); 36 | expected.add(new EngineIOPacket(EngineIOPacket.Type.MESSAGE, "0/stream,")); 37 | 38 | List result = EngineIOProtocol.decodePayload(payload); 39 | assertThat(result).isEqualTo(expected); 40 | } 41 | 42 | 43 | @Test 44 | public void binaryEncode_unicodeStrings() 45 | throws IOException 46 | { 47 | final EngineIOPacket packet = new EngineIOPacket(EngineIOPacket.Type.MESSAGE, "Привет!"); 48 | 49 | final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 50 | EngineIOProtocol.binaryEncode(packet, baos); 51 | 52 | List result = EngineIOProtocol.binaryDecodePayload(new ByteArrayInputStream(baos.toByteArray())); 53 | assertThat(result).hasSize(1); 54 | assertThat(result.get(0)).isEqualTo(packet); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Java backend for `Socket.IO` library (http://socket.io/) 2 | 3 | Supports `Socket.IO` clients version 1.0+ 4 | Requires JSR 356-compatible server (tested with Jetty 9 and Tomcat 8) 5 | 6 | Right now only websocket and XHR polling transports are implemented. 7 | 8 | Based on https://github.com/tadglines/Socket.IO-Java 9 | 10 | License: MIT 11 | 12 | ## Websocket endpoint initialization in Jetty 13 | 14 | Default websocket endpoint configuration assumes it's located in the root context and accessible via `/socket.io/` path. 15 | 16 | When `Socket.IO` backend is integrated into webapp managed by Jetty there is no need to perform additional configuration because Jetty scans for `@ServerEndpoint` annotation and initializes websocket endpoint automatically. 17 | 18 | When Jetty server is embedded into your application, websocket endpoint is located in the root context ("/") and expected to be accessible via `/socket.io/` path (default configuration), then in order to initialize endpoint you should add the following code 19 | 20 | ```java 21 | WebSocketServerContainerInitializer. 22 | configureContext(context). 23 | addEndpoint(WebsocketTransportConnection.class); 24 | 25 | ``` 26 | 27 | When Jetty server is embedded into your application, but websocket endpoint is either located not in the root context ("/") or expected to be accessible via path other than `/socket.io/`, then in order to initialize endpoint you should add the following code 28 | 29 | ```java 30 | ServerContainer serverContainer = WebSocketServerContainerInitializer. 31 | configureContext(context); 32 | serverContainer. 33 | addEndpoint(new AnnotatedServerEndpointConfig(serverContainer, 34 | WebsocketTransportConnection.class, 35 | WebsocketTransportConnection.class.getAnnotation(ServerEndpoint.class), 36 | null) { 37 | @Override 38 | public String getPath() { 39 | return "/"; // context-relative path, "/bar" for context "/foo" and path "/foo/bar" 40 | } 41 | }); 42 | ``` 43 | See example in [com.codeminders.socketio.sample.jetty.ChatServer](https://github.com/codeminders/socket.io-server-java/blob/master/samples/jetty/src/main/java/com/codeminders/socketio/sample/jetty/ChatServer.java) 44 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/common/DisconnectReason.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2010 Tad Glines 4 | * 5 | * Contributors: Ovea.com, Mycila.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | package com.codeminders.socketio.common; 26 | 27 | public enum DisconnectReason { 28 | UNKNOWN(-1), 29 | CONNECT_FAILED(1), // A connection attempt failed. 30 | DISCONNECT(2), // Disconnect was called explicitly. 31 | TIMEOUT(3), // A timeout occurred. 32 | CLOSE_FAILED(4), // The connection dropped before an orderly close could complete. 33 | ERROR(5), // A GET or POST returned an error, or an internal error occurred. 34 | CLOSED_REMOTELY(6), // Remote end point initiated a close. 35 | CLIENT_GONE(7), // Remote end point gone away (browser closed or navigated away) 36 | CLOSED(8); // Locally initiated close succeeded. 37 | 38 | private int value; 39 | 40 | DisconnectReason(int v) { this.value = v; } 41 | 42 | public int value() { return value; } 43 | 44 | public static DisconnectReason fromInt(int val) { 45 | switch (val) { 46 | case 1: 47 | return CONNECT_FAILED; 48 | case 2: 49 | return DISCONNECT; 50 | case 3: 51 | return TIMEOUT; 52 | case 4: 53 | return CLOSE_FAILED; 54 | case 5: 55 | return ERROR; 56 | case 6: 57 | return CLOSED_REMOTELY; 58 | case 7: 59 | return CLOSED; 60 | default: 61 | return UNKNOWN; 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/protocol/EventPacket.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.protocol; 24 | 25 | import com.codeminders.socketio.server.SocketIOProtocolException; 26 | 27 | import java.util.ArrayList; 28 | import java.util.Arrays; 29 | 30 | /** 31 | * @author Alexander Sova (bird@codeminders.com) 32 | */ 33 | public abstract class EventPacket extends SocketIOPacket 34 | { 35 | private String name; 36 | private Object[] args; 37 | 38 | protected EventPacket(Type type, int id, String ns, String name, Object[] args) 39 | { 40 | super(type, id, ns); 41 | this.name = name; 42 | this.args = args; 43 | } 44 | 45 | public String getName() 46 | { 47 | return name; 48 | } 49 | 50 | public Object[] getArgs() 51 | { 52 | return args; 53 | } 54 | 55 | public void setArgs(Object[] args) 56 | { 57 | this.args = args; 58 | } 59 | 60 | @Override 61 | protected String encodeArgs() throws SocketIOProtocolException 62 | { 63 | // adding name of the event as a first argument 64 | ArrayList data = new ArrayList<>(); 65 | data.add(getName()); 66 | data.addAll(Arrays.asList(getArgs())); 67 | 68 | return SocketIOProtocol.toJSON(data.toArray()); 69 | } 70 | } 71 | 72 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/TransportProvider.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.server; 24 | 25 | import javax.servlet.ServletConfig; 26 | import javax.servlet.ServletContext; 27 | import javax.servlet.ServletException; 28 | import javax.servlet.ServletRequest; 29 | import java.util.Collection; 30 | 31 | /** 32 | * Transport factory 33 | * 34 | * @author Alexander Sova (bird@codeminders.com) 35 | */ 36 | public interface TransportProvider { 37 | 38 | /** 39 | * Creates all the transports 40 | * 41 | * @param config servlet configuration 42 | * @param context servlet context 43 | * @throws ServletException if init failed 44 | */ 45 | void init(ServletConfig config, ServletContext context) 46 | throws ServletException; 47 | void destroy(); 48 | 49 | /** 50 | * Finds appropriate Transport class based on the rules defined at 51 | * https://github.com/socketio/engine.io-protocol#transports 52 | * 53 | * @param request incoming servlet request 54 | * @return appropriate Transport object 55 | * @throws UnsupportedTransportException no transport was found 56 | * @throws SocketIOProtocolException invalid request was sent 57 | */ 58 | Transport getTransport(ServletRequest request) 59 | throws UnsupportedTransportException, SocketIOProtocolException; 60 | 61 | Transport getTransport(TransportType type); 62 | Collection getTransports(); 63 | } 64 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/Transport.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2010 Tad Glines 4 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 5 | *

6 | * Contributors: Ovea.com, Mycila.com 7 | *

8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | *

15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | *

18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.codeminders.socketio.server; 27 | 28 | import javax.servlet.ServletConfig; 29 | import javax.servlet.ServletContext; 30 | import javax.servlet.ServletException; 31 | import javax.servlet.http.HttpServletRequest; 32 | import javax.servlet.http.HttpServletResponse; 33 | import java.io.IOException; 34 | 35 | public interface Transport 36 | { 37 | /** 38 | * @return The name of the transport. 39 | */ 40 | TransportType getType(); 41 | 42 | /** 43 | * Initializes the transport 44 | * 45 | * @param config Servlet config 46 | * @param context Servlet context 47 | * @throws ServletException if init fails 48 | */ 49 | void init(ServletConfig config, ServletContext context) 50 | throws ServletException; 51 | 52 | void destroy(); 53 | 54 | /** 55 | * Handles incoming HTTP request 56 | * 57 | * @param request object that contains the request the client made of the servlet 58 | * @param response object that contains the response the servlet returns to the client 59 | * @param socketIOManager session manager 60 | * @throws IOException if an input or output error occurs while the servlet is handling the request 61 | */ 62 | void handle(HttpServletRequest request, 63 | HttpServletResponse response, 64 | SocketIOManager socketIOManager) throws IOException; 65 | 66 | /** 67 | * Creates new connection 68 | * 69 | * @return new transport connection 70 | */ 71 | TransportConnection createConnection(); 72 | } 73 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/Room.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.server; 24 | 25 | import com.codeminders.socketio.common.SocketIOException; 26 | 27 | import java.util.Deque; 28 | import java.util.concurrent.ConcurrentLinkedDeque; 29 | 30 | /** 31 | * @author Alexander Sova (bird@codeminders.com) 32 | */ 33 | public class Room implements Outbound 34 | { 35 | private String id; 36 | private Deque sockets = new ConcurrentLinkedDeque<>(); 37 | 38 | Room(String id) 39 | { 40 | this.id = id; 41 | } 42 | 43 | public String getId() 44 | { 45 | return id; 46 | } 47 | 48 | @Override 49 | public void emit(String name, Object... args) throws SocketIOException 50 | { 51 | for(Socket s : sockets) 52 | { 53 | try 54 | { 55 | s.emit(name, args); 56 | } 57 | catch (SocketIOException e) 58 | { 59 | // ignore for now 60 | // TODO: add getLastError method? 61 | } 62 | } 63 | } 64 | 65 | public void join(Socket socket) 66 | { 67 | sockets.add(socket); 68 | } 69 | 70 | public void leave(Socket socket) 71 | { 72 | sockets.remove(socket); 73 | } 74 | 75 | public boolean contains(Socket socket) 76 | { 77 | return sockets.contains(socket); 78 | } 79 | 80 | public void broadcast(Socket sender, String name, Object... args) 81 | throws SocketIOException 82 | { 83 | for (Socket socket: sockets) 84 | { 85 | if (socket != sender) 86 | socket.emit(name, args); 87 | } 88 | } 89 | 90 | public Iterable getSockets() 91 | { 92 | return sockets; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/TransportConnection.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2010 Tad Glines 4 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 5 | * 6 | * Contributors: Ovea.com, Mycila.com 7 | * 8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | * 15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | * 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.codeminders.socketio.server; 27 | 28 | import com.codeminders.socketio.common.SocketIOException; 29 | import com.codeminders.socketio.protocol.EngineIOPacket; 30 | import com.codeminders.socketio.protocol.SocketIOPacket; 31 | 32 | import javax.servlet.http.HttpServletRequest; 33 | import javax.servlet.http.HttpServletResponse; 34 | import java.io.IOException; 35 | 36 | /** 37 | * @author Mathieu Carbou 38 | * @author Alexander Sova (bird@codeminders.com) 39 | */ 40 | public interface TransportConnection 41 | { 42 | void init(Config config); 43 | void setSession(Session session); 44 | Session getSession(); 45 | Transport getTransport(); 46 | 47 | void handle(HttpServletRequest request, HttpServletResponse response) 48 | throws IOException; 49 | 50 | /** 51 | * Tears down the connection. 52 | */ 53 | void abort(); 54 | 55 | void send(EngineIOPacket packet) throws SocketIOException; 56 | void send(SocketIOPacket packet) throws SocketIOException; 57 | 58 | void disconnect(String namespace, boolean closeConnection); 59 | 60 | /** 61 | * Emits an event to the socket identified by the string name. 62 | * 63 | * @param namespace namespace 64 | * @param name event name 65 | * @param args list of arguments. Arguments can contain any type of field that can result of JSON decoding, 66 | * including objects and arrays of arbitrary size. 67 | * @throws SocketIOException if IO or protocol error happens 68 | */ 69 | 70 | void emit(String namespace, String name, Object... args) throws SocketIOException; 71 | 72 | /** 73 | * @return current HTTP request, null if connection is disconnected 74 | */ 75 | HttpServletRequest getRequest(); 76 | } 77 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/protocol/BinaryACKPacket.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.protocol; 24 | 25 | import java.io.InputStream; 26 | import java.util.ArrayList; 27 | import java.util.Collection; 28 | import java.util.LinkedList; 29 | import java.util.List; 30 | 31 | /** 32 | * @author Alexander Sova (bird@codeminders.com) 33 | */ 34 | public class BinaryACKPacket extends ACKPacket implements BinaryPacket 35 | { 36 | private List attachments; 37 | private int number_attachments_expected; 38 | 39 | public BinaryACKPacket(int id, String ns, Object[] args) 40 | { 41 | super(Type.BINARY_ACK, id, ns, null); 42 | 43 | attachments = new LinkedList<>(); 44 | 45 | setArgs((Object[])SocketIOProtocol.extractBinaryObjects(args, attachments)); 46 | } 47 | 48 | public BinaryACKPacket(int id, String ns, Object[] args, int number_attachments_expected) 49 | { 50 | super(Type.BINARY_ACK, id, ns, args); 51 | 52 | this.number_attachments_expected = number_attachments_expected; 53 | this.attachments = new ArrayList<>(number_attachments_expected); 54 | } 55 | 56 | @Override 57 | protected String encodeAttachments() 58 | { 59 | return SocketIOProtocol.encodeAttachments(attachments.size()); 60 | } 61 | 62 | public Collection getAttachments() 63 | { 64 | return attachments; 65 | } 66 | 67 | /** 68 | * @return true when all expected attachment arrived, false otherwise 69 | */ 70 | public boolean isComplete() 71 | { 72 | return number_attachments_expected == 0; 73 | } 74 | 75 | /** 76 | * This method to be called when new attachement arrives to the socket 77 | * 78 | * @param attachment new attachment 79 | */ 80 | public void addAttachment(InputStream attachment) 81 | { 82 | attachments.add(attachment); 83 | number_attachments_expected -= 1; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /samples/chat/src/main/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/transport/websocket/WebsocketTransport.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2010 Tad Glines 4 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 5 | *

6 | * Contributors: Ovea.com, Mycila.com 7 | *

8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | *

15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | *

18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.codeminders.socketio.server.transport.websocket; 27 | 28 | import com.codeminders.socketio.server.SocketIOManager; 29 | import com.codeminders.socketio.server.TransportConnection; 30 | import com.codeminders.socketio.server.TransportType; 31 | import com.codeminders.socketio.server.transport.AbstractTransport; 32 | import com.codeminders.socketio.server.transport.AbstractTransportConnection; 33 | 34 | import javax.servlet.http.HttpServletRequest; 35 | import javax.servlet.http.HttpServletResponse; 36 | import java.io.IOException; 37 | import java.util.logging.Logger; 38 | 39 | public final class WebsocketTransport extends AbstractTransport 40 | { 41 | private static final Logger LOGGER = Logger.getLogger(WebsocketTransport.class.getName()); 42 | 43 | @Override 44 | public TransportType getType() 45 | { 46 | return TransportType.WEB_SOCKET; 47 | } 48 | 49 | @Override 50 | public void handle(HttpServletRequest request, 51 | HttpServletResponse response, 52 | SocketIOManager sessionManager) throws IOException 53 | { 54 | 55 | if(!"GET".equals(request.getMethod())) 56 | { 57 | response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, 58 | "Only GET method is allowed for websocket transport"); 59 | return; 60 | } 61 | 62 | if (request.getHeader("Sec-WebSocket-Key") == null) { 63 | 64 | response.sendError(HttpServletResponse.SC_BAD_REQUEST, 65 | "Missing request header 'Sec-WebSocket-Key'"); 66 | return; 67 | } 68 | 69 | final TransportConnection connection = getConnection(request, sessionManager); 70 | 71 | // a bit hacky but safe since we know the type of TransportConnection here 72 | ((AbstractTransportConnection)connection).setRequest(request); 73 | } 74 | 75 | @Override 76 | public TransportConnection createConnection() 77 | { 78 | return new WebsocketTransportConnection(this); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/transport/AbstractTransportProvider.java: -------------------------------------------------------------------------------- 1 | package com.codeminders.socketio.server.transport; 2 | 3 | import com.codeminders.socketio.protocol.EngineIOProtocol; 4 | import com.codeminders.socketio.server.*; 5 | 6 | import javax.servlet.ServletConfig; 7 | import javax.servlet.ServletContext; 8 | import javax.servlet.ServletException; 9 | import javax.servlet.ServletRequest; 10 | import java.util.*; 11 | import java.util.logging.Logger; 12 | 13 | /** 14 | * @author Alexander Sova (bird@codeminders.com) 15 | */ 16 | public abstract class AbstractTransportProvider implements TransportProvider { 17 | 18 | private static final Logger LOGGER = Logger.getLogger(AbstractTransportProvider.class.getName()); 19 | 20 | protected Map transports = new EnumMap<>(TransportType.class); 21 | 22 | /** 23 | * Creates and initializes all available transports 24 | */ 25 | @Override 26 | public void init(ServletConfig config, ServletContext context) 27 | throws ServletException 28 | { 29 | addIfNotNull(TransportType.XHR_POLLING, createXHRPollingTransport()); 30 | addIfNotNull(TransportType.JSONP_POLLING, createJSONPPollingTransport()); 31 | addIfNotNull(TransportType.WEB_SOCKET, createWebSocketTransport()); 32 | 33 | for(Transport t : transports.values()) 34 | t.init(config, context); 35 | } 36 | 37 | @Override 38 | public void destroy() 39 | { 40 | for (Transport t : getTransports()) 41 | t.destroy(); 42 | } 43 | 44 | @Override 45 | public Transport getTransport(ServletRequest request) 46 | throws UnsupportedTransportException, SocketIOProtocolException 47 | { 48 | String transportName = request.getParameter(EngineIOProtocol.TRANSPORT); 49 | if(transportName == null) 50 | throw new SocketIOProtocolException("Missing transport parameter"); 51 | 52 | TransportType type = TransportType.UNKNOWN; 53 | 54 | if("websocket".equals(transportName)) 55 | type = TransportType.from(transportName); 56 | 57 | if("polling".equals(transportName)) { 58 | if(request.getParameter(EngineIOProtocol.JSONP_INDEX) != null) 59 | type = TransportType.JSONP_POLLING; 60 | else 61 | type = TransportType.XHR_POLLING; 62 | } 63 | 64 | Transport t = transports.get(type); 65 | if(t == null) 66 | throw new UnsupportedTransportException(transportName); 67 | 68 | return t; 69 | } 70 | 71 | @Override 72 | public Transport getTransport(TransportType type) 73 | { 74 | return transports.get(type); 75 | } 76 | 77 | @Override 78 | public Collection getTransports() 79 | { 80 | return transports.values(); 81 | } 82 | 83 | protected Transport createXHRPollingTransport() 84 | { 85 | return new XHRPollingTransport(); 86 | } 87 | 88 | protected Transport createJSONPPollingTransport() 89 | { 90 | return null; 91 | } 92 | 93 | protected Transport createWebSocketTransport() 94 | { 95 | return null; 96 | } 97 | 98 | private void addIfNotNull(TransportType type, Transport transport) 99 | { 100 | if(transport != null) 101 | transports.put(type, transport); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /samples/tomcat/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 4.0.0 6 | 7 | 8 | com.codeminders.socketio 9 | socketio-sample 10 | 1.0.10 11 | 12 | 13 | socketio-sample-chat-tomcat 14 | 15 | Socket.IO Sample Chat With Embedded Tomcat 16 | 17 | 18 | 8.5.15 19 | 20 | 21 | 22 | 23 | 24 | javax.servlet 25 | javax.servlet-api 26 | 3.1.0 27 | 28 | 29 | javax.websocket 30 | javax.websocket-api 31 | 1.1 32 | 33 | 34 | com.codeminders.socketio 35 | socketio-sample-chat 36 | 1.0.10 37 | classes 38 | 39 | 40 | org.apache.tomcat.embed 41 | tomcat-embed-core 42 | ${tomcat.version} 43 | 44 | 45 | org.apache.tomcat.embed 46 | tomcat-embed-websocket 47 | ${tomcat.version} 48 | 49 | 50 | 51 | 52 | 53 | 54 | src/main/resources 55 | 56 | 57 | src/main/webapp 58 | 59 | 60 | ../chat/src/main/resources 61 | 62 | 63 | ../chat/src/main/webapp 64 | 65 | 66 | 67 | 68 | org.apache.maven.plugins 69 | maven-assembly-plugin 70 | 2.4 71 | 72 | 73 | src/assemble/distribution.xml 74 | 75 | 76 | 77 | com.codeminders.socketio.sample.tomcat.ChatServer 78 | 79 | 80 | 81 | 82 | 83 | package 84 | 85 | single 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/transport/AbstractTransport.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.server.transport; 24 | 25 | import com.codeminders.socketio.protocol.EngineIOProtocol; 26 | import com.codeminders.socketio.server.*; 27 | 28 | import javax.servlet.ServletConfig; 29 | import javax.servlet.ServletContext; 30 | import javax.servlet.ServletException; 31 | import javax.servlet.http.HttpServletRequest; 32 | import javax.servlet.http.HttpSession; 33 | 34 | /** 35 | * @author Alexander Sova (bird@codeminders.com) 36 | * @author Mathieu Carbou 37 | */ 38 | public abstract class AbstractTransport implements Transport 39 | { 40 | private Config config; 41 | 42 | @Override 43 | public void destroy() 44 | { 45 | } 46 | 47 | @Override 48 | public void init(ServletConfig config, ServletContext context) 49 | throws ServletException 50 | { 51 | this.config = new ServletBasedConfig(config, getType().toString()); 52 | } 53 | 54 | protected final Config getConfig() 55 | { 56 | return config; 57 | } 58 | 59 | protected final TransportConnection createConnection(Session session) 60 | { 61 | TransportConnection connection = createConnection(); 62 | connection.setSession(session); 63 | connection.init(getConfig()); 64 | return connection; 65 | } 66 | 67 | protected TransportConnection getConnection(HttpServletRequest request, SocketIOManager sessionManager) 68 | { 69 | String sessionId = request.getParameter(EngineIOProtocol.SESSION_ID); 70 | Session session = null; 71 | 72 | if(sessionId != null && sessionId.length() > 0) 73 | session = sessionManager.getSession(sessionId); 74 | 75 | if(session == null) 76 | return createConnection(sessionManager.createSession(request.getSession())); 77 | 78 | TransportConnection activeConnection = session.getConnection(); 79 | 80 | if(activeConnection != null && activeConnection.getTransport() == this) 81 | return activeConnection; 82 | 83 | // this is new connection considered for an upgrade 84 | return createConnection(session); 85 | } 86 | 87 | @Override 88 | public String toString() 89 | { 90 | return getType().toString(); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/transport/JSONPPollingTransport.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 4 | * 5 | * Contributors: Tad Glines, Ovea.com, Mycila.com, Alexander Sova (bird@codeminders.com) 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | * 25 | */ 26 | package com.codeminders.socketio.server.transport; 27 | 28 | import com.codeminders.socketio.protocol.EngineIOProtocol; 29 | import com.codeminders.socketio.server.SocketIOProtocolException; 30 | import com.codeminders.socketio.server.Session; 31 | import com.codeminders.socketio.server.TransportType; 32 | 33 | import javax.servlet.ServletRequest; 34 | import javax.servlet.ServletResponse; 35 | import java.io.IOException; 36 | 37 | public abstract class JSONPPollingTransport extends AbstractHttpTransport 38 | { 39 | private static final String EIO_PREFIX = "___eio"; 40 | private static final String FRAME_ID = JSONPPollingTransport.class.getName() + ".FRAME_ID"; 41 | 42 | protected JSONPPollingTransport() { } 43 | 44 | @Override 45 | public TransportType getType() 46 | { 47 | return TransportType.JSONP_POLLING; 48 | } 49 | 50 | public void startSend(Session session, ServletResponse response) throws IOException 51 | { 52 | response.setContentType("text/javascript; charset=UTF-8"); 53 | } 54 | 55 | public void writeData(Session session, ServletResponse response, String data) throws IOException 56 | { 57 | response.getOutputStream().print(EIO_PREFIX); 58 | response.getOutputStream().print("[" + session.getAttribute(FRAME_ID) + "]('"); 59 | response.getOutputStream().print(data); //TODO: encode data? 60 | response.getOutputStream().print("');"); 61 | } 62 | 63 | public void finishSend(Session session, ServletResponse response) throws IOException 64 | { 65 | response.flushBuffer(); 66 | } 67 | 68 | public void onConnect(Session session, ServletRequest request, ServletResponse response) 69 | throws IOException 70 | { 71 | try { 72 | //TODO: Use string constant for request parameter name "j" 73 | //TODO: Do we really need to enforce "j" to be an integer? 74 | session.setAttribute(FRAME_ID, Integer.parseInt(request.getParameter(EngineIOProtocol.JSONP_INDEX))); 75 | } catch (NullPointerException | NumberFormatException e) { 76 | throw new SocketIOProtocolException("Missing or invalid 'j' parameter. It suppose to be integer"); 77 | } 78 | 79 | startSend(session, response); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/ServletBasedConfig.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2010 Tad Glines 4 | *

5 | * Contributors: Ovea.com, Mycila.com 6 | *

7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | *

14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | *

17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | package com.codeminders.socketio.server; 26 | 27 | import javax.servlet.ServletConfig; 28 | import java.util.logging.Logger; 29 | 30 | /** 31 | * @author Mathieu Carbou 32 | */ 33 | public final class ServletBasedConfig implements Config 34 | { 35 | private final ServletConfig config; 36 | private final String namespace; 37 | 38 | public ServletBasedConfig(ServletConfig config, String namespace) 39 | { 40 | this.namespace = namespace; 41 | this.config = config; 42 | } 43 | 44 | @Override 45 | public long getPingInterval(long def) 46 | { 47 | return getLong(PING_INTERVAL, def); 48 | } 49 | 50 | @Override 51 | public long getTimeout(long def) 52 | { 53 | return getLong(TIMEOUT, def); 54 | } 55 | 56 | @Override 57 | public int getBufferSize() 58 | { 59 | return getInt(BUFFER_SIZE, DEFAULT_BUFFER_SIZE); 60 | } 61 | 62 | @Override 63 | public int getMaxIdle() 64 | { 65 | return getInt(MAX_IDLE, DEFAULT_MAX_IDLE); 66 | } 67 | 68 | @Override 69 | public int getInt(String param, int def) 70 | { 71 | String v = getString(param); 72 | return v == null ? def : Integer.parseInt(v); 73 | } 74 | 75 | @Override 76 | public long getLong(String param, long def) 77 | { 78 | String v = getString(param); 79 | return v == null ? def : Long.parseLong(v); 80 | } 81 | 82 | @Override 83 | public boolean getBoolean(String key, boolean def) 84 | { 85 | String v = getString(key); 86 | return v == null ? def : Boolean.parseBoolean(v); 87 | } 88 | 89 | @Override 90 | public String getNamespace() 91 | { 92 | return namespace; 93 | } 94 | 95 | @Override 96 | public String getString(String param) 97 | { 98 | String v = config.getInitParameter(namespace + "." + param); 99 | if (v == null) 100 | v = config.getInitParameter(param); 101 | 102 | return v; 103 | } 104 | 105 | @Override 106 | public String getString(String param, String def) 107 | { 108 | String v = getString(param); 109 | return v == null ? def : v; 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /samples/jetty/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 4.0.0 6 | 7 | 8 | com.codeminders.socketio 9 | socketio-sample 10 | 1.0.10 11 | 12 | 13 | socketio-sample-chat-jetty 14 | 15 | Socket.IO Sample Chat With Embedded Jetty 16 | 17 | 18 | 9.4.5.v20170502 19 | 20 | 21 | 22 | 23 | com.codeminders.socketio 24 | socketio-sample-chat 25 | 1.0.10 26 | classes 27 | 28 | 29 | org.eclipse.jetty 30 | jetty-server 31 | ${jetty.version} 32 | 33 | 34 | org.eclipse.jetty 35 | jetty-servlet 36 | ${jetty.version} 37 | 38 | 39 | org.eclipse.jetty.websocket 40 | javax-websocket-server-impl 41 | ${jetty.version} 42 | 43 | 44 | javax.servlet 45 | javax.servlet-api 46 | 3.1.0 47 | 48 | 49 | javax.websocket 50 | javax.websocket-api 51 | 1.1 52 | 53 | 54 | 55 | 56 | 57 | 58 | src/main/resources 59 | 60 | 61 | src/main/webapp 62 | 63 | 64 | ../chat/src/main/resources 65 | 66 | 67 | ../chat/src/main/webapp 68 | 69 | 70 | 71 | 72 | org.apache.maven.plugins 73 | maven-assembly-plugin 74 | 2.4 75 | 76 | 77 | src/assemble/distribution.xml 78 | 79 | 80 | 81 | com.codeminders.socketio.sample.jetty.ChatServer 82 | 83 | 84 | 85 | 86 | 87 | package 88 | 89 | single 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/transport/AbstractHttpTransport.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2010 Tad Glines 4 | *

5 | * Contributors: Tad Glines, Ovea.com, Mycila.com, Alexander Sova (bird@codeminders.com) 6 | *

7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | *

14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | *

17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | package com.codeminders.socketio.server.transport; 26 | 27 | import com.codeminders.socketio.common.ConnectionState; 28 | import com.codeminders.socketio.protocol.EngineIOProtocol; 29 | import com.codeminders.socketio.server.*; 30 | 31 | import javax.servlet.ServletRequest; 32 | import javax.servlet.ServletResponse; 33 | import javax.servlet.http.HttpServletRequest; 34 | import javax.servlet.http.HttpServletResponse; 35 | import java.io.IOException; 36 | import java.util.ArrayList; 37 | import java.util.logging.Level; 38 | import java.util.logging.Logger; 39 | 40 | public abstract class AbstractHttpTransport extends AbstractTransport 41 | { 42 | private static final Logger LOGGER = Logger.getLogger(AbstractHttpTransport.class.getName()); 43 | 44 | @Override 45 | public void handle(HttpServletRequest request, 46 | HttpServletResponse response, 47 | SocketIOManager socketIOManager) 48 | throws IOException 49 | { 50 | if (LOGGER.isLoggable(Level.FINE)) 51 | LOGGER.fine("Handling " + request.getMethod() + " request by " + getClass().getName()); 52 | 53 | TransportConnection connection = getConnection(request, socketIOManager); 54 | Session session = connection.getSession(); 55 | 56 | if (session.getConnectionState() == ConnectionState.CONNECTING) 57 | { 58 | 59 | ArrayList upgrades = new ArrayList<>(); 60 | if(socketIOManager.getTransportProvider().getTransport(TransportType.WEB_SOCKET) != null) 61 | upgrades.add("websocket"); 62 | 63 | connection.send(EngineIOProtocol.createHandshakePacket(session.getSessionId(), 64 | upgrades.toArray(new String[upgrades.size()]), 65 | getConfig().getPingInterval(Config.DEFAULT_PING_INTERVAL), 66 | getConfig().getTimeout(Config.DEFAULT_PING_TIMEOUT))); 67 | 68 | connection.handle(request, response); // called to send the handshake packet 69 | session.onConnect(connection); 70 | } 71 | else if (session.getConnectionState() == ConnectionState.CONNECTED) 72 | { 73 | connection.handle(request, response); 74 | } 75 | else 76 | response.sendError(HttpServletResponse.SC_GONE, "Socket.IO session is closed"); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/protocol/SocketIOPacket.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.protocol; 24 | 25 | import com.codeminders.socketio.server.SocketIOProtocolException; 26 | 27 | /** 28 | * @author Alexander Sova (bird@codeminders.com) 29 | */ 30 | public abstract class SocketIOPacket 31 | { 32 | public enum Type 33 | { 34 | CONNECT(0), 35 | DISCONNECT(1), 36 | EVENT(2), 37 | ACK(3), 38 | ERROR(4), 39 | BINARY_EVENT(5), 40 | BINARY_ACK(6); 41 | 42 | private int value; 43 | 44 | Type(int value) 45 | { 46 | this.value = value; 47 | } 48 | 49 | public int value() 50 | { 51 | return value; 52 | } 53 | 54 | public static Type fromInt(int i) throws SocketIOProtocolException 55 | { 56 | switch (i) 57 | { 58 | case 0: return CONNECT; 59 | case 1: return DISCONNECT; 60 | case 2: return EVENT; 61 | case 3: return ACK; 62 | case 4: return ERROR; 63 | case 5: return BINARY_EVENT; 64 | case 6: return BINARY_ACK; 65 | default: 66 | throw new SocketIOProtocolException("Unexpected packet type: " + i); 67 | } 68 | } 69 | } 70 | 71 | private int id; 72 | private Type type; 73 | private String namespace; 74 | 75 | public Type getType() 76 | { 77 | return type; 78 | } 79 | 80 | public String getNamespace() 81 | { 82 | return namespace; 83 | } 84 | 85 | public int getId() 86 | { 87 | return id; 88 | } 89 | 90 | protected abstract String encodeArgs() throws SocketIOProtocolException; 91 | 92 | protected String encodeAttachments() 93 | { 94 | return ""; 95 | } 96 | 97 | private String encodePacketId() 98 | { 99 | if(id < 0) 100 | return ""; 101 | 102 | return String.valueOf(id); 103 | } 104 | 105 | protected SocketIOPacket(Type type) 106 | { 107 | this(type, SocketIOProtocol.DEFAULT_NAMESPACE); 108 | } 109 | 110 | protected SocketIOPacket(Type type, String namespace) 111 | { 112 | this(type, -1, namespace); 113 | } 114 | 115 | protected SocketIOPacket(Type type, int id, String namespace) 116 | { 117 | this.type = type; 118 | this.namespace = namespace; 119 | this.id = id; 120 | } 121 | 122 | public String encode() throws SocketIOProtocolException 123 | { 124 | String str = String.valueOf(type.value()); 125 | 126 | String tail = encodePacketId() + encodeArgs(); 127 | 128 | str += encodeAttachments(); 129 | str += SocketIOProtocol.encodeNamespace(namespace, !tail.isEmpty()); 130 | str += tail; 131 | 132 | return str; 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/protocol/BinaryEventPacket.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.protocol; 24 | 25 | import java.io.InputStream; 26 | import java.util.ArrayList; 27 | import java.util.Collection; 28 | import java.util.LinkedList; 29 | import java.util.List; 30 | 31 | /** 32 | * Binary event packet class 33 | * 34 | * @author Alexander Sova (bird@codeminders.com) 35 | */ 36 | public class BinaryEventPacket extends EventPacket implements BinaryPacket 37 | { 38 | private List attachments; 39 | private int number_attachments_expected; 40 | 41 | /** 42 | * This constructor suppose to be called by parser when new packet arrived 43 | * 44 | * @param id packet id. Used for ACK 45 | * @param name event name 46 | * @param args event arguments as array of POJOs to be converted to JSON. 47 | * @param number_attachments_expected number of binary attachment expected to be attached to this packed 48 | */ 49 | BinaryEventPacket(int id, String ns, String name, Object[] args, int number_attachments_expected) 50 | { 51 | super(Type.BINARY_EVENT, id, ns, name, args); 52 | 53 | this.number_attachments_expected = number_attachments_expected; 54 | this.attachments = new ArrayList<>(number_attachments_expected); 55 | } 56 | 57 | /** 58 | * This constructor suppose to be called by user by emit() call 59 | * 60 | * @param id packet id 61 | * @param ns packet namespace 62 | * @param name event name 63 | * @param args event arguments as array of POJOs to be converted to JSON. 64 | * {@link java.io.InputStream} to be used for binary objects 65 | */ 66 | public BinaryEventPacket(int id, String ns, String name, Object[] args) 67 | { 68 | super(Type.BINARY_EVENT, id, ns, name, null); 69 | 70 | attachments = new LinkedList<>(); 71 | 72 | // We know that extractBinaryObjects does not change the structure of the object, 73 | // so we can safely case it to Object[] 74 | setArgs((Object[]) SocketIOProtocol.extractBinaryObjects(args, attachments)); 75 | } 76 | 77 | public Collection getAttachments() 78 | { 79 | return attachments; 80 | } 81 | 82 | @Override 83 | protected String encodeAttachments() 84 | { 85 | return SocketIOProtocol.encodeAttachments(attachments.size()); 86 | } 87 | 88 | /** 89 | * @return true when all expected attachment arrived, false otherwise 90 | */ 91 | public boolean isComplete() 92 | { 93 | return number_attachments_expected == 0; 94 | } 95 | 96 | /** 97 | * This method to be called when new attachement arrives to the socket 98 | * 99 | * @param attachment new attachment 100 | */ 101 | public void addAttachment(InputStream attachment) 102 | { 103 | attachments.add(attachment); 104 | number_attachments_expected -= 1; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/protocol/EngineIOPacket.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.protocol; 24 | 25 | import java.io.InputStream; 26 | import java.util.Objects; 27 | 28 | /** 29 | * @author Alexander Sova (bird@codeminders.com) 30 | */ 31 | public class EngineIOPacket 32 | { 33 | public enum Type 34 | { 35 | OPEN(0), 36 | CLOSE(1), 37 | PING(2), 38 | PONG(3), 39 | MESSAGE(4), 40 | UPGRADE(5), 41 | NOOP(6), 42 | UNKNOWN(-1); 43 | 44 | private int value; 45 | 46 | Type(int value) 47 | { 48 | this.value = value; 49 | } 50 | 51 | public int value() 52 | { 53 | return value; 54 | } 55 | 56 | public static Type fromInt(int i) 57 | { 58 | switch (i) 59 | { 60 | case 0: return OPEN; 61 | case 1: return CLOSE; 62 | case 2: return PING; 63 | case 3: return PONG; 64 | case 4: return MESSAGE; 65 | case 5: return UPGRADE; 66 | case 6: return NOOP; 67 | default: 68 | return UNKNOWN; 69 | } 70 | } 71 | } 72 | 73 | private Type type; 74 | private String textData; 75 | private InputStream binaryData; 76 | 77 | public Type getType() 78 | { 79 | return type; 80 | } 81 | 82 | public String getTextData() 83 | { 84 | return textData; 85 | } 86 | 87 | public InputStream getBinaryData() 88 | { 89 | return binaryData; 90 | } 91 | 92 | public EngineIOPacket(Type type, String data) 93 | { 94 | this.type = type; 95 | this.textData = data; 96 | } 97 | 98 | //TODO: support byte[] in addtion to InputStream 99 | public EngineIOPacket(Type type, InputStream binaryData) 100 | { 101 | this.type = type; 102 | this.binaryData = binaryData; 103 | } 104 | 105 | public EngineIOPacket(Type type) 106 | { 107 | this(type, ""); 108 | } 109 | 110 | @Override 111 | public String toString() 112 | { 113 | return "EngineIOPacket{" + 114 | "type=" + type + 115 | ", textData='" + textData + '\'' + 116 | ", binaryData=" + binaryData + 117 | '}'; 118 | } 119 | @Override 120 | public boolean equals(Object o) 121 | { 122 | if (this == o) return true; 123 | if (o == null || getClass() != o.getClass()) return false; 124 | EngineIOPacket that = (EngineIOPacket) o; 125 | return type == that.type && 126 | Objects.equals(textData, that.textData) && 127 | Objects.equals(binaryData, that.binaryData); 128 | } 129 | 130 | @Override 131 | public int hashCode() 132 | { 133 | return Objects.hash(type, textData, binaryData); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/Namespace.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.server; 24 | 25 | import com.codeminders.socketio.common.DisconnectReason; 26 | import com.codeminders.socketio.common.SocketIOException; 27 | 28 | import java.util.*; 29 | 30 | /** 31 | * @author Alexander Sova (bird@codeminders.com) 32 | */ 33 | public class Namespace implements Outbound, ConnectionListener, DisconnectListener 34 | { 35 | private String id; 36 | 37 | private List sockets = Collections.synchronizedList(new LinkedList()); 38 | private List connectionListeners = Collections.synchronizedList(new LinkedList()); 39 | private Map rooms = Collections.synchronizedMap(new LinkedHashMap()); 40 | 41 | Namespace(String id) 42 | { 43 | this.id = id; 44 | } 45 | 46 | public String getId() 47 | { 48 | return id; 49 | } 50 | 51 | @Override 52 | public void emit(String name, Object... args) 53 | { 54 | for(Socket s : sockets) 55 | { 56 | try 57 | { 58 | s.emit(name, args); 59 | } 60 | catch (SocketIOException e) 61 | { 62 | // ignore for now 63 | // TODO: add getLastError method? 64 | } 65 | } 66 | } 67 | 68 | 69 | public void on(ConnectionListener listener) 70 | { 71 | connectionListeners.add(listener); 72 | } 73 | 74 | @Override 75 | public void onConnect(Socket socket) 76 | throws ConnectionException 77 | { 78 | for(ConnectionListener listener : connectionListeners) 79 | listener.onConnect(socket); 80 | } 81 | 82 | public Socket createSocket(Session session) 83 | { 84 | Socket socket = new Socket(session, this); 85 | socket.on(this); 86 | sockets.add(socket); 87 | 88 | return socket; 89 | } 90 | 91 | @Override 92 | public void onDisconnect(Socket socket, DisconnectReason reason, String errorMessage) 93 | { 94 | leaveAll(socket); 95 | sockets.remove(socket); 96 | } 97 | 98 | /** 99 | * Finds or creates a room. 100 | * 101 | * @param roomId room id 102 | * @return Room object 103 | */ 104 | public Room room(String roomId) 105 | { 106 | Room room = rooms.get(roomId); 107 | if(room == null) 108 | { 109 | room = new Room(roomId); 110 | rooms.put(roomId, room); 111 | } 112 | return room; 113 | } 114 | 115 | /** 116 | * Finds or creates a room. 117 | * 118 | * @param roomId room id 119 | * @return Room object 120 | */ 121 | public Room in(String roomId) 122 | { 123 | return room(roomId); 124 | } 125 | 126 | void leaveAll(Socket socket) 127 | { 128 | for (Room room : rooms.values()) 129 | { 130 | if(room.contains(socket)) 131 | room.leave(socket); 132 | } 133 | } 134 | 135 | public Iterable getSockets() 136 | { 137 | return sockets; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /samples/tomcat/src/main/java/com/codeminders/socketio/sample/tomcat/ChatServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.sample.tomcat; 24 | 25 | import org.apache.catalina.WebResourceRoot; 26 | import org.apache.catalina.WebResourceSet; 27 | import org.apache.catalina.core.StandardContext; 28 | import org.apache.catalina.startup.Tomcat; 29 | import org.apache.catalina.webresources.DirResourceSet; 30 | import org.apache.catalina.webresources.JarResourceSet; 31 | import org.apache.catalina.webresources.StandardRoot; 32 | import org.apache.tomcat.util.scan.StandardJarScanner; 33 | 34 | import java.io.File; 35 | import java.io.FileWriter; 36 | import java.io.IOException; 37 | import java.net.URI; 38 | import java.net.URL; 39 | 40 | public class ChatServer { 41 | 42 | private static WebResourceSet[] getRoots(WebResourceRoot resources) throws Exception { 43 | URL root = ChatServer.class.getClassLoader().getResource(""); 44 | if (root == null) { 45 | root = ChatServer.class.getClassLoader().getResource("chat.html"); 46 | if (root == null) { 47 | throw new IllegalArgumentException("Cannot identify static resources root"); 48 | } 49 | } 50 | if ("jar".equals(root.getProtocol())) { 51 | String path = URI.create(root.getPath().substring(0, root.getPath().lastIndexOf("!/"))).getPath(); 52 | return new WebResourceSet[]{ 53 | new JarResourceSet(resources, "/WEB-INF/classes", path, "/"), 54 | new JarResourceSet(resources, "/", path, "/")}; 55 | } else if ("file".equals(root.getProtocol())) { 56 | return new WebResourceSet[]{ 57 | new DirResourceSet(resources, "/WEB-INF/classes", root.getPath(), "/"), 58 | new DirResourceSet(resources, "/", root.getPath(), "/") 59 | }; 60 | } else { 61 | throw new IllegalArgumentException("Cannot identify static resources root"); 62 | } 63 | } 64 | 65 | private static File createTempDirectory() throws IOException { 66 | final File temp; 67 | 68 | temp = File.createTempFile("temp", Long.toString(System.nanoTime())); 69 | 70 | if (!(temp.delete())) { 71 | throw new IOException("Could not delete temp file: " + temp.getAbsolutePath()); 72 | } 73 | 74 | if (!(temp.mkdir())) { 75 | throw new IOException("Could not create temp directory: " + temp.getAbsolutePath()); 76 | } 77 | 78 | return (temp); 79 | } 80 | 81 | public static void main(String args[]) throws Exception { 82 | 83 | Tomcat tomcat = new Tomcat(); 84 | tomcat.setPort(8080); 85 | 86 | 87 | File workdir = createTempDirectory(); 88 | File context = new File(workdir, "context.xml"); 89 | new FileWriter(context).write(""); 90 | context.deleteOnExit(); 91 | workdir.deleteOnExit(); 92 | 93 | StandardContext ctx = (StandardContext) tomcat.addWebapp("", workdir.toString()); 94 | WebResourceRoot resources = new StandardRoot(ctx); 95 | for (WebResourceSet set : getRoots(resources)) { 96 | resources.addPreResources(set); 97 | } 98 | ctx.setResources(resources); 99 | 100 | StandardJarScanner jarScanner = (StandardJarScanner) ctx.getJarScanner(); 101 | jarScanner.setScanClassPath(true); 102 | 103 | tomcat.start(); 104 | tomcat.getServer().await(); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/transport/AbstractTransportConnection.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2010 Tad Glines 4 | * 5 | * Contributors: Ovea.com, Mycila.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | */ 25 | package com.codeminders.socketio.server.transport; 26 | 27 | import com.codeminders.socketio.common.ConnectionState; 28 | import com.codeminders.socketio.common.DisconnectReason; 29 | import com.codeminders.socketio.common.SocketIOException; 30 | import com.codeminders.socketio.protocol.SocketIOPacket; 31 | import com.codeminders.socketio.protocol.SocketIOProtocol; 32 | import com.codeminders.socketio.server.*; 33 | 34 | import javax.servlet.http.HttpServletRequest; 35 | import java.util.Arrays; 36 | import java.util.logging.Logger; 37 | 38 | /** 39 | * @author Mathieu Carbou 40 | * @author Alexander Sova (bird@codeminders.com) 41 | */ 42 | public abstract class AbstractTransportConnection implements TransportConnection 43 | { 44 | private static final Logger LOGGER = Logger.getLogger(AbstractTransportConnection.class.getName()); 45 | 46 | private Config config; 47 | private Session session; 48 | private Transport transport; 49 | private HttpServletRequest request; 50 | 51 | public AbstractTransportConnection(Transport transport) 52 | { 53 | this.transport = transport; 54 | } 55 | 56 | @Override 57 | public final void init(Config config) { 58 | this.config = config; 59 | init(); 60 | } 61 | 62 | @Override 63 | public Transport getTransport() 64 | { 65 | return transport; 66 | } 67 | 68 | @Override 69 | public void setSession(Session session) { 70 | this.session = session; 71 | } 72 | 73 | protected final Config getConfig() { 74 | return config; 75 | } 76 | 77 | public Session getSession() { 78 | return session; 79 | } 80 | 81 | protected void init() 82 | { 83 | } 84 | 85 | @Override 86 | public void disconnect(String namespace, boolean closeConnection) 87 | { 88 | try 89 | { 90 | send(SocketIOProtocol.createDisconnectPacket(namespace)); 91 | getSession().setDisconnectReason(DisconnectReason.DISCONNECT); 92 | } 93 | catch (SocketIOException e) 94 | { 95 | getSession().setDisconnectReason(DisconnectReason.CLOSE_FAILED); 96 | } 97 | 98 | if(closeConnection) 99 | abort(); 100 | } 101 | 102 | @Override 103 | public void emit(String namespace, String name, Object... args) 104 | throws SocketIOException 105 | { 106 | if (getSession().getConnectionState() != ConnectionState.CONNECTED) 107 | throw new SocketIOClosedException(); 108 | 109 | ACKListener ack_listener = null; 110 | if(args.length > 0 && args[args.length-1] instanceof ACKListener) 111 | { 112 | ack_listener = (ACKListener)args[args.length-1]; 113 | args = Arrays.copyOfRange(args, 0, args.length-1); 114 | } 115 | 116 | int packet_id = -1; 117 | if(ack_listener != null) 118 | packet_id = getSession().getNewPacketId(); 119 | 120 | SocketIOPacket packet = SocketIOProtocol.createEventPacket(packet_id, namespace, name, args); 121 | 122 | if(packet_id >= 0) 123 | getSession().subscribeACK(packet_id, ack_listener); 124 | 125 | send(packet); 126 | } 127 | 128 | @Override 129 | public HttpServletRequest getRequest() 130 | { 131 | return request; 132 | } 133 | 134 | public void setRequest(HttpServletRequest request) 135 | { 136 | this.request = request; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /samples/jetty/src/main/java/com/codeminders/socketio/sample/jetty/ChatServer.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.sample.jetty; 24 | 25 | import com.codeminders.socketio.sample.chat.ChatSocketServlet; 26 | import com.codeminders.socketio.server.transport.websocket.WebsocketTransportConnection; 27 | import org.eclipse.jetty.server.Server; 28 | import org.eclipse.jetty.servlet.DefaultServlet; 29 | import org.eclipse.jetty.servlet.ServletContextHandler; 30 | import org.eclipse.jetty.util.resource.JarResource; 31 | import org.eclipse.jetty.util.resource.Resource; 32 | import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer; 33 | 34 | import java.io.File; 35 | import java.net.URI; 36 | import java.net.URL; 37 | 38 | public class ChatServer { 39 | 40 | private static Resource getRoot() throws Exception { 41 | URL root = ChatServer.class.getClassLoader().getResource(""); 42 | if (root != null) { 43 | return Resource.newResource(root); 44 | } 45 | root = ChatServer.class.getClassLoader().getResource("chat.html"); 46 | if (root == null) { 47 | throw new IllegalArgumentException("Cannot identify static resources root"); 48 | } 49 | if ("jar".equals(root.getProtocol())) { 50 | String path = root.getPath().substring(0, root.getPath().lastIndexOf("!/")); 51 | return JarResource.newJarResource(Resource.newResource(new File(URI.create(path)))); 52 | } else { 53 | throw new IllegalArgumentException("Cannot identify static resources root"); 54 | } 55 | } 56 | 57 | public static void main(String args[]) throws Exception { 58 | Server server = new Server(8080); 59 | 60 | ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); 61 | 62 | context.setContextPath("/"); 63 | 64 | context.setBaseResource(getRoot()); 65 | //context.setResourceBase(); 66 | 67 | context.setWelcomeFiles(new String[]{"chat.html"}); 68 | server.setHandler(context); 69 | context.addServlet(ChatSocketServlet.class, "/socket.io/*"); 70 | context.addServlet(DefaultServlet.class, "/*"); 71 | 72 | /* 73 | For root context endpoint initialization uses WebsocketTransportConnection annotations. 74 | Default endpoint configuration assumes it's accessible via /socket.io/ path 75 | */ 76 | WebSocketServerContainerInitializer. 77 | configureContext(context). 78 | addEndpoint(WebsocketTransportConnection.class); 79 | 80 | /* 81 | For non-root contexts endpoint initialization should override endpoint path 82 | to refer to context-specific path. For example if context's path if /foo then 83 | we should declare path as "/bar" if endpoint is accessible via /foo/bar path. 84 | Default endpoint configuration assumes it's located in the root context and accessible via 85 | /socket.io/ path. 86 | See sample initialization code below 87 | */ 88 | /* 89 | ServerContainer serverContainer = WebSocketServerContainerInitializer. 90 | configureContext(context); 91 | serverContainer. 92 | addEndpoint(new AnnotatedServerEndpointConfig(serverContainer, 93 | WebsocketTransportConnection.class, 94 | WebsocketTransportConnection.class.getAnnotation(ServerEndpoint.class), 95 | null) { 96 | @Override 97 | public String getPath() { 98 | return "/"; 99 | } 100 | }); 101 | */ 102 | 103 | server.start(); 104 | server.join(); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/SocketIOManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2010 Tad Glines 4 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 5 | *

6 | * Contributors: Ovea.com, Mycila.com 7 | *

8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | *

15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | *

18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.codeminders.socketio.server; 27 | 28 | import javax.servlet.http.HttpSession; 29 | import java.util.Map; 30 | import java.util.concurrent.*; 31 | 32 | /** 33 | * Class to manage Socket.IO sessions and namespaces. 34 | */ 35 | public final class SocketIOManager 36 | { 37 | private static final int SESSION_ID_LEN = 20; 38 | private static final char[] SYMBOLS; 39 | 40 | static 41 | { 42 | StringBuilder sb = new StringBuilder(); 43 | for (char ch = 'A'; ch <= 'Z'; ch++) 44 | sb.append(ch); 45 | for (char ch = 'a'; ch <= 'z'; ch++) 46 | sb.append(ch); 47 | SYMBOLS = sb.toString().toCharArray(); 48 | } 49 | 50 | private final Map namespaces = new ConcurrentHashMap<>(); 51 | private final ConcurrentMap sessions = new ConcurrentHashMap<>(); 52 | private TransportProvider transportProvider; 53 | 54 | final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); 55 | 56 | private static SocketIOManager instance = new SocketIOManager(); 57 | 58 | private SocketIOManager() { 59 | } 60 | 61 | public static SocketIOManager getInstance() { 62 | return instance; 63 | } 64 | 65 | private String generateSessionId() 66 | { 67 | while(true) 68 | { 69 | StringBuilder sb = new StringBuilder(SESSION_ID_LEN); 70 | for (int i = 0; i < SESSION_ID_LEN; i++) 71 | sb.append(SYMBOLS[ThreadLocalRandom.current().nextInt(SYMBOLS.length)]); 72 | 73 | String id = sb.toString(); 74 | if(sessions.get(id) == null) 75 | return id; 76 | } 77 | } 78 | 79 | /** 80 | * Creates new session 81 | * 82 | * @deprecated use {@link SocketIOManager#createSession(HttpSession)} 83 | * @return new session 84 | */ 85 | @Deprecated 86 | public Session createSession() 87 | { 88 | return createSession(null); 89 | } 90 | 91 | /** 92 | * Creates new session 93 | * 94 | * @param httpSession The HTTP session of the connecting client 95 | * @return new session 96 | */ 97 | public Session createSession(HttpSession httpSession) 98 | { 99 | Session session = new Session(this, generateSessionId(), httpSession); 100 | sessions.put(session.getSessionId(), session); 101 | return session; 102 | } 103 | 104 | /** 105 | * Finds existing session 106 | * 107 | * @param sessionId session id 108 | * @return session object or null if not found 109 | */ 110 | public Session getSession(String sessionId) 111 | { 112 | return sessions.get(sessionId); 113 | } 114 | 115 | /** 116 | * Deletes the session 117 | * 118 | * @param sessionId session id 119 | */ 120 | public void deleteSession(String sessionId) 121 | { 122 | sessions.remove(sessionId); 123 | } 124 | 125 | /** 126 | * Creates new namespace 127 | * 128 | * @param id namespace in. Should always start with '/' 129 | * @return new namespace 130 | */ 131 | public Namespace createNamespace(String id) 132 | { 133 | Namespace ns = new Namespace(id); 134 | namespaces.put(ns.getId(), ns); 135 | return ns; 136 | } 137 | 138 | public Namespace getNamespace(String id) 139 | { 140 | return namespaces.get(id); 141 | } 142 | 143 | public TransportProvider getTransportProvider() 144 | { 145 | return transportProvider; 146 | } 147 | 148 | public void setTransportProvider(TransportProvider transportProvider) 149 | { 150 | this.transportProvider = transportProvider; 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/Socket.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.server; 24 | 25 | import com.codeminders.socketio.common.DisconnectReason; 26 | import com.codeminders.socketio.common.SocketIOException; 27 | 28 | import javax.servlet.http.HttpServletRequest; 29 | import java.util.*; 30 | 31 | /** 32 | * @author Alexander Sova (bird@codeminders.com) 33 | */ 34 | public class Socket implements Outbound, DisconnectListener, EventListener 35 | { 36 | private List disconnectListeners = new LinkedList<>(); 37 | private Map eventListeners = new LinkedHashMap<>(); 38 | 39 | private Session session; // Socket is Session + Namespace 40 | private Namespace namespace; 41 | 42 | public Socket(Session session, Namespace namespace) 43 | { 44 | this.session = session; 45 | this.namespace = namespace; 46 | } 47 | 48 | public String getNamespace() 49 | { 50 | return namespace.getId(); 51 | } 52 | 53 | /** 54 | * Set listener for a named event. Only one listener per event is allowed. 55 | * 56 | * @param eventName event name 57 | * @param listener event listener 58 | */ 59 | public void on(String eventName, EventListener listener) 60 | { 61 | eventListeners.put(eventName, listener); 62 | } 63 | 64 | /** 65 | * Closes socket. 66 | * 67 | * @param closeConnection closes underlying transport connection if true 68 | */ 69 | public void disconnect(boolean closeConnection) 70 | { 71 | TransportConnection connection = getSession().getConnection(); 72 | if (connection != null) { 73 | connection.disconnect(getNamespace(), closeConnection); 74 | } 75 | } 76 | 77 | @Override 78 | public void emit(String name, Object... args) throws SocketIOException 79 | { 80 | TransportConnection connection = getSession().getConnection(); 81 | if (connection != null) { 82 | connection.emit(getNamespace(), name, args); 83 | } 84 | } 85 | 86 | /** 87 | * Adds disconnect listener 88 | * 89 | * @param listener disconnect listener 90 | */ 91 | public void on(DisconnectListener listener) 92 | { 93 | disconnectListeners.add(listener); 94 | } 95 | 96 | public Session getSession() 97 | { 98 | return session; 99 | } 100 | 101 | @Override 102 | public void onDisconnect(Socket socket, DisconnectReason reason, String errorMessage) 103 | { 104 | for (DisconnectListener listener : disconnectListeners) 105 | listener.onDisconnect(socket, reason, errorMessage); 106 | } 107 | 108 | @Override 109 | public Object onEvent(String name, Object[] args, boolean ackRequested) 110 | { 111 | EventListener listener = eventListeners.get(name); 112 | if(listener == null) 113 | return null; 114 | 115 | return listener.onEvent(name, args, ackRequested); 116 | } 117 | 118 | public void join(String room) 119 | { 120 | namespace.in(room).join(this); 121 | } 122 | 123 | public void leave(String room) 124 | { 125 | namespace.in(room).leave(this); 126 | } 127 | 128 | public void leaveAll() 129 | { 130 | namespace.leaveAll(this); 131 | } 132 | 133 | public void broadcast(String room, String name, Object... args) throws SocketIOException 134 | { 135 | namespace.in(room).broadcast(this, name, args); 136 | } 137 | 138 | public String getId() 139 | { 140 | return getSession().getSessionId() + getNamespace(); 141 | } 142 | 143 | /** 144 | * @return current HTTP request from underlying connection, null if socket is disconnected 145 | */ 146 | public HttpServletRequest getRequest() 147 | { 148 | TransportConnection connection = getSession().getConnection(); 149 | return connection == null ? null : connection.getRequest(); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /samples/chat/src/main/webapp/chat.html: -------------------------------------------------------------------------------- 1 | 27 | 28 | 29 | 30 | socket.io client test 31 | 32 | 33 | 34 | 35 | 36 | 37 | 135 | 136 |

Sample chat client

137 |

Connecting...

138 |
139 | 140 |
141 | 142 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/transport/XHRTransportConnection.java: -------------------------------------------------------------------------------- 1 | package com.codeminders.socketio.server.transport; 2 | 3 | import com.codeminders.socketio.common.SocketIOException; 4 | import com.codeminders.socketio.protocol.BinaryPacket; 5 | import com.codeminders.socketio.protocol.EngineIOPacket; 6 | import com.codeminders.socketio.protocol.EngineIOProtocol; 7 | import com.codeminders.socketio.protocol.SocketIOPacket; 8 | import com.codeminders.socketio.server.SocketIOProtocolException; 9 | import com.codeminders.socketio.server.Transport; 10 | import com.google.common.io.CharStreams; 11 | 12 | import javax.servlet.http.HttpServletRequest; 13 | import javax.servlet.http.HttpServletResponse; 14 | import java.io.IOException; 15 | import java.io.InputStream; 16 | import java.io.OutputStream; 17 | 18 | import java.util.concurrent.BlockingQueue; 19 | import java.util.concurrent.LinkedBlockingDeque; 20 | import java.util.concurrent.TimeUnit; 21 | import java.util.logging.Level; 22 | import java.util.logging.Logger; 23 | 24 | /** 25 | * @author Alexander Sova (bird@codeminders.com) 26 | */ 27 | public class XHRTransportConnection extends AbstractTransportConnection 28 | { 29 | private static final String ALLOWED_ORIGINS = "allowedOrigins"; 30 | private static final String ALLOW_ALL_ORIGINS = "allowAllOrigins"; 31 | 32 | private static final Logger LOGGER = Logger.getLogger(XHRTransportConnection.class.getName()); 33 | 34 | private BlockingQueue packets = new LinkedBlockingDeque<>(); 35 | 36 | private boolean done = false; 37 | 38 | public XHRTransportConnection(Transport transport) 39 | { 40 | super(transport); 41 | } 42 | 43 | @Override 44 | public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException 45 | { 46 | if(done) 47 | return; 48 | 49 | // store request for end-user to check for cookies, or user-agent or something else 50 | setRequest(request); 51 | 52 | if(getConfig().getBoolean(ALLOW_ALL_ORIGINS, false)) 53 | { 54 | response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin")); 55 | response.setHeader("Access-Control-Allow-Credentials", "true"); 56 | } 57 | else 58 | { 59 | String origins = getConfig().getString(ALLOWED_ORIGINS); 60 | if (origins != null) 61 | { 62 | response.setHeader("Access-Control-Allow-Origin", origins); 63 | response.setHeader("Access-Control-Allow-Credentials", "true"); 64 | } 65 | } 66 | 67 | if ("POST".equals(request.getMethod())) //incoming 68 | { 69 | response.setContentType("text/plain"); 70 | 71 | String contentType = request.getContentType(); 72 | if (contentType.startsWith("text/")) 73 | { 74 | // text encoding 75 | String payload = CharStreams.toString(request.getReader()); 76 | 77 | for (EngineIOPacket packet : EngineIOProtocol.decodePayload(payload)) 78 | getSession().onPacket(packet, this); 79 | } 80 | else 81 | if (contentType.startsWith("application/octet-stream")) 82 | { 83 | // binary encoding 84 | for (EngineIOPacket packet : EngineIOProtocol.binaryDecodePayload(request.getInputStream())) 85 | getSession().onPacket(packet, this); 86 | } 87 | else 88 | { 89 | throw new SocketIOProtocolException("Unsupported request content type for incoming polling request: " + contentType); 90 | } 91 | response.getWriter().print("ok"); 92 | } 93 | else if ("GET".equals(request.getMethod())) //outgoing 94 | { 95 | response.setContentType("application/octet-stream"); 96 | try 97 | { 98 | 99 | OutputStream os = response.getOutputStream(); 100 | for (EngineIOPacket packet = packets.poll(3, TimeUnit.MINUTES); packet != null; packet = packets.poll()) 101 | { 102 | if(done) 103 | break; 104 | EngineIOProtocol.binaryEncode(packet, os); 105 | } 106 | 107 | response.flushBuffer(); 108 | } 109 | catch (InterruptedException e) 110 | { 111 | if (LOGGER.isLoggable(Level.FINE)) 112 | LOGGER.log(Level.FINE, "Polling connection interrupted", e); 113 | } 114 | } 115 | else if(!"OPTIONS".equals(request.getMethod())) 116 | { 117 | // OPTIONS is CORS pre-flight request 118 | response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); 119 | } 120 | } 121 | 122 | @Override 123 | public void abort() 124 | { 125 | try 126 | { 127 | done = true; 128 | send(EngineIOProtocol.createNoopPacket()); 129 | } 130 | catch (SocketIOException e) 131 | { 132 | // ignore 133 | } 134 | } 135 | 136 | @Override 137 | public void send(EngineIOPacket packet) throws SocketIOException 138 | { 139 | packets.add(packet); 140 | } 141 | 142 | @Override 143 | public void send(SocketIOPacket packet) throws SocketIOException 144 | { 145 | send(EngineIOProtocol.createMessagePacket(packet.encode())); 146 | if(packet instanceof BinaryPacket) 147 | { 148 | for (InputStream is : ((BinaryPacket)packet).getAttachments()) 149 | send(EngineIOProtocol.createMessagePacket(is)); 150 | } 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/SocketIOServlet.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2010 Tad Glines 4 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 5 | *

6 | * Contributors: Ovea.com, Mycila.com 7 | *

8 | * Permission is hereby granted, free of charge, to any person obtaining a copy 9 | * of this software and associated documentation files (the "Software"), to deal 10 | * in the Software without restriction, including without limitation the rights 11 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | * copies of the Software, and to permit persons to whom the Software is 13 | * furnished to do so, subject to the following conditions: 14 | *

15 | * The above copyright notice and this permission notice shall be included in 16 | * all copies or substantial portions of the Software. 17 | *

18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | * THE SOFTWARE. 25 | */ 26 | package com.codeminders.socketio.server; 27 | 28 | import com.codeminders.socketio.protocol.EngineIOProtocol; 29 | import com.codeminders.socketio.protocol.SocketIOProtocol; 30 | import com.google.common.io.ByteStreams; 31 | 32 | import javax.servlet.ServletException; 33 | import javax.servlet.http.HttpServlet; 34 | import javax.servlet.http.HttpServletRequest; 35 | import javax.servlet.http.HttpServletResponse; 36 | import java.io.IOException; 37 | import java.io.InputStream; 38 | import java.io.OutputStream; 39 | import java.util.logging.Level; 40 | import java.util.logging.Logger; 41 | 42 | public abstract class SocketIOServlet extends HttpServlet 43 | { 44 | private static final Logger LOGGER = Logger.getLogger(SocketIOServlet.class.getName()); 45 | 46 | /** 47 | * Initializes and retrieves the given Namespace by its pathname identifier {@code id}. 48 | * 49 | * If the namespace was already initialized it returns it right away. 50 | * @param id namespace id 51 | * @return namespace object 52 | */ 53 | public Namespace of(String id) 54 | { 55 | return namespace(id); 56 | } 57 | 58 | /** 59 | * Initializes and retrieves the given Namespace by its pathname identifier {@code id}. 60 | * 61 | * If the namespace was already initialized it returns it right away. 62 | * @param id namespace id 63 | * @return namespace object 64 | */ 65 | public Namespace namespace(String id) 66 | { 67 | Namespace ns = SocketIOManager.getInstance().getNamespace(id); 68 | if (ns == null) 69 | ns = SocketIOManager.getInstance().createNamespace(id); 70 | 71 | return ns; 72 | } 73 | 74 | public void setTransportProvider(TransportProvider transportProvider) 75 | { 76 | SocketIOManager.getInstance().setTransportProvider(transportProvider); 77 | } 78 | 79 | @Override 80 | public void init() throws ServletException 81 | { 82 | of(SocketIOProtocol.DEFAULT_NAMESPACE); 83 | 84 | if (LOGGER.isLoggable(Level.INFO)) 85 | LOGGER.info("Socket.IO server stated."); 86 | } 87 | 88 | @Override 89 | public void destroy() 90 | { 91 | SocketIOManager.getInstance().getTransportProvider().destroy(); 92 | super.destroy(); 93 | } 94 | 95 | @Override 96 | protected void doGet(HttpServletRequest req, HttpServletResponse resp) 97 | throws ServletException, IOException 98 | { 99 | serve(req, resp); 100 | } 101 | 102 | @Override 103 | protected void doPost(HttpServletRequest req, HttpServletResponse resp) 104 | throws ServletException, IOException 105 | { 106 | serve(req, resp); 107 | } 108 | 109 | @Override 110 | protected void doOptions(HttpServletRequest req, HttpServletResponse resp) 111 | throws ServletException, IOException 112 | { 113 | serve(req, resp); 114 | } 115 | 116 | private void serve(HttpServletRequest request, HttpServletResponse response) 117 | throws ServletException, IOException 118 | { 119 | String path = request.getPathInfo(); 120 | 121 | if (path.startsWith("/")) path = path.substring(1); 122 | String[] parts = path.split("/"); 123 | 124 | if ("GET".equals(request.getMethod()) && "socket.io.js".equals(parts[0])) 125 | { 126 | response.setContentType("text/javascript"); 127 | InputStream is = this.getClass().getClassLoader().getResourceAsStream("com/codeminders/socketio/socket.io.js"); 128 | OutputStream os = response.getOutputStream(); 129 | ByteStreams.copy(is, os); 130 | } 131 | else 132 | { 133 | assert (SocketIOManager.getInstance().getTransportProvider() != null); 134 | 135 | try 136 | { 137 | if (LOGGER.isLoggable(Level.FINE)) 138 | LOGGER.log(Level.FINE, "Request from " + 139 | request.getRemoteHost() + ":" + request.getRemotePort() + 140 | ", transport: " + request.getParameter(EngineIOProtocol.TRANSPORT) + 141 | ", EIO protocol version:" + request.getParameter(EngineIOProtocol.VERSION)); 142 | 143 | SocketIOManager.getInstance(). 144 | getTransportProvider(). 145 | getTransport(request). 146 | handle(request, response, SocketIOManager.getInstance()); 147 | } 148 | catch (UnsupportedTransportException | SocketIOProtocolException e) 149 | { 150 | response.sendError(HttpServletResponse.SC_BAD_REQUEST); 151 | 152 | if (LOGGER.isLoggable(Level.WARNING)) 153 | LOGGER.log(Level.WARNING, "Socket IO error", e); 154 | } 155 | } 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /samples/chat/src/main/java/com/codeminders/socketio/sample/chat/ChatSocketServlet.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.sample.chat; 24 | 25 | import com.codeminders.socketio.common.DisconnectReason; 26 | import com.codeminders.socketio.common.SocketIOException; 27 | import com.codeminders.socketio.server.*; 28 | import com.codeminders.socketio.server.transport.websocket.WebsocketIOServlet; 29 | import com.google.common.io.ByteStreams; 30 | 31 | import javax.servlet.ServletConfig; 32 | import javax.servlet.ServletException; 33 | import java.io.ByteArrayInputStream; 34 | import java.io.ByteArrayOutputStream; 35 | import java.io.IOException; 36 | import java.io.InputStream; 37 | import java.util.Map; 38 | import java.util.logging.Level; 39 | import java.util.logging.Logger; 40 | 41 | public class ChatSocketServlet extends WebsocketIOServlet 42 | { 43 | private static final String ANNOUNCEMENT = "announcement"; // server to all connected clients 44 | private static final String CHAT_MESSAGE = "chat message"; // broadcast to room 45 | private static final String WELCOME = "welcome"; // single event sent by server to specific client 46 | private static final String FORCE_DISCONNECT = "force disconnect"; // client requests server to disconnect 47 | private static final String SERVER_BINARY = "server binary"; // client requests server to send a binary 48 | private static final String CLIENT_BINARY = "client binary"; // client sends binary 49 | 50 | private static final Logger LOGGER = Logger.getLogger(ChatSocketServlet.class.getName()); 51 | 52 | private static final long serialVersionUID = 1L; 53 | 54 | @Override 55 | @SuppressWarnings("unchecked") 56 | public void init(ServletConfig config) throws ServletException 57 | { 58 | super.init(config); 59 | 60 | of("/chat").on(new ConnectionListener() 61 | { 62 | @Override 63 | public void onConnect(final Socket socket) 64 | { 65 | try 66 | { 67 | socket.emit(WELCOME, "Welcome to Socket.IO Chat, " + socket.getId() + "!"); 68 | 69 | socket.join("room"); 70 | } 71 | catch (SocketIOException e) 72 | { 73 | e.printStackTrace(); 74 | socket.disconnect(true); 75 | } 76 | 77 | socket.on(new DisconnectListener() { 78 | 79 | @Override 80 | public void onDisconnect(Socket socket, DisconnectReason reason, String errorMessage) 81 | { 82 | of("/chat").emit(ANNOUNCEMENT, socket.getSession().getSessionId() + " disconnected"); 83 | } 84 | }); 85 | 86 | socket.on(CHAT_MESSAGE, new EventListener() 87 | { 88 | @Override 89 | public Object onEvent(String name, Object[] args, boolean ackRequested) 90 | { 91 | LOGGER.log(Level.FINE, "Received chat message: " + args[0]); 92 | 93 | try 94 | { 95 | socket.broadcast("room", CHAT_MESSAGE, socket.getId(), args[0]); 96 | } 97 | catch (SocketIOException e) 98 | { 99 | e.printStackTrace(); 100 | } 101 | 102 | return "OK"; //this object will be sent back to the client in ACK packet 103 | } 104 | }); 105 | 106 | socket.on(FORCE_DISCONNECT, new EventListener() 107 | { 108 | @Override 109 | public Object onEvent(String name, Object[] args, boolean ackRequested) 110 | { 111 | socket.disconnect(false); 112 | return null; 113 | } 114 | }); 115 | 116 | socket.on(CLIENT_BINARY, new EventListener() 117 | { 118 | @Override 119 | public Object onEvent(String name, Object[] args, boolean ackRequested) 120 | { 121 | Map map = (Map)args[0]; 122 | InputStream is = (InputStream) map.get("buffer"); 123 | ByteArrayOutputStream os = new ByteArrayOutputStream(); 124 | try 125 | { 126 | ByteStreams.copy(is, os); 127 | byte []array = os.toByteArray(); 128 | String s = "["; 129 | for (byte b : array) 130 | s += " " + b; 131 | s += " ]"; 132 | LOGGER.log(Level.FINE, "Binary received: " + s); 133 | } 134 | catch (IOException e) 135 | { 136 | e.printStackTrace(); 137 | } 138 | 139 | return "OK"; 140 | } 141 | }); 142 | 143 | socket.on(SERVER_BINARY, new EventListener() 144 | { 145 | @Override 146 | public Object onEvent(String name, Object[] args, boolean ackRequested) 147 | { 148 | try 149 | { 150 | socket.emit(SERVER_BINARY, 151 | new ByteArrayInputStream(new byte[] {1, 2, 3, 4}), 152 | new ACKListener() 153 | { 154 | @Override 155 | public void onACK(Object[] args) 156 | { 157 | System.out.println("ACK received: " + args[0]); 158 | } 159 | }); 160 | } 161 | catch (SocketIOException e) 162 | { 163 | socket.disconnect(true); 164 | } 165 | 166 | return null; 167 | } 168 | }); 169 | } 170 | }); 171 | 172 | // Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(new Runnable() 173 | // { 174 | // @Override 175 | // public void run() 176 | // { 177 | // try 178 | // { 179 | // of("/chat").in("room").emit("time", new Date().toString()); 180 | // } 181 | // catch (SocketIOException e) 182 | // { 183 | // e.printStackTrace(); 184 | // } 185 | // } 186 | // }, 0, 20, TimeUnit.SECONDS); 187 | 188 | 189 | // of("/news").on(new ConnectionListener() 190 | // { 191 | // @Override 192 | // public void onConnect(Socket socket) 193 | // { 194 | // socket.on(); 195 | // } 196 | // }); 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/server/transport/websocket/WebsocketTransportConnection.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.server.transport.websocket; 24 | 25 | import com.codeminders.socketio.common.ConnectionState; 26 | import com.codeminders.socketio.common.DisconnectReason; 27 | import com.codeminders.socketio.common.SocketIOException; 28 | import com.codeminders.socketio.protocol.BinaryPacket; 29 | import com.codeminders.socketio.protocol.EngineIOPacket; 30 | import com.codeminders.socketio.protocol.EngineIOProtocol; 31 | import com.codeminders.socketio.protocol.SocketIOPacket; 32 | import com.codeminders.socketio.server.*; 33 | import com.codeminders.socketio.server.transport.AbstractTransportConnection; 34 | import com.google.common.io.ByteStreams; 35 | 36 | import javax.servlet.http.HttpServletRequest; 37 | import javax.servlet.http.HttpServletResponse; 38 | import javax.servlet.http.HttpSession; 39 | import javax.websocket.*; 40 | import javax.websocket.Session; 41 | import javax.websocket.server.HandshakeRequest; 42 | import javax.websocket.server.ServerEndpoint; 43 | import java.io.ByteArrayOutputStream; 44 | import java.io.IOException; 45 | import java.io.InputStream; 46 | import java.util.Collection; 47 | import java.util.List; 48 | import java.util.logging.Level; 49 | import java.util.logging.Logger; 50 | 51 | /** 52 | * @author Alexander Sova (bird@codeminders.com) 53 | * @author Alex Saveliev (lyolik@codeminders.com) 54 | */ 55 | @ServerEndpoint(value="/socket.io/", configurator = WebsocketConfigurator.class) 56 | public final class WebsocketTransportConnection extends AbstractTransportConnection 57 | { 58 | private static final Logger LOGGER = Logger.getLogger(WebsocketTransportConnection.class.getName()); 59 | 60 | private static Class websocketIOClass = WebsocketIO.class; 61 | 62 | private WebsocketIO websocketIO; 63 | 64 | public WebsocketTransportConnection() { 65 | super(WebsocketTransportProvider.websocket); 66 | } 67 | 68 | public WebsocketTransportConnection(Transport transport) 69 | { 70 | super(transport); 71 | } 72 | 73 | /** 74 | * 75 | * @param clazz class responsible for I/O operations 76 | */ 77 | public static void setWebsocketIOClass(Class clazz) { 78 | WebsocketTransportConnection.websocketIOClass = clazz; 79 | } 80 | 81 | @Override 82 | protected void init() 83 | { 84 | getSession().setTimeout(getConfig().getTimeout(Config.DEFAULT_PING_TIMEOUT)); 85 | 86 | if (LOGGER.isLoggable(Level.FINE)) 87 | LOGGER.fine(getConfig().getNamespace() + " WebSocket configuration:" + 88 | " timeout=" + getSession().getTimeout()); 89 | } 90 | 91 | @OnOpen 92 | public void onOpen(javax.websocket.Session session, EndpointConfig config) throws Exception 93 | { 94 | setupIO(session); 95 | setupSession(session); 96 | init(new ServletBasedConfig( 97 | ServletConfigHolder.getInstance().getConfig(), 98 | getTransport().getType().toString())); 99 | session.setMaxBinaryMessageBufferSize(getConfig().getBufferSize()); 100 | session.setMaxIdleTimeout(getConfig().getMaxIdle()); 101 | session.setMaxTextMessageBufferSize(getConfig().getInt(Config.MAX_TEXT_MESSAGE_SIZE, 32000)); 102 | 103 | if(getSession().getConnectionState() == ConnectionState.CONNECTING) 104 | { 105 | try 106 | { 107 | send(EngineIOProtocol.createHandshakePacket(getSession().getSessionId(), 108 | new String[]{}, 109 | getConfig().getPingInterval(Config.DEFAULT_PING_INTERVAL), 110 | getConfig().getTimeout(Config.DEFAULT_PING_TIMEOUT))); 111 | 112 | getSession().onConnect(this); 113 | } 114 | catch (SocketIOException e) 115 | { 116 | LOGGER.log(Level.SEVERE, "Cannot connect", e); 117 | getSession().setDisconnectReason(DisconnectReason.CONNECT_FAILED); 118 | abort(); 119 | } 120 | } 121 | } 122 | 123 | private void setupIO(Session session) throws Exception { 124 | websocketIO = websocketIOClass.getConstructor(Session.class).newInstance(session); 125 | } 126 | 127 | @OnClose 128 | public void onClose(javax.websocket.Session session, CloseReason closeReason) 129 | { 130 | if(LOGGER.isLoggable(Level.FINE)) 131 | LOGGER.log(Level.FINE, "Session[" + getSession().getSessionId() + "]:" + 132 | " websocket closed. " + closeReason.toString()); 133 | 134 | //If close is unexpected then try to guess the reason based on closeCode, otherwise the reason is already set 135 | if(getSession().getConnectionState() != ConnectionState.CLOSING) 136 | getSession().setDisconnectReason(fromCloseCode(closeReason.getCloseCode().getCode())); 137 | 138 | getSession().setDisconnectMessage(closeReason.getReasonPhrase()); 139 | getSession().onShutdown(); 140 | } 141 | 142 | @OnMessage 143 | public void onMessage(String text) 144 | { 145 | if (LOGGER.isLoggable(Level.FINE)) 146 | LOGGER.fine("Session[" + getSession().getSessionId() + "]: text received: " + text); 147 | 148 | getSession().resetTimeout(); 149 | 150 | try 151 | { 152 | getSession().onPacket(EngineIOProtocol.decode(text), this); 153 | } 154 | catch (SocketIOProtocolException e) 155 | { 156 | if(LOGGER.isLoggable(Level.WARNING)) 157 | LOGGER.log(Level.WARNING, "Invalid packet received", e); 158 | } 159 | } 160 | 161 | @OnMessage 162 | public void onMessage(InputStream is) 163 | { 164 | if (LOGGER.isLoggable(Level.FINE)) 165 | LOGGER.fine("Session[" + getSession().getSessionId() + "]: binary received"); 166 | 167 | getSession().resetTimeout(); 168 | 169 | try 170 | { 171 | getSession().onPacket(EngineIOProtocol.decode(is), this); 172 | } 173 | catch (SocketIOProtocolException e) 174 | { 175 | if(LOGGER.isLoggable(Level.WARNING)) 176 | LOGGER.log(Level.WARNING, "Problem processing binary received", e); 177 | } 178 | } 179 | 180 | @OnError 181 | public void onError(javax.websocket.Session session, Throwable error) { 182 | // TODO implement 183 | // One reason might be when you are refreshing web page causing connection to be dropped 184 | } 185 | 186 | @Override 187 | public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException 188 | { 189 | response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Unexpected request on upgraded WebSocket connection"); 190 | } 191 | 192 | @Override 193 | public void abort() 194 | { 195 | getSession().clearTimeout(); 196 | if (websocketIO != null) 197 | { 198 | disconnectEndpoint(); 199 | websocketIO = null; 200 | } 201 | } 202 | 203 | @Override 204 | public void send(EngineIOPacket packet) throws SocketIOException 205 | { 206 | sendString(EngineIOProtocol.encode(packet)); 207 | } 208 | 209 | @Override 210 | public void send(SocketIOPacket packet) throws SocketIOException 211 | { 212 | send(EngineIOProtocol.createMessagePacket(packet.encode())); 213 | if(packet instanceof BinaryPacket) 214 | { 215 | Collection attachments = ((BinaryPacket) packet).getAttachments(); 216 | for (InputStream is : attachments) 217 | { 218 | ByteArrayOutputStream os = new ByteArrayOutputStream(); 219 | try 220 | { 221 | os.write(EngineIOPacket.Type.MESSAGE.value()); 222 | ByteStreams.copy(is, os); 223 | } 224 | catch (IOException e) 225 | { 226 | if(LOGGER.isLoggable(Level.WARNING)) 227 | LOGGER.log(Level.SEVERE, "Cannot load binary object to send it to the socket", e); 228 | } 229 | sendBinary(os.toByteArray()); 230 | } 231 | } 232 | } 233 | 234 | protected void sendString(String data) throws SocketIOException 235 | { 236 | if (LOGGER.isLoggable(Level.FINE)) 237 | LOGGER.log(Level.FINE, "Session[" + getSession().getSessionId() + "]: send text: " + data); 238 | 239 | try 240 | { 241 | websocketIO.sendString(data); 242 | } 243 | catch (IOException e) 244 | { 245 | disconnectEndpoint(); 246 | throw new SocketIOException(e); 247 | } 248 | } 249 | 250 | //TODO: implement streaming. right now it is all in memory. 251 | //TODO: read and send in chunks using sendPartialBytes() 252 | protected void sendBinary(byte[] data) throws SocketIOException 253 | { 254 | if (LOGGER.isLoggable(Level.FINE)) 255 | LOGGER.log(Level.FINE, "Session[" + getSession().getSessionId() + "]: send binary"); 256 | 257 | try 258 | { 259 | websocketIO.sendBinary(data); 260 | } 261 | catch (IOException e) 262 | { 263 | disconnectEndpoint(); 264 | throw new SocketIOException(e); 265 | } 266 | } 267 | 268 | private void disconnectEndpoint() 269 | { 270 | try 271 | { 272 | websocketIO.disconnect(); 273 | } 274 | catch (IOException ex) 275 | { 276 | // ignore 277 | } 278 | } 279 | 280 | /** 281 | * @link https://tools.ietf.org/html/rfc6455#section-11.7 282 | */ 283 | private DisconnectReason fromCloseCode(int code) 284 | { 285 | switch (code) { 286 | case 1000: 287 | return DisconnectReason.CLOSED; // Normal Closure 288 | case 1001: 289 | return DisconnectReason.CLIENT_GONE; // Going Away 290 | default: 291 | return DisconnectReason.ERROR; 292 | } 293 | } 294 | 295 | /** 296 | * @param session websocket session 297 | * @return session id extracted from handshake request's parameter 298 | */ 299 | private String getSessionId(javax.websocket.Session session) 300 | { 301 | HandshakeRequest handshake = (HandshakeRequest) 302 | session.getUserProperties().get(HandshakeRequest.class.getName()); 303 | if (handshake == null) { 304 | return null; 305 | } 306 | List values = handshake.getParameterMap().get(EngineIOProtocol.SESSION_ID); 307 | if (values == null || values.isEmpty()) { 308 | return null; 309 | } 310 | return values.get(0); 311 | } 312 | 313 | private HttpSession getHttpSession(javax.websocket.Session session) 314 | { 315 | HandshakeRequest handshake = (HandshakeRequest) 316 | session.getUserProperties().get(HandshakeRequest.class.getName()); 317 | if (handshake == null) 318 | { 319 | return null; 320 | } 321 | if (!(handshake.getHttpSession() instanceof HttpSession)) 322 | { 323 | return null; 324 | } 325 | return (HttpSession) handshake.getHttpSession(); 326 | } 327 | 328 | /** 329 | * Initializes socket.io session 330 | * @param session 331 | * @throws Exception 332 | */ 333 | private void setupSession(javax.websocket.Session session) throws Exception 334 | { 335 | String sessionId = getSessionId(session); 336 | com.codeminders.socketio.server.Session sess = null; 337 | if (sessionId != null) { 338 | sess = SocketIOManager.getInstance().getSession(sessionId); 339 | } 340 | if (sess == null) { 341 | HttpSession httpSession = getHttpSession(session); 342 | sess = SocketIOManager.getInstance().createSession(httpSession); 343 | } 344 | setSession(sess); 345 | } 346 | } 347 | -------------------------------------------------------------------------------- /socket-io/src/main/java/com/codeminders/socketio/protocol/EngineIOProtocol.java: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License 3 | * Copyright (c) 2015 Alexander Sova (bird@codeminders.com) 4 | *

5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | *

12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | *

15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | package com.codeminders.socketio.protocol; 24 | 25 | import com.codeminders.socketio.server.SocketIOProtocolException; 26 | import com.google.common.io.ByteStreams; 27 | 28 | import java.io.*; 29 | import java.text.DecimalFormat; 30 | import java.text.ParsePosition; 31 | import java.util.ArrayList; 32 | import java.util.LinkedHashMap; 33 | import java.util.List; 34 | import java.util.Map; 35 | 36 | /** 37 | * Implementation of Engine.IO Protocol version 3 38 | * 39 | * @author Alexander Sova (bird@codeminders.com) 40 | */ 41 | public final class EngineIOProtocol 42 | { 43 | public static final String SESSION_ID = "sid"; 44 | public static final String TRANSPORT = "transport"; 45 | public static final String JSONP_INDEX = "j"; 46 | public static final String BASE64_FLAG = "b64"; 47 | public static final String VERSION = "EIO"; 48 | 49 | private EngineIOProtocol() 50 | { 51 | } 52 | 53 | public static String encode(EngineIOPacket packet) 54 | { 55 | return String.valueOf(packet.getType().value()) + packet.getTextData(); 56 | } 57 | 58 | public static void binaryEncode(EngineIOPacket packet, OutputStream os) 59 | throws IOException 60 | { 61 | if (packet.getBinaryData() != null) 62 | { 63 | ByteArrayInputStream bytes; 64 | InputStream is = packet.getBinaryData(); 65 | if(is instanceof ByteArrayInputStream) 66 | { 67 | bytes = (ByteArrayInputStream)is; 68 | } 69 | else 70 | { 71 | // Cannot avoid double copy. The protocol requires to send the length before the data 72 | //TODO: ask user to provide length? Could be useful to send files 73 | ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 74 | ByteStreams.copy(is, buffer); 75 | bytes = new ByteArrayInputStream(buffer.toByteArray()); 76 | } 77 | os.write(1); // binary packet 78 | os.write(encodeLength(bytes.available() + 1)); // +1 for packet type 79 | os.write(255); 80 | os.write(packet.getType().value()); 81 | ByteStreams.copy(bytes, os); 82 | } 83 | else 84 | { 85 | assert(packet.getTextData() != null); 86 | 87 | os.write(0); // text packet 88 | final byte[] bytes = packet.getTextData().getBytes("UTF-8"); 89 | os.write(encodeLength(bytes.length + 1)); // +1 for packet type 90 | os.write(255); 91 | os.write(packet.getType().value() + '0'); 92 | os.write(bytes); 93 | } 94 | 95 | } 96 | 97 | //this is most ridiculous encoding I ever seen 98 | private static byte[] encodeLength(int len) 99 | { 100 | byte[] bytes = String.valueOf(len).getBytes(); 101 | for(int i = 0; i < bytes.length; i++) 102 | bytes[i] -= '0'; 103 | return bytes; 104 | } 105 | 106 | public static EngineIOPacket decode(String raw) 107 | throws SocketIOProtocolException 108 | { 109 | assert (raw != null); 110 | 111 | if (raw.length() < 1) 112 | throw new SocketIOProtocolException("Empty EIO packet"); 113 | 114 | try 115 | { 116 | return new EngineIOPacket( 117 | EngineIOPacket.Type.fromInt(Integer.parseInt(raw.substring(0, 1))), 118 | raw.substring(1)); 119 | } 120 | catch (NumberFormatException e) 121 | { 122 | throw new SocketIOProtocolException("Invalid EIO packet type: " + raw); 123 | } 124 | } 125 | 126 | 127 | public static EngineIOPacket decode(InputStream raw) 128 | throws SocketIOProtocolException 129 | { 130 | assert (raw != null); 131 | 132 | try 133 | { 134 | int type = raw.read(); 135 | if (type == -1) 136 | throw new SocketIOProtocolException("Empty binary object received"); 137 | 138 | return new EngineIOPacket(EngineIOPacket.Type.fromInt(type), raw); 139 | } 140 | catch (IOException e) 141 | { 142 | throw new SocketIOProtocolException("Cannot read packet type from binary object"); 143 | } 144 | } 145 | 146 | public static EngineIOPacket createHandshakePacket(String session_id, 147 | String[] upgrades, 148 | long ping_interval, 149 | long ping_timeout) 150 | { 151 | Map map = new LinkedHashMap<>(); 152 | map.put("sid", session_id); 153 | map.put("upgrades", upgrades); 154 | map.put("pingInterval", ping_interval); 155 | map.put("pingTimeout", ping_timeout); 156 | 157 | try 158 | { 159 | return new EngineIOPacket(EngineIOPacket.Type.OPEN, SocketIOProtocol.toJSON(map)); 160 | } 161 | catch (SocketIOProtocolException e) 162 | { 163 | // ignore. never happen 164 | return null; 165 | } 166 | } 167 | 168 | public static EngineIOPacket createOpenPacket() 169 | { 170 | return new EngineIOPacket(EngineIOPacket.Type.OPEN); 171 | } 172 | 173 | public static EngineIOPacket createClosePacket() 174 | { 175 | return new EngineIOPacket(EngineIOPacket.Type.CLOSE); 176 | } 177 | 178 | public static EngineIOPacket createPingPacket(String data) 179 | { 180 | return new EngineIOPacket(EngineIOPacket.Type.PING, data); 181 | } 182 | 183 | public static EngineIOPacket createPongPacket(String data) 184 | { 185 | return new EngineIOPacket(EngineIOPacket.Type.PONG, data); 186 | } 187 | 188 | public static EngineIOPacket createMessagePacket(String data) 189 | { 190 | return new EngineIOPacket(EngineIOPacket.Type.MESSAGE, data); 191 | } 192 | 193 | public static EngineIOPacket createMessagePacket(InputStream data) 194 | { 195 | return new EngineIOPacket(EngineIOPacket.Type.MESSAGE, data); 196 | } 197 | 198 | public static EngineIOPacket createUpgradePacket() 199 | { 200 | return new EngineIOPacket(EngineIOPacket.Type.UPGRADE); 201 | } 202 | 203 | public static EngineIOPacket createNoopPacket() 204 | { 205 | return new EngineIOPacket(EngineIOPacket.Type.NOOP); 206 | } 207 | 208 | public static List decodePayload(String payload) 209 | throws SocketIOProtocolException 210 | { 211 | ArrayList packets = new ArrayList<>(); 212 | 213 | ParsePosition pos = new ParsePosition(0); 214 | 215 | while(pos.getIndex() < payload.length()) 216 | { 217 | int len = decodePacketLength(payload, pos); 218 | EngineIOPacket.Type type = decodePacketType(payload, pos); 219 | String data = payload.substring(pos.getIndex(), pos.getIndex() + len - 1); 220 | pos.setIndex(pos.getIndex() - 1 + len); 221 | 222 | switch (type) 223 | { 224 | case CLOSE: 225 | packets.add(createClosePacket()); 226 | break; 227 | case PING: 228 | packets.add(createPingPacket(data)); 229 | break; 230 | case MESSAGE: 231 | packets.add(createMessagePacket(data)); 232 | break; 233 | case UPGRADE: 234 | packets.add(createUpgradePacket()); 235 | break; 236 | case NOOP: 237 | packets.add(createNoopPacket()); 238 | break; 239 | default: 240 | throw new SocketIOProtocolException("Unexpected EIO packet type: " + type); 241 | } 242 | } 243 | 244 | return packets; 245 | } 246 | 247 | static int decodePacketLength(String data, ParsePosition pos) 248 | throws SocketIOProtocolException 249 | { 250 | Number len = new DecimalFormat("#").parse(data, pos); 251 | if (len == null) 252 | throw new SocketIOProtocolException("No packet length defined"); 253 | 254 | pos.setIndex(pos.getIndex() + 1); 255 | 256 | return len.intValue(); 257 | } 258 | 259 | static EngineIOPacket.Type decodePacketType(String data, ParsePosition pos) 260 | throws SocketIOProtocolException 261 | { 262 | int idx = pos.getIndex(); 263 | EngineIOPacket.Type type = EngineIOPacket.Type.fromInt(Integer.parseInt(data.substring(idx, idx + 1))); 264 | pos.setIndex(idx + 1); 265 | return type; 266 | } 267 | 268 | static int decodePacketLength(InputStream is) 269 | throws IOException 270 | { 271 | int len = 0; 272 | 273 | while (true) 274 | { 275 | int b = is.read(); 276 | if(b < 0) 277 | return -1; // end of stream. time to go 278 | if(b > 9) 279 | break; // end of encoded length 280 | len = len * 10 + b; 281 | } 282 | 283 | return len; 284 | } 285 | 286 | static EngineIOPacket.Type decodePacketType(int packetFormat, InputStream is) 287 | throws IOException 288 | { 289 | int i = is.read(); 290 | if(i < 0) 291 | throw new SocketIOProtocolException("Unexpected end of stream"); 292 | if(packetFormat == TEXT_FORMAT) 293 | i = Integer.parseInt(String.valueOf((char)i)); 294 | 295 | return EngineIOPacket.Type.fromInt(i); 296 | } 297 | 298 | public final static int TEXT_FORMAT = 0; 299 | public final static int BINARY_FORMAT = 1; 300 | public static List binaryDecodePayload(InputStream is) throws IOException 301 | { 302 | final ArrayList packets = new ArrayList<>(); 303 | while (true) 304 | { 305 | final int packetFormat = is.read(); 306 | if(packetFormat == -1) 307 | break; // end of payload stream, done 308 | if(packetFormat != BINARY_FORMAT && packetFormat != TEXT_FORMAT) 309 | throw new SocketIOProtocolException("Unknown packet format (should be 0 or 1) :" + packetFormat); 310 | final int len = decodePacketLength(is); 311 | if(len < 0) // end of payload stream, done 312 | break; 313 | if(packetFormat == BINARY_FORMAT && len == 0) 314 | throw new SocketIOProtocolException("Empty binary attachment"); 315 | final EngineIOPacket.Type packetType = decodePacketType(packetFormat,is); 316 | byte[] data = new byte[len-1]; 317 | ByteStreams.readFully(is, data, 0, data.length); 318 | 319 | switch (packetType) 320 | { 321 | case CLOSE: 322 | packets.add(createClosePacket()); 323 | break; 324 | case PING: 325 | if(packetFormat == TEXT_FORMAT) 326 | packets.add(createPingPacket(new String(data,"UTF-8"))); 327 | else 328 | throw new SocketIOProtocolException("No implementation for binary PING"); 329 | break; 330 | case MESSAGE: 331 | if(packetFormat == TEXT_FORMAT) 332 | packets.add(createMessagePacket(new String(data,"UTF-8"))); 333 | else 334 | packets.add(createMessagePacket(new ByteArrayInputStream(data))); 335 | break; 336 | case UPGRADE: 337 | packets.add(createUpgradePacket()); 338 | break; 339 | case NOOP: 340 | packets.add(createNoopPacket()); 341 | break; 342 | default: 343 | throw new SocketIOProtocolException("Unexpected EIO packet type: " + packetType); 344 | } 345 | } 346 | return packets; 347 | } 348 | } 349 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 4.0.0 6 | 7 | com.codeminders.socketio 8 | socketio-parent 9 | 1.0.10 10 | pom 11 | 12 | Socket.IO Java Server 13 | Java backend for Socket.IO javascript library 14 | https://github.com/codeminders/socket.io-server-java 15 | 2010 16 | 17 | 18 | 1.7 19 | UTF-8 20 | 21 | 22 | 23 | 24 | alexsova 25 | Alexander Sova 26 | bird@codeminders.com 27 | -8 28 | 29 | owner 30 | developer 31 | 32 | 33 | 34 | 35 | 36 | 37 | Tad Glines 38 | tad.glines@gmail.com 39 | -8 40 | 41 | contributor 42 | 43 | 44 | 45 | David Avenante 46 | d.avenante@ovea.com 47 | Ovea 48 | http://www.ovea.com/ 49 | -5 50 | 51 | contributor 52 | 53 | 54 | 55 | Mathieu Carbou 56 | mathieu.carbou@gmail.com 57 | Mycila 58 | http://www.mycila.com/ 59 | -5 60 | 61 | contributor 62 | 63 | 64 | 65 | SQReder 66 | sqreder@gmail.com 67 | +3 68 | 69 | contributor 70 | 71 | 72 | 73 | 74 | 75 | 76 | The MIT License 77 | http://www.opensource.org/licenses/mit-license.php 78 | repo 79 | 80 | 81 | 82 | 83 | github 84 | https://github.com/codeminders/socket.io-server-java/issues 85 | 86 | 87 | 88 | scm:git:git@github.com:codeminders/socket.io-server-java.git 89 | scm:git:git@github.com:codeminders/socket.io-server-java.git 90 | git@github.com:codeminders/socket.io-server-java.git 91 | 92 | 93 | 94 | socket-io 95 | samples 96 | 97 | 98 | 99 | 100 | ossrh 101 | https://oss.sonatype.org/content/repositories/snapshots 102 | 103 | 104 | ossrh 105 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 106 | 107 | 108 | 109 | 110 | 111 | 112 | org.apache.maven.wagon 113 | wagon-webdav 114 | 1.0-beta-2 115 | 116 | 117 | org.apache.maven.wagon 118 | wagon-ssh-external 119 | 1.0-beta-7 120 | 121 | 122 | 123 | 124 | 125 | maven-enforcer-plugin 126 | 1.0-beta-1 127 | 128 | 129 | 130 | (,2.1.0),(2.1.0,2.2.0),(2.2.0,) 131 | 132 | Maven 2.1.0 and 2.2.0 produce incorrect GPG signatures and checksums respectively. 133 | 134 | 135 | 136 | 137 | 138 | 139 | maven-compiler-plugin 140 | 2.3.2 141 | 142 | UTF-8 143 | 1.6 144 | 1.6 145 | ${jdk.version} 146 | ${jdk.version} 147 | 148 | 149 | 150 | org.apache.maven.plugins 151 | maven-gpg-plugin 152 | 1.5 153 | 154 | 155 | 156 | maven-release-plugin 157 | 2.1 158 | 159 | true 160 | 161 | 162 | 163 | maven-war-plugin 164 | 2.6 165 | 166 | false 167 | 168 | 169 | 170 | maven-source-plugin 171 | 2.1.2 172 | 173 | 174 | maven-jar-plugin 175 | 2.3.1 176 | 177 | 178 | maven-jarsigner-plugin 179 | 1.2 180 | 181 | 182 | maven-javadoc-plugin 183 | 2.7 184 | 185 | ${jdk.version} 186 | UTF-8 187 | 1g 188 | 189 | 190 | 191 | maven-deploy-plugin 192 | 2.5 193 | 194 | 195 | maven-clean-plugin 196 | 2.4.1 197 | 198 | 199 | maven-shade-plugin 200 | 1.4 201 | 202 | 203 | maven-assembly-plugin 204 | 2.2 205 | 206 | 207 | maven-antrun-plugin 208 | 1.6 209 | 210 | 211 | maven-dependency-plugin 212 | 2.1 213 | 214 | 215 | maven-surefire-plugin 216 | 2.6 217 | 218 | 219 | org.codehaus.groovy.maven 220 | gmaven-plugin 221 | 1.0 222 | 223 | 224 | org.sonatype.plugins 225 | nexus-staging-maven-plugin 226 | 1.6.3 227 | true 228 | 229 | ossrh 230 | https://oss.sonatype.org/ 231 | false 232 | 233 | 234 | 235 | 236 | 237 | 238 | maven-enforcer-plugin 239 | 240 | 241 | enforce-maven 242 | 243 | enforce 244 | 245 | 246 | 247 | 248 | 249 | 250 | maven-jar-plugin 251 | 252 | 253 | 254 | jar 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | target/site 264 | 265 | 266 | maven-javadoc-plugin 267 | 2.7 268 | 269 | ${jdk.version} 270 | UTF-8 271 | 1g 272 | 273 | http://download.oracle.com/javase/6/docs/api/ 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | javax.servlet 283 | javax.servlet-api 284 | 3.0.1 285 | provided 286 | 287 | 288 | com.google.guava 289 | guava 290 | 23.0 291 | 292 | 293 | 294 | 295 | 296 | 297 | default 298 | 299 | true 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | release 309 | 310 | 311 | 312 | maven-source-plugin 313 | 314 | 315 | 316 | jar 317 | 318 | 319 | 320 | 321 | 322 | 323 | maven-javadoc-plugin 324 | 325 | 326 | attach-javadocs 327 | 328 | jar 329 | 330 | 331 | 332 | 333 | 334 | 335 | maven-gpg-plugin 336 | 337 | 338 | sign-artifacts 339 | verify 340 | 341 | sign 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | --------------------------------------------------------------------------------