longpoll api update, token auth
This commit is contained in:
parent
bafd220a4c
commit
89fde1afc9
30
src/main/java/com/alterdekim/game/component/LongPoll.java
Normal file
30
src/main/java/com/alterdekim/game/component/LongPoll.java
Normal file
@ -0,0 +1,30 @@
|
||||
package com.alterdekim.game.component;
|
||||
|
||||
import com.alterdekim.game.dto.LongPollResult;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
|
||||
@Component
|
||||
@Getter
|
||||
@Slf4j
|
||||
public class LongPoll {
|
||||
|
||||
private final BlockingQueue<LongPollingSession> longPollingQueue = new ArrayBlockingQueue<>(100);
|
||||
|
||||
@Scheduled(fixedRate = 5000)
|
||||
private void longPoll() {
|
||||
getLongPollingQueue().forEach(longPollingSession -> {
|
||||
try {
|
||||
longPollingSession.getDeferredResult().setResult(new LongPollResult());
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
});
|
||||
getLongPollingQueue().removeIf(e -> e.getDeferredResult().isSetOrExpired());
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.alterdekim.game.component;
|
||||
|
||||
import com.alterdekim.game.dto.LongPollResult;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.springframework.web.context.request.async.DeferredResult;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
|
||||
public class LongPollingSession {
|
||||
private Long last_chat_id;
|
||||
private DeferredResult<LongPollResult> deferredResult;
|
||||
}
|
@ -1,20 +1,21 @@
|
||||
package com.alterdekim.game.controller;
|
||||
|
||||
|
||||
import com.alterdekim.game.component.LongPoll;
|
||||
import com.alterdekim.game.component.LongPollingSession;
|
||||
import com.alterdekim.game.dto.*;
|
||||
import com.alterdekim.game.entities.Chat;
|
||||
import com.alterdekim.game.entities.Room;
|
||||
import com.alterdekim.game.entities.User;
|
||||
import com.alterdekim.game.service.*;
|
||||
import com.alterdekim.game.util.Hash;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.context.request.async.DeferredResult;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
@ -47,11 +48,16 @@ public class APIController {
|
||||
@Autowired
|
||||
private UserServiceImpl userService;
|
||||
|
||||
@Autowired
|
||||
private LongPoll longPoll;
|
||||
|
||||
@GetMapping("/api/v1/games/list")
|
||||
public ResponseEntity<List<RoomResult>> gamesList() {
|
||||
List<RoomResult> results = roomService.getAll()
|
||||
.stream()
|
||||
.map(room -> new RoomResult(room, roomPlayerService.findByRoomId(room.getId())))
|
||||
.map(room -> new RoomResult(room.getId(), room.getPlayerCount(), roomPlayerService.findByRoomId(room.getId()).stream()
|
||||
.map(p -> userService.findById(p.getId()))
|
||||
.map(p -> new UserResult(p.getId(), p.getUsername())).collect(Collectors.toList())))
|
||||
.collect(Collectors.toList());
|
||||
return ResponseEntity.ok(results);
|
||||
}
|
||||
@ -126,10 +132,22 @@ public class APIController {
|
||||
return ResponseEntity.accepted().build();
|
||||
}
|
||||
|
||||
@GetMapping("/api/v1/notify/get/{last_chat_id}/")
|
||||
public ResponseEntity<LongPollResult> getNotify(@PathVariable Long last_chat_id ) {
|
||||
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
@GetMapping("/async/notify/get/")
|
||||
@ResponseBody
|
||||
public DeferredResult<LongPollResult> getNotify(@RequestParam("last_chat_id") Long last_chat_id,
|
||||
@RequestParam("accessToken") String accessToken,
|
||||
@RequestParam("uid") Long userId) {
|
||||
try {
|
||||
User u = userService.findById(userId);
|
||||
if (u == null) return null;
|
||||
if (!Hash.sha256((u.getId() + u.getUsername() + u.getPassword()).getBytes()).equals(accessToken))
|
||||
return null;
|
||||
} catch ( Exception e ) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
final DeferredResult<LongPollResult> deferredResult = new DeferredResult<>();
|
||||
longPoll.getLongPollingQueue().add(new LongPollingSession(last_chat_id, deferredResult));
|
||||
/*Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
Long userId = userService.findByUsername(((org.springframework.security.core.userdetails.User) authentication.getPrincipal()).getUsername()).getId();
|
||||
userService.updateOnline(userId);
|
||||
|
||||
@ -160,6 +178,15 @@ public class APIController {
|
||||
c.setMessage(message);
|
||||
return c;
|
||||
}).collect(Collectors.toList());
|
||||
return ResponseEntity.ok(new LongPollResult(onlineCount, results, users));
|
||||
// Room stuff
|
||||
|
||||
List<Room> rooms = roomService.getAllActive();
|
||||
List<RoomResult> roomResults = rooms.stream()
|
||||
.map( r -> new RoomResult(r.getId(), r.getPlayerCount(), roomPlayerService.findByRoomId(r.getId()).stream()
|
||||
.map(p -> userService.findById(p.getId()))
|
||||
.map(p -> new UserResult(p.getId(), p.getUsername())).collect(Collectors.toList())))
|
||||
.collect(Collectors.toList());
|
||||
return ResponseEntity.ok(new LongPollResult(onlineCount, results, users, roomResults));*/
|
||||
return deferredResult;
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,11 @@ import com.alterdekim.game.entities.Invite;
|
||||
import com.alterdekim.game.entities.User;
|
||||
import com.alterdekim.game.service.InviteService;
|
||||
import com.alterdekim.game.service.UserService;
|
||||
import jakarta.servlet.http.Cookie;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
@ -33,33 +36,12 @@ public class AuthController {
|
||||
return "game";
|
||||
}
|
||||
|
||||
@GetMapping("/rules")
|
||||
public String rulesPage(Model model) {
|
||||
return "rules";
|
||||
}
|
||||
|
||||
@GetMapping("/login")
|
||||
public String loginPage(Model model) {
|
||||
model.addAttribute("title", "Login" + base_title);
|
||||
return "login";
|
||||
}
|
||||
|
||||
@GetMapping("/games")
|
||||
public String gamesPage(Model model) {
|
||||
return "games";
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public String homePage(Model model) {
|
||||
return "index";
|
||||
}
|
||||
|
||||
@GetMapping("/access-denied")
|
||||
public String accessDenied(Model model) {
|
||||
model.addAttribute("title", "Access denied");
|
||||
return "access-denied";
|
||||
}
|
||||
|
||||
@GetMapping("/signup")
|
||||
public String showRegistrationForm(Model model) {
|
||||
UserDTO userDto = new UserDTO();
|
||||
|
@ -0,0 +1,51 @@
|
||||
package com.alterdekim.game.controller;
|
||||
|
||||
import com.alterdekim.game.dto.AuthApiObject;
|
||||
import com.alterdekim.game.entities.User;
|
||||
import com.alterdekim.game.service.UserServiceImpl;
|
||||
import com.alterdekim.game.util.Hash;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
@Slf4j
|
||||
@Controller
|
||||
public class StaticController {
|
||||
|
||||
@Autowired
|
||||
private UserServiceImpl userService;
|
||||
|
||||
@GetMapping("/rules")
|
||||
public String rulesPage(Model model) {
|
||||
return "rules";
|
||||
}
|
||||
|
||||
@GetMapping("/games")
|
||||
public String gamesPage(Model model) {
|
||||
try {
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
User u = userService.findByUsername(((org.springframework.security.core.userdetails.User) authentication.getPrincipal()).getUsername());
|
||||
Long userId = u.getId();
|
||||
String apiKey = Hash.sha256((u.getId() + u.getUsername() + u.getPassword()).getBytes());
|
||||
model.addAttribute("auth_obj", new AuthApiObject(apiKey, userId));
|
||||
} catch ( Exception e ) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
return "games";
|
||||
}
|
||||
|
||||
@GetMapping("/")
|
||||
public String homePage(Model model) {
|
||||
return "index";
|
||||
}
|
||||
|
||||
@GetMapping("/access-denied")
|
||||
public String accessDenied(Model model) {
|
||||
model.addAttribute("title", "Access denied");
|
||||
return "access-denied";
|
||||
}
|
||||
}
|
13
src/main/java/com/alterdekim/game/dto/AuthApiObject.java
Normal file
13
src/main/java/com/alterdekim/game/dto/AuthApiObject.java
Normal file
@ -0,0 +1,13 @@
|
||||
package com.alterdekim.game.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
public class AuthApiObject {
|
||||
private String accessToken;
|
||||
private Long uid;
|
||||
}
|
@ -14,4 +14,5 @@ public class LongPollResult {
|
||||
private Integer onlineCount;
|
||||
private List<Chat> messages;
|
||||
private List<UserResult> users;
|
||||
private List<RoomResult> rooms;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package com.alterdekim.game.dto;
|
||||
|
||||
import com.alterdekim.game.entities.Room;
|
||||
import com.alterdekim.game.entities.RoomPlayer;
|
||||
import com.alterdekim.game.entities.User;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
@ -12,6 +13,7 @@ import java.util.List;
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
public class RoomResult {
|
||||
private Room room;
|
||||
private List<RoomPlayer> players;
|
||||
private Long id;
|
||||
private Integer playerCount;
|
||||
private List<UserResult> players;
|
||||
}
|
||||
|
@ -3,8 +3,14 @@ package com.alterdekim.game.repository;
|
||||
import com.alterdekim.game.entities.Room;
|
||||
import com.alterdekim.game.entities.User;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface RoomRepository extends JpaRepository<Room, Long> {
|
||||
|
||||
@Query(value = "SELECT r FROM Room r WHERE r.isPrivate = false")
|
||||
List<Room> findAllByActiveTrue();
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package com.alterdekim.game.security;
|
||||
|
||||
import com.alterdekim.game.handler.CustomAccessDeniedHandler;
|
||||
import jakarta.servlet.DispatcherType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@ -13,6 +14,7 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
import org.springframework.security.web.context.SecurityContextHolderFilter;
|
||||
import org.springframework.security.web.firewall.StrictHttpFirewall;
|
||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||
@ -31,6 +33,7 @@ public class SpringSecurity {
|
||||
http.csrf().disable()
|
||||
.authorizeHttpRequests((authorize) ->
|
||||
authorize
|
||||
.requestMatchers("/async/**").permitAll()
|
||||
.requestMatchers("/game").hasAnyAuthority("ROLE_ADMIN")
|
||||
.requestMatchers("/games").hasAnyAuthority("ROLE_ADMIN")
|
||||
.requestMatchers("/profile/**").hasAnyAuthority("ROLE_ADMIN")
|
||||
|
@ -18,4 +18,8 @@ public class RoomServiceImpl implements RoomService {
|
||||
public List<Room> getAll() {
|
||||
return roomRepository.findAll();
|
||||
}
|
||||
|
||||
public List<Room> getAllActive() {
|
||||
return roomRepository.findAllByActiveTrue();
|
||||
}
|
||||
}
|
||||
|
22
src/main/java/com/alterdekim/game/util/Hash.java
Normal file
22
src/main/java/com/alterdekim/game/util/Hash.java
Normal file
@ -0,0 +1,22 @@
|
||||
package com.alterdekim.game.util;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
|
||||
public class Hash {
|
||||
public static String sha256( byte[] b ) throws Exception {
|
||||
MessageDigest digest = MessageDigest.getInstance("SHA-256");
|
||||
return bytesToHex(digest.digest(b));
|
||||
}
|
||||
|
||||
private static String bytesToHex(byte[] hash) {
|
||||
StringBuilder hexString = new StringBuilder(2 * hash.length);
|
||||
for (byte b : hash) {
|
||||
String hex = Integer.toHexString(0xff & b);
|
||||
if (hex.length() == 1) {
|
||||
hexString.append('0');
|
||||
}
|
||||
hexString.append(hex);
|
||||
}
|
||||
return hexString.toString();
|
||||
}
|
||||
}
|
@ -23,9 +23,9 @@ function findUser(users, id) {
|
||||
|
||||
function parseTime(unix_timestamp) {
|
||||
var date = new Date(unix_timestamp * 1000);
|
||||
var hours = date.getHours();
|
||||
var hours = "0" + date.getHours();
|
||||
var minutes = "0" + date.getMinutes();
|
||||
return hours + ':' + minutes.substr(-2);
|
||||
return hours.substr(-2) + ':' + minutes.substr(-2);
|
||||
}
|
||||
|
||||
function replyButtonClicked(obj) {
|
||||
@ -35,8 +35,15 @@ function replyButtonClicked(obj) {
|
||||
}
|
||||
|
||||
setInterval(function() {
|
||||
let accessToken = $("api-tag").attr("data-access-token");
|
||||
let uid = $("api-tag").attr("data-uid");
|
||||
$.ajax({
|
||||
url: "/api/v1/notify/get/" + last_chat_id + "/",
|
||||
url: "/async/notify/get/",
|
||||
data: {
|
||||
last_chat_id: last_chat_id,
|
||||
accessToken: accessToken,
|
||||
uid: uid
|
||||
},
|
||||
method: "GET"
|
||||
}).done(function(data) {
|
||||
console.log(data);
|
||||
|
@ -401,6 +401,7 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
<api-tag th:data-access-token="${auth_obj.accessToken}" th:data-uid="${auth_obj.uid}"></api-tag>
|
||||
</head>
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/navbar}"></th:block>
|
||||
|
Loading…
x
Reference in New Issue
Block a user