From c3c679009312503a1caa79262b7463c2c1b3b622 Mon Sep 17 00:00:00 2001 From: Arm Suwarnaratana Date: Fri, 16 Sep 2016 00:10:19 -0500 Subject: [PATCH 1/4] add support for more than 25 devices by starting up multiple connectors. See applicatons.properties for how many ports to open --- .../java/com/armzilla/ha/SpringbootEntry.java | 9 ++++ .../com/armzilla/ha/TomcatConnectorBean.java | 45 +++++++++++++++++++ .../java/com/armzilla/ha/hue/HueMulator.java | 15 +++++-- .../com/armzilla/ha/upnp/UpnpListener.java | 20 ++++++--- .../ha/upnp/UpnpSettingsResource.java | 10 +++-- src/main/resources/application.properties | 4 +- 6 files changed, 89 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/armzilla/ha/TomcatConnectorBean.java diff --git a/src/main/java/com/armzilla/ha/SpringbootEntry.java b/src/main/java/com/armzilla/ha/SpringbootEntry.java index 304201e..5835e35 100644 --- a/src/main/java/com/armzilla/ha/SpringbootEntry.java +++ b/src/main/java/com/armzilla/ha/SpringbootEntry.java @@ -1,10 +1,17 @@ package com.armzilla.ha; +import org.apache.catalina.connector.Connector; +import org.apache.coyote.http11.Http11NioProtocol; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory; +import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.scheduling.annotation.EnableScheduling; +import java.io.IOException; + @SpringBootApplication @EnableScheduling @ComponentScan @@ -13,4 +20,6 @@ public class SpringbootEntry { public static void main(String[] args) { SpringApplication.run(SpringbootEntry.class, args); } + + } diff --git a/src/main/java/com/armzilla/ha/TomcatConnectorBean.java b/src/main/java/com/armzilla/ha/TomcatConnectorBean.java new file mode 100644 index 0000000..e802566 --- /dev/null +++ b/src/main/java/com/armzilla/ha/TomcatConnectorBean.java @@ -0,0 +1,45 @@ +package com.armzilla.ha; + +import org.apache.catalina.connector.Connector; +import org.apache.coyote.http11.Http11NioProtocol; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory; +import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +import java.util.Set; + +/** + * Created by arm on 9/12/15. + */ +@Component + +public class TomcatConnectorBean { + @Value("${emulator.portbase}") + private int portBase; + @Value("${emulator.portcount}") + private int portCount; + @Bean + public EmbeddedServletContainerFactory servletContainer() { + TomcatEmbeddedServletContainerFactory tomcat = null; + for(int i = 0; i < portCount; i ++) { + if(tomcat == null){ + tomcat = new TomcatEmbeddedServletContainerFactory(portBase + i); + }else{ + tomcat.addAdditionalTomcatConnectors(createConnector(portBase + i)); + } + } + return tomcat; + } + + private Connector createConnector(int portNumber) { + Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol"); + Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler(); + connector.setScheme("http"); + connector.setPort(portNumber); + return connector; + } +} diff --git a/src/main/java/com/armzilla/ha/hue/HueMulator.java b/src/main/java/com/armzilla/ha/hue/HueMulator.java index 35af355..f15b197 100644 --- a/src/main/java/com/armzilla/ha/hue/HueMulator.java +++ b/src/main/java/com/armzilla/ha/hue/HueMulator.java @@ -19,6 +19,7 @@ import org.apache.http.util.EntityUtils; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.http.HttpHeaders; @@ -50,6 +51,10 @@ public class HueMulator { private HttpClient httpClient; private ObjectMapper mapper; + @Value("${emulator.portbase}") + private int portBase; + @Value("${emulator.portcount}") + private int portCount; public HueMulator(){ httpClient = HttpClients.createDefault(); //patched for now, moving away from HueMulator doing work @@ -60,8 +65,10 @@ public HueMulator(){ @RequestMapping(value = "/{userId}/lights", method = RequestMethod.GET, produces = "application/json") public ResponseEntity> getUpnpConfiguration(@PathVariable(value = "userId") String userId, HttpServletRequest request) { - log.info("hue lights list requested: " + userId + " from " + request.getRemoteAddr()); - Page deviceList = repository.findByDeviceType("switch", new PageRequest(0,100)); + log.info("hue lights list requested: " + userId + " from " + request.getRemoteAddr() + request.getLocalPort()); + + int pageNumber = request.getLocalPort()-portBase; + Page deviceList = repository.findByDeviceType("switch", new PageRequest(pageNumber, 25)); Map deviceResponseMap = new HashMap<>(); for (DeviceDescriptor device : deviceList) { deviceResponseMap.put(device.getId(), device.getName()); @@ -71,13 +78,15 @@ public ResponseEntity> getUpnpConfiguration(@PathVariable(va @RequestMapping(value = "/*", method = RequestMethod.POST, produces = "application/json") public ResponseEntity postAPI(HttpServletRequest request) { + log.info("registered device: " + request.toString()); return new ResponseEntity("[{\"success\":{\"username\":\"lights\"}}]", HttpStatus.OK); } @RequestMapping(value = "/{userId}", method = RequestMethod.GET, produces = "application/json") public ResponseEntity getApi(@PathVariable(value = "userId") String userId, HttpServletRequest request) { log.info("hue api root requested: " + userId + " from " + request.getRemoteAddr()); - Page descriptorList = repository.findByDeviceType("switch", new PageRequest(0, 100)); + int pageNumber = request.getLocalPort()-portBase; + Page descriptorList = repository.findByDeviceType("switch", new PageRequest(pageNumber, 25)); if (descriptorList == null) { return new ResponseEntity<>(null, null, HttpStatus.NOT_FOUND); } diff --git a/src/main/java/com/armzilla/ha/upnp/UpnpListener.java b/src/main/java/com/armzilla/ha/upnp/UpnpListener.java index 00e59ec..b169946 100644 --- a/src/main/java/com/armzilla/ha/upnp/UpnpListener.java +++ b/src/main/java/com/armzilla/ha/upnp/UpnpListener.java @@ -1,5 +1,6 @@ package com.armzilla.ha.upnp; +import com.armzilla.ha.PortsConfiguration; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -26,12 +27,17 @@ public class UpnpListener { @Value("${upnp.response.port}") private int upnpResponsePort; - @Value("${server.port}") - private int httpServerPort; + @Autowired + private PortsConfiguration portsConfiguration; @Value("${upnp.config.address}") private String responseAddress; + @Value("${emulator.portbase}") + private int portBase; + @Value("${emulator.portcount}") + private int portCount; + @Autowired private ApplicationContext applicationContext; @@ -71,7 +77,9 @@ public void startListening(){ String packetString = new String(packet.getData()); if(isSSDPDiscovery(packetString)){ log.debug("Got SSDP Discovery packet from " + packet.getAddress().getHostAddress() + ":" + packet.getPort()); - sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort()); + for(int i = 0; i < portCount; i ++) { + sendUpnpResponse(responseSocket, packet.getAddress(), packet.getPort(), portBase+i, i); + } } } @@ -100,13 +108,13 @@ protected boolean isSSDPDiscovery(String body){ String discoveryTemplate = "HTTP/1.1 200 OK\r\n" + "CACHE-CONTROL: max-age=86400\r\n" + "EXT:\r\n" + - "LOCATION: http://%s:%s/upnp/amazon-ha-bridge/setup.xml\r\n" + + "LOCATION: http://%s:%s/upnp/%s/setup.xml\r\n" + "OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" + "01-NLS: %s\r\n" + "ST: urn:schemas-upnp-org:device:basic:1\r\n" + "USN: uuid:Socket-1_0-221438K0100073::urn:Belkin:device:**\r\n\r\n"; - protected void sendUpnpResponse(DatagramSocket socket, InetAddress requester, int sourcePort) throws IOException { - String discoveryResponse = String.format(discoveryTemplate, responseAddress, httpServerPort, getRandomUUIDString()); + protected void sendUpnpResponse(DatagramSocket socket, InetAddress requester, int sourcePort, int gatewayPort, int emulatorId) throws IOException { + String discoveryResponse = String.format(discoveryTemplate, responseAddress, gatewayPort, "amazon-ha-bridge" + emulatorId, "D1710C33-328D-4152-A5FA-5382541A92FF"); DatagramPacket response = new DatagramPacket(discoveryResponse.getBytes(), discoveryResponse.length(), requester, sourcePort); socket.send(response); } diff --git a/src/main/java/com/armzilla/ha/upnp/UpnpSettingsResource.java b/src/main/java/com/armzilla/ha/upnp/UpnpSettingsResource.java index b8fbcc6..dd90b01 100644 --- a/src/main/java/com/armzilla/ha/upnp/UpnpSettingsResource.java +++ b/src/main/java/com/armzilla/ha/upnp/UpnpSettingsResource.java @@ -1,6 +1,7 @@ package com.armzilla.ha.upnp; import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; @@ -16,8 +17,9 @@ @Controller @RequestMapping("/upnp") public class UpnpSettingsResource { - private Logger log = Logger.getLogger(UpnpSettingsResource.class); + @Value("${emulator.portcount}") + private int portCount; private String hueTemplate = "\n" + "\n" + @@ -35,8 +37,8 @@ public class UpnpSettingsResource { "Philips hue bridge 2012\n" + "929000226503\n" + "http://www.armzilla.com/amazon-echo-ha-bridge\n" + - "01189998819991197253\n" + - "uuid:88f6698f-2c83-4393-bd03-cd54a9f8595\n" + + "%s\n" + + "uuid:%s\n" + "\n" + "\n" + "(null)\n" + @@ -72,7 +74,7 @@ public ResponseEntity getUpnpConfiguration(@PathVariable(value="deviceId log.info("upnp device settings requested: " + deviceId + " from " + request.getRemoteAddr()); String hostName = request.getLocalAddr(); String portNumber = Integer.toString(request.getLocalPort()); - String filledTemplate = String.format(hueTemplate, hostName, portNumber, hostName); + String filledTemplate = String.format(hueTemplate, hostName, request.getLocalPort(), hostName, deviceId, deviceId); return new ResponseEntity<>(filledTemplate, null, HttpStatus.OK); } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index ed8db7f..f0dec91 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,3 +1,5 @@ upnp.response.port=50000 -server.port=8080 upnp.config.address=192.168.1.1 +devices.per.gateway=5 +portBase=8080 +portCount=3 From e52783b1b072d9c252cb2201c2212d5fed3e1c10 Mon Sep 17 00:00:00 2001 From: Arm Suwarnaratana Date: Fri, 16 Sep 2016 00:14:37 -0500 Subject: [PATCH 2/4] removed old ref to experimental port class --- src/main/java/com/armzilla/ha/upnp/UpnpListener.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/com/armzilla/ha/upnp/UpnpListener.java b/src/main/java/com/armzilla/ha/upnp/UpnpListener.java index b169946..6523f50 100644 --- a/src/main/java/com/armzilla/ha/upnp/UpnpListener.java +++ b/src/main/java/com/armzilla/ha/upnp/UpnpListener.java @@ -1,6 +1,5 @@ package com.armzilla.ha.upnp; -import com.armzilla.ha.PortsConfiguration; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -27,9 +26,6 @@ public class UpnpListener { @Value("${upnp.response.port}") private int upnpResponsePort; - @Autowired - private PortsConfiguration portsConfiguration; - @Value("${upnp.config.address}") private String responseAddress; From df39d549701a53885a972ede2cf2a0795dc48c15 Mon Sep 17 00:00:00 2001 From: Arm Suwarnaratana Date: Fri, 16 Sep 2016 00:19:53 -0500 Subject: [PATCH 3/4] fixed oopsies in app.properties, tired --- src/main/resources/application.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index f0dec91..7bef4b0 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,5 +1,5 @@ upnp.response.port=50000 upnp.config.address=192.168.1.1 devices.per.gateway=5 -portBase=8080 -portCount=3 +emulator.portbase=8080 +emulator.portcount=3 From 2717fb7d8e0e4a90f61b091ede6c684580d96516 Mon Sep 17 00:00:00 2001 From: Arm Suwarnaratana Date: Fri, 16 Sep 2016 16:26:55 -0500 Subject: [PATCH 4/4] fixed 'tests' --- src/main/java/com/armzilla/ha/SpringbootEntry.java | 2 +- src/test/java/demo/DemoApplicationTests.java | 2 ++ src/test/resources/test.properties | 5 +++++ 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 src/test/resources/test.properties diff --git a/src/main/java/com/armzilla/ha/SpringbootEntry.java b/src/main/java/com/armzilla/ha/SpringbootEntry.java index 08907b9..93009c1 100644 --- a/src/main/java/com/armzilla/ha/SpringbootEntry.java +++ b/src/main/java/com/armzilla/ha/SpringbootEntry.java @@ -21,5 +21,5 @@ public class SpringbootEntry { public static void main(String[] args) { SpringApplication.run(SpringbootEntry.class, args); } - + } diff --git a/src/test/java/demo/DemoApplicationTests.java b/src/test/java/demo/DemoApplicationTests.java index 8ca1356..2f51058 100644 --- a/src/test/java/demo/DemoApplicationTests.java +++ b/src/test/java/demo/DemoApplicationTests.java @@ -3,12 +3,14 @@ import com.armzilla.ha.SpringbootEntry; import org.junit.Test; import org.junit.runner.RunWith; +import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = SpringbootEntry.class) +@TestPropertySource(locations="classpath:test.properties") @WebAppConfiguration public class DemoApplicationTests { diff --git a/src/test/resources/test.properties b/src/test/resources/test.properties new file mode 100644 index 0000000..841379d --- /dev/null +++ b/src/test/resources/test.properties @@ -0,0 +1,5 @@ +upnp.response.port=50000 +upnp.config.address=192.168.1.1 +emulator.portbase=8080 +emulator.portcount=3 +upnp.disable=false