diff --git a/docs/API for Conductor.txt b/docs/API for Conductor.txt new file mode 100644 index 00000000..3f46671a --- /dev/null +++ b/docs/API for Conductor.txt @@ -0,0 +1,20 @@ +# API for Conductor + +## Outbound HTTP API to Conductor + +Configuration: base URL + +* Sync Timer + * PUT /timers/:name: + * { + "state": + WAITING_TO_START -> "Waiting" + RUNNING -> "Running" + PAUSED -> "Paused" + FINISHED -> "Finished", + "driver": "name", + "navigator": "name", + "nextDriver": "name", + "restOfParticipants": ["name1", "name2"], + "timeRemainingSeconds": 99 + } diff --git a/src/main/java/com/jitterted/mobreg/EnsemblerConfiguration.java b/src/main/java/com/jitterted/mobreg/EnsemblerConfiguration.java index 0f0f21e4..04c6c854 100644 --- a/src/main/java/com/jitterted/mobreg/EnsemblerConfiguration.java +++ b/src/main/java/com/jitterted/mobreg/EnsemblerConfiguration.java @@ -1,5 +1,6 @@ package com.jitterted.mobreg; +import com.jitterted.mobreg.adapter.out.CompositeBroadcaster; import com.jitterted.mobreg.adapter.out.clock.ScheduledExecutorSecondsTicker; import com.jitterted.mobreg.adapter.out.jdbc.EnsembleJdbcRepository; import com.jitterted.mobreg.application.DefaultMemberService; @@ -14,6 +15,7 @@ import com.jitterted.mobreg.domain.Ensemble; import com.jitterted.mobreg.domain.Member; import com.jitterted.mobreg.domain.MemberId; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.CommandLineRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -22,6 +24,7 @@ import java.net.URI; import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.util.List; @Configuration public class EnsemblerConfiguration { @@ -43,7 +46,14 @@ public EnsembleService createEnsembleService(EnsembleRepository ensembleReposito } @Bean - public EnsembleTimerHolder ensembleTimerHolder(EnsembleRepository ensembleRepository, MemberRepository memberRepository, Broadcaster broadcaster) { + public Broadcaster compositeBroadcaster(List broadcasters) { + return new CompositeBroadcaster(broadcasters); + } + + @Bean + public EnsembleTimerHolder ensembleTimerHolder(EnsembleRepository ensembleRepository, + MemberRepository memberRepository, + @Qualifier("compositeBroadcaster") Broadcaster broadcaster) { return new EnsembleTimerHolder(ensembleRepository, memberRepository, broadcaster, diff --git a/src/main/java/com/jitterted/mobreg/adapter/out/CompositeBroadcaster.java b/src/main/java/com/jitterted/mobreg/adapter/out/CompositeBroadcaster.java new file mode 100644 index 00000000..a60f7624 --- /dev/null +++ b/src/main/java/com/jitterted/mobreg/adapter/out/CompositeBroadcaster.java @@ -0,0 +1,25 @@ +package com.jitterted.mobreg.adapter.out; + +import com.jitterted.mobreg.application.port.Broadcaster; +import com.jitterted.mobreg.domain.EnsembleTimer; + +import java.util.List; + +public class CompositeBroadcaster implements Broadcaster { + + private final List broadcasters; + + public CompositeBroadcaster(List broadcasters) { + this.broadcasters = broadcasters; + } + + @Override + public void sendCurrentTimer(EnsembleTimer ensembleTimer) { + broadcasters.forEach(broadcaster -> broadcaster.sendCurrentTimer(ensembleTimer)); + } + + @Override + public void sendEvent(EnsembleTimer.TimerEvent timerEvent) { + broadcasters.forEach(broadcaster -> broadcaster.sendEvent(timerEvent)); + } +} diff --git a/src/main/java/com/jitterted/mobreg/adapter/out/conductor/ConductorHttpBroadcaster.java b/src/main/java/com/jitterted/mobreg/adapter/out/conductor/ConductorHttpBroadcaster.java new file mode 100644 index 00000000..b3bb9708 --- /dev/null +++ b/src/main/java/com/jitterted/mobreg/adapter/out/conductor/ConductorHttpBroadcaster.java @@ -0,0 +1,46 @@ +package com.jitterted.mobreg.adapter.out.conductor; + +import com.jitterted.mobreg.application.port.Broadcaster; +import com.jitterted.mobreg.domain.CountdownTimer; +import com.jitterted.mobreg.domain.EnsembleTimer; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestClient; + +import static org.springframework.http.MediaType.APPLICATION_JSON; + +@Component +public class ConductorHttpBroadcaster implements Broadcaster { + private final RestClient restClient = RestClient.create(); + + @Override + public void sendCurrentTimer(EnsembleTimer ensembleTimer) { + + if (ensembleTimer.state() == CountdownTimer.TimerState.WAITING_TO_START) { + CreateTimerRequest createTimerRequest = new CreateTimerRequest( + ensembleTimer.ensembleName(), + ensembleTimer.timeRemaining() + .minutes() * 60); + try { + ResponseEntity responseEntity = + restClient.post() + .uri("https://conductor-service-ld5mdxm4za-ey.a.run.app/timers") + .contentType(APPLICATION_JSON) + .body(createTimerRequest) + .retrieve() + .toBodilessEntity(); + System.out.println("POST response: " + responseEntity); + } catch (HttpClientErrorException e) { + System.err.println(e.getMessage()); + } + } + } + + @Override + public void sendEvent(EnsembleTimer.TimerEvent timerEvent) { + } + + record CreateTimerRequest(String name, int durationSeconds) { + } +} diff --git a/src/main/resources/static/tailwind.css b/src/main/resources/static/tailwind.css index 4f08240d..c5e82c56 100644 --- a/src/main/resources/static/tailwind.css +++ b/src/main/resources/static/tailwind.css @@ -906,6 +906,18 @@ select { width: 100%; } +.w-1\/2 { + width: 50%; +} + +.w-1\/3 { + width: 33.333333%; +} + +.w-1\/4 { + width: 25%; +} + .min-w-0 { min-width: 0; } @@ -966,6 +978,14 @@ select { grid-template-columns: repeat(4, minmax(0, 1fr)); } +.grid-cols-6 { + grid-template-columns: repeat(6, minmax(0, 1fr)); +} + +.grid-cols-5 { + grid-template-columns: repeat(5, minmax(0, 1fr)); +} + .flex-row { flex-direction: row; } @@ -1019,6 +1039,15 @@ select { row-gap: 1.5rem; } +.gap-x-6 { + -moz-column-gap: 1.5rem; + column-gap: 1.5rem; +} + +.gap-y-8 { + row-gap: 2rem; +} + .space-x-4 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; margin-right: calc(1rem * var(--tw-space-x-reverse)); @@ -1224,6 +1253,10 @@ select { padding: 1rem; } +.p-5 { + padding: 1.25rem; +} + .p-8 { padding: 2rem; } @@ -1696,6 +1729,11 @@ select { background-color: rgb(185 28 28 / var(--tw-bg-opacity)); } +.hover\:bg-green-500:hover { + --tw-bg-opacity: 1; + background-color: rgb(34 197 94 / var(--tw-bg-opacity)); +} + .hover\:text-blue-600:hover { --tw-text-opacity: 1; color: rgb(37 99 235 / var(--tw-text-opacity)); diff --git a/src/test/java/com/jitterted/mobreg/adapter/in/web/admin/EnsembleTimerHolderTest.java b/src/test/java/com/jitterted/mobreg/adapter/in/web/admin/EnsembleTimerHolderTest.java index a38c2447..8f84b25c 100644 --- a/src/test/java/com/jitterted/mobreg/adapter/in/web/admin/EnsembleTimerHolderTest.java +++ b/src/test/java/com/jitterted/mobreg/adapter/in/web/admin/EnsembleTimerHolderTest.java @@ -308,9 +308,10 @@ private BroadcastFixture createBroadcasterWithStartedEnsembleTimer(int ensembleI Ensemble ensemble = new EnsembleBuilder().id(ensembleId) .startsNow() .build(); - TestEnsembleServiceBuilder builder = new TestEnsembleServiceBuilder() - .saveEnsemble(ensemble) - .withThreeParticipants(); + TestEnsembleServiceBuilder builder = + new TestEnsembleServiceBuilder() + .saveEnsemble(ensemble) + .withThreeParticipants(); MockBroadcaster mockBroadcaster = new MockBroadcaster(ensembleId, expectedTimerState, expectedTimeRemaining); EnsembleTimerHolder ensembleTimerHolder = EnsembleTimerHolder.createNull(builder.ensembleRepository(), builder.memberRepository(), diff --git a/src/test/java/com/jitterted/mobreg/application/EnsembleServiceFindTest.java b/src/test/java/com/jitterted/mobreg/application/EnsembleServiceFindTest.java index b8bd21ab..739ff4a1 100644 --- a/src/test/java/com/jitterted/mobreg/application/EnsembleServiceFindTest.java +++ b/src/test/java/com/jitterted/mobreg/application/EnsembleServiceFindTest.java @@ -47,7 +47,10 @@ void allEnsemblesOrderedByDateTimeDescendingIsInCorrectOrder() throws Exception assertThat(ensembles) .extracting(Ensemble::name) - .containsExactly("three", "two", "one"); + .containsExactly( + "three", + "two", + "one"); } }