├── .gitignore ├── README.md ├── deployGlassfish.sh ├── deployTomcat.sh ├── deployWildFly.sh ├── pom.xml ├── shutdownTomcat.sh └── src ├── main ├── java │ └── org │ │ └── springframework │ │ └── samples │ │ └── websocket │ │ ├── client │ │ ├── GreetingService.java │ │ ├── SimpleClientWebSocketHandler.java │ │ └── SimpleGreetingService.java │ │ ├── config │ │ ├── DispatcherServletInitializer.java │ │ └── WebConfig.java │ │ ├── echo │ │ ├── DefaultEchoService.java │ │ ├── EchoService.java │ │ └── EchoWebSocketHandler.java │ │ └── snake │ │ ├── Direction.java │ │ ├── Location.java │ │ ├── Snake.java │ │ ├── SnakeTimer.java │ │ ├── SnakeUtils.java │ │ └── SnakeWebSocketHandler.java ├── js │ ├── echo-issue4.js │ └── node_modules │ │ └── sockjs-client │ │ ├── .npmignore │ │ ├── README.md │ │ ├── index.js │ │ ├── lib │ │ └── sockjs-client.js │ │ ├── node_modules │ │ └── node-uuid │ │ │ ├── .npmignore │ │ │ ├── LICENSE.md │ │ │ ├── README.md │ │ │ ├── benchmark │ │ │ ├── README.md │ │ │ ├── bench.gnu │ │ │ ├── bench.sh │ │ │ ├── benchmark-native.c │ │ │ └── benchmark.js │ │ │ ├── package.json │ │ │ ├── test │ │ │ ├── compare_v1.js │ │ │ ├── test.html │ │ │ └── test.js │ │ │ └── uuid.js │ │ └── package.json ├── resources │ └── log4j2.xml └── webapp │ ├── echo.html │ ├── index.html │ └── snake.html └── test ├── java └── org │ └── springframework │ └── samples │ └── websocket │ └── echo │ ├── JettyClient.java │ └── StandardClient.java └── resources └── log4j.xml /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | .project 3 | .classpath 4 | .settings 5 | *.iml 6 | /.idea/ 7 | bin 8 | .gradle 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Overview 2 | 3 | Demonstrates Spring WebSocket and SockJS support in the Spring Framework. For a longer overview please see the [Spring Framework reference](https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/web.html#websocket). 4 | 5 | **IMPORTANT:** The `master` branch contains examples using Spring's `WebSocketHandler` including with SockJS fallback options. The `endpoint` branch contains examples of using JSR-356 `Endpoint` and `@ServerEndpoint`. 6 | 7 | **NOTE:** Also check out the [Stock Portfolio](https://github.com/rstoyanchev/spring-websocket-portfolio) sample that demonstrates the use of a higher-level messaging over WebSocket. 8 | 9 | ### Tomcat 10 | 11 | Set `TOMCAT_HOME` as an environment variable and use [deployTomcat.sh](https://github.com/rstoyanchev/spring-websocket-test/blob/master/deployTomcat.sh) and [shutdownTomcat.sh](https://github.com/rstoyanchev/spring-websocket-test/blob/master/shutdownTomcat.sh) in this directory. 12 | 13 | Open a browser and go to 14 | 15 | ### Jetty 16 | 17 | The easiest way to run on Jetty is with `mvn jetty:run`. 18 | 19 | Open a browser and go to 20 | 21 | **Note:** To deploy to a Jetty installation, add this to Jetty's `start.ini`: 22 | 23 | OPTIONS=plus 24 | etc/jetty-plus.xml 25 | OPTIONS=annotations 26 | etc/jetty-annotations.xml 27 | 28 | ### WildFly 10+ 29 | 30 | Unzip the WildFly server. 31 | 32 | Set `WILDFLY_HOME` as an environment variable and use [deployWildFly.sh](https://github.com/rstoyanchev/spring-websocket-test/blob/master/deployWildFly.sh) in this directory. 33 | 34 | Open a browser and go to 35 | 36 | ### WebSphere Liberty 16+ 37 | 38 | Build and deploy with the following server configuration: 39 | 40 | 41 | 42 | 43 | 44 | jsp-2.3 45 | webSocket-1.1 46 | 47 | 48 | 51 | 52 | 53 | 54 | 55 | ### Glassfish 56 | 57 | Glassfish 4 provides JSR-356 support. 58 | 59 | Download Glassfish 4 and unzip the downloaded distribution. 60 | 61 | Start the server: 62 | 63 | cd /glassfish4 64 | bin/asadmin start-domain 65 | 66 | Deploy the WAR file using the script in this directory. 67 | 68 | Open a browser and go to 69 | 70 | Watch the logs: 71 | 72 | cd /glassfish4 73 | less `glassfish/domains/domain1/logs/server.log` 74 | 75 | -------------------------------------------------------------------------------- /deployGlassfish.sh: -------------------------------------------------------------------------------- 1 | 2 | if [ -z "$GLASSFISH4_HOME" ]; then 3 | echo -e "\n\nPlease set GLASSFISH4_HOME\n" 4 | echo -e "Also make sure you've called \`\$GLASSFISH4_HOME/bin/asadmin stop-domain\`\n\n" 5 | exit 1 6 | fi 7 | 8 | mvn -DskipTests clean package 9 | 10 | $GLASSFISH4_HOME/bin/asadmin deploy --force=true target/spring-websocket-test.war 11 | -------------------------------------------------------------------------------- /deployTomcat.sh: -------------------------------------------------------------------------------- 1 | 2 | if [ -z "$TOMCAT_HOME" ]; then 3 | echo -e "\n\nPlease set TOMCAT_HOME\n\n" 4 | exit 1 5 | fi 6 | 7 | mvn -DskipTests clean package 8 | 9 | rm -rf $TOMCAT_HOME/webapps/spring-websocket-test* 10 | 11 | cp target/spring-websocket-test.war $TOMCAT_HOME/webapps/ 12 | 13 | $TOMCAT_HOME/bin/startup.sh 14 | -------------------------------------------------------------------------------- /deployWildFly.sh: -------------------------------------------------------------------------------- 1 | 2 | if [ -z "$WILDFLY_HOME" ]; then 3 | echo -e "\n\nPlease set WILDFLY_HOME\n\n" 4 | exit 1 5 | fi 6 | 7 | mvn -DskipTests clean package 8 | 9 | rm -rf $WILDFLY_HOME/standalone/deployments/spring-websocket-test* 10 | 11 | cp target/spring-websocket-test.war $WILDFLY_HOME/standalone/deployments/ 12 | 13 | $WILDFLY_HOME/bin/standalone.sh 14 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | org.springframework.samples 5 | spring-websocket-test 6 | war 7 | 1.0.0-SNAPSHOT 8 | 9 | 10 | 11 | 12 | org.springframework 13 | spring-framework-bom 14 | pom 15 | import 16 | 5.3.13 17 | 18 | 19 | org.eclipse.jetty 20 | jetty-bom 21 | pom 22 | import 23 | 10.0.7 24 | 25 | 26 | org.apache.logging.log4j 27 | log4j-bom 28 | pom 29 | import 30 | 2.15.0 31 | 32 | 33 | 34 | 35 | 36 | 9.0.56 37 | 38 | 39 | 40 | 41 | org.springframework 42 | spring-context 43 | 44 | 45 | org.springframework 46 | spring-webmvc 47 | 48 | 49 | org.springframework 50 | spring-websocket 51 | 52 | 53 | javax.servlet 54 | javax.servlet-api 55 | 4.0.1 56 | provided 57 | 58 | 59 | 60 | 61 | com.fasterxml.jackson.core 62 | jackson-databind 63 | 2.12.0 64 | 65 | 66 | 67 | org.apache.logging.log4j 68 | log4j-api 69 | 70 | 71 | org.apache.logging.log4j 72 | log4j-core 73 | 74 | 75 | org.apache.logging.log4j 76 | log4j-slf4j-impl 77 | 78 | 79 | org.apache.logging.log4j 80 | log4j-jul 81 | 82 | 83 | 84 | org.apache.tomcat 85 | tomcat-websocket 86 | ${tomcat.version} 87 | test 88 | 89 | 90 | org.apache.tomcat.embed 91 | tomcat-embed-core 92 | ${tomcat.version} 93 | provided 94 | 95 | 96 | org.apache.tomcat.embed 97 | tomcat-embed-websocket 98 | ${tomcat.version} 99 | provided 100 | 101 | 102 | org.eclipse.jetty.websocket 103 | websocket-jetty-client 104 | test 105 | 106 | 107 | 108 | 109 | ${project.artifactId} 110 | 111 | 112 | org.apache.maven.plugins 113 | maven-compiler-plugin 114 | 115 | 11 116 | 11 117 | 118 | 119 | 120 | org.apache.maven.plugins 121 | maven-war-plugin 122 | 123 | false 124 | 125 | 126 | 127 | org.apache.maven.plugins 128 | maven-resources-plugin 129 | 130 | UTF-8 131 | 132 | 133 | 134 | org.eclipse.jetty 135 | jetty-maven-plugin 136 | 137 | 138 | /${project.artifactId} 139 | 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /shutdownTomcat.sh: -------------------------------------------------------------------------------- 1 | 2 | if [ -z "$TOMCAT_HOME" ]; then 3 | echo -e "\n\nPlease set TOMCAT_HOME\n\n" 4 | exit 1 5 | fi 6 | 7 | $TOMCAT_HOME/bin/shutdown.sh 8 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/samples/websocket/client/GreetingService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.websocket.client; 17 | 18 | public interface GreetingService { 19 | 20 | String getGreeting(); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/samples/websocket/client/SimpleClientWebSocketHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.websocket.client; 17 | 18 | import org.apache.logging.log4j.LogManager; 19 | import org.apache.logging.log4j.Logger; 20 | 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.web.socket.TextMessage; 23 | import org.springframework.web.socket.WebSocketSession; 24 | import org.springframework.web.socket.handler.TextWebSocketHandler; 25 | 26 | public class SimpleClientWebSocketHandler extends TextWebSocketHandler { 27 | 28 | protected Logger logger = LogManager.getLogger(SimpleClientWebSocketHandler.class); 29 | 30 | private final GreetingService greetingService; 31 | 32 | 33 | @Autowired 34 | public SimpleClientWebSocketHandler(GreetingService greetingService) { 35 | this.greetingService = greetingService; 36 | } 37 | 38 | @Override 39 | public void afterConnectionEstablished(WebSocketSession session) throws Exception { 40 | TextMessage message = new TextMessage(this.greetingService.getGreeting()); 41 | session.sendMessage(message); 42 | } 43 | 44 | @Override 45 | public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { 46 | logger.debug("Received: " + message); 47 | session.close(); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/samples/websocket/client/SimpleGreetingService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.websocket.client; 17 | 18 | public class SimpleGreetingService implements GreetingService { 19 | 20 | @Override 21 | public String getGreeting() { 22 | return "Hello world!"; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/samples/websocket/config/DispatcherServletInitializer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.springframework.samples.websocket.config; 18 | 19 | import javax.servlet.ServletRegistration.Dynamic; 20 | 21 | import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; 22 | 23 | public class DispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { 24 | 25 | @Override 26 | protected Class[] getRootConfigClasses() { 27 | return null; 28 | } 29 | 30 | @Override 31 | protected Class[] getServletConfigClasses() { 32 | return new Class[] { WebConfig.class }; 33 | } 34 | 35 | @Override 36 | protected String[] getServletMappings() { 37 | return new String[] { "/" }; 38 | } 39 | 40 | @Override 41 | protected void customizeRegistration(Dynamic registration) { 42 | registration.setInitParameter("dispatchOptionsRequest", "true"); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/samples/websocket/config/WebConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2021 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.websocket.config; 17 | 18 | import org.springframework.context.annotation.Bean; 19 | import org.springframework.context.annotation.Configuration; 20 | import org.springframework.samples.websocket.echo.DefaultEchoService; 21 | import org.springframework.samples.websocket.echo.EchoWebSocketHandler; 22 | import org.springframework.samples.websocket.snake.SnakeWebSocketHandler; 23 | import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; 24 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 25 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; 26 | import org.springframework.web.socket.WebSocketHandler; 27 | import org.springframework.web.socket.config.annotation.EnableWebSocket; 28 | import org.springframework.web.socket.config.annotation.WebSocketConfigurer; 29 | import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry; 30 | import org.springframework.web.socket.handler.PerConnectionWebSocketHandler; 31 | 32 | @Configuration 33 | @EnableWebMvc 34 | @EnableWebSocket 35 | public class WebConfig implements WebMvcConfigurer, WebSocketConfigurer { 36 | 37 | @Override 38 | public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { 39 | 40 | registry.addHandler(echoWebSocketHandler(), "/echo", "/echo-issue4"); 41 | registry.addHandler(snakeWebSocketHandler(), "/snake"); 42 | 43 | registry.addHandler(echoWebSocketHandler(), "/sockjs/echo").withSockJS(); 44 | registry.addHandler(echoWebSocketHandler(), "/sockjs/echo-issue4").withSockJS().setHttpMessageCacheSize(20000); 45 | 46 | registry.addHandler(snakeWebSocketHandler(), "/sockjs/snake").withSockJS(); 47 | } 48 | 49 | @Bean 50 | public WebSocketHandler echoWebSocketHandler() { 51 | return new EchoWebSocketHandler(echoService()); 52 | } 53 | 54 | @Bean 55 | public WebSocketHandler snakeWebSocketHandler() { 56 | return new PerConnectionWebSocketHandler(SnakeWebSocketHandler.class); 57 | } 58 | 59 | @Bean 60 | public DefaultEchoService echoService() { 61 | return new DefaultEchoService("Did you say \"%s\"?"); 62 | } 63 | 64 | // Allow serving HTML files through the default Servlet 65 | 66 | @Override 67 | public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { 68 | configurer.enable(); 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/samples/websocket/echo/DefaultEchoService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.websocket.echo; 17 | 18 | public class DefaultEchoService implements EchoService { 19 | 20 | private final String echoFormat; 21 | 22 | public DefaultEchoService(String echoFormat) { 23 | this.echoFormat = (echoFormat != null) ? echoFormat : "%s"; 24 | } 25 | 26 | @Override 27 | public String getMessage(String message) { 28 | return String.format(this.echoFormat, message); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/samples/websocket/echo/EchoService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.websocket.echo; 17 | 18 | public interface EchoService { 19 | 20 | String getMessage(String message); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/samples/websocket/echo/EchoWebSocketHandler.java: -------------------------------------------------------------------------------- 1 | package org.springframework.samples.websocket.echo; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.web.socket.TextMessage; 5 | import org.springframework.web.socket.WebSocketHandler; 6 | import org.springframework.web.socket.WebSocketSession; 7 | import org.springframework.web.socket.handler.TextWebSocketHandler; 8 | 9 | /** 10 | * Echo messages by implementing a Spring {@link WebSocketHandler} abstraction. 11 | */ 12 | public class EchoWebSocketHandler extends TextWebSocketHandler { 13 | 14 | private final EchoService echoService; 15 | 16 | 17 | @Autowired 18 | public EchoWebSocketHandler(EchoService echoService) { 19 | this.echoService = echoService; 20 | } 21 | 22 | @Override 23 | public void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { 24 | String reply = this.echoService.getMessage(message.getPayload()); 25 | session.sendMessage(new TextMessage(reply)); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/samples/websocket/snake/Direction.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.springframework.samples.websocket.snake; 18 | 19 | public enum Direction { 20 | NONE, NORTH, SOUTH, EAST, WEST 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/samples/websocket/snake/Location.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.springframework.samples.websocket.snake; 18 | 19 | 20 | public class Location { 21 | 22 | public static final int PLAYFIELD_WIDTH = 640; 23 | public static final int PLAYFIELD_HEIGHT = 480; 24 | public static final int GRID_SIZE = 10; 25 | 26 | public int x; 27 | public int y; 28 | 29 | public Location(int x, int y) { 30 | this.x = x; 31 | this.y = y; 32 | } 33 | 34 | public Location getAdjacentLocation(Direction direction) { 35 | switch (direction) { 36 | case NORTH: 37 | return new Location(x, y - GRID_SIZE); 38 | case SOUTH: 39 | return new Location(x, y + GRID_SIZE); 40 | case EAST: 41 | return new Location(x + GRID_SIZE, y); 42 | case WEST: 43 | return new Location(x - GRID_SIZE, y); 44 | case NONE: 45 | // fall through 46 | default: 47 | return this; 48 | } 49 | } 50 | 51 | @Override 52 | public boolean equals(Object o) { 53 | if (this == o) return true; 54 | if (o == null || getClass() != o.getClass()) return false; 55 | 56 | Location location = (Location) o; 57 | 58 | if (x != location.x) return false; 59 | if (y != location.y) return false; 60 | 61 | return true; 62 | } 63 | 64 | @Override 65 | public int hashCode() { 66 | int result = x; 67 | result = 31 * result + y; 68 | return result; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/samples/websocket/snake/Snake.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.springframework.samples.websocket.snake; 18 | 19 | import java.util.ArrayDeque; 20 | import java.util.Collection; 21 | import java.util.Deque; 22 | 23 | import org.springframework.web.socket.TextMessage; 24 | import org.springframework.web.socket.WebSocketSession; 25 | 26 | 27 | public class Snake { 28 | 29 | private static final int DEFAULT_LENGTH = 5; 30 | 31 | private final int id; 32 | private final WebSocketSession session; 33 | 34 | private Direction direction; 35 | private int length = DEFAULT_LENGTH; 36 | private Location head; 37 | private final Deque tail = new ArrayDeque(); 38 | private final String hexColor; 39 | 40 | public Snake(int id, WebSocketSession session) { 41 | this.id = id; 42 | this.session = session; 43 | this.hexColor = SnakeUtils.getRandomHexColor(); 44 | resetState(); 45 | } 46 | 47 | private void resetState() { 48 | this.direction = Direction.NONE; 49 | this.head = SnakeUtils.getRandomLocation(); 50 | this.tail.clear(); 51 | this.length = DEFAULT_LENGTH; 52 | } 53 | 54 | private synchronized void kill() throws Exception { 55 | resetState(); 56 | sendMessage("{'type': 'dead'}"); 57 | } 58 | 59 | private synchronized void reward() throws Exception { 60 | length++; 61 | sendMessage("{'type': 'kill'}"); 62 | } 63 | 64 | 65 | protected void sendMessage(String msg) throws Exception { 66 | session.sendMessage(new TextMessage(msg)); 67 | } 68 | 69 | public synchronized void update(Collection snakes) throws Exception { 70 | Location nextLocation = head.getAdjacentLocation(direction); 71 | if (nextLocation.x >= SnakeUtils.PLAYFIELD_WIDTH) { 72 | nextLocation.x = 0; 73 | } 74 | if (nextLocation.y >= SnakeUtils.PLAYFIELD_HEIGHT) { 75 | nextLocation.y = 0; 76 | } 77 | if (nextLocation.x < 0) { 78 | nextLocation.x = SnakeUtils.PLAYFIELD_WIDTH; 79 | } 80 | if (nextLocation.y < 0) { 81 | nextLocation.y = SnakeUtils.PLAYFIELD_HEIGHT; 82 | } 83 | if (direction != Direction.NONE) { 84 | tail.addFirst(head); 85 | if (tail.size() > length) { 86 | tail.removeLast(); 87 | } 88 | head = nextLocation; 89 | } 90 | 91 | handleCollisions(snakes); 92 | } 93 | 94 | private void handleCollisions(Collection snakes) throws Exception { 95 | for (Snake snake : snakes) { 96 | boolean headCollision = id != snake.id && snake.getHead().equals(head); 97 | boolean tailCollision = snake.getTail().contains(head); 98 | if (headCollision || tailCollision) { 99 | kill(); 100 | if (id != snake.id) { 101 | snake.reward(); 102 | } 103 | } 104 | } 105 | } 106 | 107 | public synchronized Location getHead() { 108 | return head; 109 | } 110 | 111 | public synchronized Collection getTail() { 112 | return tail; 113 | } 114 | 115 | public synchronized void setDirection(Direction direction) { 116 | this.direction = direction; 117 | } 118 | 119 | public synchronized String getLocationsJson() { 120 | StringBuilder sb = new StringBuilder(); 121 | sb.append(String.format("{x: %d, y: %d}", 122 | Integer.valueOf(head.x), Integer.valueOf(head.y))); 123 | for (Location location : tail) { 124 | sb.append(','); 125 | sb.append(String.format("{x: %d, y: %d}", 126 | Integer.valueOf(location.x), Integer.valueOf(location.y))); 127 | } 128 | return String.format("{'id':%d,'body':[%s]}", 129 | Integer.valueOf(id), sb.toString()); 130 | } 131 | 132 | public int getId() { 133 | return id; 134 | } 135 | 136 | public String getHexColor() { 137 | return hexColor; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/samples/websocket/snake/SnakeTimer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.springframework.samples.websocket.snake; 18 | 19 | import java.util.Collection; 20 | import java.util.Collections; 21 | import java.util.Iterator; 22 | import java.util.Timer; 23 | import java.util.TimerTask; 24 | import java.util.concurrent.ConcurrentHashMap; 25 | 26 | import org.apache.logging.log4j.LogManager; 27 | import org.apache.logging.log4j.Logger; 28 | 29 | /** 30 | * Sets up the timer for the multi-player snake game WebSocket example. 31 | */ 32 | public class SnakeTimer { 33 | 34 | private static final Logger log = LogManager.getLogger(SnakeTimer.class); 35 | 36 | private static Timer gameTimer = null; 37 | 38 | private static final long TICK_DELAY = 100; 39 | 40 | private static final ConcurrentHashMap snakes = 41 | new ConcurrentHashMap(); 42 | 43 | public static synchronized void addSnake(Snake snake) { 44 | if (snakes.size() == 0) { 45 | startTimer(); 46 | } 47 | snakes.put(Integer.valueOf(snake.getId()), snake); 48 | } 49 | 50 | 51 | public static Collection getSnakes() { 52 | return Collections.unmodifiableCollection(snakes.values()); 53 | } 54 | 55 | 56 | public static synchronized void removeSnake(Snake snake) { 57 | snakes.remove(Integer.valueOf(snake.getId())); 58 | if (snakes.size() == 0) { 59 | stopTimer(); 60 | } 61 | } 62 | 63 | 64 | public static void tick() throws Exception { 65 | StringBuilder sb = new StringBuilder(); 66 | for (Iterator iterator = SnakeTimer.getSnakes().iterator(); 67 | iterator.hasNext();) { 68 | Snake snake = iterator.next(); 69 | snake.update(SnakeTimer.getSnakes()); 70 | sb.append(snake.getLocationsJson()); 71 | if (iterator.hasNext()) { 72 | sb.append(','); 73 | } 74 | } 75 | broadcast(String.format("{'type': 'update', 'data' : [%s]}", 76 | sb.toString())); 77 | } 78 | 79 | public static void broadcast(String message) throws Exception { 80 | for (Snake snake : SnakeTimer.getSnakes()) { 81 | snake.sendMessage(message); 82 | } 83 | } 84 | 85 | 86 | public static void startTimer() { 87 | gameTimer = new Timer(SnakeTimer.class.getSimpleName() + " Timer"); 88 | gameTimer.scheduleAtFixedRate(new TimerTask() { 89 | @Override 90 | public void run() { 91 | try { 92 | tick(); 93 | } catch (Throwable e) { 94 | log.error("Caught to prevent timer from shutting down", e); 95 | } 96 | } 97 | }, TICK_DELAY, TICK_DELAY); 98 | } 99 | 100 | 101 | public static void stopTimer() { 102 | if (gameTimer != null) { 103 | gameTimer.cancel(); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/samples/websocket/snake/SnakeUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.springframework.samples.websocket.snake; 18 | 19 | import java.awt.Color; 20 | import java.util.Random; 21 | 22 | public class SnakeUtils { 23 | 24 | public static final int PLAYFIELD_WIDTH = 640; 25 | public static final int PLAYFIELD_HEIGHT = 480; 26 | public static final int GRID_SIZE = 10; 27 | 28 | private static final Random random = new Random(); 29 | 30 | 31 | public static String getRandomHexColor() { 32 | float hue = random.nextFloat(); 33 | // sat between 0.1 and 0.3 34 | float saturation = (random.nextInt(2000) + 1000) / 10000f; 35 | float luminance = 0.9f; 36 | Color color = Color.getHSBColor(hue, saturation, luminance); 37 | return '#' + Integer.toHexString( 38 | (color.getRGB() & 0xffffff) | 0x1000000).substring(1); 39 | } 40 | 41 | 42 | public static Location getRandomLocation() { 43 | int x = roundByGridSize(random.nextInt(PLAYFIELD_WIDTH)); 44 | int y = roundByGridSize(random.nextInt(PLAYFIELD_HEIGHT)); 45 | return new Location(x, y); 46 | } 47 | 48 | 49 | private static int roundByGridSize(int value) { 50 | value = value + (GRID_SIZE / 2); 51 | value = value / GRID_SIZE; 52 | value = value * GRID_SIZE; 53 | return value; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/org/springframework/samples/websocket/snake/SnakeWebSocketHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | package org.springframework.samples.websocket.snake; 18 | 19 | import java.awt.Color; 20 | import java.util.Iterator; 21 | import java.util.Random; 22 | import java.util.concurrent.atomic.AtomicInteger; 23 | 24 | import org.springframework.web.socket.CloseStatus; 25 | import org.springframework.web.socket.TextMessage; 26 | import org.springframework.web.socket.WebSocketSession; 27 | import org.springframework.web.socket.handler.TextWebSocketHandler; 28 | 29 | public class SnakeWebSocketHandler extends TextWebSocketHandler { 30 | 31 | public static final int PLAYFIELD_WIDTH = 640; 32 | public static final int PLAYFIELD_HEIGHT = 480; 33 | public static final int GRID_SIZE = 10; 34 | 35 | private static final AtomicInteger snakeIds = new AtomicInteger(0); 36 | private static final Random random = new Random(); 37 | 38 | 39 | private final int id; 40 | private Snake snake; 41 | 42 | public static String getRandomHexColor() { 43 | float hue = random.nextFloat(); 44 | // sat between 0.1 and 0.3 45 | float saturation = (random.nextInt(2000) + 1000) / 10000f; 46 | float luminance = 0.9f; 47 | Color color = Color.getHSBColor(hue, saturation, luminance); 48 | return '#' + Integer.toHexString( 49 | (color.getRGB() & 0xffffff) | 0x1000000).substring(1); 50 | } 51 | 52 | 53 | public static Location getRandomLocation() { 54 | int x = roundByGridSize(random.nextInt(PLAYFIELD_WIDTH)); 55 | int y = roundByGridSize(random.nextInt(PLAYFIELD_HEIGHT)); 56 | return new Location(x, y); 57 | } 58 | 59 | 60 | private static int roundByGridSize(int value) { 61 | value = value + (GRID_SIZE / 2); 62 | value = value / GRID_SIZE; 63 | value = value * GRID_SIZE; 64 | return value; 65 | } 66 | 67 | public SnakeWebSocketHandler() { 68 | this.id = snakeIds.getAndIncrement(); 69 | } 70 | 71 | 72 | @Override 73 | public void afterConnectionEstablished(WebSocketSession session) throws Exception { 74 | this.snake = new Snake(id, session); 75 | SnakeTimer.addSnake(snake); 76 | StringBuilder sb = new StringBuilder(); 77 | for (Iterator iterator = SnakeTimer.getSnakes().iterator(); 78 | iterator.hasNext();) { 79 | Snake snake = iterator.next(); 80 | sb.append(String.format("{id: %d, color: '%s'}", 81 | Integer.valueOf(snake.getId()), snake.getHexColor())); 82 | if (iterator.hasNext()) { 83 | sb.append(','); 84 | } 85 | } 86 | SnakeTimer.broadcast(String.format("{'type': 'join','data':[%s]}", 87 | sb.toString())); 88 | } 89 | 90 | 91 | @Override 92 | protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { 93 | String payload = message.getPayload(); 94 | if ("west".equals(payload)) { 95 | snake.setDirection(Direction.WEST); 96 | } else if ("north".equals(payload)) { 97 | snake.setDirection(Direction.NORTH); 98 | } else if ("east".equals(payload)) { 99 | snake.setDirection(Direction.EAST); 100 | } else if ("south".equals(payload)) { 101 | snake.setDirection(Direction.SOUTH); 102 | } 103 | } 104 | 105 | 106 | @Override 107 | public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { 108 | SnakeTimer.removeSnake(snake); 109 | SnakeTimer.broadcast(String.format("{'type': 'leave', 'id': %d}", 110 | Integer.valueOf(id))); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/main/js/echo-issue4.js: -------------------------------------------------------------------------------- 1 | 2 | var sjsc = require('sockjs-client'); 3 | 4 | // See: 5 | // https://github.com/rstoyanchev/spring-websocket-test/issues/4 6 | 7 | var client = sjsc.create("http://localhost:8080/spring-websocket-test/sockjs/echo-issue4"); 8 | 9 | client.on('connection', function () { 10 | console.log("Woohoo, connected"); 11 | for (var i = 0; i < 20000; i++) { 12 | client.write('Message ' + (i + 1)); 13 | } 14 | }); 15 | 16 | client.on('data', function (msg) { 17 | console.log("Got data: " + msg); 18 | }); 19 | 20 | client.on('error', function (e) { 21 | console.log("Got error: " + e); 22 | }); 23 | -------------------------------------------------------------------------------- /src/main/js/node_modules/sockjs-client/.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *~ 3 | -------------------------------------------------------------------------------- /src/main/js/node_modules/sockjs-client/README.md: -------------------------------------------------------------------------------- 1 | # SockJS Client Node 2 | 3 | Node client for [SockJS](https://github.com/sockjs). Currently, only 4 | the XHR Streaming transport is supported. 5 | 6 | ## Usage 7 | 8 | var sjsc = require('sockjs-client'); 9 | var client = sjsc.create("http://localhost/sjsServer"); 10 | client.on('connection', function () { // connection is established }); 11 | client.on('data', function (msg) { // received some data }); 12 | client.on('error', function (e) { // something went wrong }); 13 | client.write("Have some text you mighty SockJS server!"); 14 | -------------------------------------------------------------------------------- /src/main/js/node_modules/sockjs-client/index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/sockjs-client'); 2 | -------------------------------------------------------------------------------- /src/main/js/node_modules/sockjs-client/lib/sockjs-client.js: -------------------------------------------------------------------------------- 1 | (function (parent) { 2 | 'use strict'; 3 | 4 | var url = require('url'), 5 | http = require('http'), 6 | https = require('https'), 7 | uuid = require('node-uuid'), 8 | events = require('events'), 9 | util; 10 | 11 | function InvalidURL (parsedURL) { 12 | this.parsedURL = parsedURL; 13 | } 14 | InvalidURL.prototype = { 15 | prototype: Error.prototype, 16 | toString: function () { return "Invalid URL: " + this.parsedURL.href; } 17 | }; 18 | 19 | function InvalidState (extra) { 20 | this.extra = extra; 21 | } 22 | InvalidState.prototype = { 23 | prototype: Error.prototype, 24 | toString: function () { return "Invalid State " + this.extra; } 25 | }; 26 | 27 | util = (function () { 28 | var empty = {}; 29 | return { 30 | hasOwnProperty: function (obj, field) { 31 | return empty.hasOwnProperty.call(obj, field); 32 | }, 33 | 34 | shallowCopy: function (src, dest) { 35 | var keys = Object.keys(src), 36 | i; 37 | for (i = 0; i < keys.length; i += 1) { 38 | dest[keys[i]] = src[keys[i]]; 39 | } 40 | }, 41 | 42 | liftFunctions: function (src, dest, fields) { 43 | var i, field; 44 | for (i = 0; i < fields.length; i += 1) { 45 | field = fields[i]; 46 | if (undefined !== src[field] && 47 | undefined !== src[field].call) { 48 | dest[field] = src[field].bind(src); 49 | } 50 | } 51 | } 52 | }; 53 | }()); 54 | 55 | function SockJSClient (server) { 56 | var parsed, serverId, sessionId; 57 | 58 | parsed = url.parse(server); 59 | 60 | if ('http:' === parsed.protocol) { 61 | this.client = http; 62 | } else if ('https:' === parsed.protocol) { 63 | this.client = https; 64 | } else { 65 | throw new InvalidURL(parsed); 66 | } 67 | 68 | if (parsed.pathname === '/') { 69 | parsed.pathname = ''; 70 | } 71 | 72 | serverId = Math.round(Math.random() * 999); 73 | sessionId = uuid(); 74 | 75 | this.server = url.parse( 76 | parsed.protocol + "//" + parsed.host + parsed.pathname + 77 | "/" + serverId + "/" + sessionId); 78 | 79 | this.error = Object.getPrototypeOf(this).error.bind(this); 80 | this.connection = Object.getPrototypeOf(this).connection.bind(this); 81 | this.closed = Object.getPrototypeOf(this).closed.bind(this); 82 | 83 | this.emitter = new events.EventEmitter(); 84 | util.liftFunctions( 85 | this.emitter, this, 86 | ['on', 'once', 'removeListener', 'removeAllListeners', 'emit']); 87 | 88 | this.writeBuffer = []; 89 | } 90 | 91 | SockJSClient.prototype = { 92 | isReady: false, 93 | isClosing: false, 94 | isClosed: false, 95 | 96 | connect: function () { 97 | if (this.isReady || this.isClosing || this.isClosed) { 98 | return; 99 | } 100 | var transport = new XHRStreaming(this); 101 | transport.on('error', this.error); 102 | transport.on('connection', this.connection); 103 | transport.on('close', this.closed); 104 | (new StateMachine(transport)).invoke(); 105 | }, 106 | 107 | connection: function (transport) { 108 | if (this.isClosing) { 109 | transport.close(); 110 | } else if (! (this.isReady || this.isClosed)) { 111 | this.isReady = true; 112 | this.transport = transport; 113 | this.emit('connection'); 114 | if (0 !== this.writeBuffer.length) { 115 | transport.write(this.writeBuffer); 116 | this.writeBuffer = []; 117 | } 118 | } 119 | }, 120 | 121 | error: function () { 122 | this.isReady = false; 123 | var args = Array.prototype.slice.call(arguments, 0); 124 | args.unshift('error'); 125 | this.emit.apply(this, args); 126 | if (this.isClosing) { 127 | this.closed(); 128 | } 129 | }, 130 | 131 | write: function (message) { 132 | if (this.isClosed || this.isClosing) { 133 | return; 134 | } else if (this.isReady) { 135 | return this.transport.write([message]); 136 | } else { 137 | this.writeBuffer.push(message); 138 | } 139 | }, 140 | 141 | close: function () { 142 | if (! (this.isClosing || this.isClosed)) { 143 | this.isClosing = true; 144 | if (this.isReady) { 145 | this.isReady = false; 146 | this.transport.close(); 147 | } 148 | } 149 | }, 150 | 151 | closed: function () { 152 | if (! this.isClosed) { 153 | var args = Array.prototype.slice.call(arguments, 0); 154 | args.unshift('close'); 155 | this.emit.apply(this, args); 156 | } 157 | this.isClosed = true; 158 | this.isClosing = false; 159 | this.isReady = false; 160 | } 161 | }; 162 | 163 | function XHRStreaming (sjs) { 164 | this.sjs = sjs; 165 | this.emitter = new events.EventEmitter(); 166 | util.liftFunctions( 167 | this.emitter, this, 168 | ['on', 'once', 'removeListener', 'removeAllListeners', 'emit']); 169 | this.error = Object.getPrototypeOf(this).error.bind(this); 170 | this.initialPayloadRemaining = this.initialPayloadLength; 171 | this.partialChunk = ""; 172 | } 173 | XHRStreaming.prototype = { 174 | fsm: {'start': 'connected', 175 | 'connected': 'dataInitial', 176 | 'dataInitial': 'dataOpen', 177 | 'dataOpen': 'running', 178 | 'running': 'running', 179 | 'errored': 'errored' 180 | }, 181 | 182 | initialPayloadLength: 2049, 183 | 184 | start: function (sm) { 185 | var request = {method: 'POST', 186 | headers: {'Content-Length': 0}}, 187 | clientRequest; 188 | util.shallowCopy(this.sjs.server, request); 189 | request.path += '/xhr_streaming'; 190 | clientRequest = this.sjs.client.request(request, sm.stepper()); 191 | clientRequest.on('error', this.error.bind(this, sm)); 192 | clientRequest.end(); 193 | }, 194 | 195 | write: function (message) { 196 | var data = JSON.stringify(message), 197 | request = {method: 'POST', 198 | headers: { 199 | 'Content-Type': 'application/json', 200 | 'Content-Length': Buffer.byteLength(data,'utf8')}}, 201 | clientRequest; 202 | util.shallowCopy(this.sjs.server, request); 203 | request.path += '/xhr_send'; 204 | clientRequest = this.sjs.client.request(request); 205 | clientRequest.write(data); 206 | clientRequest.end(); 207 | }, 208 | 209 | close: function () { 210 | if (undefined !== this.response) { 211 | this.response.removeAllListeners(); 212 | this.response.destroy(); 213 | } 214 | this.emit('close'); 215 | }, 216 | 217 | connected: function (sm, result) { 218 | this.response = result; 219 | if (200 !== result.statusCode) { 220 | this.error(sm, result.statusCode); 221 | } else { 222 | result.setEncoding('utf8'); 223 | result.on('data', sm.stepper()); 224 | result.on('end', this.reopen.bind(this, sm)); 225 | } 226 | }, 227 | 228 | dataInitial: function (sm, chunk) { 229 | var remaining = this.initialPayloadRemaining - chunk.length; 230 | if (remaining > 0) { 231 | this.initialPayloadRemaining = remaining; 232 | sm.switchTo('dataInitial'); 233 | } else { 234 | this.initialPayloadRemaining = this.initialPayloadLength; 235 | if (remaining < 0) { 236 | (sm.stepper())(sm, chunk.slice(this.initialPayloadRemaining)); 237 | } 238 | } 239 | }, 240 | 241 | dataOpen: function (sm, chunk) { 242 | var fsm; 243 | chunk = this.partialChunk.concat(chunk); 244 | if (chunk.length < 2) { 245 | this.partialChunk = chunk; 246 | sm.switchTo('dataOpen'); 247 | } else { 248 | this.partialChunk = ""; 249 | if ('o\n' === chunk.slice(0, 2)) { 250 | fsm = {}; 251 | util.shallowCopy(this.fsm, fsm); 252 | this.fsm = fsm; 253 | fsm['dataInitial'] = 'running'; // from here on, another 'o\n' is an error 254 | this.emit('connection', this); 255 | if (2 < chunk.length) { 256 | (sm.stepper())(sm, chunk.slice(2)); 257 | } 258 | } else { 259 | this.error(sm, chunk); 260 | } 261 | } 262 | }, 263 | 264 | running: function (sm, chunk) { 265 | var type; 266 | chunk = this.partialChunk.concat(chunk); 267 | if (1 < chunk.length) { 268 | type = chunk.charAt(0); 269 | switch (type) { 270 | case 'h': // heartbeat 271 | this.partialChunk = chunk.slice(2); 272 | break; 273 | case 'a': // data 274 | this.emitData(chunk, this.partialChunk.length); 275 | break; 276 | case 'c': // close frame 277 | this.close(); 278 | break; 279 | default: 280 | this.error(sm, "Unexpected frame type", type, chunk); 281 | } 282 | } else { 283 | this.partialChunk = chunk; 284 | } 285 | }, 286 | 287 | emitData: function (chunk, searchStart) { 288 | var index = chunk.indexOf('\n', searchStart), 289 | array, i; 290 | if (-1 === index) { 291 | this.partialChunk = chunk; 292 | } else { 293 | index += 1; 294 | if (index === chunk.length) { 295 | this.partialChunk = ""; 296 | } else { 297 | this.partialChunk = chunk.slice(index); 298 | } 299 | array = JSON.parse(chunk.slice(1, index)); 300 | for (i = 0; i < array.length; i += 1) { 301 | this.sjs.emit('data', array[i]); 302 | } 303 | } 304 | }, 305 | 306 | reopen: function (sm) { 307 | (sm.stepper('start'))(); 308 | }, 309 | 310 | error: function () { 311 | if (undefined !== this.response) { 312 | this.response.removeAllListeners(); 313 | this.response.destroy(); 314 | } 315 | var args = Array.prototype.slice.call(arguments, 0), 316 | sm; 317 | sm = args.shift(); 318 | sm.switchTo('errored'); 319 | this.emit('error', args); 320 | }, 321 | 322 | errored: function () {} 323 | } 324 | 325 | function StateMachine (callbacks) { 326 | this.callbacks = callbacks; 327 | this.stepper = Object.getPrototypeOf(this).stepper.bind(this); 328 | this.fun = this.stepper(); 329 | } 330 | StateMachine.prototype = { 331 | invoke: function () { 332 | if (undefined === this.fun) { 333 | throw new InvalidState(this); 334 | } 335 | var args = Array.prototype.slice.call(arguments, 0); 336 | console.log(args); 337 | args.unshift(this); 338 | return this.fun.apply(this.callbacks, args); 339 | }, 340 | 341 | nextStateName: function () { 342 | if (util.hasOwnProperty(this, 'switchedTo')) { 343 | return this.switchedTo; 344 | } else if (util.hasOwnProperty(this, 'stateName')) { 345 | return this.callbacks.fsm[this.stateName]; 346 | } else { 347 | return 'start'; 348 | } 349 | }, 350 | 351 | switchTo: function (name) { 352 | if (undefined === name) { 353 | delete this.switchedTo; 354 | } else { 355 | this.switchedTo = name; 356 | } 357 | }, 358 | 359 | stepper: function (name) { 360 | return (function () { 361 | if (undefined !== name) { 362 | this.switchTo(name); 363 | } 364 | this.stateName = this.nextStateName(); 365 | this.switchTo(); 366 | this.fun = this.callbacks[this.stateName]; 367 | this.invoke.apply(this, arguments); 368 | }).bind(this); 369 | } 370 | }; 371 | 372 | exports.create = function (url) { 373 | var sjsc = new SockJSClient(url); 374 | sjsc.connect(); 375 | return sjsc; 376 | }; 377 | exports.InvalidURL = InvalidURL; 378 | exports.InvalidState = InvalidState; 379 | 380 | }(this)); 381 | -------------------------------------------------------------------------------- /src/main/js/node_modules/sockjs-client/node_modules/node-uuid/.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /src/main/js/node_modules/sockjs-client/node_modules/node-uuid/LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 Robert Kieffer 2 | 3 | Dual licensed under the [MIT](http://en.wikipedia.org/wiki/MIT_License) and [GPL](http://en.wikipedia.org/wiki/GNU_General_Public_License) licenses. 4 | -------------------------------------------------------------------------------- /src/main/js/node_modules/sockjs-client/node_modules/node-uuid/README.md: -------------------------------------------------------------------------------- 1 | # node-uuid 2 | 3 | Simple, fast generation of [RFC4122](http://www.ietf.org/rfc/rfc4122.txt) UUIDS. 4 | 5 | Features: 6 | 7 | * Generate RFC4122 version 1 or version 4 UUIDs 8 | * Runs in node.js and all browsers. 9 | * Cryptographically strong random # generation on supporting platforms 10 | * 1.1K minified and gzip'ed (Want something smaller? Check this [crazy shit](https://gist.github.com/982883) out! ) 11 | * [Annotated source code](http://broofa.github.com/node-uuid/docs/uuid.html) 12 | 13 | ## Getting Started 14 | 15 | Install it in your browser: 16 | 17 | ```html 18 | 19 | ``` 20 | 21 | Or in node.js: 22 | 23 | ``` 24 | npm install node-uuid 25 | ``` 26 | 27 | ```javascript 28 | var uuid = require('node-uuid'); 29 | ``` 30 | 31 | Then create some ids ... 32 | 33 | ```javascript 34 | // Generate a v1 (time-based) id 35 | uuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a' 36 | 37 | // Generate a v4 (random) id 38 | uuid.v4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1' 39 | ``` 40 | 41 | ## API 42 | 43 | ### uuid.v1([`options` [, `buffer` [, `offset`]]]) 44 | 45 | Generate and return a RFC4122 v1 (timestamp-based) UUID. 46 | 47 | * `options` - (Object) Optional uuid state to apply. Properties may include: 48 | 49 | * `node` - (Array) Node id as Array of 6 bytes (per 4.1.6). Default: Randomnly generated ID. See note 1. 50 | * `clockseq` - (Number between 0 - 0x3fff) RFC clock sequence. Default: An internally maintained clockseq is used. 51 | * `msecs` - (Number | Date) Time in milliseconds since unix Epoch. Default: The current time is used. 52 | * `nsecs` - (Number between 0-9999) additional time, in 100-nanosecond units. Ignored if `msecs` is unspecified. Default: internal uuid counter is used, as per 4.2.1.2. 53 | 54 | * `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written. 55 | * `offset` - (Number) Starting index in `buffer` at which to begin writing. 56 | 57 | Returns `buffer`, if specified, otherwise the string form of the UUID 58 | 59 | Notes: 60 | 61 | 1. The randomly generated node id is only guaranteed to stay constant for the lifetime of the current JS runtime. (Future versions of this module may use persistent storage mechanisms to extend this guarantee.) 62 | 63 | Example: Generate string UUID with fully-specified options 64 | 65 | ```javascript 66 | uuid.v1({ 67 | node: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab], 68 | clockseq: 0x1234, 69 | msecs: new Date('2011-11-01').getTime(), 70 | nsecs: 5678 71 | }); // -> "710b962e-041c-11e1-9234-0123456789ab" 72 | ``` 73 | 74 | Example: In-place generation of two binary IDs 75 | 76 | ```javascript 77 | // Generate two ids in an array 78 | var arr = new Array(32); // -> [] 79 | uuid.v1(null, arr, 0); // -> [02 a2 ce 90 14 32 11 e1 85 58 0b 48 8e 4f c1 15] 80 | uuid.v1(null, arr, 16); // -> [02 a2 ce 90 14 32 11 e1 85 58 0b 48 8e 4f c1 15 02 a3 1c b0 14 32 11 e1 85 58 0b 48 8e 4f c1 15] 81 | 82 | // Optionally use uuid.unparse() to get stringify the ids 83 | uuid.unparse(buffer); // -> '02a2ce90-1432-11e1-8558-0b488e4fc115' 84 | uuid.unparse(buffer, 16) // -> '02a31cb0-1432-11e1-8558-0b488e4fc115' 85 | ``` 86 | 87 | ### uuid.v4([`options` [, `buffer` [, `offset`]]]) 88 | 89 | Generate and return a RFC4122 v4 UUID. 90 | 91 | * `options` - (Object) Optional uuid state to apply. Properties may include: 92 | 93 | * `random` - (Number[16]) Array of 16 numbers (0-255) to use in place of randomly generated values 94 | * `rng` - (Function) Random # generator to use. Set to one of the built-in generators - `uuid.mathRNG` (all platforms), `uuid.nodeRNG` (node.js only), `uuid.whatwgRNG` (WebKit only) - or a custom function that returns an array[16] of byte values. 95 | 96 | * `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written. 97 | * `offset` - (Number) Starting index in `buffer` at which to begin writing. 98 | 99 | Returns `buffer`, if specified, otherwise the string form of the UUID 100 | 101 | Example: Generate string UUID with fully-specified options 102 | 103 | ```javascript 104 | uuid.v4({ 105 | random: [ 106 | 0x10, 0x91, 0x56, 0xbe, 0xc4, 0xfb, 0xc1, 0xea, 107 | 0x71, 0xb4, 0xef, 0xe1, 0x67, 0x1c, 0x58, 0x36 108 | ] 109 | }); 110 | // -> "109156be-c4fb-41ea-b1b4-efe1671c5836" 111 | ``` 112 | 113 | Example: Generate two IDs in a single buffer 114 | 115 | ```javascript 116 | var buffer = new Array(32); // (or 'new Buffer' in node.js) 117 | uuid.v4(null, buffer, 0); 118 | uuid.v4(null, buffer, 16); 119 | ``` 120 | 121 | ### uuid.parse(id[, buffer[, offset]]) 122 | ### uuid.unparse(buffer[, offset]) 123 | 124 | Parse and unparse UUIDs 125 | 126 | * `id` - (String) UUID(-like) string 127 | * `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written. Default: A new Array or Buffer is used 128 | * `offset` - (Number) Starting index in `buffer` at which to begin writing. Default: 0 129 | 130 | Example parsing and unparsing a UUID string 131 | 132 | ```javascript 133 | var bytes = uuid.parse('797ff043-11eb-11e1-80d6-510998755d10'); // -> 134 | var string = uuid.unparse(bytes); // -> '797ff043-11eb-11e1-80d6-510998755d10' 135 | ``` 136 | 137 | ### uuid.noConflict() 138 | 139 | (Browsers only) Set `uuid` property back to it's previous value. 140 | 141 | Returns the node-uuid object. 142 | 143 | Example: 144 | 145 | ```javascript 146 | var myUuid = uuid.noConflict(); 147 | myUuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a' 148 | ``` 149 | 150 | ## Deprecated APIs 151 | 152 | Support for the following v1.2 APIs is available in v1.3, but is deprecated and will be removed in the next major version. 153 | 154 | ### uuid([format [, buffer [, offset]]]) 155 | 156 | uuid() has become uuid.v4(), and the `format` argument is now implicit in the `buffer` argument. (i.e. if you specify a buffer, the format is assumed to be binary). 157 | 158 | ### uuid.BufferClass 159 | 160 | The class of container created when generating binary uuid data if no buffer argument is specified. This is expected to go away, with no replacement API. 161 | 162 | ## Testing 163 | 164 | In node.js 165 | 166 | ``` 167 | > cd test 168 | > node uuid.js 169 | ``` 170 | 171 | In Browser 172 | 173 | ``` 174 | open test/test.html 175 | ``` 176 | 177 | ### Benchmarking 178 | 179 | Requires node.js 180 | 181 | ``` 182 | npm install uuid uuid-js 183 | node test/benchmark.js 184 | ``` 185 | 186 | For a more complete discussion of node-uuid performance, please see the `benchmark/README.md` file, and the [benchmark wiki](https://github.com/broofa/node-uuid/wiki/Benchmark) 187 | 188 | For browser performance [checkout the JSPerf tests](http://jsperf.com/node-uuid-performance). 189 | 190 | ## Release notes 191 | 192 | v1.3.2: 193 | * Improve tests and handling of v1() options (Issue #24) 194 | * Expose RNG option to allow for perf testing with different generators 195 | 196 | v1.3: 197 | * Support for version 1 ids, thanks to [@ctavan](https://github.com/ctavan)! 198 | * Support for node.js crypto API 199 | * De-emphasizing performance in favor of a) cryptographic quality PRNGs where available and b) more manageable code 200 | -------------------------------------------------------------------------------- /src/main/js/node_modules/sockjs-client/node_modules/node-uuid/benchmark/README.md: -------------------------------------------------------------------------------- 1 | # node-uuid Benchmarks 2 | 3 | ### Results 4 | 5 | To see the results of our benchmarks visit https://github.com/broofa/node-uuid/wiki/Benchmark 6 | 7 | ### Run them yourself 8 | 9 | node-uuid comes with some benchmarks to measure performance of generating UUIDs. These can be run using node.js. node-uuid is being benchmarked against some other uuid modules, that are available through npm namely `uuid` and `uuid-js`. 10 | 11 | To prepare and run the benchmark issue; 12 | 13 | ``` 14 | npm install uuid uuid-js 15 | node benchmark/benchmark.js 16 | ``` 17 | 18 | You'll see an output like this one: 19 | 20 | ``` 21 | # v4 22 | nodeuuid.v4(): 854700 uuids/second 23 | nodeuuid.v4('binary'): 788643 uuids/second 24 | nodeuuid.v4('binary', buffer): 1336898 uuids/second 25 | uuid(): 479386 uuids/second 26 | uuid('binary'): 582072 uuids/second 27 | uuidjs.create(4): 312304 uuids/second 28 | 29 | # v1 30 | nodeuuid.v1(): 938086 uuids/second 31 | nodeuuid.v1('binary'): 683060 uuids/second 32 | nodeuuid.v1('binary', buffer): 1644736 uuids/second 33 | uuidjs.create(1): 190621 uuids/second 34 | ``` 35 | 36 | * The `uuid()` entries are for Nikhil Marathe's [uuid module](https://bitbucket.org/nikhilm/uuidjs) which is a wrapper around the native libuuid library. 37 | * The `uuidjs()` entries are for Patrick Negri's [uuid-js module](https://github.com/pnegri/uuid-js) which is a pure javascript implementation based on [UUID.js](https://github.com/LiosK/UUID.js) by LiosK. 38 | 39 | If you want to get more reliable results you can run the benchmark multiple times and write the output into a log file: 40 | 41 | ``` 42 | for i in {0..9}; do node benchmark/benchmark.js >> benchmark/bench_0.4.12.log; done; 43 | ``` 44 | 45 | If you're interested in how performance varies between different node versions, you can issue the above command multiple times. 46 | 47 | You can then use the shell script `bench.sh` provided in this directory to calculate the averages over all benchmark runs and draw a nice plot: 48 | 49 | ``` 50 | (cd benchmark/ && ./bench.sh) 51 | ``` 52 | 53 | This assumes you have [gnuplot](http://www.gnuplot.info/) and [ImageMagick](http://www.imagemagick.org/) installed. You'll find a nice `bench.png` graph in the `benchmark/` directory then. 54 | -------------------------------------------------------------------------------- /src/main/js/node_modules/sockjs-client/node_modules/node-uuid/benchmark/bench.gnu: -------------------------------------------------------------------------------- 1 | #!/opt/local/bin/gnuplot -persist 2 | # 3 | # 4 | # G N U P L O T 5 | # Version 4.4 patchlevel 3 6 | # last modified March 2011 7 | # System: Darwin 10.8.0 8 | # 9 | # Copyright (C) 1986-1993, 1998, 2004, 2007-2010 10 | # Thomas Williams, Colin Kelley and many others 11 | # 12 | # gnuplot home: http://www.gnuplot.info 13 | # faq, bugs, etc: type "help seeking-assistance" 14 | # immediate help: type "help" 15 | # plot window: hit 'h' 16 | set terminal postscript eps noenhanced defaultplex \ 17 | leveldefault color colortext \ 18 | solid linewidth 1.2 butt noclip \ 19 | palfuncparam 2000,0.003 \ 20 | "Helvetica" 14 21 | set output 'bench.eps' 22 | unset clip points 23 | set clip one 24 | unset clip two 25 | set bar 1.000000 front 26 | set border 31 front linetype -1 linewidth 1.000 27 | set xdata 28 | set ydata 29 | set zdata 30 | set x2data 31 | set y2data 32 | set timefmt x "%d/%m/%y,%H:%M" 33 | set timefmt y "%d/%m/%y,%H:%M" 34 | set timefmt z "%d/%m/%y,%H:%M" 35 | set timefmt x2 "%d/%m/%y,%H:%M" 36 | set timefmt y2 "%d/%m/%y,%H:%M" 37 | set timefmt cb "%d/%m/%y,%H:%M" 38 | set boxwidth 39 | set style fill empty border 40 | set style rectangle back fc lt -3 fillstyle solid 1.00 border lt -1 41 | set style circle radius graph 0.02, first 0, 0 42 | set dummy x,y 43 | set format x "% g" 44 | set format y "% g" 45 | set format x2 "% g" 46 | set format y2 "% g" 47 | set format z "% g" 48 | set format cb "% g" 49 | set angles radians 50 | unset grid 51 | set key title "" 52 | set key outside left top horizontal Right noreverse enhanced autotitles columnhead nobox 53 | set key noinvert samplen 4 spacing 1 width 0 height 0 54 | set key maxcolumns 2 maxrows 0 55 | unset label 56 | unset arrow 57 | set style increment default 58 | unset style line 59 | set style line 1 linetype 1 linewidth 2.000 pointtype 1 pointsize default pointinterval 0 60 | unset style arrow 61 | set style histogram clustered gap 2 title offset character 0, 0, 0 62 | unset logscale 63 | set offsets graph 0.05, 0.15, 0, 0 64 | set pointsize 1.5 65 | set pointintervalbox 1 66 | set encoding default 67 | unset polar 68 | unset parametric 69 | unset decimalsign 70 | set view 60, 30, 1, 1 71 | set samples 100, 100 72 | set isosamples 10, 10 73 | set surface 74 | unset contour 75 | set clabel '%8.3g' 76 | set mapping cartesian 77 | set datafile separator whitespace 78 | unset hidden3d 79 | set cntrparam order 4 80 | set cntrparam linear 81 | set cntrparam levels auto 5 82 | set cntrparam points 5 83 | set size ratio 0 1,1 84 | set origin 0,0 85 | set style data points 86 | set style function lines 87 | set xzeroaxis linetype -2 linewidth 1.000 88 | set yzeroaxis linetype -2 linewidth 1.000 89 | set zzeroaxis linetype -2 linewidth 1.000 90 | set x2zeroaxis linetype -2 linewidth 1.000 91 | set y2zeroaxis linetype -2 linewidth 1.000 92 | set ticslevel 0.5 93 | set mxtics default 94 | set mytics default 95 | set mztics default 96 | set mx2tics default 97 | set my2tics default 98 | set mcbtics default 99 | set xtics border in scale 1,0.5 mirror norotate offset character 0, 0, 0 100 | set xtics norangelimit 101 | set xtics () 102 | set ytics border in scale 1,0.5 mirror norotate offset character 0, 0, 0 103 | set ytics autofreq norangelimit 104 | set ztics border in scale 1,0.5 nomirror norotate offset character 0, 0, 0 105 | set ztics autofreq norangelimit 106 | set nox2tics 107 | set noy2tics 108 | set cbtics border in scale 1,0.5 mirror norotate offset character 0, 0, 0 109 | set cbtics autofreq norangelimit 110 | set title "" 111 | set title offset character 0, 0, 0 font "" norotate 112 | set timestamp bottom 113 | set timestamp "" 114 | set timestamp offset character 0, 0, 0 font "" norotate 115 | set rrange [ * : * ] noreverse nowriteback # (currently [8.98847e+307:-8.98847e+307] ) 116 | set autoscale rfixmin 117 | set autoscale rfixmax 118 | set trange [ * : * ] noreverse nowriteback # (currently [-5.00000:5.00000] ) 119 | set autoscale tfixmin 120 | set autoscale tfixmax 121 | set urange [ * : * ] noreverse nowriteback # (currently [-10.0000:10.0000] ) 122 | set autoscale ufixmin 123 | set autoscale ufixmax 124 | set vrange [ * : * ] noreverse nowriteback # (currently [-10.0000:10.0000] ) 125 | set autoscale vfixmin 126 | set autoscale vfixmax 127 | set xlabel "" 128 | set xlabel offset character 0, 0, 0 font "" textcolor lt -1 norotate 129 | set x2label "" 130 | set x2label offset character 0, 0, 0 font "" textcolor lt -1 norotate 131 | set xrange [ * : * ] noreverse nowriteback # (currently [-0.150000:3.15000] ) 132 | set autoscale xfixmin 133 | set autoscale xfixmax 134 | set x2range [ * : * ] noreverse nowriteback # (currently [0.00000:3.00000] ) 135 | set autoscale x2fixmin 136 | set autoscale x2fixmax 137 | set ylabel "" 138 | set ylabel offset character 0, 0, 0 font "" textcolor lt -1 rotate by -270 139 | set y2label "" 140 | set y2label offset character 0, 0, 0 font "" textcolor lt -1 rotate by -270 141 | set yrange [ 0.00000 : 1.90000e+06 ] noreverse nowriteback # (currently [:] ) 142 | set autoscale yfixmin 143 | set autoscale yfixmax 144 | set y2range [ * : * ] noreverse nowriteback # (currently [0.00000:1.90000e+06] ) 145 | set autoscale y2fixmin 146 | set autoscale y2fixmax 147 | set zlabel "" 148 | set zlabel offset character 0, 0, 0 font "" textcolor lt -1 norotate 149 | set zrange [ * : * ] noreverse nowriteback # (currently [-10.0000:10.0000] ) 150 | set autoscale zfixmin 151 | set autoscale zfixmax 152 | set cblabel "" 153 | set cblabel offset character 0, 0, 0 font "" textcolor lt -1 rotate by -270 154 | set cbrange [ * : * ] noreverse nowriteback # (currently [8.98847e+307:-8.98847e+307] ) 155 | set autoscale cbfixmin 156 | set autoscale cbfixmax 157 | set zero 1e-08 158 | set lmargin -1 159 | set bmargin -1 160 | set rmargin -1 161 | set tmargin -1 162 | set pm3d explicit at s 163 | set pm3d scansautomatic 164 | set pm3d interpolate 1,1 flush begin noftriangles nohidden3d corners2color mean 165 | set palette positive nops_allcF maxcolors 0 gamma 1.5 color model RGB 166 | set palette rgbformulae 7, 5, 15 167 | set colorbox default 168 | set colorbox vertical origin screen 0.9, 0.2, 0 size screen 0.05, 0.6, 0 front bdefault 169 | set loadpath 170 | set fontpath 171 | set fit noerrorvariables 172 | GNUTERM = "aqua" 173 | plot 'bench_results.txt' using 2:xticlabel(1) w lp lw 2, '' using 3:xticlabel(1) w lp lw 2, '' using 4:xticlabel(1) w lp lw 2, '' using 5:xticlabel(1) w lp lw 2, '' using 6:xticlabel(1) w lp lw 2, '' using 7:xticlabel(1) w lp lw 2, '' using 8:xticlabel(1) w lp lw 2, '' using 9:xticlabel(1) w lp lw 2 174 | # EOF 175 | -------------------------------------------------------------------------------- /src/main/js/node_modules/sockjs-client/node_modules/node-uuid/benchmark/bench.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # for a given node version run: 4 | # for i in {0..9}; do node benchmark.js >> bench_0.6.2.log; done; 5 | 6 | PATTERNS=('nodeuuid.v1()' "nodeuuid.v1('binary'," 'nodeuuid.v4()' "nodeuuid.v4('binary'," "uuid()" "uuid('binary')" 'uuidjs.create(1)' 'uuidjs.create(4)' '140byte') 7 | FILES=(node_uuid_v1_string node_uuid_v1_buf node_uuid_v4_string node_uuid_v4_buf libuuid_v4_string libuuid_v4_binary uuidjs_v1_string uuidjs_v4_string 140byte_es) 8 | INDICES=(2 3 2 3 2 2 2 2 2) 9 | VERSIONS=$( ls bench_*.log | sed -e 's/^bench_\([0-9\.]*\)\.log/\1/' | tr "\\n" " " ) 10 | TMPJOIN="tmp_join" 11 | OUTPUT="bench_results.txt" 12 | 13 | for I in ${!FILES[*]}; do 14 | F=${FILES[$I]} 15 | P=${PATTERNS[$I]} 16 | INDEX=${INDICES[$I]} 17 | echo "version $F" > $F 18 | for V in $VERSIONS; do 19 | (VAL=$( grep "$P" bench_$V.log | LC_ALL=en_US awk '{ sum += $'$INDEX' } END { print sum/NR }' ); echo $V $VAL) >> $F 20 | done 21 | if [ $I == 0 ]; then 22 | cat $F > $TMPJOIN 23 | else 24 | join $TMPJOIN $F > $OUTPUT 25 | cp $OUTPUT $TMPJOIN 26 | fi 27 | rm $F 28 | done 29 | 30 | rm $TMPJOIN 31 | 32 | gnuplot bench.gnu 33 | convert -density 200 -resize 800x560 -flatten bench.eps bench.png 34 | rm bench.eps 35 | -------------------------------------------------------------------------------- /src/main/js/node_modules/sockjs-client/node_modules/node-uuid/benchmark/benchmark-native.c: -------------------------------------------------------------------------------- 1 | /* 2 | Test performance of native C UUID generation 3 | 4 | To Compile: cc -luuid benchmark-native.c -o benchmark-native 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | int main() { 13 | uuid_t myid; 14 | char buf[36+1]; 15 | int i; 16 | struct timeval t; 17 | double start, finish; 18 | 19 | gettimeofday(&t, NULL); 20 | start = t.tv_sec + t.tv_usec/1e6; 21 | 22 | int n = 2e5; 23 | for (i = 0; i < n; i++) { 24 | uuid_generate(myid); 25 | uuid_unparse(myid, buf); 26 | } 27 | 28 | gettimeofday(&t, NULL); 29 | finish = t.tv_sec + t.tv_usec/1e6; 30 | double dur = finish - start; 31 | 32 | printf("%d uuids/sec", (int)(n/dur)); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /src/main/js/node_modules/sockjs-client/node_modules/node-uuid/benchmark/benchmark.js: -------------------------------------------------------------------------------- 1 | try { 2 | var nodeuuid = require('../uuid'); 3 | } catch (e) { 4 | console.error('node-uuid require failed - skipping tests'); 5 | } 6 | 7 | try { 8 | var uuid = require('uuid'); 9 | } catch (e) { 10 | console.error('uuid require failed - skipping tests'); 11 | } 12 | 13 | try { 14 | var uuidjs = require('uuid-js'); 15 | } catch (e) { 16 | console.error('uuid-js require failed - skipping tests'); 17 | } 18 | 19 | var N = 5e5; 20 | 21 | function rate(msg, t) { 22 | console.log(msg + ': ' + 23 | (N / (Date.now() - t) * 1e3 | 0) + 24 | ' uuids/second'); 25 | } 26 | 27 | console.log('# v4'); 28 | 29 | // node-uuid - string form 30 | if (nodeuuid) { 31 | for (var i = 0, t = Date.now(); i < N; i++) nodeuuid.v4(); 32 | rate('nodeuuid.v4() - using node.js crypto RNG', t); 33 | 34 | for (var i = 0, t = Date.now(); i < N; i++) nodeuuid.v4({rng: nodeuuid.mathRNG}); 35 | rate('nodeuuid.v4() - using Math.random() RNG', t); 36 | 37 | for (var i = 0, t = Date.now(); i < N; i++) nodeuuid.v4('binary'); 38 | rate('nodeuuid.v4(\'binary\')', t); 39 | 40 | var buffer = new nodeuuid.BufferClass(16); 41 | for (var i = 0, t = Date.now(); i < N; i++) nodeuuid.v4('binary', buffer); 42 | rate('nodeuuid.v4(\'binary\', buffer)', t); 43 | } 44 | 45 | // libuuid - string form 46 | if (uuid) { 47 | for (var i = 0, t = Date.now(); i < N; i++) uuid(); 48 | rate('uuid()', t); 49 | 50 | for (var i = 0, t = Date.now(); i < N; i++) uuid('binary'); 51 | rate('uuid(\'binary\')', t); 52 | } 53 | 54 | // uuid-js - string form 55 | if (uuidjs) { 56 | for (var i = 0, t = Date.now(); i < N; i++) uuidjs.create(4); 57 | rate('uuidjs.create(4)', t); 58 | } 59 | 60 | // 140byte.es 61 | for (var i = 0, t = Date.now(); i < N; i++) 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g,function(s,r){r=Math.random()*16|0;return (s=='x'?r:r&0x3|0x8).toString(16)}); 62 | rate('140byte.es_v4', t); 63 | 64 | console.log(''); 65 | console.log('# v1'); 66 | 67 | // node-uuid - v1 string form 68 | if (nodeuuid) { 69 | for (var i = 0, t = Date.now(); i < N; i++) nodeuuid.v1(); 70 | rate('nodeuuid.v1()', t); 71 | 72 | for (var i = 0, t = Date.now(); i < N; i++) nodeuuid.v1('binary'); 73 | rate('nodeuuid.v1(\'binary\')', t); 74 | 75 | var buffer = new nodeuuid.BufferClass(16); 76 | for (var i = 0, t = Date.now(); i < N; i++) nodeuuid.v1('binary', buffer); 77 | rate('nodeuuid.v1(\'binary\', buffer)', t); 78 | } 79 | 80 | // uuid-js - v1 string form 81 | if (uuidjs) { 82 | for (var i = 0, t = Date.now(); i < N; i++) uuidjs.create(1); 83 | rate('uuidjs.create(1)', t); 84 | } 85 | -------------------------------------------------------------------------------- /src/main/js/node_modules/sockjs-client/node_modules/node-uuid/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-uuid", 3 | "description": "Rigorous implementation of RFC4122 (v1 and v4) UUIDs.", 4 | "url": "http://github.com/broofa/node-uuid", 5 | "keywords": [ 6 | "uuid", 7 | "guid", 8 | "rfc4122" 9 | ], 10 | "author": { 11 | "name": "Robert Kieffer", 12 | "email": "robert@broofa.com" 13 | }, 14 | "contributors": [ 15 | { 16 | "name": "Christoph Tavan", 17 | "email": "dev@tavan.de" 18 | } 19 | ], 20 | "lib": ".", 21 | "main": "./uuid.js", 22 | "repository": { 23 | "type": "git", 24 | "url": "git://github.com/broofa/node-uuid.git" 25 | }, 26 | "version": "1.3.3", 27 | "_id": "node-uuid@1.3.3", 28 | "dependencies": {}, 29 | "devDependencies": {}, 30 | "optionalDependencies": {}, 31 | "engines": { 32 | "node": "*" 33 | }, 34 | "_engineSupported": true, 35 | "_npmVersion": "1.1.21", 36 | "_nodeVersion": "v0.6.19", 37 | "_defaultsLoaded": true, 38 | "_from": "node-uuid@1.3.3" 39 | } 40 | -------------------------------------------------------------------------------- /src/main/js/node_modules/sockjs-client/node_modules/node-uuid/test/compare_v1.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'), 2 | nodeuuid = require('../uuid'), 3 | uuidjs = require('uuid-js'), 4 | libuuid = require('uuid').generate, 5 | util = require('util'), 6 | exec = require('child_process').exec, 7 | os = require('os'); 8 | 9 | // On Mac Os X / macports there's only the ossp-uuid package that provides uuid 10 | // On Linux there's uuid-runtime which provides uuidgen 11 | var uuidCmd = os.type() === 'Darwin' ? 'uuid -1' : 'uuidgen -t'; 12 | 13 | function compare(ids) { 14 | console.log(ids); 15 | for (var i = 0; i < ids.length; i++) { 16 | var id = ids[i].split('-'); 17 | id = [id[2], id[1], id[0]].join(''); 18 | ids[i] = id; 19 | } 20 | var sorted = ([].concat(ids)).sort(); 21 | 22 | if (sorted.toString() !== ids.toString()) { 23 | console.log('Warning: sorted !== ids'); 24 | } else { 25 | console.log('everything in order!'); 26 | } 27 | } 28 | 29 | // Test time order of v1 uuids 30 | var ids = []; 31 | while (ids.length < 10e3) ids.push(nodeuuid.v1()); 32 | 33 | var max = 10; 34 | console.log('node-uuid:'); 35 | ids = []; 36 | for (var i = 0; i < max; i++) ids.push(nodeuuid.v1()); 37 | compare(ids); 38 | 39 | console.log(''); 40 | console.log('uuidjs:'); 41 | ids = []; 42 | for (var i = 0; i < max; i++) ids.push(uuidjs.create(1).toString()); 43 | compare(ids); 44 | 45 | console.log(''); 46 | console.log('libuuid:'); 47 | ids = []; 48 | var count = 0; 49 | var last = function() { 50 | compare(ids); 51 | } 52 | var cb = function(err, stdout, stderr) { 53 | ids.push(stdout.substring(0, stdout.length-1)); 54 | count++; 55 | if (count < max) { 56 | return next(); 57 | } 58 | last(); 59 | }; 60 | var next = function() { 61 | exec(uuidCmd, cb); 62 | }; 63 | next(); 64 | -------------------------------------------------------------------------------- /src/main/js/node_modules/sockjs-client/node_modules/node-uuid/test/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/main/js/node_modules/sockjs-client/node_modules/node-uuid/test/test.js: -------------------------------------------------------------------------------- 1 | if (!this.uuid) { 2 | // node.js 3 | uuid = require('../uuid'); 4 | } 5 | 6 | // 7 | // x-platform log/assert shims 8 | // 9 | 10 | function _log(msg, type) { 11 | type = type || 'log'; 12 | 13 | if (typeof(document) != 'undefined') { 14 | document.write('
' + msg.replace(/\n/g, '
') + '
'); 15 | } 16 | if (typeof(console) != 'undefined') { 17 | var color = { 18 | log: '\033[39m', 19 | warn: '\033[33m', 20 | error: '\033[31m' 21 | } 22 | console[type](color[type] + msg + color.log); 23 | } 24 | } 25 | 26 | function log(msg) {_log(msg, 'log');} 27 | function warn(msg) {_log(msg, 'warn');} 28 | function error(msg) {_log(msg, 'error');} 29 | 30 | function assert(res, msg) { 31 | if (!res) { 32 | error('FAIL: ' + msg); 33 | } else { 34 | log('Pass: ' + msg); 35 | } 36 | } 37 | 38 | // 39 | // Unit tests 40 | // 41 | 42 | // Verify ordering of v1 ids created with explicit times 43 | var TIME = 1321644961388; // 2011-11-18 11:36:01.388-08:00 44 | 45 | function compare(name, ids) { 46 | ids = ids.map(function(id) { 47 | return id.split('-').reverse().join('-'); 48 | }).sort(); 49 | var sorted = ([].concat(ids)).sort(); 50 | 51 | assert(sorted.toString() == ids.toString(), name + ' have expected order'); 52 | } 53 | 54 | // Verify ordering of v1 ids created using default behavior 55 | compare('uuids with current time', [ 56 | uuid.v1(), 57 | uuid.v1(), 58 | uuid.v1(), 59 | uuid.v1(), 60 | uuid.v1() 61 | ]); 62 | 63 | // Verify ordering of v1 ids created with explicit times 64 | compare('uuids with time option', [ 65 | uuid.v1({msecs: TIME - 10*3600*1000}), 66 | uuid.v1({msecs: TIME - 1}), 67 | uuid.v1({msecs: TIME}), 68 | uuid.v1({msecs: TIME + 1}), 69 | uuid.v1({msecs: TIME + 28*24*3600*1000}), 70 | ]); 71 | 72 | assert( 73 | uuid.v1({msecs: TIME}) != uuid.v1({msecs: TIME}), 74 | 'IDs created at same msec are different' 75 | ); 76 | 77 | // Verify throw if too many ids created 78 | var thrown = false; 79 | try { 80 | uuid.v1({msecs: TIME, nsecs: 10000}); 81 | } catch (e) { 82 | thrown = true; 83 | } 84 | assert(thrown, 'Exception thrown when > 10K ids created in 1 ms'); 85 | 86 | // Verify clock regression bumps clockseq 87 | var uidt = uuid.v1({msecs: TIME}); 88 | var uidtb = uuid.v1({msecs: TIME - 1}); 89 | assert( 90 | parseInt(uidtb.split('-')[3], 16) - parseInt(uidt.split('-')[3], 16) === 1, 91 | 'Clock regression by msec increments the clockseq' 92 | ); 93 | 94 | // Verify clock regression bumps clockseq 95 | var uidtn = uuid.v1({msecs: TIME, nsecs: 10}); 96 | var uidtnb = uuid.v1({msecs: TIME, nsecs: 9}); 97 | assert( 98 | parseInt(uidtnb.split('-')[3], 16) - parseInt(uidtn.split('-')[3], 16) === 1, 99 | 'Clock regression by nsec increments the clockseq' 100 | ); 101 | 102 | // Verify explicit options produce expected id 103 | var id = uuid.v1({ 104 | msecs: 1321651533573, 105 | nsecs: 5432, 106 | clockseq: 0x385c, 107 | node: [ 0x61, 0xcd, 0x3c, 0xbb, 0x32, 0x10 ] 108 | }); 109 | assert(id == 'd9428888-122b-11e1-b85c-61cd3cbb3210', 'Explicit options produce expected id'); 110 | 111 | // Verify adjacent ids across a msec boundary are 1 time unit apart 112 | var u0 = uuid.v1({msecs: TIME, nsecs: 9999}); 113 | var u1 = uuid.v1({msecs: TIME + 1, nsecs: 0}); 114 | 115 | var before = u0.split('-')[0], after = u1.split('-')[0]; 116 | var dt = parseInt(after, 16) - parseInt(before, 16); 117 | assert(dt === 1, 'Ids spanning 1ms boundary are 100ns apart'); 118 | 119 | // 120 | // Test parse/unparse 121 | // 122 | 123 | id = '00112233445566778899aabbccddeeff'; 124 | assert(uuid.unparse(uuid.parse(id.substr(0,10))) == 125 | '00112233-4400-0000-0000-000000000000', 'Short parse'); 126 | assert(uuid.unparse(uuid.parse('(this is the uuid -> ' + id + id)) == 127 | '00112233-4455-6677-8899-aabbccddeeff', 'Dirty parse'); 128 | 129 | // 130 | // Perf tests 131 | // 132 | 133 | var generators = { 134 | v1: uuid.v1, 135 | v4: uuid.v4 136 | }; 137 | 138 | var UUID_FORMAT = { 139 | v1: /[0-9a-f]{8}-[0-9a-f]{4}-1[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i, 140 | v4: /[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i 141 | }; 142 | 143 | var N = 1e4; 144 | 145 | // Get %'age an actual value differs from the ideal value 146 | function divergence(actual, ideal) { 147 | return Math.round(100*100*(actual - ideal)/ideal)/100; 148 | } 149 | 150 | function rate(msg, t) { 151 | log(msg + ': ' + (N / (Date.now() - t) * 1e3 | 0) + ' uuids\/second'); 152 | } 153 | 154 | for (var version in generators) { 155 | var counts = {}, max = 0; 156 | var generator = generators[version]; 157 | var format = UUID_FORMAT[version]; 158 | 159 | log('\nSanity check ' + N + ' ' + version + ' uuids'); 160 | for (var i = 0, ok = 0; i < N; i++) { 161 | id = generator(); 162 | if (!format.test(id)) { 163 | throw Error(id + ' is not a valid UUID string'); 164 | } 165 | 166 | if (id != uuid.unparse(uuid.parse(id))) { 167 | assert(fail, id + ' is not a valid id'); 168 | } 169 | 170 | // Count digits for our randomness check 171 | if (version == 'v4') { 172 | var digits = id.replace(/-/g, '').split(''); 173 | for (var j = digits.length-1; j >= 0; j--) { 174 | var c = digits[j]; 175 | max = Math.max(max, counts[c] = (counts[c] || 0) + 1); 176 | } 177 | } 178 | } 179 | 180 | // Check randomness for v4 UUIDs 181 | if (version == 'v4') { 182 | // Limit that we get worried about randomness. (Purely empirical choice, this!) 183 | var limit = 2*100*Math.sqrt(1/N); 184 | 185 | log('\nChecking v4 randomness. Distribution of Hex Digits (% deviation from ideal)'); 186 | 187 | for (var i = 0; i < 16; i++) { 188 | var c = i.toString(16); 189 | var bar = '', n = counts[c], p = Math.round(n/max*100|0); 190 | 191 | // 1-3,5-8, and D-F: 1:16 odds over 30 digits 192 | var ideal = N*30/16; 193 | if (i == 4) { 194 | // 4: 1:1 odds on 1 digit, plus 1:16 odds on 30 digits 195 | ideal = N*(1 + 30/16); 196 | } else if (i >= 8 && i <= 11) { 197 | // 8-B: 1:4 odds on 1 digit, plus 1:16 odds on 30 digits 198 | ideal = N*(1/4 + 30/16); 199 | } else { 200 | // Otherwise: 1:16 odds on 30 digits 201 | ideal = N*30/16; 202 | } 203 | var d = divergence(n, ideal); 204 | 205 | // Draw bar using UTF squares (just for grins) 206 | var s = n/max*50 | 0; 207 | while (s--) bar += '='; 208 | 209 | assert(Math.abs(d) < limit, c + ' |' + bar + '| ' + counts[c] + ' (' + d + '% < ' + limit + '%)'); 210 | } 211 | } 212 | } 213 | 214 | // Perf tests 215 | for (var version in generators) { 216 | log('\nPerformance testing ' + version + ' UUIDs'); 217 | var generator = generators[version]; 218 | var buf = new uuid.BufferClass(16); 219 | 220 | if (version == 'v4') { 221 | ['mathRNG', 'whatwgRNG', 'nodeRNG'].forEach(function(rng) { 222 | if (uuid[rng]) { 223 | var options = {rng: uuid[rng]}; 224 | for (var i = 0, t = Date.now(); i < N; i++) generator(options); 225 | rate('uuid.' + version + '() with ' + rng, t); 226 | } else { 227 | log('uuid.' + version + '() with ' + rng + ': not defined'); 228 | } 229 | }); 230 | } else { 231 | for (var i = 0, t = Date.now(); i < N; i++) generator(); 232 | rate('uuid.' + version + '()', t); 233 | } 234 | 235 | for (var i = 0, t = Date.now(); i < N; i++) generator('binary'); 236 | rate('uuid.' + version + '(\'binary\')', t); 237 | 238 | for (var i = 0, t = Date.now(); i < N; i++) generator('binary', buf); 239 | rate('uuid.' + version + '(\'binary\', buffer)', t); 240 | } 241 | -------------------------------------------------------------------------------- /src/main/js/node_modules/sockjs-client/node_modules/node-uuid/uuid.js: -------------------------------------------------------------------------------- 1 | // node-uuid/uuid.js 2 | // 3 | // Copyright (c) 2010 Robert Kieffer 4 | // Dual licensed under the MIT and GPL licenses. 5 | // Documentation and details at https://github.com/broofa/node-uuid 6 | (function() { 7 | var _global = this; 8 | 9 | // Unique ID creation requires a high quality random # generator, but 10 | // Math.random() does not guarantee "cryptographic quality". So we feature 11 | // detect for more robust APIs, normalizing each method to return 128-bits 12 | // (16 bytes) of random data. 13 | var mathRNG, nodeRNG, whatwgRNG; 14 | 15 | // Math.random()-based RNG. All platforms, very fast, unknown quality 16 | var _rndBytes = new Array(16); 17 | mathRNG = function() { 18 | var r, b = _rndBytes, i = 0; 19 | 20 | for (var i = 0, r; i < 16; i++) { 21 | if ((i & 0x03) == 0) r = Math.random() * 0x100000000; 22 | b[i] = r >>> ((i & 0x03) << 3) & 0xff; 23 | } 24 | 25 | return b; 26 | } 27 | 28 | // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto 29 | // WebKit only (currently), moderately fast, high quality 30 | if (_global.crypto && crypto.getRandomValues) { 31 | var _rnds = new Uint32Array(4); 32 | whatwgRNG = function() { 33 | crypto.getRandomValues(_rnds); 34 | 35 | for (var c = 0 ; c < 16; c++) { 36 | _rndBytes[c] = _rnds[c >> 2] >>> ((c & 0x03) * 8) & 0xff; 37 | } 38 | return _rndBytes; 39 | } 40 | } 41 | 42 | // Node.js crypto-based RNG - http://nodejs.org/docs/v0.6.2/api/crypto.html 43 | // Node.js only, moderately fast, high quality 44 | try { 45 | var _rb = require('crypto').randomBytes; 46 | nodeRNG = _rb && function() { 47 | return _rb(16); 48 | }; 49 | } catch (e) {} 50 | 51 | // Select RNG with best quality 52 | var _rng = nodeRNG || whatwgRNG || mathRNG; 53 | 54 | // Buffer class to use 55 | var BufferClass = typeof(Buffer) == 'function' ? Buffer : Array; 56 | 57 | // Maps for number <-> hex string conversion 58 | var _byteToHex = []; 59 | var _hexToByte = {}; 60 | for (var i = 0; i < 256; i++) { 61 | _byteToHex[i] = (i + 0x100).toString(16).substr(1); 62 | _hexToByte[_byteToHex[i]] = i; 63 | } 64 | 65 | // **`parse()` - Parse a UUID into it's component bytes** 66 | function parse(s, buf, offset) { 67 | var i = (buf && offset) || 0, ii = 0; 68 | 69 | buf = buf || []; 70 | s.toLowerCase().replace(/[0-9a-f]{2}/g, function(byte) { 71 | if (ii < 16) { // Don't overflow! 72 | buf[i + ii++] = _hexToByte[byte]; 73 | } 74 | }); 75 | 76 | // Zero out remaining bytes if string was short 77 | while (ii < 16) { 78 | buf[i + ii++] = 0; 79 | } 80 | 81 | return buf; 82 | } 83 | 84 | // **`unparse()` - Convert UUID byte array (ala parse()) into a string** 85 | function unparse(buf, offset) { 86 | var i = offset || 0, bth = _byteToHex; 87 | return bth[buf[i++]] + bth[buf[i++]] + 88 | bth[buf[i++]] + bth[buf[i++]] + '-' + 89 | bth[buf[i++]] + bth[buf[i++]] + '-' + 90 | bth[buf[i++]] + bth[buf[i++]] + '-' + 91 | bth[buf[i++]] + bth[buf[i++]] + '-' + 92 | bth[buf[i++]] + bth[buf[i++]] + 93 | bth[buf[i++]] + bth[buf[i++]] + 94 | bth[buf[i++]] + bth[buf[i++]]; 95 | } 96 | 97 | // **`v1()` - Generate time-based UUID** 98 | // 99 | // Inspired by https://github.com/LiosK/UUID.js 100 | // and http://docs.python.org/library/uuid.html 101 | 102 | // random #'s we need to init node and clockseq 103 | var _seedBytes = _rng(); 104 | 105 | // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1) 106 | var _nodeId = [ 107 | _seedBytes[0] | 0x01, 108 | _seedBytes[1], _seedBytes[2], _seedBytes[3], _seedBytes[4], _seedBytes[5] 109 | ]; 110 | 111 | // Per 4.2.2, randomize (14 bit) clockseq 112 | var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff; 113 | 114 | // Previous uuid creation time 115 | var _lastMSecs = 0, _lastNSecs = 0; 116 | 117 | // See https://github.com/broofa/node-uuid for API details 118 | function v1(options, buf, offset) { 119 | var i = buf && offset || 0; 120 | var b = buf || []; 121 | 122 | options = options || {}; 123 | 124 | var clockseq = options.clockseq != null ? options.clockseq : _clockseq; 125 | 126 | // UUID timestamps are 100 nano-second units since the Gregorian epoch, 127 | // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so 128 | // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs' 129 | // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00. 130 | var msecs = options.msecs != null ? options.msecs : new Date().getTime(); 131 | 132 | // Per 4.2.1.2, use count of uuid's generated during the current clock 133 | // cycle to simulate higher resolution clock 134 | var nsecs = options.nsecs != null ? options.nsecs : _lastNSecs + 1; 135 | 136 | // Time since last uuid creation (in msecs) 137 | var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs)/10000; 138 | 139 | // Per 4.2.1.2, Bump clockseq on clock regression 140 | if (dt < 0 && options.clockseq == null) { 141 | clockseq = clockseq + 1 & 0x3fff; 142 | } 143 | 144 | // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new 145 | // time interval 146 | if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) { 147 | nsecs = 0; 148 | } 149 | 150 | // Per 4.2.1.2 Throw error if too many uuids are requested 151 | if (nsecs >= 10000) { 152 | throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec'); 153 | } 154 | 155 | _lastMSecs = msecs; 156 | _lastNSecs = nsecs; 157 | _clockseq = clockseq; 158 | 159 | // Per 4.1.4 - Convert from unix epoch to Gregorian epoch 160 | msecs += 12219292800000; 161 | 162 | // `time_low` 163 | var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; 164 | b[i++] = tl >>> 24 & 0xff; 165 | b[i++] = tl >>> 16 & 0xff; 166 | b[i++] = tl >>> 8 & 0xff; 167 | b[i++] = tl & 0xff; 168 | 169 | // `time_mid` 170 | var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff; 171 | b[i++] = tmh >>> 8 & 0xff; 172 | b[i++] = tmh & 0xff; 173 | 174 | // `time_high_and_version` 175 | b[i++] = tmh >>> 24 & 0xf | 0x10; // include version 176 | b[i++] = tmh >>> 16 & 0xff; 177 | 178 | // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant) 179 | b[i++] = clockseq >>> 8 | 0x80; 180 | 181 | // `clock_seq_low` 182 | b[i++] = clockseq & 0xff; 183 | 184 | // `node` 185 | var node = options.node || _nodeId; 186 | for (var n = 0; n < 6; n++) { 187 | b[i + n] = node[n]; 188 | } 189 | 190 | return buf ? buf : unparse(b); 191 | } 192 | 193 | // **`v4()` - Generate random UUID** 194 | 195 | // See https://github.com/broofa/node-uuid for API details 196 | function v4(options, buf, offset) { 197 | // Deprecated - 'format' argument, as supported in v1.2 198 | var i = buf && offset || 0; 199 | 200 | if (typeof(options) == 'string') { 201 | buf = options == 'binary' ? new BufferClass(16) : null; 202 | options = null; 203 | } 204 | options = options || {}; 205 | 206 | var rnds = options.random || (options.rng || _rng)(); 207 | 208 | // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` 209 | rnds[6] = (rnds[6] & 0x0f) | 0x40; 210 | rnds[8] = (rnds[8] & 0x3f) | 0x80; 211 | 212 | // Copy bytes to buffer, if provided 213 | if (buf) { 214 | for (var ii = 0; ii < 16; ii++) { 215 | buf[i + ii] = rnds[ii]; 216 | } 217 | } 218 | 219 | return buf || unparse(rnds); 220 | } 221 | 222 | // Export public API 223 | var uuid = v4; 224 | uuid.v1 = v1; 225 | uuid.v4 = v4; 226 | uuid.parse = parse; 227 | uuid.unparse = unparse; 228 | uuid.BufferClass = BufferClass; 229 | 230 | // Export RNG options 231 | uuid.mathRNG = mathRNG; 232 | uuid.nodeRNG = nodeRNG; 233 | uuid.whatwgRNG = whatwgRNG; 234 | 235 | if (typeof(module) != 'undefined') { 236 | // Play nice with node.js 237 | module.exports = uuid; 238 | } else { 239 | // Play nice with browsers 240 | var _previousRoot = _global.uuid; 241 | 242 | // **`noConflict()` - (browser only) to reset global 'uuid' var** 243 | uuid.noConflict = function() { 244 | _global.uuid = _previousRoot; 245 | return uuid; 246 | } 247 | _global.uuid = uuid; 248 | } 249 | }()); 250 | -------------------------------------------------------------------------------- /src/main/js/node_modules/sockjs-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sockjs-client", 3 | "author": { 4 | "name": "Matthew Sackman" 5 | }, 6 | "version": "0.1.3", 7 | "keywords": [ 8 | "websockets", 9 | "websocket" 10 | ], 11 | "repository": { 12 | "type": "git", 13 | "url": "git://github.com/sockjs/sockjs-client-node.git" 14 | }, 15 | "main": "index", 16 | "description": "Client library for SockJS", 17 | "dependencies": { 18 | "node-uuid": "1.3.3" 19 | }, 20 | "_id": "sockjs-client@0.1.3", 21 | "devDependencies": {}, 22 | "optionalDependencies": {}, 23 | "engines": { 24 | "node": "*" 25 | }, 26 | "_engineSupported": true, 27 | "_npmVersion": "1.1.21", 28 | "_nodeVersion": "v0.6.19", 29 | "_defaultsLoaded": true, 30 | "_from": "sockjs-client" 31 | } 32 | -------------------------------------------------------------------------------- /src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main/webapp/echo.html: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | WebSocket/SockJS Echo Sample (Adapted from Tomcat's echo sample) 21 | 52 | 53 | 54 | 55 | 138 | 139 | 140 | 143 |
144 |
145 | 146 | 147 |
148 | 149 | 150 | 162 |
163 | 164 | 165 |
166 |
167 | 168 |
169 |
170 | 171 |
172 |
173 |
174 |
175 |
176 |
177 | 178 | 179 | -------------------------------------------------------------------------------- /src/main/webapp/index.html: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | WebSocket/SockJS Examples 21 | 22 | 23 |

Please select the sample you would like to try.

24 | 28 | 29 | -------------------------------------------------------------------------------- /src/main/webapp/snake.html: -------------------------------------------------------------------------------- 1 | 17 | 19 | 20 | 21 | 22 | Apache Tomcat WebSocket Examples: Multiplayer Snake 23 | 52 | 53 | 54 | 57 | 58 |
59 | 60 |
61 |
62 |
63 |
64 | 65 | 66 | 67 | 253 | 254 | 255 | -------------------------------------------------------------------------------- /src/test/java/org/springframework/samples/websocket/echo/JettyClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2021 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.websocket.echo; 17 | 18 | import org.springframework.context.annotation.AnnotationConfigApplicationContext; 19 | import org.springframework.context.annotation.Bean; 20 | import org.springframework.context.annotation.Configuration; 21 | import org.springframework.samples.websocket.client.GreetingService; 22 | import org.springframework.samples.websocket.client.SimpleClientWebSocketHandler; 23 | import org.springframework.samples.websocket.client.SimpleGreetingService; 24 | import org.springframework.web.socket.client.WebSocketConnectionManager; 25 | import org.springframework.web.socket.client.jetty.JettyWebSocketClient; 26 | 27 | public class JettyClient { 28 | 29 | private static final String WS_URI = "ws://localhost:8080/spring-websocket-test/echo"; 30 | 31 | 32 | public static void main(String[] args) { 33 | try{ 34 | AnnotationConfigApplicationContext cxt = new AnnotationConfigApplicationContext(ClientConfig.class); 35 | System.out.println("\n\n\nWhen ready, press any key to exit\n\n\n"); 36 | System.in.read(); 37 | cxt.close(); 38 | } 39 | catch (Throwable t) { 40 | t.printStackTrace(); 41 | } 42 | finally { 43 | System.exit(0); 44 | } 45 | } 46 | 47 | @Configuration 48 | static class ClientConfig { 49 | 50 | @Bean 51 | public WebSocketConnectionManager connectionManager() { 52 | 53 | WebSocketConnectionManager manager = new WebSocketConnectionManager(client(), handler(), WS_URI); 54 | manager.setAutoStartup(true); 55 | 56 | return manager; 57 | } 58 | 59 | @Bean 60 | public JettyWebSocketClient client() { 61 | return new JettyWebSocketClient(); 62 | } 63 | 64 | @Bean 65 | public SimpleClientWebSocketHandler handler() { 66 | return new SimpleClientWebSocketHandler(greetingService()); 67 | } 68 | 69 | @Bean 70 | public GreetingService greetingService() { 71 | return new SimpleGreetingService(); 72 | } 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/test/java/org/springframework/samples/websocket/echo/StandardClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.springframework.samples.websocket.echo; 17 | 18 | import java.io.IOException; 19 | 20 | import org.springframework.context.annotation.AnnotationConfigApplicationContext; 21 | import org.springframework.context.annotation.Bean; 22 | import org.springframework.context.annotation.Configuration; 23 | import org.springframework.samples.websocket.client.GreetingService; 24 | import org.springframework.samples.websocket.client.SimpleClientWebSocketHandler; 25 | import org.springframework.samples.websocket.client.SimpleGreetingService; 26 | import org.springframework.web.socket.client.WebSocketConnectionManager; 27 | import org.springframework.web.socket.client.standard.StandardWebSocketClient; 28 | 29 | public class StandardClient { 30 | 31 | private static final String WS_URI = "ws://localhost:8080/spring-websocket-test/echo"; 32 | 33 | 34 | public static void main(String[] args) throws IOException { 35 | try{ 36 | AnnotationConfigApplicationContext cxt = new AnnotationConfigApplicationContext(ClientConfig.class); 37 | System.out.println("\n\n\nWhen ready, press any key to exit\n\n\n"); 38 | System.in.read(); 39 | cxt.close(); 40 | } 41 | catch (Throwable t) { 42 | t.printStackTrace(); 43 | } 44 | finally { 45 | System.exit(0); 46 | } 47 | } 48 | 49 | @Configuration 50 | static class ClientConfig { 51 | 52 | @Bean 53 | public WebSocketConnectionManager connectionManager() { 54 | WebSocketConnectionManager manager = new WebSocketConnectionManager(client(), handler(), WS_URI); 55 | manager.setAutoStartup(true); 56 | return manager; 57 | } 58 | 59 | @Bean 60 | public StandardWebSocketClient client() { 61 | return new StandardWebSocketClient(); 62 | } 63 | 64 | @Bean 65 | public SimpleClientWebSocketHandler handler() { 66 | return new SimpleClientWebSocketHandler(greetingService()); 67 | } 68 | 69 | @Bean 70 | public GreetingService greetingService() { 71 | return new SimpleGreetingService(); 72 | } 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/test/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | --------------------------------------------------------------------------------