Use USERNAMELOOKUP message to get the current SessionState for a model
This commit is contained in:
parent
cea5eac9de
commit
7577379885
|
@ -1,52 +1,32 @@
|
||||||
package ctbrec.sites.mfc;
|
package ctbrec.sites.mfc;
|
||||||
|
|
||||||
import static ctbrec.io.HttpConstants.*;
|
|
||||||
import static ctbrec.sites.mfc.MessageTypes.*;
|
|
||||||
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.URLDecoder;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Queue;
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.locks.Lock;
|
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import com.google.common.cache.Cache;
|
import com.google.common.cache.Cache;
|
||||||
import com.google.common.cache.CacheBuilder;
|
import com.google.common.cache.CacheBuilder;
|
||||||
import com.squareup.moshi.JsonAdapter;
|
import com.squareup.moshi.JsonAdapter;
|
||||||
import com.squareup.moshi.Moshi;
|
import com.squareup.moshi.Moshi;
|
||||||
|
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.StringUtil;
|
import ctbrec.StringUtil;
|
||||||
import ctbrec.io.HttpException;
|
import ctbrec.io.HttpException;
|
||||||
import okhttp3.Cookie;
|
import okhttp3.*;
|
||||||
import okhttp3.Request;
|
|
||||||
import okhttp3.Response;
|
|
||||||
import okhttp3.WebSocket;
|
|
||||||
import okhttp3.WebSocketListener;
|
|
||||||
import okio.ByteString;
|
import okio.ByteString;
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import static ctbrec.io.HttpConstants.*;
|
||||||
|
import static ctbrec.sites.mfc.MessageTypes.*;
|
||||||
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
|
|
||||||
public class MyFreeCamsClient {
|
public class MyFreeCamsClient {
|
||||||
|
|
||||||
|
@ -213,7 +193,7 @@ public class MyFreeCamsClient {
|
||||||
MyFreeCamsClient.this.ws = null;
|
MyFreeCamsClient.this.ws = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private StringBuilder msgBuffer = new StringBuilder();
|
private final StringBuilder msgBuffer = new StringBuilder();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(WebSocket webSocket, String text) {
|
public void onMessage(WebSocket webSocket, String text) {
|
||||||
|
@ -284,7 +264,7 @@ public class MyFreeCamsClient {
|
||||||
break;
|
break;
|
||||||
case EXTDATA:
|
case EXTDATA:
|
||||||
if (message.getArg1() == MessageTypes.LOGIN) {
|
if (message.getArg1() == MessageTypes.LOGIN) {
|
||||||
|
// noop
|
||||||
} else if (message.getArg1() == MessageTypes.MANAGELIST) {
|
} else if (message.getArg1() == MessageTypes.MANAGELIST) {
|
||||||
requestExtData(message.getMessage());
|
requestExtData(message.getMessage());
|
||||||
} else {
|
} else {
|
||||||
|
@ -305,7 +285,7 @@ public class MyFreeCamsClient {
|
||||||
json = new JSONObject(message.getMessage());
|
json = new JSONObject(message.getMessage());
|
||||||
tkx = json.getString("tkx");
|
tkx = json.getString("tkx");
|
||||||
cxid = json.getInt("cxid");
|
cxid = json.getInt("cxid");
|
||||||
ctxenc = URLDecoder.decode(json.getString("ctxenc"), "utf-8");
|
ctxenc = URLDecoder.decode(json.getString("ctxenc"), UTF_8);
|
||||||
JSONArray ctxArray = json.getJSONArray("ctx");
|
JSONArray ctxArray = json.getJSONArray("ctx");
|
||||||
ctx = new int[ctxArray.length()];
|
ctx = new int[ctxArray.length()];
|
||||||
for (int i = 0; i < ctxArray.length(); i++) {
|
for (int i = 0; i < ctxArray.length(); i++) {
|
||||||
|
@ -317,8 +297,6 @@ public class MyFreeCamsClient {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
LOG.error("Error while decoding ctxenc URL", e);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error("Exception occured while processing websocket message {}", msgBuffer, e);
|
LOG.error("Exception occured while processing websocket message {}", msgBuffer, e);
|
||||||
ws.close(1000, "");
|
ws.close(1000, "");
|
||||||
|
@ -360,7 +338,7 @@ public class MyFreeCamsClient {
|
||||||
LOG.trace("Requesting EXTDATA {}", url);
|
LOG.trace("Requesting EXTDATA {}", url);
|
||||||
try (Response resp = mfc.getHttpClient().execute(req)) {
|
try (Response resp = mfc.getHttpClient().execute(req)) {
|
||||||
if (resp.isSuccessful()) {
|
if (resp.isSuccessful()) {
|
||||||
parseExtDataSessionStates(resp.body().string());
|
parseExtDataSessionStates(Objects.requireNonNull(resp.body(), "HTTP response is null").string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -483,7 +461,7 @@ public class MyFreeCamsClient {
|
||||||
return websocket;
|
return websocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Message parseMessage(StringBuilder msgBuffer) throws UnsupportedEncodingException {
|
private Message parseMessage(StringBuilder msgBuffer) {
|
||||||
int packetLengthBytes = 6;
|
int packetLengthBytes = 6;
|
||||||
if (msgBuffer.length() < packetLengthBytes) {
|
if (msgBuffer.length() < packetLengthBytes) {
|
||||||
// packet size not transmitted completely
|
// packet size not transmitted completely
|
||||||
|
@ -503,12 +481,12 @@ public class MyFreeCamsClient {
|
||||||
int receiver = parseNextInt(rawMessage);
|
int receiver = parseNextInt(rawMessage);
|
||||||
int arg1 = parseNextInt(rawMessage);
|
int arg1 = parseNextInt(rawMessage);
|
||||||
int arg2 = parseNextInt(rawMessage);
|
int arg2 = parseNextInt(rawMessage);
|
||||||
Message message = new Message(type, sender, receiver, arg1, arg2, URLDecoder.decode(rawMessage.toString(), "utf-8"));
|
Message message = new Message(type, sender, receiver, arg1, arg2, URLDecoder.decode(rawMessage.toString(), UTF_8));
|
||||||
msgBuffer.delete(0, packetLength);
|
msgBuffer.delete(0, packetLength);
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error("StringBuilder contains invalid data {}", msgBuffer.toString(), e);
|
LOG.error("StringBuilder contains invalid data {}", msgBuffer, e);
|
||||||
String logfile = "mfc_messages.log";
|
String logfile = "mfc_messages.log";
|
||||||
try (FileOutputStream fout = new FileOutputStream(logfile)) {
|
try (FileOutputStream fout = new FileOutputStream(logfile)) {
|
||||||
for (String string : receivedTextHistory) {
|
for (String string : receivedTextHistory) {
|
||||||
|
@ -564,7 +542,7 @@ public class MyFreeCamsClient {
|
||||||
if (isBroadcasterOnOBS(state)) {
|
if (isBroadcasterOnOBS(state)) {
|
||||||
JSONArray array = new JSONArray();
|
JSONArray array = new JSONArray();
|
||||||
Arrays.stream(ctx).forEach(array::put);
|
Arrays.stream(ctx).forEach(array::put);
|
||||||
userData.put("vidctx", Base64.getEncoder().encodeToString(array.toString().getBytes(StandardCharsets.UTF_8)));
|
userData.put("vidctx", Base64.getEncoder().encodeToString(array.toString().getBytes(UTF_8)));
|
||||||
userData.put("cxid", cxid);
|
userData.put("cxid", cxid);
|
||||||
}
|
}
|
||||||
userData.put("mode", "DOWNLOAD");
|
userData.put("mode", "DOWNLOAD");
|
||||||
|
@ -599,11 +577,10 @@ public class MyFreeCamsClient {
|
||||||
MyFreeCamsClient.this.ws = null;
|
MyFreeCamsClient.this.ws = null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// we are establishing a new connection at the moment, not need to
|
// we are establishing a new connection at the moment, no need to do anything
|
||||||
// do anything
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread.sleep(TimeUnit.SECONDS.toMillis(15));
|
TimeUnit.SECONDS.sleep(15);
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
LOG.warn("Websocket watchdog has been interrupted");
|
LOG.warn("Websocket watchdog has been interrupted");
|
||||||
|
@ -621,7 +598,7 @@ public class MyFreeCamsClient {
|
||||||
for (SessionState state : sessionStates.asMap().values()) {
|
for (SessionState state : sessionStates.asMap().values()) {
|
||||||
Optional<String> nm = Optional.ofNullable(state.getNm());
|
Optional<String> nm = Optional.ofNullable(state.getNm());
|
||||||
Optional<String> name = Optional.ofNullable(model.getName());
|
Optional<String> name = Optional.ofNullable(model.getName());
|
||||||
if(!nm.isPresent() || !name.isPresent()) {
|
if(nm.isEmpty() || name.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -675,8 +652,7 @@ public class MyFreeCamsClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
public SessionState getSessionState(ctbrec.Model model) {
|
public SessionState getSessionState(ctbrec.Model model) {
|
||||||
if (model instanceof MyFreeCamsModel) {
|
if (model instanceof MyFreeCamsModel mfcModel) {
|
||||||
MyFreeCamsModel mfcModel = (MyFreeCamsModel) model;
|
|
||||||
for (SessionState state : sessionStates.asMap().values()) {
|
for (SessionState state : sessionStates.asMap().values()) {
|
||||||
if (mfcModel.getUid() > 0 && state.getUid() != null && state.getUid() > 0 && mfcModel.getUid() == state.getUid()) {
|
if (mfcModel.getUid() > 0 && state.getUid() != null && state.getUid() > 0 && mfcModel.getUid() == state.getUid()) {
|
||||||
return state;
|
return state;
|
||||||
|
@ -691,39 +667,40 @@ public class MyFreeCamsClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ctbrec.Model> search(String q) throws InterruptedException {
|
public List<ctbrec.Model> search(String q) throws InterruptedException {
|
||||||
LOG.debug("Sending USERNAMELOOKUP for {}", q);
|
|
||||||
int msgId = messageId++;
|
|
||||||
Object monitor = new Object();
|
|
||||||
List<ctbrec.Model> result = new ArrayList<>();
|
List<ctbrec.Model> result = new ArrayList<>();
|
||||||
responseHandlers.put(msgId, msg -> {
|
if (ws != null) {
|
||||||
LOG.debug("Search result: {}", msg);
|
LOG.trace("Sending USERNAMELOOKUP for {}", q);
|
||||||
if (StringUtil.isNotBlank(msg.getMessage()) && !Objects.equals(msg.getMessage(), q)) {
|
Object monitor = new Object();
|
||||||
JSONObject json = new JSONObject(msg.getMessage());
|
int msgId = messageId++;
|
||||||
String name = json.getString("nm");
|
responseHandlers.put(msgId, msg -> {
|
||||||
MyFreeCamsModel model = mfc.createModel(name);
|
LOG.trace("Search result: {}", msg);
|
||||||
model.setUid(json.getInt("uid"));
|
if (StringUtil.isNotBlank(msg.getMessage()) && !Objects.equals(msg.getMessage(), q)) {
|
||||||
model.setMfcState(State.of(json.getInt("vs")));
|
JSONObject json = new JSONObject(msg.getMessage());
|
||||||
String uid = Integer.toString(model.getUid());
|
String name = json.getString("nm");
|
||||||
String uidStart = uid.substring(0, 3);
|
MyFreeCamsModel model = mfc.createModel(name);
|
||||||
String previewUrl = "https://img.mfcimg.com/photos2/" + uidStart + '/' + uid + "/avatar.90x90.jpg";
|
model.setUid(json.getInt("uid"));
|
||||||
model.setPreview(previewUrl);
|
model.setMfcState(State.of(json.getInt("vs")));
|
||||||
result.add(model);
|
String uid = Integer.toString(model.getUid());
|
||||||
}
|
String uidStart = uid.substring(0, 3);
|
||||||
|
String previewUrl = "https://img.mfcimg.com/photos2/" + uidStart + '/' + uid + "/avatar.90x90.jpg";
|
||||||
|
model.setPreview(previewUrl);
|
||||||
|
result.add(model);
|
||||||
|
}
|
||||||
|
synchronized (monitor) {
|
||||||
|
monitor.notifyAll();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ws.send("10 " + sessionId + " 0 " + msgId + " 0 " + q + "\n");
|
||||||
synchronized (monitor) {
|
synchronized (monitor) {
|
||||||
monitor.notifyAll();
|
monitor.wait();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
ws.send("10 " + sessionId + " 0 " + msgId + " 0 " + q + "\n");
|
|
||||||
synchronized (monitor) {
|
|
||||||
monitor.wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (MyFreeCamsModel model : models.asMap().values()) {
|
for (MyFreeCamsModel model : models.asMap().values()) {
|
||||||
if (StringUtil.isNotBlank(model.getName()) && model.getName().toLowerCase().contains(q.toLowerCase())) {
|
if (StringUtil.isNotBlank(model.getName()) && model.getName().toLowerCase().contains(q.toLowerCase())) {
|
||||||
result.add(model);
|
result.add(model);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,22 +59,13 @@ public class MyFreeCamsModel extends AbstractModel {
|
||||||
@Override
|
@Override
|
||||||
public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException {
|
public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException {
|
||||||
if (ignoreCache) {
|
if (ignoreCache) {
|
||||||
String sessionId = MyFreeCamsClient.getInstance().getSessionId(getName());
|
List<ctbrec.Model> searchResult = MyFreeCamsClient.getInstance().search(getName());
|
||||||
boolean online = !(sessionId.isEmpty() || sessionId.equals("0"));
|
if (!searchResult.isEmpty()) {
|
||||||
SessionState sessionState = MyFreeCamsClient.getInstance().getSessionState(this);
|
MyFreeCamsModel m = (MyFreeCamsModel) searchResult.get(0);
|
||||||
if (online) {
|
this.onlineState = m.getOnlineState(true);
|
||||||
if (sessionState == null) {
|
|
||||||
LOG.warn("MFC model {} [{}] seems to be online but a SessionState could not be found", getName(), getUid());
|
|
||||||
} else {
|
|
||||||
return state == ctbrec.sites.mfc.State.ONLINE;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
state = ctbrec.sites.mfc.State.OFFLINE;
|
|
||||||
}
|
}
|
||||||
return online;
|
|
||||||
} else {
|
|
||||||
return isOnline();
|
|
||||||
}
|
}
|
||||||
|
return isOnline();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -369,7 +360,7 @@ public class MyFreeCamsModel extends AbstractModel {
|
||||||
Map<String, String> headers = new HashMap<>();
|
Map<String, String> headers = new HashMap<>();
|
||||||
headers.put(ACCEPT, "*/*");
|
headers.put(ACCEPT, "*/*");
|
||||||
headers.put(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage());
|
headers.put(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage());
|
||||||
headers.put(CONNECTION, KEEP_ALIVE);
|
headers.put(CONNECTION, "close");
|
||||||
if (getSite() != null) {
|
if (getSite() != null) {
|
||||||
headers.put(ORIGIN, getSite().getBaseUrl());
|
headers.put(ORIGIN, getSite().getBaseUrl());
|
||||||
headers.put(REFERER, getSite().getBaseUrl());
|
headers.put(REFERER, getSite().getBaseUrl());
|
||||||
|
|
Loading…
Reference in New Issue