forked from j62/ctbrec
Count the websocket uses wth AtomicInteger
This commit is contained in:
parent
fc6aeff94a
commit
64c82748dc
|
@ -96,7 +96,7 @@ public class JavaFxModel implements Model {
|
||||||
return pausedProperty;
|
return pausedProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
Model getDelegate() {
|
public Model getDelegate() {
|
||||||
return delegate;
|
return delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,17 +9,18 @@ import ctbrec.Model;
|
||||||
import ctbrec.sites.ConfigUI;
|
import ctbrec.sites.ConfigUI;
|
||||||
import ctbrec.sites.fc2live.Fc2Live;
|
import ctbrec.sites.fc2live.Fc2Live;
|
||||||
import ctbrec.sites.fc2live.Fc2Model;
|
import ctbrec.sites.fc2live.Fc2Model;
|
||||||
|
import ctbrec.ui.JavaFxModel;
|
||||||
import ctbrec.ui.Player;
|
import ctbrec.ui.Player;
|
||||||
import ctbrec.ui.TabProvider;
|
import ctbrec.ui.TabProvider;
|
||||||
import ctbrec.ui.sites.AbstractSiteUi;
|
import ctbrec.ui.sites.AbstractSiteUi;
|
||||||
|
|
||||||
public class Fc2LiveSiteUi extends AbstractSiteUi {
|
public class Fc2LiveSiteUi extends AbstractSiteUi {
|
||||||
private static final transient Logger LOG = LoggerFactory.getLogger(Fc2LiveSiteUi.class);
|
private static final transient Logger LOG = LoggerFactory.getLogger(Fc2LiveSiteUi.class);
|
||||||
private Fc2Live fc2live;
|
//private Fc2Live fc2live;
|
||||||
private Fc2TabProvider tabProvider;
|
private Fc2TabProvider tabProvider;
|
||||||
|
|
||||||
public Fc2LiveSiteUi(Fc2Live fc2live) {
|
public Fc2LiveSiteUi(Fc2Live fc2live) {
|
||||||
this.fc2live = fc2live;
|
//this.fc2live = fc2live;
|
||||||
this.tabProvider = new Fc2TabProvider(fc2live);
|
this.tabProvider = new Fc2TabProvider(fc2live);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,22 +42,17 @@ public class Fc2LiveSiteUi extends AbstractSiteUi {
|
||||||
@Override
|
@Override
|
||||||
public boolean play(Model model) {
|
public boolean play(Model model) {
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
Fc2Model m = (Fc2Model) model;
|
Fc2Model m;
|
||||||
|
if(model instanceof JavaFxModel) {
|
||||||
|
m = (Fc2Model) ((JavaFxModel)model).getDelegate();
|
||||||
|
} else {
|
||||||
|
m = (Fc2Model) model;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
boolean opened = m.openWebsocket();
|
m.openWebsocket();
|
||||||
if(opened) {
|
LOG.debug("Starting player for {}", model);
|
||||||
LOG.debug("Opened new websocket for player");
|
|
||||||
} else {
|
|
||||||
LOG.debug("Using existing websocket for player");
|
|
||||||
}
|
|
||||||
LOG.debug("Starting player");
|
|
||||||
Player.play(model, false);
|
Player.play(model, false);
|
||||||
if(opened) {
|
m.closeWebsocket();
|
||||||
LOG.debug("Closing websocket for player");
|
|
||||||
m.closeWebsocket();
|
|
||||||
} else {
|
|
||||||
LOG.debug("Leaving websocket for player open");
|
|
||||||
}
|
|
||||||
} catch (InterruptedException | IOException e) {
|
} catch (InterruptedException | IOException e) {
|
||||||
LOG.error("Error opening websocket connection", e);
|
LOG.error("Error opening websocket connection", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,9 @@ package ctbrec.sites.fc2live;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.Model;
|
import ctbrec.Model;
|
||||||
import ctbrec.io.HttpClient;
|
import ctbrec.io.HttpClient;
|
||||||
|
@ -9,16 +12,23 @@ import ctbrec.recorder.download.MergedHlsDownload;
|
||||||
|
|
||||||
public class Fc2MergedHlsDownload extends MergedHlsDownload {
|
public class Fc2MergedHlsDownload extends MergedHlsDownload {
|
||||||
|
|
||||||
private Fc2WebSocketClient ws;
|
private static final transient Logger LOG = LoggerFactory.getLogger(Fc2MergedHlsDownload.class);
|
||||||
|
|
||||||
public Fc2MergedHlsDownload(HttpClient client) {
|
public Fc2MergedHlsDownload(HttpClient client) {
|
||||||
super(client);
|
super(client);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start(Model model, Config config) throws IOException {
|
public void start(Model model, Config config) throws IOException {
|
||||||
super.start(model, config);
|
Fc2Model fc2Model = (Fc2Model) model;
|
||||||
|
try {
|
||||||
|
fc2Model.openWebsocket();
|
||||||
|
super.start(model, config);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
LOG.error("Couldn't start download for {}", model, e);
|
||||||
|
} finally {
|
||||||
|
fc2Model.closeWebsocket();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -6,6 +6,8 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
|
@ -22,10 +24,13 @@ import com.iheartradio.m3u8.data.MasterPlaylist;
|
||||||
import com.iheartradio.m3u8.data.Playlist;
|
import com.iheartradio.m3u8.data.Playlist;
|
||||||
import com.iheartradio.m3u8.data.PlaylistData;
|
import com.iheartradio.m3u8.data.PlaylistData;
|
||||||
import com.iheartradio.m3u8.data.StreamInfo;
|
import com.iheartradio.m3u8.data.StreamInfo;
|
||||||
|
import com.squareup.moshi.JsonReader;
|
||||||
|
import com.squareup.moshi.JsonWriter;
|
||||||
|
|
||||||
import ctbrec.AbstractModel;
|
import ctbrec.AbstractModel;
|
||||||
import ctbrec.Config;
|
import ctbrec.Config;
|
||||||
import ctbrec.io.HttpException;
|
import ctbrec.io.HttpException;
|
||||||
|
import ctbrec.recorder.download.Download;
|
||||||
import ctbrec.recorder.download.StreamSource;
|
import ctbrec.recorder.download.StreamSource;
|
||||||
import okhttp3.FormBody;
|
import okhttp3.FormBody;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
|
@ -43,6 +48,7 @@ public class Fc2Model extends AbstractModel {
|
||||||
private String version;
|
private String version;
|
||||||
private WebSocket ws;
|
private WebSocket ws;
|
||||||
private String playlistUrl;
|
private String playlistUrl;
|
||||||
|
private AtomicInteger websocketUsage = new AtomicInteger(0);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException {
|
public boolean isOnline(boolean ignoreCache) throws IOException, ExecutionException, InterruptedException {
|
||||||
|
@ -98,16 +104,15 @@ public class Fc2Model extends AbstractModel {
|
||||||
@Override
|
@Override
|
||||||
public List<StreamSource> getStreamSources() throws IOException, ExecutionException, ParseException, PlaylistException {
|
public List<StreamSource> getStreamSources() throws IOException, ExecutionException, ParseException, PlaylistException {
|
||||||
try {
|
try {
|
||||||
boolean opened = openWebsocket();
|
openWebsocket();
|
||||||
List<StreamSource> sources = new ArrayList<>();
|
List<StreamSource> sources = new ArrayList<>();
|
||||||
LOG.debug("Paylist url {}", playlistUrl);
|
LOG.debug("Paylist url {}", playlistUrl);
|
||||||
sources.addAll(parseMasterPlaylist(playlistUrl));
|
sources.addAll(parseMasterPlaylist(playlistUrl));
|
||||||
if(opened) {
|
|
||||||
closeWebsocket();
|
|
||||||
}
|
|
||||||
return sources;
|
return sources;
|
||||||
} catch (InterruptedException e1) {
|
} catch (InterruptedException e1) {
|
||||||
throw new ExecutionException(e1);
|
throw new ExecutionException(e1);
|
||||||
|
} finally {
|
||||||
|
closeWebsocket();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,14 +231,18 @@ public class Fc2Model extends AbstractModel {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens a chat websocket connection. This connection is used to retrieve the HLS playlist url. It also has to be kept open as long as the HLS stream is
|
* Opens a chat websocket connection. This connection is used to retrieve the HLS playlist url. It also has to be kept open as long as the HLS stream is
|
||||||
* "played"
|
* "played". Fc2Model keeps track of the number of objects, which tried to open or close the websocket. As long as at least one object is using the
|
||||||
|
* websocket, it is kept open. If the last object, which is using it, calls closeWebsocket, the websocket is closed.
|
||||||
*
|
*
|
||||||
* @return true, if a new websocket connection is opened. If the connection was already open, this method returns false
|
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
public boolean openWebsocket() throws InterruptedException, IOException {
|
public void openWebsocket() throws InterruptedException, IOException {
|
||||||
|
// TODO send heartbeat (maybe every minute) {"name":"heartbeat","arguments":{},"id":2}
|
||||||
|
|
||||||
|
int usage = websocketUsage.incrementAndGet();
|
||||||
|
LOG.debug("{} objects using the websocket for {}", usage, this);
|
||||||
if(ws != null) {
|
if(ws != null) {
|
||||||
return false;
|
return;
|
||||||
} else {
|
} else {
|
||||||
Object monitor = new Object();
|
Object monitor = new Object();
|
||||||
loadModelInfo();
|
loadModelInfo();
|
||||||
|
@ -268,6 +277,10 @@ public class Fc2Model extends AbstractModel {
|
||||||
synchronized (monitor) {
|
synchronized (monitor) {
|
||||||
monitor.notify();
|
monitor.notify();
|
||||||
}
|
}
|
||||||
|
} else if(json.optString("name").equals("user_count") || json.optString("name").equals("comment")) {
|
||||||
|
// ignore
|
||||||
|
} else {
|
||||||
|
LOG.debug("WS <-- {}", text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,15 +302,40 @@ public class Fc2Model extends AbstractModel {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
synchronized (monitor) {
|
synchronized (monitor) {
|
||||||
monitor.wait();
|
// wait at max 10 seconds, otherwise we can assume, that the stream is not available
|
||||||
|
LOG.debug("No playlist response for 10 seconds");
|
||||||
|
monitor.wait(TimeUnit.SECONDS.toMillis(10));
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean closeWebsocket() {
|
public void closeWebsocket() {
|
||||||
ws.close(1000, "");
|
int websocketUsers = websocketUsage.decrementAndGet();
|
||||||
ws = null;
|
LOG.debug("{} objects using the websocket for {}", websocketUsers, this);
|
||||||
return true;
|
if(websocketUsers == 0) {
|
||||||
|
LOG.debug("Closing the websocket for {}", this);
|
||||||
|
ws.close(1000, "");
|
||||||
|
ws = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Download createDownload() {
|
||||||
|
if(Config.isServerMode()) {
|
||||||
|
return super.createDownload(); // TODO implement fc2 download for server
|
||||||
|
} else {
|
||||||
|
return new Fc2MergedHlsDownload(getSite().getHttpClient());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readSiteSpecificData(JsonReader reader) throws IOException {
|
||||||
|
reader.nextName();
|
||||||
|
id = reader.nextString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeSiteSpecificData(JsonWriter writer) throws IOException {
|
||||||
|
writer.name("id").value(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue