[chuni] Add auto version matching

pull/1/head
samnyan 2020-12-14 17:18:21 +08:00
parent b3a8e80399
commit aa2e8cdea4
15 changed files with 256 additions and 21 deletions

View File

@ -17,8 +17,11 @@ import java.io.InputStream;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.UUID;
import java.util.zip.DataFormatException;
import static icu.samnyan.aqua.sega.util.AquaConst.DEFAULT_KEYCHIP_ID;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@ -53,17 +56,22 @@ public class AllNetController {
byte[] bytes = dataStream.readAllBytes();
Map<String, String> reqMap = Decoder.decode(bytes);
logger.info("Request: PowerOn, " + new ObjectMapper().writeValueAsString(reqMap));
logger.info("Request: PowerOn, " + mapper.writeValueAsString(reqMap));
// TODO: Verify KeyChip id
String gameId = reqMap.getOrDefault("game_id", "");
String ver = reqMap.getOrDefault("ver", "1.0");
String serial = reqMap.getOrDefault("serial", DEFAULT_KEYCHIP_ID);
if (serial.equals(DEFAULT_KEYCHIP_ID)) {
serial = UUID.randomUUID().toString();
}
String format_ver = reqMap.getOrDefault("format_ver", "");
PowerOnResponse resp;
if (format_ver.startsWith("2")) {
var now = LocalDateTime.now();
resp = new PowerOnResponseV2(
1,
switchUri(gameId),
switchUri(gameId, ver, serial),
switchHost(gameId),
"123",
"",
@ -87,7 +95,7 @@ public class AllNetController {
} else {
resp = new PowerOnResponseV3(
1,
switchUri(gameId),
switchUri(gameId, ver, serial),
switchHost(gameId),
"123",
"",
@ -110,10 +118,10 @@ public class AllNetController {
return resp.toString().concat("\n");
}
private String switchUri(String gameId) {
private String switchUri(String gameId, String ver, String serial) {
switch (gameId) {
case "SDBT":
return "http://" + HOST + ":" + PORT + "/";
return "http://" + HOST + ":" + PORT + "/ChuniServlet/" + ver + "/" + serial + "/";
case "SBZV":
return "http://" + HOST + ":" + PORT + "/diva/";
case "SDDT":

View File

@ -4,10 +4,7 @@ package icu.samnyan.aqua.sega.chunithm.controller;
import com.fasterxml.jackson.core.JsonProcessingException;
import icu.samnyan.aqua.sega.chunithm.handler.impl.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@ -15,7 +12,7 @@ import java.util.Map;
* @author samnyan (privateamusement@protonmail.com)
*/
@RestController
@RequestMapping("ChuniServlet")
@RequestMapping({"/ChuniServlet/{ROM_VERSION}/{CLIENT_ID}/ChuniServlet", "/ChuniServlet"})
public class ChuniServletController {
private final GameLoginHandler gameLoginHandler;
@ -242,8 +239,8 @@ public class ChuniServletController {
}
@PostMapping("UpsertClientSettingApi")
String upsertClientSetting(@ModelAttribute Map<String, Object> request) {
return "{\"returnCode\":\"1\"}";
String upsertClientSetting(@ModelAttribute Map<String, Object> request) throws JsonProcessingException {
return upsertClientSettingHandler.handle(request);
}
@PostMapping("UpsertClientTestmodeApi")

View File

@ -5,13 +5,17 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.HandlerMapping;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import static icu.samnyan.aqua.sega.util.AquaConst.*;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@ -28,12 +32,16 @@ public class ChuniServletControllerAdvice {
*/
@ModelAttribute
public Map<String, Object> preHandle(HttpServletRequest request) throws IOException {
var pathVar = (Map<String, String>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
byte[] src = request.getInputStream().readAllBytes();
String outputString = new String(src, StandardCharsets.UTF_8).trim();
logger.info("Request " + request.getRequestURI() + ": " + outputString);
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(outputString, new TypeReference<>() {
Map<String, Object> result = mapper.readValue(outputString, new TypeReference<>() {
});
result.put(SERIAL_KEY, pathVar.getOrDefault(SERIAL_KEY, DEFAULT_KEYCHIP_ID));
result.put(VERSION_KEY, pathVar.getOrDefault(VERSION_KEY, CHUNI_DEFAULT_VERSION));
return result;
}
}

View File

@ -3,7 +3,9 @@ package icu.samnyan.aqua.sega.chunithm.handler.impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import icu.samnyan.aqua.sega.chunithm.handler.BaseHandler;
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserData;
import icu.samnyan.aqua.sega.general.service.ClientSettingService;
import icu.samnyan.aqua.sega.chunithm.service.UserDataService;
import icu.samnyan.aqua.sega.util.VersionUtil;
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -15,6 +17,8 @@ import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import static icu.samnyan.aqua.sega.util.AquaConst.SERIAL_KEY;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@ -25,6 +29,8 @@ public class GetUserDataHandler implements BaseHandler {
private final StringMapper mapper;
private final ClientSettingService clientSettingService;
private final UserDataService userDataService;
private final boolean overwriteVersion;
@ -33,12 +39,13 @@ public class GetUserDataHandler implements BaseHandler {
@Autowired
public GetUserDataHandler(StringMapper mapper,
UserDataService userDataService,
ClientSettingService clientSettingService, UserDataService userDataService,
@Value("${game.chunithm.overwrite-version}") boolean overwriteVersion,
@Value("${game.chunithm.rom-version}") String romVersion,
@Value("${game.chunithm.data-version}") String dataVersion
) {
this.mapper = mapper;
this.clientSettingService = clientSettingService;
this.userDataService = userDataService;
this.overwriteVersion = overwriteVersion;
this.romVersion = romVersion;
@ -55,10 +62,13 @@ public class GetUserDataHandler implements BaseHandler {
resultMap.put("userId", userId);
UserData user = userDataOptional.get();
if (overwriteVersion) {
user.setLastRomVersion(romVersion);
user.setLastDataVersion(dataVersion);
var vo = clientSettingService.getSetting((String) request.get(SERIAL_KEY));
if (vo.isPresent()) {
var version = vo.get();
user.setLastRomVersion(VersionUtil.getTargetVersion(user.getLastRomVersion(), version.getRomVersion()));
user.setLastDataVersion(VersionUtil.getTargetVersion(user.getLastDataVersion(), version.getDataVersion()));
}
resultMap.put("userData", user);
String json = mapper.write(resultMap);
logger.info("Response: " + json);

View File

@ -6,9 +6,11 @@ import icu.samnyan.aqua.sega.chunithm.model.response.GetUserPreviewResp;
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserCharacter;
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserData;
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserGameOption;
import icu.samnyan.aqua.sega.general.service.ClientSettingService;
import icu.samnyan.aqua.sega.chunithm.service.UserCharacterService;
import icu.samnyan.aqua.sega.chunithm.service.UserDataService;
import icu.samnyan.aqua.sega.chunithm.service.UserGameOptionService;
import icu.samnyan.aqua.sega.util.VersionUtil;
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -19,6 +21,8 @@ import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.Optional;
import static icu.samnyan.aqua.sega.util.AquaConst.SERIAL_KEY;
/**
* The handler for loading basic profile information.
* <p>
@ -33,6 +37,8 @@ public class GetUserPreviewHandler implements BaseHandler {
private final StringMapper mapper;
private final ClientSettingService clientSettingService;
private final UserDataService userDataService;
private final UserCharacterService userCharacterService;
private final UserGameOptionService userGameOptionService;
@ -43,7 +49,7 @@ public class GetUserPreviewHandler implements BaseHandler {
@Autowired
public GetUserPreviewHandler(StringMapper mapper,
UserDataService userDataService,
ClientSettingService clientSettingService, UserDataService userDataService,
UserCharacterService userCharacterService,
UserGameOptionService userGameOptionService,
@Value("${game.chunithm.overwrite-version}") boolean overwriteVersion,
@ -51,6 +57,7 @@ public class GetUserPreviewHandler implements BaseHandler {
@Value("${game.chunithm.data-version}") String dataVersion
) {
this.mapper = mapper;
this.clientSettingService = clientSettingService;
this.userDataService = userDataService;
this.userCharacterService = userCharacterService;
this.userGameOptionService = userGameOptionService;
@ -84,8 +91,15 @@ public class GetUserPreviewHandler implements BaseHandler {
resp.setPlayerRating(user.getPlayerRating());
resp.setLastGameId(user.getLastGameId());
resp.setLastRomVersion(user.getLastRomVersion());
resp.setLastDataVersion(user.getLastDataVersion());
var vo = clientSettingService.getSetting((String) request.get(SERIAL_KEY));
if (vo.isPresent()) {
var version = vo.get();
resp.setLastRomVersion(VersionUtil.getTargetVersion(user.getLastRomVersion(), version.getRomVersion()));
resp.setLastDataVersion(VersionUtil.getTargetVersion(user.getLastDataVersion(), version.getDataVersion()));
} else {
resp.setLastRomVersion(user.getLastRomVersion());
resp.setLastDataVersion(user.getLastDataVersion());
}
if (overwriteVersion) {
resp.setLastRomVersion(romVersion);

View File

@ -1,10 +1,42 @@
package icu.samnyan.aqua.sega.chunithm.handler.impl;
import com.fasterxml.jackson.core.JsonProcessingException;
import icu.samnyan.aqua.sega.chunithm.handler.BaseHandler;
import icu.samnyan.aqua.sega.chunithm.model.requet.ClientSettingRequest;
import icu.samnyan.aqua.sega.general.model.GameVersion;
import icu.samnyan.aqua.sega.general.service.ClientSettingService;
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Map;
import static icu.samnyan.aqua.sega.util.AquaConst.DEFAULT_KEYCHIP_ID;
import static icu.samnyan.aqua.sega.util.AquaConst.SERIAL_KEY;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
public class UpsertClientSettingHandler {
public class UpsertClientSettingHandler implements BaseHandler {
private final StringMapper mapper;
private final ClientSettingService clientSettingService;
public UpsertClientSettingHandler(StringMapper mapper, ClientSettingService clientSettingService) {
this.mapper = mapper;
this.clientSettingService = clientSettingService;
}
@Override
public String handle(Map<String, Object> request) throws JsonProcessingException {
var req = mapper.convert(request, ClientSettingRequest.class);
var set = req.getClientSetting();
var serial = (String) request.get(SERIAL_KEY);
if (!serial.equals(DEFAULT_KEYCHIP_ID)) {
clientSettingService.writeSetting(new GameVersion(serial, set.getRomVersion(), set.getDataVersion(), LocalDateTime.now()));
}
return "{\"returnCode\":\"1\"}";
}
}

View File

@ -0,0 +1,21 @@
package icu.samnyan.aqua.sega.chunithm.model.requet;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ClientSetting {
private String placeId;
private String clientId;
private String placeName;
private String regionId;
private String regionName;
private String allNetId;
private String bordId;
private String romVersion;
private String dataVersion;
private String dumpFileNum;
}

View File

@ -0,0 +1,12 @@
package icu.samnyan.aqua.sega.chunithm.model.requet;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ClientSettingRequest {
private ClientSetting clientSetting;
}

View File

@ -0,0 +1,21 @@
package icu.samnyan.aqua.sega.general.dao;
import icu.samnyan.aqua.security.model.WebUser;
import icu.samnyan.aqua.sega.general.model.Card;
import icu.samnyan.aqua.sega.general.model.GameVersion;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Repository("GameVersionRepository")
public interface GameVersionRepository extends JpaRepository<GameVersion, String> {
Optional<GameVersion> findByUuid(String uuid);
List<GameVersion> findByLastTimeBefore(LocalDateTime time);
}

View File

@ -0,0 +1,21 @@
package icu.samnyan.aqua.sega.general.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity(name = "SegaGameVersion")
@Table(name = "sega_game_version")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class GameVersion {
@Id
private String uuid;
private String romVersion;
private String dataVersion;
private LocalDateTime lastTime;
}

View File

@ -0,0 +1,42 @@
package icu.samnyan.aqua.sega.general.service;
import icu.samnyan.aqua.sega.general.dao.GameVersionRepository;
import icu.samnyan.aqua.sega.general.model.GameVersion;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.Optional;
import static icu.samnyan.aqua.sega.util.AquaConst.DEFAULT_KEYCHIP_ID;
@Service
public class ClientSettingService {
private final GameVersionRepository gameVersionRepository;
public ClientSettingService(GameVersionRepository gameVersionRepository) {
this.gameVersionRepository = gameVersionRepository;
}
public void writeSetting(GameVersion setting) {
gameVersionRepository.save(setting);
}
public Optional<GameVersion> getSetting(String serial) {
if (serial.equals(DEFAULT_KEYCHIP_ID)) {
return Optional.empty();
}
try {
var vo = gameVersionRepository.findByUuid(serial);
if (vo.isPresent()) {
var v = vo.get();
v.setLastTime(LocalDateTime.now());
gameVersionRepository.save(v);
return Optional.of(v);
}
return Optional.empty();
} catch (Exception e) {
return Optional.empty();
}
}
}

View File

@ -0,0 +1,8 @@
package icu.samnyan.aqua.sega.util;
public class AquaConst {
public static String SERIAL_KEY = "CLIENT_ID";
public static String VERSION_KEY = "ROM_VERSION";
public static String CHUNI_DEFAULT_VERSION = "1.30";
public static String DEFAULT_KEYCHIP_ID = "A69E01A8888";
}

View File

@ -0,0 +1,25 @@
package icu.samnyan.aqua.sega.util;
public class VersionUtil {
public static String getTargetVersion(String savedVersion, String currentVersion) {
var v1s = savedVersion.split("\\.");
var v2s = currentVersion.split("\\.");
try {
for (int i = 0; i < v1s.length; i++) {
int v1n = Integer.parseInt(v1s[i]);
int v2n = Integer.parseInt(v2s[i]);
if (v1n > v2n) {
return currentVersion;
}
if (v1n < v2n) {
return savedVersion;
}
}
// if all same
return savedVersion;
} catch (Exception e) {
return savedVersion;
}
}
}

View File

@ -0,0 +1,8 @@
create table sega_game_version
(
uuid varchar(255)
primary key,
rom_version varchar(255) not null,
data_version varchar(255) not null,
last_time DATETIME not null
);

View File

@ -0,0 +1,8 @@
create table sega_game_version
(
uuid varchar
primary key,
rom_version varchar not null,
data_version varchar not null,
last_time DATETIME not null
);