diff --git a/common/src/main/java/ctbrec/sites/mfc/MyFreeCamsClient.java b/common/src/main/java/ctbrec/sites/mfc/MyFreeCamsClient.java index 1e4f5ca5..45178981 100644 --- a/common/src/main/java/ctbrec/sites/mfc/MyFreeCamsClient.java +++ b/common/src/main/java/ctbrec/sites/mfc/MyFreeCamsClient.java @@ -40,6 +40,7 @@ import com.squareup.moshi.Moshi; import ctbrec.Config; import ctbrec.StringUtil; +import ctbrec.io.HttpException; import okhttp3.Cookie; import okhttp3.Request; import okhttp3.Response; @@ -93,6 +94,7 @@ public class MyFreeCamsClient { } public void start() throws IOException { + requestLandingPage(); // to get some cookies running = true; serverConfig = new ServerConfig(mfc); List websocketServers = new ArrayList<>(serverConfig.wsServers.size()); @@ -134,6 +136,21 @@ public class MyFreeCamsClient { watchDog.start(); } + private void requestLandingPage() throws IOException { + Request req = new Request.Builder() + .url(MyFreeCams.baseUrl) + .header(ACCEPT, "*/*") + .header(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage()) + .header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent) + .header(CONNECTION, KEEP_ALIVE) + .build(); + try(Response resp = mfc.getHttpClient().execute(req)) { + if(!resp.isSuccessful()) { + throw new HttpException(resp.code(), resp.message()); + } + } + } + public void stop() { running = false; ws.close(1000, "Good Bye"); // terminate normally (1000) @@ -455,54 +472,6 @@ public class MyFreeCamsClient { model.update(state, getStreamUrl(state)); } - private Message parseMessage(StringBuilder msgBuffer) throws UnsupportedEncodingException { - int packetLengthBytes = 6; - if (msgBuffer.length() < packetLengthBytes) { - // packet size not transmitted completely - return null; - } else { - try { - int packetLength = Integer.parseInt(msgBuffer.substring(0, packetLengthBytes)); - if (packetLength > msgBuffer.length() - packetLengthBytes) { - // packet not complete - return null; - } else { - LOG.trace("<-- {}", msgBuffer); - msgBuffer.delete(0, packetLengthBytes); - StringBuilder rawMessage = new StringBuilder(msgBuffer.substring(0, packetLength)); - int type = parseNextInt(rawMessage); - int sender = parseNextInt(rawMessage); - int receiver = parseNextInt(rawMessage); - int arg1 = parseNextInt(rawMessage); - int arg2 = parseNextInt(rawMessage); - Message message = new Message(type, sender, receiver, arg1, arg2, URLDecoder.decode(rawMessage.toString(), "utf-8")); - msgBuffer.delete(0, packetLength); - return message; - } - } catch (Exception e) { - LOG.error("StringBuilder contains invalid data {}", msgBuffer.toString(), e); - String logfile = "mfc_messages.log"; - try (FileOutputStream fout = new FileOutputStream(logfile)) { - for (String string : receivedTextHistory) { - fout.write(string.getBytes()); - fout.write(10); - } - } catch (Exception e1) { - LOG.error("Couldn't write mfc message history to {}", logfile, e1); - } - msgBuffer.setLength(0); - return null; - } - } - } - - private int parseNextInt(StringBuilder s) { - int nextSpace = s.indexOf(" "); - int i = Integer.parseInt(s.substring(0, nextSpace)); - s.delete(0, nextSpace + 1); - return i; - } - @Override public void onMessage(WebSocket webSocket, ByteString bytes) { super.onMessage(webSocket, bytes); @@ -512,6 +481,58 @@ public class MyFreeCamsClient { return websocket; } + private Message parseMessage(StringBuilder msgBuffer) throws UnsupportedEncodingException { + int packetLengthBytes = parsePacketLengthBytes(msgBuffer); + if (packetLengthBytes < 0) { + // packet size not transmitted completely + return null; + } else { + try { + int packetLength = Integer.parseInt(msgBuffer.substring(0, packetLengthBytes)); + if (packetLength > msgBuffer.length() - packetLengthBytes) { + // packet not complete + return null; + } else { + LOG.trace("<-- {}", msgBuffer); + msgBuffer.delete(0, packetLengthBytes); + StringBuilder rawMessage = new StringBuilder(msgBuffer.substring(0, packetLength)); + int type = parseNextInt(rawMessage); + int sender = parseNextInt(rawMessage); + int receiver = parseNextInt(rawMessage); + int arg1 = parseNextInt(rawMessage); + int arg2 = parseNextInt(rawMessage); + Message message = new Message(type, sender, receiver, arg1, arg2, URLDecoder.decode(rawMessage.toString(), "utf-8")); + msgBuffer.delete(0, packetLength); + return message; + } + } catch (Exception e) { + LOG.error("StringBuilder contains invalid data {}", msgBuffer.toString(), e); + String logfile = "mfc_messages.log"; + try (FileOutputStream fout = new FileOutputStream(logfile)) { + for (String string : receivedTextHistory) { + fout.write(string.getBytes()); + fout.write(10); + } + } catch (Exception e1) { + LOG.error("Couldn't write mfc message history to {}", logfile, e1); + } + msgBuffer.setLength(0); + return null; + } + } + } + + private int parsePacketLengthBytes(StringBuilder msgBuffer) { + return msgBuffer.indexOf(" ") - 2; + } + + private int parseNextInt(StringBuilder s) { + int nextSpace = s.indexOf(" "); + int i = Integer.parseInt(s.substring(0, nextSpace)); + s.delete(0, nextSpace + 1); + return i; + } + protected boolean follow(int uid) { if (ws != null) { return ws.send(ADDFRIENDREQ + " " + sessionId + " 0 " + uid + " 1\n"); @@ -703,4 +724,18 @@ public class MyFreeCamsClient { public Collection getSessionStates() { return Collections.unmodifiableCollection(sessionStates.asMap().values()); } + + public void joinChannel(MyFreeCamsModel model) { + SessionState state = getSessionState(model); + int userChannel = 100000000 + state.getUid(); + LOG.debug("Joining chat channel for model {}", model.getDisplayName()); + try { + search(model.getName()); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + ws.send(MessageTypes.ROOMDATA + " " + sessionId + " 0 1 0\n"); + ws.send(MessageTypes.UEOPT + " " + sessionId + " 0 66 1 111111\n"); + ws.send(MessageTypes.JOINCHAN + " " + sessionId + " 0 " + userChannel + " 9\n"); + } } diff --git a/common/src/test/java/ctbrec/ReflectionUtil.java b/common/src/test/java/ctbrec/ReflectionUtil.java new file mode 100644 index 00000000..37bbba44 --- /dev/null +++ b/common/src/test/java/ctbrec/ReflectionUtil.java @@ -0,0 +1,21 @@ +package ctbrec; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class ReflectionUtil { + + private ReflectionUtil () {} + + @SuppressWarnings("unchecked") + public static T call(Object target, String methodName, Object...args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + List> argTypes = Arrays.stream(args).map(arg -> arg.getClass()).collect(Collectors.toList()); + Class[] argTypeArray = argTypes.toArray(new Class[0]); + Method method = target.getClass().getDeclaredMethod(methodName, argTypeArray); + method.setAccessible(true); + return (T) method.invoke(target, args); + } +} diff --git a/common/src/test/java/ctbrec/sites/mfc/MyFreeCamsClientTest.java b/common/src/test/java/ctbrec/sites/mfc/MyFreeCamsClientTest.java new file mode 100644 index 00000000..d8bbdac3 --- /dev/null +++ b/common/src/test/java/ctbrec/sites/mfc/MyFreeCamsClientTest.java @@ -0,0 +1,38 @@ +package ctbrec.sites.mfc; + +import static org.junit.Assert.*; + +import java.lang.reflect.InvocationTargetException; + +import org.json.JSONObject; +import org.junit.Test; + +import ctbrec.ReflectionUtil; + +public class MyFreeCamsClientTest { + + @Test + public void testMessageParsing() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + MyFreeCamsClient client = MyFreeCamsClient.getInstance(); + StringBuilder input = new StringBuilder("082720 418550763 419337943 0 37761695 %7B%22lv%22%3A4%2C%22nm%22%3A%22AliceArras%22%2C%22pid%22%3A1%2C%22sid%22%3A418550763%2C%22uid%22%3A37761695%2C%22vs%22%3A0%2C%22u%22%3A%7B%22age%22%3A19%2C%22avatar%22%3A1%2C%22blurb%22%3A%22Open%20minded%2C%20willing%20to%20try%20new%20horny%20things%20all%20the%20time!%22%2C%22camserv%22%3A1205%2C%22chat_font%22%3A0%2C%22chat_opt%22%3A1%2C%22city%22%3A%22Tallinn%22%2C%22country%22%3A%22Estonia%22%2C%22creation%22%3A1596715285%2C%22ethnic%22%3A%22Caucasian%22%2C%22photos%22%3A1%2C%22profile%22%3A1%2C%22status%22%3A%22%22%7D%2C%22m%22%3A%7B%22camscore%22%3A629.800%2C%22continent%22%3A%22EU%22%2C%22flags%22%3A3104%2C%22kbit%22%3A0%2C%22lastnews%22%3A0%2C%22mg%22%3A0%2C%22missmfc%22%3A0%2C%22new_model%22%3A1%2C%22rank%22%3A0%2C%22rc%22%3A4%2C%22sfw%22%3A0%2C%22topic%22%3A%22%22%7D%7D"); + Message msg = ReflectionUtil.call(client, "parseMessage", input); + assertEquals(20, msg.getType()); + assertEquals(418550763, msg.getSender()); + assertEquals(419337943, msg.getReceiver()); + assertEquals(0, msg.getArg1()); + assertEquals(37761695, msg.getArg2()); + assertEquals(JSONObject.class, new JSONObject(msg.getMessage()).getClass()); + } + + @Test + public void testMessageLengthParsing() throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + MyFreeCamsClient client = MyFreeCamsClient.getInstance(); + StringBuilder input = new StringBuilder("082720 418550763 419337943 0 37761695"); + int packetBytesLenth = ReflectionUtil.call(client, "parsePacketLengthBytes", input); + assertEquals(4, packetBytesLenth); + + input = new StringBuilder("82720 418550763 419337943 0 37761695"); + packetBytesLenth = ReflectionUtil.call(client, "parsePacketLengthBytes", input); + assertEquals(3, packetBytesLenth); + } +}