diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..798cc316 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +/rc_images +/dist +/release +/bin +/.gradle +/.settings +/config.ini +/css +/cdata.* +/*.jar \ No newline at end of file diff --git a/lib/Java-WebSocket-1.5.5.jar b/lib/Java-WebSocket-1.5.5.jar new file mode 100644 index 00000000..a3f8b805 Binary files /dev/null and b/lib/Java-WebSocket-1.5.5.jar differ diff --git a/src/com/tivo/kmttg/gui/remote/info.java b/src/com/tivo/kmttg/gui/remote/info.java index 97a75584..f2918ba0 100755 --- a/src/com/tivo/kmttg/gui/remote/info.java +++ b/src/com/tivo/kmttg/gui/remote/info.java @@ -240,61 +240,61 @@ private void RC_infoCB(final String tivoName) { info += String.format("%-30s %s\n", fields[i], json.get(fields[i])); } - if (! r.awayMode() ) { - // More detailed info - JSONObject j = new JSONObject(); - j.put("bodyId", r.bodyId_get()); - JSONObject response = r.Command("systemInformationGet", j); - if (response != null) { - String integers[] = { - "remoteAddress", "recordingCapacityHdHours", - "recordingCapacitySdHours", "freeDiskSpaceSdHours", - "freeDiskSpaceHdHours" - }; - String strings[] = { - "internalTemperature", - "zipCode", "remoteBatteryLevel", "activeVideoOutputFormat", - "platform", "netflixEsn", - "hdcpVersionInfo", "collabSliceVersion", - "programInfoTo", "gcCompletionTime", "indexCompletionTime", - "dialInCode", "serviceState", "serviceLevel", "serviceMapInfo", - }; - String jsons[] = { "serviceConnectionInfo", "vcmConnectionInfo" }; - for (int i=0; i0) - info += "; "; - info += whatson[i]; - } - info += "\n"; + } + + // What's On info + String [] whatson = getWhatsOn(tivoName); + if (whatson != null) { + info += String.format("%-30s ", "What's On"); + for (int i=0; i0) + info += "; "; + info += whatson[i]; } info += "\n"; + } + info += "\n"; + if (! r.awayMode() ) { // Tuner info reply = r.Command("TunerInfo", new JSONObject()); if (reply != null && reply.has("state")) { diff --git a/src/com/tivo/kmttg/main/config.java b/src/com/tivo/kmttg/main/config.java index 77ba9bfb..26517688 100644 --- a/src/com/tivo/kmttg/main/config.java +++ b/src/com/tivo/kmttg/main/config.java @@ -36,6 +36,7 @@ import java.util.Stack; import com.tivo.kmttg.rpc.Remote; +import com.tivo.kmttg.rpc.TiVoRPCWS; import com.tivo.kmttg.util.*; import com.tivo.kmttg.gui.gui; import com.tivo.kmttg.httpserver.kmttgServer; @@ -631,11 +632,9 @@ public static void twpDeleteEnabledSet(Boolean state) { public static Remote initRemote(String tivoName) { if (rpcEnabled(tivoName)) { - Remote r = new Remote(tivoName); - return(r); + return new Remote(tivoName); } else { - Remote r = new Remote(tivoName, true); - return(r); + return new Remote(tivoName, true); } } diff --git a/src/com/tivo/kmttg/rpc/Remote.java b/src/com/tivo/kmttg/rpc/Remote.java index c3b7beae..7ababc2b 100755 --- a/src/com/tivo/kmttg/rpc/Remote.java +++ b/src/com/tivo/kmttg/rpc/Remote.java @@ -23,6 +23,7 @@ import java.io.FileWriter; import java.net.DatagramSocket; import java.net.InetAddress; +import java.net.URISyntaxException; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.Arrays; @@ -48,25 +49,44 @@ import com.tivo.kmttg.util.log; import com.tivo.kmttg.util.string; -public class Remote extends TiVoRPC { - public final Boolean success; - private final boolean away; +public class Remote{ + public Boolean success; + protected TiVoRPCWS ws; + protected TiVoRPC s; + protected final boolean away; + private String tivoName; + protected final String IP; + protected final int port; /** perform a socket setup and auth. all public constructors call this. */ private Remote(String tivoName, boolean away, String IP, String mak, String programDir, int port, String cdata) { - super(tivoName, IP, mak, programDir, port, cdata, - // oldSchema, debug - (config.rpcOld == 1), com.tivo.kmttg.util.debug.enabled); - // super calls RemoteInit which in turn calls Auth which is overridden in this class to also call Auth_web() or bodyId_get() + this.tivoName = tivoName; + this.IP = IP; + this.port = port; this.away = away; - - // record the init result in the expected public field - this.success = getSuccess(); + try { + if (away) { + ws = TiVoRPCWS.init( + tivoName, + IP, + port + ); + this.success = ws.waitForReady(); + } else { + s = new TiVoRPC(tivoName, IP, mak, programDir, port, cdata, + (config.rpcOld == 1), com.tivo.kmttg.util.debug.enabled); + this.success = s.getSuccess(); + } + } catch (URISyntaxException | InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + this.success = false; + } } // This constructor designed to be use by kmttg public Remote(String tivoName) { - this(null, false, // doesn't actually set this.tivoName + this(tivoName, false, // doesn't actually set this.tivoName getIPForTivo(tivoName), config.MAK, config.programDir, getPortForTivo(tivoName), @@ -99,7 +119,7 @@ public Remote(String tivoName, String IP, int port, String MAK, String cdata) { port, cdata); } - private static String getIPForTivo(String tivoName) { + public static String getIPForTivo(String tivoName) { String tivoIP = config.TIVOS.get(tivoName); // if config for tivoName is null, pass tivoName as IP, else config @@ -110,7 +130,13 @@ private static String getIPForTivo(String tivoName) { } } - private static int getPortForTivo(String tivoName) { + public boolean isConnected() { + return this.away + ? this.ws.isOpen() + : this.s.isConnected(); + } + + public static int getPortForTivo(String tivoName) { String wanrpc = config.getWanSetting(tivoName, "rpc"); // if "rpc" WanSetting for tivoName is null, use default port, else WanSetting @@ -121,31 +147,15 @@ private static int getPortForTivo(String tivoName) { } } - /** - * Override performs a tivo.com authentication if IP ends with tivo.com, else performs default followed by a bodyId_get() - */ - @Override - protected boolean Auth(String MAK) { - if (IP.endsWith("tivo.com") || IP.endsWith("tivoservice.com")) { - if ( ! Auth_web() ) { - return false; - } - } else { - if ( ! super.Auth(MAK) ) { - return false; - } - bodyId_get(); - } - return true; - } - - /** * Returns cached bodyId or performs a bodyConfigSearch and returns the bodyId. * NOTE: This retrieves and stores bodyId in config hashtable if not previously stored * @return bodyId or "-" */ public String bodyId_get() { + if (this.away) { + return ws.getTsn(); + } String id = config.bodyId_get(IP, port); if (id.equals("")) { JSONObject json = new JSONObject(); @@ -169,104 +179,24 @@ public String bodyId_get() { id = "-"; return id; } - - /** - * Perform a middlemind tivo.com bodyAuthenticate with configured username/password - * @return - */ - private Boolean Auth_web() { - try { - if (config.getTivoUsername() == null || config.getTivoPassword() == null) { - log.error("tivo.com username & password not set in kmttg or pyTivo config"); - return false; - } - if (config.isDomainTokenExpired() || config.getDomainToken() == null) { - log.warn("Domain Token expired refreshing token"); - GetDomainToken getDT = new GetDomainToken(); - try { - getDT.getToken(); - } catch (Exception e) { - log.error("Failed to get domain token. Check your tivo.com username or password."); - return false; - } - if (config.isDomainTokenExpired()) { - log.error("Failed to get domain token. Check your tivo.com username or password."); - return false; - } - } - - JSONObject credential = new JSONObject(); - JSONObject h = new JSONObject(); - JSONObject domainToken = new JSONObject(); - domainToken.put("domain", "tivo"); - domainToken.put("type", "domainToken"); - domainToken.put("token", config.getDomainToken()); - - credential.put("type", "domainTokenCredential"); - credential.put("domainToken", domainToken); -// credential.put("username", config.getTivoUsername()); -// credential.put("password", config.getTivoPassword()); - h.put("credential", credential); - String req = RpcRequest("bodyAuthenticate", false, h); - if (Write(req) ) { - JSONObject result = ReadRemote(); - if (result.has("status")) { - if (result.get("status").equals("success")) { - // Look for tivoName bodyId in deviceId JSONArray - Boolean found = false; - if (result.has("deviceId")) { - JSONArray a = result.getJSONArray("deviceId"); - for (int i=0; i getCategoryNames(String tivoName) { log.error("Remote getCategoryNames - " + e.getMessage()); return null; } - r.disconnect(); + disconnect(); } return categories; } @@ -2722,7 +2663,7 @@ private String getCategoryId(String tivoName, String categoryName) { for (int i=0; i responseMap = new HashMap(); + + protected void error(String msg) { + log.error(msg); + } + protected void print(String msg) { + log.print(msg); + } + protected void warn(String msg) { + log.warn(msg); + } + + public TiVoRPCWS(URI uri, Draft protocal, String tivoName, String IP, int port) { + super(uri, protocal); + this.tivoName = tivoName; + this.IP = IP; + this.port = port; + } + + + public static TiVoRPCWS init(String tivoName, String IP, int port) throws URISyntaxException, InterruptedException { + //System.setProperty(org.slf4j.impl.SimpleLogger.DEFAULT_LOG_LEVEL_KEY, "TRACE"); + Draft_6455 draft_mindrpc = new Draft_6455(Collections.emptyList(), + Collections.singletonList(new Protocol("com.tivo.mindrpc.2"))); + TiVoRPCWS ws = new TiVoRPCWS( + new URI("wss://xmind-tp2.tivoservice.com:2196/"), + draft_mindrpc, + tivoName, + IP, + port + ); + + ws.connectBlocking(); + + return ws; + } + + public boolean waitForReady() throws InterruptedException { + if (!this.isOpen()) { + return false; + } + if (this.ready) { + return true; + } + synchronized(this.ready){ + while (!this.ready) { + if (!this.isOpen()) { + return false; + } + this.ready.wait(); + } + return this.isOpen(); + } + } + + + @Override + public void onOpen(ServerHandshake handshakedata) { + //send("Hello, it is me. Mario :)"); + log.print("WS connection started"); + TiVoRPCWS wc = this; + Thread thread = new Thread(){ + public void run(){ + Boolean readyLock = wc.ready; + try { + JSONObject credential = new JSONObject(); + JSONObject h = new JSONObject(); + JSONObject domainToken = new JSONObject(); + domainToken.put("domain", "tivo"); + domainToken.put("type", "domainToken"); + domainToken.put("token", config.getDomainToken()); + + credential.put("type", "domainTokenCredential"); + credential.put("domainToken", domainToken); + h.put("credential", credential); + String req = RpcRequest("bodyAuthenticate", false, h); + String lock = ""; + synchronized(lock){ + responseMap.put(rpc_id, lock); + wc.send(req); + lock.wait(); + String response = responseMap.get(rpc_id); + responseMap.remove(rpc_id); + JSONObject result = new JSONObject(response); + if (result.has("status")) { + if (result.get("status").equals("success")) { + // Look for tivoName bodyId in deviceId JSONArray + boolean found = false; + if (result.has("deviceId")) { + JSONArray a = result.getJSONArray("deviceId"); + for (int i=0; i