001/* 002 * $Rev: 1021 $: Revision of last commit 003 * $Author: tgutwin $: Author of last commit 004 * $Date: 2015-10-28 15:59:29 -0700 (Wed, 28 Oct 2015) $: Date of last commit 005 * $URL: svn://svn.webarts.bc.ca/open/trunk/projects/WebARTS/ca/bc/webarts/tools/lednet/LedNetProxySocketServer.java $ 006 */ 007/* 008 * 009 * Written by Tom Gutwin - WebARTS Design. 010 * Copyright (C) 2016-2017 WebARTS Design, North Vancouver Canada 011 * http://www.webarts.bc.ca 012 * 013 * This program is free software; you can redistribute it and/or modify 014 * it under the terms of the GNU General Public License as published by 015 * the Free Software Foundation; either version 2 of the License, or 016 * (at your option) any later version. 017 * 018 * This program is distributed in the hope that it will be useful, 019 * but WITHOUT ANY WARRANTY; without_ even the implied warranty of 020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 021 * GNU General Public License for more details. 022 * 023 * You should have received a copy of the GNU General Public License 024 * along with this program; if not, write to the Free Software 025 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 026 */ 027 028package ca.bc.webarts.tools.lednet; 029 030import java.io.DataInputStream; 031import java.io.PrintStream; 032import java.io.IOException; 033import java.util.Arrays; 034import java.net.Socket; 035import java.net.ServerSocket; 036import java.util.concurrent.ArrayBlockingQueue; 037 038//import ca.bc.webarts.tools.NativeAppLauncher; 039//import ca.bc.webarts.widgets.ProcessRunner; 040import ca.bc.webarts.tools.TCPSocketServer; 041 042/** 043 * Proxy Server for <a href="http://forum.universal-devices.com/topic/19913-magic-ufo-controller-for-rgbw">ledeNet</a> Magic led STRIP LIGHT WiFI enabled CONTROLLER.<br> 044 * <img src="https://fred.webarts.bc.ca:9443/roller/tom/mediaresource/372c0d8a-c3bf-4294-89b7-66293851a567?t=true" align="right"/> 045 * A Multi-Threaded TCP Socket server that listens for requests and then performs specific functions 046 * (wrapped in the {@link clentThread() clentThread}) on the server. 047 * <br />It makes calls to my 048 * <a href="https://fred.webarts.bc.ca:9443/roller/tom/mediaresource/372c0d8a-c3bf-4294-89b7-66293851a567">Controller Software class.</a> 049 * It acts as a Network based listener to relay requests to the lednET led STRIP LIGHT CONTROLLER.<br /><br /> 050 * Simply start it up<br /> 051 * Usage: <pre> 052 java ca.bc.webarts.tools.lednet.LedNetProxySocketServer <portNumber> 053 </pre> 054 * Then send TCP messages to its port directly<br /> OR<br />http get requests to the port with parameters<br /> 055 * For example: 056 * <ul> 057 <li><a href="http://fred.webarts.bc.ca:44445/b">http://fred.webarts.bc.ca:44445/b</a></li> 058 <li><a href="http://localhost:44445/colour?r=5">http://localhost:44445/colour?r=5</a></li> 059 </ul> 060 * params it listens and relays are: <pre>on, off, r, g, b, p, y, w, ww, cw, cyan, fun, nightfade, colour?r=10&g=2&b=14</pre><br /> 061 * 062 **/ 063public class LedNetProxySocketServer extends TCPSocketServer 064{ 065 public static final int DEFAULT_LEDNETPROXY_PORT = DEFAULT_PORT+1; 066 LedNetProxy instance = new LedNetProxy(); 067 068 069 /** Default Constructor using defaults. **/ 070 public LedNetProxySocketServer() 071 { 072 portNumber_ = DEFAULT_LEDNETPROXY_PORT; 073 initPortProcessors(); 074 } 075 076 077 /** Constructor to allow a custom port. **/ 078 public LedNetProxySocketServer(int portNum) 079 { 080 portNumber_ = portNum; 081 initPortProcessors(); 082 } 083 084 085 /** call this when a new connection comes in to start the procesing of the action that is taken. **/ 086 public boolean postConnection(Socket s, int maxBlockTime_ms ) 087 { 088 int waiter = 0;int sleepTime=250; //int maxBlockTime_ms = 1500 089 if (acceptingConnections_) 090 { 091 clientSocket_=s; 092 Thread ct = new lednetClientThread(clientSocket_); // does something with the request 093 if (debug_>1) System.out.println(" >Posting a new client connection: "); 094 while(!clientQueue_.offer(ct)) 095 { 096 while( waiter<maxBlockTime_ms) {ca.bc.webarts.widgets.Util.sleep(sleepTime);waiter+=sleepTime;} 097 //System.out.println("Maximum Clients Reached: "+MAX_CLIENTS_COUNT); 098 } 099 } 100 101 boolean retVal = acceptingConnections_; 102 if (acceptingConnections_) retVal = (waiter<maxBlockTime_ms); 103 return retVal; 104 } 105 106 107 /** 108 * Starts the port listener server. 109 * Usage: <pre> 110 java ca.bc.webarts.tools.lednet.LedNetProxySocketServer <portNumber> 111 </pre> 112 **/ 113 public static void main(String args[]) 114 { 115 int portToUse= LedNetProxySocketServer.DEFAULT_LEDNETPROXY_PORT; 116 if (args.length < 1) 117 { 118 System.out.println("Usage: java ca.bc.webarts.tools.lednet.LedNetProxySocketServer <portNumber>\n" + "Now using DEFAULT port number=" + portToUse); 119 } 120 else 121 { 122 try 123 { 124 portToUse= Integer.valueOf(args[0]).intValue(); 125 } 126 catch (Exception ex){} // use defaults 127 } 128 System.out.println("LedNetProxySocketServer Started.\n" +"Now using port number=" + portToUse); 129 LedNetProxySocketServer tcpServer = new LedNetProxySocketServer(portToUse); 130 131 int i = 0; 132 boolean posted = false; 133 while (tcpServer.getSocket()!=null) 134 { 135 try 136 { 137 // Listening for another client connection 138 if (debug_>1) System.out.println("Accepting new connections "); 139 posted = tcpServer.postConnection(tcpServer.getSocket().accept()); // accept blocks until a connection comes in 140 141 //if (debug_>1) System.out.println("connectionPosted> "+posted); 142 if (!posted) 143 { 144 if (debug_>0) System.out.println(" NOT Posted: clientThreads MAXXED: "); 145 } 146 } 147 catch (IOException e) 148 { 149 System.out.println(e); 150 } 151 } 152 if (debug_>0) System.out.println("Done, Exiting"); 153 } 154 155/* ******************** */ 156 /** 157 * The client thread (part of the TCPSocketServer) that gets created when a connectiuon comes in. 158 * This client thread opens the input and the output streams for a particular client, 159 * gets the client request, executes it and terminates. 160 * 161 * @see TCPSocketServer 162 */ 163 class lednetClientThread extends Thread 164 { 165 int debug_=2; 166 private String clientRequest = null; 167 private DataInputStream is = null; 168 private PrintStream os = null; 169 private Socket clientSocket = null; 170 171 172 public lednetClientThread(Socket clientSocket) 173 { 174 this.clientSocket = clientSocket; 175 } 176 177 178 public void run() 179 { 180 String TEMP_DIR = System.getProperty("java.io.tmpdir"); 181 try 182 { 183 /* 184 * Create input and output streams for this client. 185 */ 186 if (debug_>1) System.out.println(" >Starting LedNetProxySocketServer.lednetClientThread: "+ Thread.currentThread().getId()); 187 188 is = new DataInputStream(clientSocket.getInputStream()); 189 os = new PrintStream(clientSocket.getOutputStream()); 190 String clientRequest = ""; 191 192 //os.println("?"); 193 clientRequest = is.readLine().trim(); 194 System.out.println(" > ClientRequest: "+clientRequest); 195 String[] cmdArgs = clientRequest.split("\\s"); 196 java.util.List <String> cmdList = java.util.Arrays.asList(cmdArgs); 197 198 /* Execute the request. */ 199 synchronized (this) 200 { 201 System.out.println(" --> Doing something with the socket request"); 202 proxyCommand( clientRequest); 203 os.println(TCPSocketServer.END); 204 } 205 if (debug_>1) System.out.println(" >Closing clientThread: "+ Thread.currentThread().getId()); 206 207 /* 208 * Close the output stream, close the input stream, close the socket. 209 */ 210 is.close(); 211 os.close(); 212 clientSocket.close(); 213 } 214 catch (IOException e) 215 { 216 } 217 } 218 219 220 private void proxyCommand(String clientRequest) 221 { 222 clientRequest=clientRequest.trim(); 223 String[] cmdArgs = clientRequest.split("\\s"); 224 String[] parmArgs = null; 225 java.util.List <String> cmdList = java.util.Arrays.asList(cmdArgs); 226 227 boolean httpRequest = false; // if using a browser 228 if(clientRequest.startsWith("GET /")) 229 { 230 System.out.println("Got a Browser GET request '"+clientRequest+"'"); 231 httpRequest = true; 232 clientRequest = clientRequest.substring("GET /".length(), clientRequest.length()-" HTTP/1.1".length() ).trim(); 233 System.out.println(" clientRequest '"+clientRequest+"'"); 234 if(clientRequest.contains("?")) // url has parameters 235 { 236 String parms = clientRequest.substring(clientRequest.indexOf("?")+1); 237 System.out.println(" with parameters: "+parms); 238 clientRequest.substring(0,clientRequest.indexOf("?")); 239 parmArgs = parms.split("&"); 240 System.out.println(" "+Arrays.toString(parmArgs)); 241 } 242 } 243 244 System.out.println(" Proxying the LEDNet '"+clientRequest+"' command."); 245 System.out.println(" "+Arrays.toString(cmdArgs)); 246 if (clientRequest.equalsIgnoreCase("on")) 247 { 248 //instance.sendQueryOnOffCommand(true, true); 249 String queryResponse = instance.sendQueryOnOffCommand(true, true); 250 } 251 else if (clientRequest.equalsIgnoreCase("off")) 252 { 253 //instance.sendQueryOnOffCommand(true, true); 254 String queryResponse = instance.sendQueryOnOffCommand(false, true); 255 } 256 else if (clientRequest.equalsIgnoreCase("r")) 257 { 258 //instance.sendQueryOnOffCommand(true, true); 259 instance.sendColourCommand(255,0,0,0); 260 } 261 else if (clientRequest.equalsIgnoreCase("g")) 262 { 263 //instance.sendQueryOnOffCommand(true, true); 264 instance.sendColourCommand(0,255,0,0); 265 } 266 else if (clientRequest.equalsIgnoreCase("b")) 267 { 268 //instance.sendQueryOnOffCommand(true, true); 269 instance.sendColourCommand(0,0,255,0); 270 } 271 else if (clientRequest.equalsIgnoreCase("p")) 272 { 273 //instance.sendQueryOnOffCommand(true, true); 274 instance.sendColourCommand(5,0,14,0); 275 } 276 else if (clientRequest.equalsIgnoreCase("y")) 277 { 278 //instance.sendQueryOnOffCommand(true, true); 279 instance.sendColourCommand(255,255,0,0); 280 } 281 else if (clientRequest.equalsIgnoreCase("w")) 282 { 283 //instance.sendQueryOnOffCommand(true, true); 284 instance.sendColourCommand(200,200,200,255); 285 } 286 else if (clientRequest.equalsIgnoreCase("ww")) 287 { 288 //instance.sendQueryOnOffCommand(true, true); 289 instance.sendColourCommand(0,0,0,255); 290 } 291 else if (clientRequest.equalsIgnoreCase("cw")) 292 { 293 //instance.sendQueryOnOffCommand(true, true); 294 instance.sendColourCommand(240,240,255,80); 295 } 296 else if (clientRequest.equalsIgnoreCase("cyan")) 297 { 298 //instance.sendQueryOnOffCommand(true, true); 299 instance.sendColourCommand(0,20,10,0); 300 } 301 else if (clientRequest.equalsIgnoreCase("dumplevels")) 302 { 303 //instance.sendQueryOnOffCommand(true, true); 304 instance.dumpLevels(); 305 instance.dumpReverseLevels(); 306 } 307 else if (cmdArgs[0].equalsIgnoreCase("fun")) 308 { 309 //instance.sendQueryOnOffCommand(true, true); 310 instance.fun((cmdArgs.length>1?Integer.parseInt(cmdArgs[1]):-1), 311 (cmdArgs.length>2?Integer.parseInt(cmdArgs[2]):200)); // loopTime, pause 312 } 313 else if (clientRequest.startsWith("colour") || cmdArgs[0].equalsIgnoreCase("colour")) 314 { 315 int r = 0; 316 int g = 0; 317 int b = 0; 318 int w = 0; 319 320 if(httpRequest) 321 { 322 if(parmArgs!=null) 323 for(int i=0; i<parmArgs.length;i++) 324 { 325 if(parmArgs[i].startsWith("r=")) r=Integer.parseInt(parmArgs[i].substring(parmArgs[i].indexOf("=")+1)); 326 if(parmArgs[i].startsWith("g=")) g=Integer.parseInt(parmArgs[i].substring(parmArgs[i].indexOf("=")+1)); 327 if(parmArgs[i].startsWith("b=")) b=Integer.parseInt(parmArgs[i].substring(parmArgs[i].indexOf("=")+1)); 328 if(parmArgs[i].startsWith("w=")) w=Integer.parseInt(parmArgs[i].substring(parmArgs[i].indexOf("=")+1)); 329 } 330 System.out.println(" Parsing parmArgs:"+Arrays.toString( parmArgs)); 331 System.out.println(" r="+r+" g="+g+ " b="+b+" w="+w); 332 } 333 else 334 { 335 r = (cmdArgs.length>1?Integer.parseInt(cmdArgs[1]):0); 336 g = (cmdArgs.length>2?Integer.parseInt(cmdArgs[2]):0); 337 b = (cmdArgs.length>3?Integer.parseInt(cmdArgs[3]):0); 338 w = (cmdArgs.length>4?Integer.parseInt(cmdArgs[4]):0); 339 } 340 341 //instance.sendQueryOnOffCommand(true, true); 342 instance.sendColourCommand(r,g,b,w); 343 } 344 else if (cmdArgs[0].equalsIgnoreCase("nightFade")) 345 { 346 instance.sendQueryOnOffCommand(true, false); 347 348 while(true) 349 { 350 instance.stepBetween(1,0,1,0, 8,0,16,0); 351 instance.stepBetween(8,0,16,0, 1,0,1,0); 352 } 353 } 354 } 355 } 356}