Skip to content

Commit

Permalink
Merge branch 'dev' into v3
Browse files Browse the repository at this point in the history
  • Loading branch information
schnapster committed Jul 20, 2018
2 parents 6cb0f81 + 371f272 commit 0adc5c8
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,84 +31,76 @@
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.atomic.AtomicBoolean;

public class AudioLoader implements AudioLoadResultHandler {

private static final Logger log = LoggerFactory.getLogger(AudioLoader.class);
private static final LoadResult NO_MATCHES = new LoadResult(Collections.emptyList(),
null, ResultStatus.NO_MATCHES, null);
private static final LoadResult LOAD_FAILED = new LoadResult(Collections.emptyList(),
null, ResultStatus.LOAD_FAILED, null);

private final AudioPlayerManager audioPlayerManager;

private List<AudioTrack> loadedItems;
private String playlistName = null;
private Integer selectedTrack = null;
private ResultStatus status = ResultStatus.UNKNOWN;
private boolean used = false;
private final CompletableFuture<LoadResult> loadResult = new CompletableFuture<>();
private final AtomicBoolean used = new AtomicBoolean(false);

public AudioLoader(AudioPlayerManager audioPlayerManager) {
this.audioPlayerManager = audioPlayerManager;
}

LoadResult loadSync(String identifier) throws InterruptedException {
if(used)
public CompletionStage<LoadResult> load(String identifier) {
boolean isUsed = this.used.getAndSet(true);
if (isUsed) {
throw new IllegalStateException("This loader can only be used once per instance");

used = true;

audioPlayerManager.loadItem(identifier, this);

synchronized (this) {
this.wait();
}

if (status == ResultStatus.UNKNOWN)
throw new IllegalStateException("Load Type == UNKNOWN (shouldn't happen!)");
return new LoadResult(loadedItems, playlistName, status, selectedTrack);
log.trace("Loading item with identifier {}", identifier);
this.audioPlayerManager.loadItem(identifier, this);

return loadResult;
}

@Override
public void trackLoaded(AudioTrack audioTrack) {
loadedItems = new ArrayList<>();
loadedItems.add(audioTrack);
status = ResultStatus.TRACK_LOADED;
log.info("Loaded track " + audioTrack.getInfo().title);
synchronized (this) {
this.notify();
}
ArrayList<AudioTrack> result = new ArrayList<>();
result.add(audioTrack);
this.loadResult.complete(new LoadResult(result, null, ResultStatus.TRACK_LOADED, null));
}

@Override
public void playlistLoaded(AudioPlaylist audioPlaylist) {
log.info("Loaded playlist " + audioPlaylist.getName());

String playlistName = null;
Integer selectedTrack = null;
if (!audioPlaylist.isSearchResult()) {
playlistName = audioPlaylist.getName();
selectedTrack = audioPlaylist.getTracks().indexOf(audioPlaylist.getSelectedTrack());
}

log.info("Loaded playlist " + audioPlaylist.getName());
status = audioPlaylist.isSearchResult() ? ResultStatus.SEARCH_RESULT : ResultStatus.PLAYLIST_LOADED;
loadedItems = audioPlaylist.getTracks();
synchronized (this) {
this.notify();
}
ResultStatus status = audioPlaylist.isSearchResult() ? ResultStatus.SEARCH_RESULT : ResultStatus.PLAYLIST_LOADED;
List<AudioTrack> loadedItems = audioPlaylist.getTracks();

this.loadResult.complete(new LoadResult(loadedItems, playlistName, status, selectedTrack));
}

@Override
public void noMatches() {
log.info("No matches found");
status = ResultStatus.NO_MATCHES;
loadedItems = new ArrayList<>();
synchronized (this) {
this.notify();
}
this.loadResult.complete(NO_MATCHES);
}

@Override
public void loadFailed(FriendlyException e) {
log.error("Load failed", e);
status = ResultStatus.LOAD_FAILED;
loadedItems = new ArrayList<>();
synchronized (this) {
this.notify();
}
this.loadResult.complete(LOAD_FAILED);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,22 @@
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

@Controller
@RestController
public class AudioLoaderRestHandler {

private static final Logger log = LoggerFactory.getLogger(AudioLoaderRestHandler.class);
Expand All @@ -59,18 +63,18 @@ private void log(HttpServletRequest request) {
log.info("GET " + path);
}

private boolean isAuthorized(HttpServletRequest request, HttpServletResponse response) {
//returns an empty answer if the auth succeeded, or a response to send back immediately
private <T> Optional<ResponseEntity<T>> checkAuthorization(HttpServletRequest request) {
if (request.getHeader("Authorization") == null) {
response.setStatus(403);
return false;
return Optional.of(new ResponseEntity<>(HttpStatus.UNAUTHORIZED));
}

if (!request.getHeader("Authorization").equals(serverConfig.getPassword())) {
log.warn("Authorization failed");
response.setStatus(403);
return false;
return Optional.of(new ResponseEntity<>(HttpStatus.FORBIDDEN));
}
return true;

return Optional.empty();
}

private JSONObject trackToJSON(AudioTrack audioTrack) {
Expand All @@ -87,19 +91,10 @@ private JSONObject trackToJSON(AudioTrack audioTrack) {
.put("position", audioTrack.getPosition());
}

@GetMapping(value = "/loadtracks", produces = "application/json")
@ResponseBody
public String getLoadTracks(HttpServletRequest request, HttpServletResponse response, @RequestParam String identifier)
throws IOException, InterruptedException {
log(request);

if (!isAuthorized(request, response))
return "";

private JSONObject encodeLoadResult(LoadResult result) {
JSONObject json = new JSONObject();
JSONObject playlist = new JSONObject();
JSONArray tracks = new JSONArray();
LoadResult result = new AudioLoader(audioPlayerManager).loadSync(identifier);

result.tracks.forEach(track -> {
JSONObject object = new JSONObject();
Expand All @@ -110,7 +105,7 @@ public String getLoadTracks(HttpServletRequest request, HttpServletResponse resp
object.put("track", encoded);
tracks.put(object);
} catch (IOException e) {
throw new RuntimeException();
log.warn("Failed to encode a track {}, skipping", track.getIdentifier(), e);
}
});

Expand All @@ -121,29 +116,54 @@ public String getLoadTracks(HttpServletRequest request, HttpServletResponse resp
json.put("loadType", result.loadResultType);
json.put("tracks", tracks);

return json.toString();
return json;
}

@GetMapping(value = "/loadtracks", produces = "application/json")
@ResponseBody
public CompletionStage<ResponseEntity<String>> getLoadTracks(HttpServletRequest request,
@RequestParam String identifier) {

log(request);

Optional<ResponseEntity<String>> notAuthed = checkAuthorization(request);
if (notAuthed.isPresent()) {
return CompletableFuture.completedFuture(notAuthed.get());
}

return new AudioLoader(audioPlayerManager).load(identifier)
.thenApply(this::encodeLoadResult)
.thenApply(loadResultJson -> new ResponseEntity<>(loadResultJson.toString(), HttpStatus.OK));
}

@GetMapping(value = "/decodetrack", produces = "application/json")
@ResponseBody
public String getDecodeTrack(HttpServletRequest request, HttpServletResponse response, @RequestParam String track) throws IOException {
public ResponseEntity<String> getDecodeTrack(HttpServletRequest request, @RequestParam String track)
throws IOException {

log(request);

if (!isAuthorized(request, response))
return "";
Optional<ResponseEntity<String>> notAuthed = checkAuthorization(request);
if (notAuthed.isPresent()) {
return notAuthed.get();
}

AudioTrack audioTrack = Util.toAudioTrack(audioPlayerManager, track);

return trackToJSON(audioTrack).toString();
return new ResponseEntity<>(trackToJSON(audioTrack).toString(), HttpStatus.OK);
}

@PostMapping(value = "/decodetracks", consumes = "application/json", produces = "application/json")
@ResponseBody
public String postDecodeTracks(HttpServletRequest request, HttpServletResponse response, @RequestBody String body) throws IOException {
public ResponseEntity<String> postDecodeTracks(HttpServletRequest request, @RequestBody String body)
throws IOException {

log(request);

if (!isAuthorized(request, response))
return "";
Optional<ResponseEntity<String>> notAuthed = checkAuthorization(request);
if (notAuthed.isPresent()) {
return notAuthed.get();
}

JSONArray requestJSON = new JSONArray(body);
JSONArray responseJSON = new JSONArray();
Expand All @@ -160,6 +180,6 @@ public String postDecodeTracks(HttpServletRequest request, HttpServletResponse r
responseJSON.put(trackJSON);
}

return responseJSON.toString();
return new ResponseEntity<>(responseJSON.toString(), HttpStatus.OK);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.sedmelluq.discord.lavaplayer.track.AudioTrack;

import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;

Expand All @@ -11,7 +12,9 @@ class LoadResult {
public ResultStatus loadResultType;
public Integer selectedTrack;

LoadResult(List<AudioTrack> tracks, String playlistName, ResultStatus loadResultType, Integer selectedTrack) {
public LoadResult(List<AudioTrack> tracks, @Nullable String playlistName, ResultStatus loadResultType,
@Nullable Integer selectedTrack) {

this.tracks = Collections.unmodifiableList(tracks);
this.playlistName = playlistName;
this.loadResultType = loadResultType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@ public enum ResultStatus {
PLAYLIST_LOADED,
SEARCH_RESULT,
NO_MATCHES,
LOAD_FAILED,
UNKNOWN
LOAD_FAILED
}

0 comments on commit 0adc5c8

Please sign in to comment.