-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
{REFACTOR} Refactored API and service-layer classes (#68)
Refactored API by changing: changed PUT /plaver/device/connect - to POST /player/devices changed PUT /player/device/switch to PUT /player/device Moved creation of Command classes from controller to HandlerMethodArgumentResolver(s). Moved methods that used to manipulate with player from entity to domain model(CurrentPlayerState).
- Loading branch information
1 parent
5a2458d
commit 59f8d48
Showing
49 changed files
with
924 additions
and
327 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 24 additions & 0 deletions
24
src/main/java/com/odeyalo/sonata/connect/config/WebfluxConfiguration.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package com.odeyalo.sonata.connect.config; | ||
|
||
|
||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.core.codec.Decoder; | ||
import org.springframework.http.codec.DecoderHttpMessageReader; | ||
import org.springframework.http.codec.HttpMessageReader; | ||
import org.springframework.http.codec.json.Jackson2JsonDecoder; | ||
|
||
@Configuration | ||
public class WebfluxConfiguration { | ||
|
||
@Bean | ||
public Decoder<?> jackson2JsonDecoder(ObjectMapper mapper) { | ||
return new Jackson2JsonDecoder(mapper); | ||
} | ||
|
||
@Bean | ||
public HttpMessageReader<?> httpMessageReader(Decoder<?> decoder) { | ||
return new DecoderHttpMessageReader<>(decoder); | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
src/main/java/com/odeyalo/sonata/connect/controller/DevicesController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package com.odeyalo.sonata.connect.controller; | ||
|
||
import com.odeyalo.sonata.connect.model.Device; | ||
import com.odeyalo.sonata.connect.model.User; | ||
import com.odeyalo.sonata.connect.service.player.DeviceOperations; | ||
import com.odeyalo.sonata.connect.service.player.DisconnectDeviceArgs; | ||
import com.odeyalo.sonata.connect.service.player.SwitchDeviceCommandArgs; | ||
import com.odeyalo.sonata.connect.service.player.TargetDeactivationDevices; | ||
import com.odeyalo.sonata.connect.service.player.sync.TargetDevices; | ||
import com.odeyalo.sonata.connect.service.support.mapper.dto.AvailableDevicesResponseDtoConverter; | ||
import com.odeyalo.sonata.connect.support.web.HttpStatus; | ||
import com.odeyalo.sonata.connect.support.web.annotation.ConnectionTarget; | ||
import com.odeyalo.sonata.connect.support.web.annotation.TransferPlaybackTargets; | ||
import lombok.RequiredArgsConstructor; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.*; | ||
import reactor.core.publisher.Mono; | ||
import reactor.core.scheduler.Schedulers; | ||
|
||
@RestController | ||
@RequestMapping("/player") | ||
@RequiredArgsConstructor | ||
public class DevicesController { | ||
private final DeviceOperations deviceOperations; | ||
private final AvailableDevicesResponseDtoConverter availableDevicesConverter; | ||
|
||
@GetMapping(value = "/devices", produces = MediaType.APPLICATION_JSON_VALUE) | ||
public Mono<ResponseEntity<?>> getAvailableDevices(@NotNull final User user) { | ||
|
||
return deviceOperations.getConnectedDevices(user) | ||
.map(availableDevicesConverter::convertTo) | ||
.subscribeOn(Schedulers.boundedElastic()) | ||
.map(HttpStatus::ok); | ||
} | ||
|
||
@PostMapping(value = "/devices", produces = MediaType.APPLICATION_JSON_VALUE) | ||
public Mono<ResponseEntity<?>> addDevice(@NotNull final User user, | ||
@NotNull @ConnectionTarget final Device device) { | ||
|
||
return deviceOperations.addDevice(user, device) | ||
.subscribeOn(Schedulers.boundedElastic()) | ||
.thenReturn(HttpStatus.default204Response()); | ||
} | ||
|
||
@PutMapping(value = "/devices", produces = MediaType.APPLICATION_JSON_VALUE) | ||
public Mono<ResponseEntity<?>> switchDevices(@NotNull final User user, | ||
@NotNull final SwitchDeviceCommandArgs switchDeviceCommandArgs, | ||
@NotNull final TargetDeactivationDevices targetDeactivationDevices, | ||
@NotNull @TransferPlaybackTargets final TargetDevices transferPlaybackTargets) { | ||
return deviceOperations.transferPlayback( | ||
user, | ||
switchDeviceCommandArgs, | ||
targetDeactivationDevices, | ||
transferPlaybackTargets) | ||
.subscribeOn(Schedulers.boundedElastic()) | ||
.thenReturn(HttpStatus.default204Response()); | ||
} | ||
|
||
@DeleteMapping(value = "/devices", produces = MediaType.APPLICATION_JSON_VALUE) | ||
public Mono<ResponseEntity<?>> disconnectDevice(@NotNull final DisconnectDeviceArgs disconnectDeviceArgs, | ||
@NotNull final User user) { | ||
return deviceOperations.disconnectDevice(user, disconnectDeviceArgs) | ||
.subscribeOn(Schedulers.boundedElastic()) | ||
.thenReturn(HttpStatus.default204Response()); | ||
} | ||
} |
119 changes: 37 additions & 82 deletions
119
src/main/java/com/odeyalo/sonata/connect/controller/PlayerController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,125 +1,80 @@ | ||
package com.odeyalo.sonata.connect.controller; | ||
|
||
import com.odeyalo.sonata.connect.dto.*; | ||
import com.odeyalo.sonata.connect.model.*; | ||
import com.odeyalo.sonata.connect.service.player.*; | ||
import com.odeyalo.sonata.connect.service.player.sync.TargetDevices; | ||
import com.odeyalo.sonata.connect.dto.CurrentlyPlayingPlayerStateDto; | ||
import com.odeyalo.sonata.connect.dto.PlayerStateDto; | ||
import com.odeyalo.sonata.connect.model.CurrentlyPlayingPlayerState; | ||
import com.odeyalo.sonata.connect.model.ShuffleMode; | ||
import com.odeyalo.sonata.connect.model.User; | ||
import com.odeyalo.sonata.connect.model.Volume; | ||
import com.odeyalo.sonata.connect.service.player.BasicPlayerOperations; | ||
import com.odeyalo.sonata.connect.service.player.PlayCommandContext; | ||
import com.odeyalo.sonata.connect.service.support.mapper.Converter; | ||
import com.odeyalo.sonata.connect.service.support.mapper.dto.ConnectDeviceRequest2DeviceConverter; | ||
import com.odeyalo.sonata.connect.service.support.mapper.dto.CurrentPlayerState2PlayerStateDtoConverter; | ||
import com.odeyalo.sonata.connect.service.support.mapper.dto.Devices2DevicesDtoConverter; | ||
import jakarta.validation.Valid; | ||
import com.odeyalo.sonata.connect.support.web.HttpStatus; | ||
import lombok.RequiredArgsConstructor; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.springframework.http.HttpHeaders; | ||
import org.springframework.http.MediaType; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.*; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.PutMapping; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import reactor.core.publisher.Mono; | ||
import reactor.core.scheduler.Schedulers; | ||
|
||
@RestController | ||
@RequestMapping("/player") | ||
@RequiredArgsConstructor | ||
public class PlayerController { | ||
public final class PlayerController { | ||
private final BasicPlayerOperations playerOperations; | ||
private final CurrentPlayerState2PlayerStateDtoConverter playerState2PlayerStateDtoConverter; | ||
private final Devices2DevicesDtoConverter devicesDtoConverter; | ||
private final ConnectDeviceRequest2DeviceConverter deviceModelConverter; | ||
private final Converter<CurrentlyPlayingPlayerState, CurrentlyPlayingPlayerStateDto> currentlyPlayingPlayerStateDtoConverter; | ||
|
||
@GetMapping("/state") | ||
public Mono<PlayerStateDto> currentPlayerState(User user) { | ||
|
||
@GetMapping(value = "/state", produces = MediaType.APPLICATION_JSON_VALUE) | ||
public Mono<PlayerStateDto> currentPlayerState(@NotNull final User user) { | ||
return playerOperations.currentState(user) | ||
.subscribeOn(Schedulers.boundedElastic()) | ||
.map(playerState2PlayerStateDtoConverter::convertTo); | ||
} | ||
|
||
@GetMapping("/currently-playing") | ||
public Mono<ResponseEntity<CurrentlyPlayingPlayerStateDto>> currentlyPlaying(User user) { | ||
@GetMapping(value = "/currently-playing", produces = MediaType.APPLICATION_JSON_VALUE) | ||
public Mono<ResponseEntity<CurrentlyPlayingPlayerStateDto>> currentlyPlaying(@NotNull final User user) { | ||
return playerOperations.currentlyPlayingState(user) | ||
.map(state -> ResponseEntity.ok(convertToCurrentlyPlayingStateDto(state))) | ||
.defaultIfEmpty(ResponseEntity.noContent().build()); | ||
} | ||
|
||
@GetMapping("/devices") | ||
public Mono<ResponseEntity<?>> getAvailableDevices(User user) { | ||
return playerOperations.getDeviceOperations().getConnectedDevices(user) | ||
.map(this::convertToAvailableDevicesResponseDto) | ||
.map(body -> ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(body)); | ||
.subscribeOn(Schedulers.boundedElastic()) | ||
.map(currentlyPlayingPlayerStateDtoConverter::convertTo) | ||
.map(HttpStatus::ok) | ||
.defaultIfEmpty(HttpStatus.default204Response()); | ||
} | ||
|
||
@PutMapping("/play") | ||
public Mono<ResponseEntity<?>> playOrResume(User user, @RequestBody PlayResumePlaybackRequest body) { | ||
return playerOperations.playOrResume(user, PlayCommandContext.of(body.getContextUri()), null) | ||
.thenReturn(default204Response()); | ||
@PutMapping(value = "/play", produces = MediaType.APPLICATION_JSON_VALUE) | ||
public Mono<ResponseEntity<?>> playOrResume(@NotNull final User user, | ||
@NotNull final PlayCommandContext commandContext) { | ||
return playerOperations.playOrResume(user, commandContext, null) | ||
.subscribeOn(Schedulers.boundedElastic()) | ||
.thenReturn(HttpStatus.default204Response()); | ||
} | ||
|
||
@PutMapping("/pause") | ||
public Mono<ResponseEntity<?>> pause(User user) { | ||
return playerOperations.pause(user).thenReturn( | ||
default204Response() | ||
); | ||
@PutMapping(value = "/pause", produces = MediaType.APPLICATION_JSON_VALUE) | ||
public Mono<ResponseEntity<?>> pause(@NotNull final User user) { | ||
return playerOperations.pause(user) | ||
.subscribeOn(Schedulers.boundedElastic()) | ||
.thenReturn(HttpStatus.default204Response()); | ||
} | ||
|
||
@PutMapping("/shuffle") | ||
@PutMapping(value = "/shuffle", produces = MediaType.APPLICATION_JSON_VALUE) | ||
public Mono<ResponseEntity<?>> changeShuffleMode(@NotNull final User user, | ||
@NotNull final ShuffleMode shuffleMode) { | ||
|
||
return playerOperations.changeShuffle(user, shuffleMode) | ||
.subscribeOn(Schedulers.boundedElastic()) | ||
.map(playerState -> default204Response()); | ||
} | ||
|
||
@PutMapping(value = "/device/connect", produces = MediaType.APPLICATION_JSON_VALUE) | ||
public Mono<ResponseEntity<?>> addDevice(User user, | ||
@Valid @RequestBody ConnectDeviceRequest body) { | ||
Device device = deviceModelConverter.convertTo(body); | ||
|
||
return playerOperations.getDeviceOperations().addDevice(user, device) | ||
.thenReturn(default204Response()); | ||
} | ||
|
||
@PutMapping(value = "/device/switch", produces = MediaType.APPLICATION_JSON_VALUE) | ||
public Mono<ResponseEntity<?>> switchDevices(User user, @RequestBody DeviceSwitchRequest body) { | ||
return playerOperations.getDeviceOperations().transferPlayback( | ||
user, | ||
SwitchDeviceCommandArgs.noMatter(), | ||
TargetDeactivationDevices.empty(), | ||
TargetDevices.fromDeviceIds(body.getDeviceIds())) | ||
.thenReturn(default204Response()); | ||
.map(playerState -> HttpStatus.default204Response()); | ||
} | ||
|
||
@PutMapping(value = "/volume", produces = MediaType.APPLICATION_JSON_VALUE) | ||
public Mono<ResponseEntity<?>> changePlayerVolume(@NotNull final Volume volume, | ||
@NotNull final User user) { | ||
return playerOperations.changeVolume(user, volume) | ||
.map(it -> default204Response()); | ||
} | ||
|
||
@DeleteMapping(value = "/device") | ||
public Mono<ResponseEntity<?>> disconnectDevice(@RequestParam("device_id") String deviceId, User user) { | ||
return playerOperations.getDeviceOperations() | ||
.disconnectDevice(user, DisconnectDeviceArgs.withDeviceId(deviceId)) | ||
.thenReturn(default204Response()); | ||
} | ||
|
||
@NotNull | ||
private CurrentlyPlayingPlayerStateDto convertToCurrentlyPlayingStateDto(CurrentlyPlayingPlayerState state) { | ||
return currentlyPlayingPlayerStateDtoConverter.convertTo(state); | ||
} | ||
|
||
@NotNull | ||
private AvailableDevicesResponseDto convertToAvailableDevicesResponseDto(Devices devices) { | ||
DevicesDto devicesDto = devicesDtoConverter.convertTo(devices); | ||
return AvailableDevicesResponseDto.of(devicesDto); | ||
} | ||
|
||
@NotNull | ||
private static ResponseEntity<?> default204Response() { | ||
return ResponseEntity.noContent() | ||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) | ||
.build(); | ||
.subscribeOn(Schedulers.boundedElastic()) | ||
.map(it -> HttpStatus.default204Response()); | ||
} | ||
} |
Oops, something went wrong.