88import org .slf4j .LoggerFactory ;
99import org .springframework .http .HttpStatus ;
1010import org .springframework .http .MediaType ;
11+ import org .springframework .http .ResponseEntity ;
1112import org .springframework .http .codec .ServerSentEvent ;
1213import org .springframework .http .server .reactive .ServerHttpResponse ;
13- import org .springframework .web .bind .annotation .GetMapping ;
14- import org .springframework .web .bind .annotation .PathVariable ;
15- import org .springframework .web .bind .annotation .PutMapping ;
16- import org .springframework .web .bind .annotation .RequestBody ;
17- import org .springframework .web .bind .annotation .RequestMapping ;
18- import org .springframework .web .bind .annotation .ResponseStatus ;
19- import org .springframework .web .bind .annotation .RestController ;
14+ import org .springframework .web .bind .annotation .*;
2015import reactor .core .publisher .Flux ;
2116import sh .mob .timer .web .Room .TimerRequest ;
2217
2318@ RestController
2419@ RequestMapping ()
2520public class RoomApiController {
2621
27- private static final String SMOKETEST_ROOM_NAME = "testroom-310a9c47-515c-4ad7-a229-ae8efbab7387" ;
2822 private static final Logger log = LoggerFactory .getLogger (RoomApiController .class );
2923 private final RoomRepository roomRepository ;
3024 private final Clock clock ;
@@ -50,11 +44,17 @@ public Flux<ServerSentEvent<Object>> getEventStream(
5044 var room = roomRepository .get (roomId );
5145
5246 var timerRequestFlux =
53- room .sink ()
47+ room .timerRequestSink ()
5448 .asFlux ()
5549 .map (
5650 timerRequest ->
5751 ServerSentEvent .builder ().event ("TIMER_REQUEST" ).data (timerRequest ).build ());
52+ var goalRequestFlux =
53+ room .goalRequestSink ()
54+ .asFlux ()
55+ .map (
56+ goalRequest ->
57+ ServerSentEvent .builder ().event ("GOAL_REQUEST" ).data (goalRequest ).build ());
5858 var keepAliveFlux =
5959 Flux .interval (Duration .ofSeconds (5L ))
6060 .map (
@@ -67,7 +67,7 @@ public Flux<ServerSentEvent<Object>> getEventStream(
6767 Flux .just (room .historyWithoutLatest ())
6868 .map (list -> ServerSentEvent .builder ().event ("INITIAL_HISTORY" ).data (list ).build ());
6969
70- return Flux .concat (initialHistory , keepAliveFlux .mergeWith (timerRequestFlux ));
70+ return Flux .concat (initialHistory , keepAliveFlux .mergeWith (timerRequestFlux ). mergeWith ( goalRequestFlux ) );
7171 }
7272
7373 @ PutMapping ("/{roomId:[A-Za-z0-9-_]+}" )
@@ -76,14 +76,14 @@ public void publishEvent(@PathVariable String roomId, @RequestBody PutTimerReque
7676 var room = roomRepository .get (roomId );
7777 if (timerRequest .timer () != null ) {
7878 long timer = truncateTooLongTimers (timerRequest .timer ());
79- room .add (
79+ room .addTimer (
8080 timer , timerRequest .user (), Instant .now (clock ));
8181 log .info (
8282 "Add timer {} by user {} for room {}" ,
8383 timerRequest .timer ,
8484 timerRequest .user ,
8585 room .name ());
86- incrementTimerStatsExceptForTestRoom (room , timer );
86+ stats . incrementTimer (room . name () , timer );
8787 } else if (timerRequest .breaktimer () != null ) {
8888 long breaktimer = truncateTooLongTimers (timerRequest .breaktimer ());
8989 room .addBreaktimer (breaktimer , timerRequest .user ());
@@ -92,91 +92,63 @@ public void publishEvent(@PathVariable String roomId, @RequestBody PutTimerReque
9292 timerRequest .breaktimer (),
9393 timerRequest .user ,
9494 room .name ());
95- incrementBreakTimerStatsExceptForTestRoom (room , breaktimer );
95+ stats . incrementBreaktimer (room . name () , breaktimer );
9696 } else {
9797 log .warn ("Could not understand PUT request for room {}" , roomId );
9898 }
9999 }
100100
101- private void incrementBreakTimerStatsExceptForTestRoom (Room room , long breaktimer ) {
102- if (!Objects .equals (room .name (), SMOKETEST_ROOM_NAME )) {
103- stats .incrementBreaktimer (breaktimer );
101+ @ PutMapping ("/{roomId:[A-Za-z0-9-_]+}/goal" )
102+ @ ResponseStatus (HttpStatus .ACCEPTED )
103+ public void putGoal (@ PathVariable String roomId , @ RequestBody PutGoalRequest goalRequest ) {
104+ var room = roomRepository .get (roomId );
105+ if (goalRequest .goal () != null ) {
106+ String goal = truncateTooLongGoal (goalRequest .goal ());
107+ room .setGoal (
108+ goal , goalRequest .user (), Instant .now (clock ));
109+ log .info (
110+ "Add goal \" {}\" by user {} for room {}" ,
111+ goalRequest .goal (),
112+ goalRequest .user (),
113+ room .name ());
114+ stats .incrementGoalCount (room .name ());
115+ } else {
116+ log .warn ("Could not understand PUT goal request for room {}" , roomId );
104117 }
105118 }
106119
107- private void incrementTimerStatsExceptForTestRoom (Room room , long timer ) {
108- if (!Objects .equals (room .name (), SMOKETEST_ROOM_NAME )) {
109- stats .incrementTimer (timer );
120+ @ DeleteMapping ("/{roomId:[A-Za-z0-9-_]+}/goal" )
121+ @ ResponseStatus (HttpStatus .ACCEPTED )
122+ public void deleteGoal (@ PathVariable String roomId , @ RequestBody DeleteGoalRequest deleteGoalRequest ) {
123+ var room = roomRepository .get (roomId );
124+ room .deleteGoal (deleteGoalRequest .user (), Instant .now (clock ));
125+ }
126+
127+ @ GetMapping ("/{roomId:[A-Za-z0-9-_]+}/goal" )
128+ @ ResponseStatus (HttpStatus .NO_CONTENT )
129+ public ResponseEntity <GoalResponse > getGoal (@ PathVariable String roomId ) {
130+ var room = roomRepository .get (roomId );
131+ if (!room .hasGoal ()){
132+ return ResponseEntity .noContent ().build ();
110133 }
134+ return ResponseEntity .ofNullable (GoalResponse .of (room .currentGoal ()));
111135 }
112136
113137 private static long truncateTooLongTimers (Long timer ) {
114138 return Math .min (60 * 24 , Math .max (0 , timer ));
115139 }
116140
117- static final class PutTimerRequest {
118-
119- private final Long timer ;
120- private final Long breaktimer ;
121- private final String user ;
122-
123- PutTimerRequest (Long timer , Long breaktimer , String user ) {
124- this .timer = timer ;
125- this .user = user ;
126- this .breaktimer = breaktimer ;
127- }
128-
129- public Long timer () {
130- return timer ;
131- }
132-
133- public Long breaktimer () {
134- return breaktimer ;
135- }
136-
137- public String user () {
138- return user ;
139- }
140-
141- public Long getTimer () {
142- return timer ;
143- }
144-
145- public Long getBreaktimer () {
146- return breaktimer ;
147- }
148-
149- public String getUser () {
150- return user ;
151- }
152-
153- @ Override
154- public boolean equals (Object obj ) {
155- if (obj == this ) return true ;
156- if (obj == null || obj .getClass () != this .getClass ()) return false ;
157- var that = (PutTimerRequest ) obj ;
158- return Objects .equals (this .timer , that .timer )
159- && Objects .equals (this .breaktimer , that .breaktimer )
160- && Objects .equals (this .user , that .user );
161- }
162-
163- @ Override
164- public int hashCode () {
165- return Objects .hash (timer , breaktimer , user );
166- }
141+ private static String truncateTooLongGoal (String goal ) {
142+ return goal .length () > 256 ? goal .substring (0 ,256 -1 -3 ) + "..." : goal ;
143+ }
167144
168- @ Override
169- public String toString () {
170- return "PutTimerRequest["
171- + "timer="
172- + timer
173- + ", "
174- + "breaktimer="
175- + breaktimer
176- + ", "
177- + "user="
178- + user
179- + ']' ;
145+ public record GoalResponse (String goal ){
146+ public static GoalResponse of (Room .Goal goal ){
147+ return new GoalResponse (goal .goal ());
180148 }
181149 }
150+
151+ public record PutGoalRequest (String goal , String user ){}
152+ public record DeleteGoalRequest (String user ){}
153+ public record PutTimerRequest (Long timer , Long breaktimer , String user ){}
182154}
0 commit comments