Compare commits

..

5 Commits

Author SHA1 Message Date
shi ddf141c4c2 feat(game): 添加平台管理全部获取接口并优化登录逻辑
- 在 GamePlatformController 中添加了获取所有平台信息的接口
- 优化了 SysLoginController 中的验证码校验逻辑
- 新增了平台服务的依赖注入
- 添加了权限控制注解
2025-04-12 13:13:07 +08:00
shi 8f7b618b97 Merge branch 'main' into main-pt
# Conflicts:
#	ff-base/src/main/java/com/ff/base/constant/Constants.java
#	ff-base/src/main/java/com/ff/base/enums/GamePlatforms.java
#	ff-game/src/main/java/com/ff/member/service/impl/MemberServiceImpl.java
2025-04-12 10:36:03 +08:00
shi 26e8e1986d feat(ff-game): 添加 PT 平台支持
- 在 GamePlatforms枚举中添加 PT 平台
- 实现 PT 平台的会员创建、信息获取、登录等功能
- 添加 PT 平台的错误处理和 SSL 证书加载逻辑
- 更新 MemberService 以支持 PT 平台的会员账户生成
- 删除不必要的接口和类,精简代码结构
2025-03-31 10:43:44 +08:00
shi f229c9ca4f feat(api): 添加 PT API 客户端示例代码
- 新增 PTAPIClient 类,用于演示如何调用 PT API
- 添加证书文件和密码文件
- 实现了加载证书、初始化 SSL 上下文和发送 HTTPS 请求的逻辑
- 包含了跳过证书和主机名验证的实现
2025-03-29 10:32:08 +08:00
shi 529bd5f1d0 feat(game): 添加 PT 游戏接口实现
- 新增 PT游戏服务实现类 GamesPTServiceImpl
- 添加 PT 游戏相关的 DTO 类和接口
- 实现了创建成员、获取会员信息、登录、游戏列表、投注记录等功能
- 集成 Forest框架进行 HTTP 请求
2025-03-28 20:29:07 +08:00
38 changed files with 671 additions and 1979 deletions

View File

@ -137,14 +137,8 @@ public class CacheConstants {
public static final String SV388_TIME_FROM= "sv388:time:from";
public static final String SV388_GAMES = "sv388_games:";
/**
* pp
*/
public static final String PP_GAMES= "pp_games:";
/**
* pp
*/
public static final String PP_TIME_POINT = "pp:time:point:";
}

View File

@ -19,8 +19,9 @@ public enum GamePlatforms {
PGT("PGT", "PGT"),
FBSports("FBSports", "FB体育"),
SV388("SV388", "SV388真人"),
PP("PP", "PP"),
DBSports("DBSports", "DB体育");
DBSports("DBSports", "DB体育"),
PT("PT", "PT"),
;
private final String code;
private final String info;

View File

@ -1,64 +0,0 @@
package com.ff.base.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Optional;
import java.util.stream.Stream;
/**
* xkgame
*
* @author shi
* @date 2024/11/13
*/
@Getter
@AllArgsConstructor
public enum PPGameType {
ELECTRONIC("vs", 1,"电子"),
// CARD_GAME("rl",2, "轮盘"),
// VIDEO("vp",6, "视频扑克"),
// SCRATCH_CARD("sc",7, "刮刮乐"),
// BLACK_JACK("bj",2, "21点"),
// CLASSIC_SLOTS("cs",1, "电子"),
// BACCARAT_NEW("bn",2, "百家乐新"),
// BACCARAT("bc",2, "百家乐"),
// LIVE_GAMES("lg",6, "现场游戏"),
;
private final String code;
private final Integer systemCode;
private final String info;
/**
*
*
* @param code
* @return {@link String }
*/
public static Integer findSystemByCode(String code) {
Optional<Integer> system = Stream.of(PPGameType.values())
.filter(gameType -> gameType.getCode().equals(code))
.map(PPGameType::getSystemCode)
.findFirst();
return system.orElse(null);
}
/**
*
*
* @param code
* @return {@link String }
*/
public static String findInfoByCode(String code) {
Optional<String> system = Stream.of(PPGameType.values())
.filter(gameType -> gameType.getCode().equals(code))
.map(PPGameType::getInfo)
.findFirst();
return system.orElse(null);
}
}

View File

@ -975,23 +975,4 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
}
}
/**
* (UTC)
*
* @param dateStr
* @param pattern ("yyyy-MM-dd HH:mm:ss")
* @return
* @throws ParseException
*/
public static long toTimestamp(String dateStr, String pattern) {
try {
SimpleDateFormat sdf = new SimpleDateFormat(pattern);
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
return sdf.parse(dateStr).getTime();
} catch (Exception e) {
return 0;
}
}
}

View File

@ -159,8 +159,6 @@ public class ApiGameController extends BaseController {
ApiException.notNull(targetLang, ErrorCode.LANG_NOT_EXIST.getCode());
ApiException.isTrue(game.getStopStatus(), ErrorCode.GAME_NOT_EXIST.getCode());
Member member = memberService.selectMemberByAccount(loginRequest.getAccount(), loginRequest.getCurrencyCode(), platform.getPlatformCode());
ApiException.notNull(member, ErrorCode.ACCOUNT_NOT_EXIST.getCode());

View File

@ -25,7 +25,7 @@ public class ApiCFBalanceTransferResponseDTO {
* ID
*/
@JsonProperty("BankID")
private Long bankID;
private int bankID;
/**
* ID

View File

@ -25,7 +25,7 @@ public class ApiCFBalanceTransferStatusResponseDTO {
* ID
*/
@JsonProperty("bankID")
private Long bankId;
private int bankId;
/**
* ID

View File

@ -56,7 +56,7 @@ public interface PGXClient {
* @param parameters
* @return {@link PGXGameLoginResponse }
*/
@Get("/launchGames.aspx?${parameters}")
@Post("/launchGames.aspx?${parameters}")
PGXGameLoginResponse loginWithoutRedirect(@Var("parameters") String parameters);
/**

View File

@ -1,35 +0,0 @@
package com.ff.game.api.pp.address;
import com.dtflys.forest.callback.AddressSource;
import com.dtflys.forest.http.ForestAddress;
import com.dtflys.forest.http.ForestRequest;
import com.ff.base.enums.GamePlatforms;
import com.ff.game.domain.Platform;
import com.ff.game.service.IPlatformService;
import com.sun.media.jfxmediaimpl.platform.PlatformManager;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* jili address
*
* @author shi
* @date 2025/02/10
*/
@Component
public class MyPPAddressSource implements AddressSource {
@Resource
private IPlatformService platformService;
@Override
public ForestAddress getAddress(ForestRequest request) {
Platform platform = platformService.get(GamePlatforms.PP.getCode());
String apiBaseUrl = platform.getUrlInfo().getUrl();
String host = platform.getUrlInfo().getHost();
String https = platform.getUrlInfo().getHttps();
return new ForestAddress(https, apiBaseUrl, Integer.parseInt(host), "/IntegrationService/v3");
}
}

View File

@ -1,121 +0,0 @@
package com.ff.game.api.pp.client;
import com.dtflys.forest.annotation.*;
import com.ff.game.api.pp.address.MyPPAddressSource;
import com.ff.game.api.pp.dto.*;
import com.ff.game.api.pp.forest.MySuccessCondition;
import java.util.Map;
/**
* pp
*
* @author shi
* @date 2025/02/10
*/
@Address(source = MyPPAddressSource.class)
public interface PPClient {
/**
*
*
* @param params
* @return {@link PPUserAccountResponse }
*/
@Post( url ="/http/CasinoGameAPI/player/account/create/",
headers = {
"Content-type: application/x-www-form-urlencoded"
})
PPUserAccountResponse createMember(@Body Map<String, Object> params);
/**
*
*
* @param params
* @return {@link PPPlayerAccountResponse }
*/
@Post( url ="/http/CasinoGameAPI/balance/current/",
headers = {
"Content-type: application/x-www-form-urlencoded"
})
PPPlayerAccountResponse getMemberInfo(@Body Map<String, Object> params);
/**
*
*
* @param params
* @return {@link PPGameLaunchResponse }
*/
@Post(url ="/http/CasinoGameAPI/game/start/",
headers = {
"Content-type: application/x-www-form-urlencoded"
})
PPGameLaunchResponse loginWithoutRedirect(@Body Map<String, Object> params);
/**
*
*
* @param params
* @return {@link PPGameResponseDTO }
*/
@Post( url ="/http/CasinoGameAPI/getCasinoGames/",
headers = {
"Content-type: application/x-www-form-urlencoded"
})
PPGameResponseDTO getGameList(@Body Map<String, Object> params);
/**
* id
*
* @param params
* @return {@link PPTransactionResponse }
*/
@Post(url = "/http/CasinoGameAPI/balance/transfer/",
headers = {
"Content-type: application/x-www-form-urlencoded"
})
@Success(condition = MySuccessCondition.class)
PPTransactionResponse exchangeTransfer(@Body Map<String, Object> params);
/**
*
*
* @param params
* @return {@link PPTransactionStatusResponse }
*/
@Post(url = "/http/CasinoGameAPI/balance/transfer/status/",
headers = {
"Content-type: application/x-www-form-urlencoded"
})
PPTransactionStatusResponse exchangeTransferStatus( @Body Map<String, Object> params);
/**
*
*
* @param params
* @return {@link String }
*/
@Get(url ="/DataFeeds/gamerounds/finished/?{params}")
String getBetRecordByTime(@Var("params") String params);
/**
*
*
* @param params
* @return {@link PPResponse }
*/
@Post(url = "/http/CasinoGameAPI/game/session/terminate/",
headers = {
"Content-type: application/x-www-form-urlencoded"
})
PPResponse kickMember(@Body Map<String, Object> params);
}

View File

@ -1,129 +0,0 @@
package com.ff.game.api.pp.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
/**
* dgbet
*
* @author shi
* @date 2025/03/27
*/
@Data
public class DGBetRecordResponseDTO {
/** 错误码 (参考文档定义) */
@JsonProperty("codeId")
private Integer codeId;
/** 错误信息 */
@JsonProperty("msg")
private String msg;
/** 注单报告 */
@JsonProperty("list")
private List<ReportDTO> list;
/**
*
*/
@Data
public static class ReportDTO {
/** 注单ID唯一 */
@JsonProperty("id")
private Long id;
/** 游戏桌号(红包小费记录没有) */
@JsonProperty("tableId")
private Integer tableId;
/** 游戏靴号(红包小费记录没有) */
@JsonProperty("shoeId")
private Long shoeId;
/** 当靴局号(红包小费记录没有) */
@JsonProperty("playId")
private Long playId;
/** 游戏厅号1:旗舰厅2:亚洲厅34:现场厅5:性感厅8,9:区块链厅) */
@JsonProperty("lobbyId")
private Integer lobbyId;
/** 注单类型1:注单2:红包小费) */
@JsonProperty("gameType")
private Integer gameType;
/** 游戏类型(百家乐,龙虎等) */
@JsonProperty("gameId")
private Integer gameId;
/** 下注时间 */
@JsonProperty("betTime")
private Date betTime;
/** 结算时间 */
@JsonProperty("calTime")
private Date calTime;
/** 派彩金额(含本金) */
@JsonProperty("winOrLoss")
private BigDecimal winOrLoss;
/** 下注前余额(仅作参考) */
@JsonProperty("balanceBefore")
private BigDecimal balanceBefore;
/** 下注金额(下注扣款金额) */
@JsonProperty("betPoints")
private BigDecimal betPoints;
/** 洗码金额(用于计算佣金) */
@JsonProperty("availableBet")
private BigDecimal availableBet;
/** 会员账号 */
@JsonProperty("userName")
private String userName;
/** 游戏结果 */
@JsonProperty("result")
private String result;
/** 注单详情 */
@JsonProperty("betDetail")
private String betDetail;
/** 客户端IP */
@JsonProperty("ip")
private String ip;
/** 游戏唯一局号 */
@JsonProperty("ext")
private String ext;
/** 结算状态0:未结算1:已结算2:已撤销3:冻结) */
@JsonProperty("isRevocation")
private Integer isRevocation;
/** 更改单时对应的注单记录 */
@JsonProperty("parentBetId")
private Long parentBetId;
/** 币种ID请参考对应关系说明 */
@JsonProperty("currencyId")
private Integer currencyId;
/** 客户端平台ID1: PC 2: 安卓 3: 苹果 5: H5 */
@JsonProperty("deviceType")
private Integer deviceType;
/** 钱包扣款记录转账模式API没有 */
@JsonProperty("transfers")
private String transfers;
}
}

View File

@ -1,74 +0,0 @@
package com.ff.game.api.pp.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
/**
*
*/
@Data
public class DGLoginWithoutRedirectResponse {
/**
* ID
*/
@JsonProperty("codeId")
private int codeId;
/**
*
*/
@JsonProperty("msg")
private String msg;
/**
* token
*/
@JsonProperty("token")
private String token;
/**
*
*/
@JsonProperty("domains")
private String domains;
/**
*
*/
@JsonProperty("list")
private List<String> list;
/**
*
*/
@JsonProperty("limitGroup")
private String limitGroup;
/**
*
*/
@JsonProperty("limits")
private List<Limit> limits;
/**
*
*/
@Data
public static class Limit {
/**
*
*/
@JsonProperty("min")
private int min;
/**
*
*/
@JsonProperty("max")
private int max;
}
}

View File

@ -1,26 +0,0 @@
package com.ff.game.api.pp.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
*
*
* @author shi
* @date 2025/03/26
*/
@Data
public class DGResponse {
/**
* ID
*/
@JsonProperty("codeId")
private int codeId;
/**
*
*/
@JsonProperty("msg")
private String msg;
}

View File

@ -1,45 +0,0 @@
package com.ff.game.api.pp.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
*
*
* @author shi
* @date 2025/03/27
*/
@Data
public class DGTransactionResponseDTO {
/** 响应代码 */
@JsonProperty("codeId")
private Integer codeId;
/** 响应消息 */
@JsonProperty("msg")
private String msg;
/** 用户名 */
@JsonProperty("username")
private String username;
/** 交易金额 */
@JsonProperty("amount")
private BigDecimal amount;
/** 账户余额 */
@JsonProperty("balance")
private BigDecimal balance;
/** 交易流水号 */
@JsonProperty("serial")
private String serial;
/** 交易时间 */
@JsonProperty("time")
private String time;
}

View File

@ -1,40 +0,0 @@
package com.ff.game.api.pp.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
*
*
* @author shi
* @date 2025/03/26
*/
@Data
public class DGUserAccountResponse {
/**
* ID
*/
@JsonProperty("codeId")
private int codeId;
/**
*
*/
@JsonProperty("msg")
private String msg;
/**
*
*/
@JsonProperty("username")
private String username;
/**
*
*/
@JsonProperty("balance")
private BigDecimal balance;
}

View File

@ -1,70 +0,0 @@
package com.ff.game.api.pp.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
/**
*
*
* @author shi
* @date 2025/03/27
*/
@Data
public class DGUserListResponseDTO {
/**
* ID
*/
@JsonProperty("codeId")
private int codeId;
/**
*
*/
@JsonProperty("msg")
private String msg;
/** 用户列表 */
@JsonProperty("list")
private List<UserDTO> list;
/**
*
*/
@Data
public static class UserDTO {
/** 用户名 */
@JsonProperty("username")
private String username;
/** 昵称 */
@JsonProperty("nickname")
private String nickname;
/** 币种名称 */
@JsonProperty("currencyName")
private String currencyName;
/** 用户IP */
@JsonProperty("ip")
private String ip;
/** 用户设备 */
@JsonProperty("device")
private String device;
/** 登录时间 */
@JsonProperty("login")
private String login;
/** 会员ID */
@JsonProperty("memberId")
private Long memberId;
/** 用户余额 */
@JsonProperty("balance")
private Double balance;
}
}

View File

@ -1,35 +0,0 @@
package com.ff.game.api.pp.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* ppgame
*
* @author shi
* @date 2025/04/14
*/
@Data
public class PPGameLaunchResponse {
/**
*
* : "0"
*/
@JsonProperty("error")
private String error;
/**
*
* : "OK"
*/
@JsonProperty("description")
private String description;
/**
* URL
* token
*/
@JsonProperty("gameURL")
private String gameUrl;
}

View File

@ -1,111 +0,0 @@
package com.ff.game.api.pp.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
/**
* -
*
* @author shi
* @date 2025/03/27
*/
@Data
public class PPGameResponseDTO {
/** 错误码 (参考文档定义) */
@JsonProperty("error")
private String error;
/** 错误信息 */
@JsonProperty("description")
private String description;
/** 游戏信息列表 */
@JsonProperty("gameList")
private List<CasinoGame> gameList;
/**
*
*/
@Data
public static class CasinoGame {
/** 游戏唯一标识符 */
@JsonProperty("gameID")
private String gameID;
/** 游戏名称 */
@JsonProperty("gameName")
private String gameName;
/** 游戏类型标识符 */
@JsonProperty("gameTypeID")
private String gameTypeID;
/** 游戏类型描述 */
@JsonProperty("typeDescription")
private String typeDescription;
/** 游戏技术描述 */
@JsonProperty("technology")
private String technology;
/** 游戏支持的平台 */
@JsonProperty("platform")
private String platform;
/** 是否提供演示游戏 */
@JsonProperty("demoGameAvailable")
private boolean demoGameAvailable;
/** 游戏宽高比 */
@JsonProperty("aspectRatio")
private String aspectRatio;
/** 游戏技术标识符 */
@JsonProperty("technologyID")
private String technologyID;
/** 数值型游戏 ID */
@JsonProperty("gameIdNumeric")
private Long gameIdNumeric;
/** 是否提供免费回合奖励 */
@JsonProperty("frbAvailable")
private boolean frbAvailable;
/** 是否提供可变免费回合奖励 */
@JsonProperty("variableFrbAvailable")
private boolean variableFrbAvailable;
/** 游戏的投注线数 */
@JsonProperty("lines")
private Integer lines;
/** 游戏支持的功能列表 */
@JsonProperty("features")
private List<String> features;
/** 游戏数据类型 */
@JsonProperty("dataType")
private String dataType;
/** 支持的司法管辖区列表 */
@JsonProperty("jurisdictions")
private List<String> jurisdictions;
/**
* id
*/
private String systemGameId;
/**
*
*/
private Integer systemPlatformType;
}
}

View File

@ -1,279 +0,0 @@
package com.ff.game.api.pp.dto;
import com.ff.base.utils.DateUtils;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* ppgame
*
* @author shi
* @date 2025/04/15
*/
@Data
public class PPGameRoundRecord {
private static final DateTimeFormatter DATE_FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
/**
* Unix
* <p> timepoint=1618298161139</p>
*/
private Long timepoint;
/**
* Pragmatic PlayID
*
* @example 531288
*/
private String playerID;
/**
* ID
*
* @example 889325
*/
private String extPlayerID;
/**
*
*
* @example "vs20magicpot"
*/
private String gameID;
/**
* ID
* <p></p>
*
* @example 50994065
*/
private String playSessionID;
/**
* ID
* <p>ID</p>
*
* @example 50994064
*/
private String parentSessionID;
/**
*
* <p>yyyy-MM-dd HH:mm:ss</p>
*
* @example "2021-04-13 07:06:18"
*/
private Long startDate;
/**
*
* <p>nullyyyy-MM-dd HH:mm:ss</p>
*
* @example "2021-04-13 07:06:18"
*/
private Long endDate;
/**
*
* <p>
* <ul>
* <li>C - </li>
* <li>F - /</li>
* </ul>
* </p>
*
* @example "C"
*/
private String status;
/**
*
* <p>
* <ul>
* <li>F - </li>
* </ul>
* </p>
*
* @example "F"
*/
private String type;
/**
* 2
*
* @example 0.00
*/
private BigDecimal bet;
/**
* 2
*
* @example 0.00
*/
private BigDecimal win;
/**
* ISO 3
*
* @example "EUR"
*/
private String currency;
/**
* 2
*
* @example 0.00
*/
private BigDecimal jackpot;
/**
* ID
* <p>"null"</p>
*
* @example "null"
*/
private String bonusCode;
/**
* 2
*
* @example 0.00
*/
private BigDecimal bonusBet;
/**
* 2
*
* @example 0.00
*/
private BigDecimal bonusWin;
public static List<PPGameRoundRecord> parse(String data) {
List<PPGameRoundRecord> transactions = new ArrayList<>();
// 按行分割数据
String[] lines = data.split("\n");
if (lines.length < 3) {
return new ArrayList<>();
}
// 解析列名(第二行)
String[] headers = lines[1].trim().split(",");
for (int j = 2; j < lines.length; j++) {
// 解析数据行(第三行开始)
String[] values = lines[j].trim().split(",");
// 确保列数和值数匹配
if (headers.length != values.length) {
continue;
}
// 创建交易记录对象
PPGameRoundRecord transaction = new PPGameRoundRecord();
// 根据列名设置对应的值
for (int i = 0; i < headers.length; i++) {
String header = headers[i].trim();
String value = values[i].trim();
switch (header) {
case "playerID":
transaction.setPlayerID(value);
break;
case "extPlayerID":
transaction.setExtPlayerID(value);
break;
case "gameID":
transaction.setGameID(value);
break;
case "playSessionID":
transaction.setPlaySessionID(value);
break;
case "parentSessionID":
transaction.setParentSessionID(value);
break;
case "startDate":
transaction.setStartDate(DateUtils.toTimestamp(value, DateUtils.YYYY_MM_DD_HH_MM_SS));
break;
case "endDate":
transaction.setEndDate(DateUtils.toTimestamp(value, DateUtils.YYYY_MM_DD_HH_MM_SS));
break;
case "status":
transaction.setStatus(value);
break;
case "type":
transaction.setType(value);
break;
case "bet":
transaction.setBet(new BigDecimal(value));
break;
case "win":
transaction.setWin(new BigDecimal(value));
break;
case "currency":
transaction.setCurrency(value);
break;
case "jackpot":
transaction.setJackpot(new BigDecimal(value));
break;
case "bonusCode":
transaction.setBonusCode("null".equals(value) ? null : value);
break;
case "bonusBet":
transaction.setBonusBet(new BigDecimal(value));
break;
case "bonusWin":
transaction.setBonusWin(new BigDecimal(value));
break;
}
}
transactions.add(transaction);
}
return transactions;
}
/**
*
*
* @param s s
* @return {@link Long }
*/// 辅助解析方法
private static Long parseLong(String s) {
return s.isEmpty() ? null : Long.parseLong(s);
}
/**
*
*
* @param s s
* @return {@link BigDecimal }
*/
private static BigDecimal parseDouble(String s) {
return s.isEmpty() ? null : new BigDecimal(s);
}
/**
*
*
* @param s s
* @return {@link LocalDateTime }
*/
private static Date parseDateTime(String s) {
return s.isEmpty() ? null : DateUtils.parseDate(s);
}
}

View File

@ -1,35 +0,0 @@
package com.ff.game.api.pp.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
*
*/
@Data
public class PPPlayerAccountResponse {
/**
* ()
* : "0"
*/
@JsonProperty("error")
private String error;
/**
* ()
* : "OK"
*/
@JsonProperty("description")
private String description;
/**
* ()
* : 999.99
*/
@JsonProperty("balance")
private BigDecimal balance;
}

View File

@ -1,30 +0,0 @@
package com.ff.game.api.pp.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* ppgame
*
* @author shi
* @date 2025/04/14
*/
@Data
public class PPResponse {
/**
*
* : "0"
*/
@JsonProperty("error")
private String error;
/**
*
* : "OK"
*/
@JsonProperty("description")
private String description;
}

View File

@ -1,43 +0,0 @@
package com.ff.game.api.pp.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
*
*
* @author shi
* @date 2025/04/14
*/
@Data
public class PPTransactionResponse {
/**
* ()
* : "0"
*/
@JsonProperty("error")
private String error;
/**
* ()
* : "OK"
*/
@JsonProperty("description")
private String description;
/**
* ID ()
* : 1908759
*/
@JsonProperty("transactionId")
private String transactionId;
/**
* ()
* : 999.99
*/
@JsonProperty("balance")
private BigDecimal balance;
}

View File

@ -1,90 +0,0 @@
package com.ff.game.api.pp.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
*
*
* @author shi
* @date 2025/04/14
*/
@Data
public class PPTransactionStatusResponse {
/**
*
* <p>
*
* <ul>
* <li>"0" - </li>
* <li> - </li>
* </ul>
* </p>
*
* @apiNote
* @example "0"
*/
@JsonProperty("error")
private String error;
/**
*
* <p></p>
*
* @apiNote
* @example "OK"
*/
@JsonProperty("description")
private String description;
/**
*
* <p></p>
*
* @apiNote
* @example 1908759
*/
@JsonProperty("transactionId")
private Long transactionId;
/**
*
* <p>
*
* <ul>
* <li>"Success" - </li>
* <li>"Pending" - </li>
* <li>"Failed" - </li>
* </ul>
* </p>
*
* @apiNote
* @example "Success"
*/
@JsonProperty("status")
private String status;
/**
*
* <p>
*
* </p>
*
* @apiNote
* @example "999.99"
*/
@JsonProperty("amount")
private BigDecimal amount;
/**
*
* <p>使BigDecimal</p>
*
* @apiNote null
* @example 999.99
*/
@JsonProperty("balance")
private BigDecimal balance;
}

View File

@ -1,33 +0,0 @@
package com.ff.game.api.pp.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
*
* -
*/
@Data
public class PPUserAccountResponse {
/**
* ()
* : "0"
*/
@JsonProperty("error")
private String error;
/**
* ()
* : "OK"
*/
@JsonProperty("description")
private String description;
/**
* ()
* : 6749178
*/
@JsonProperty("playerId")
private Long playerId;
}

View File

@ -1,31 +0,0 @@
package com.ff.game.api.pp.forest;
import com.dtflys.forest.callback.SuccessWhen;
import com.dtflys.forest.http.ForestRequest;
import com.dtflys.forest.http.ForestResponse;
/**
* kmsuccess
*
* @author shi
* @date 2025/04/02
*/
public class MySuccessCondition implements SuccessWhen {
/**
*
* @param req Forest
* @param res Forest
* @return true: false:
*/
@Override
public boolean successWhen(ForestRequest req, ForestResponse res) {
// req 为Forest请求对象即 ForestRequest 类实例
// res 为Forest响应对象即 ForestResponse 类实例
// 返回值为 ture 则表示请求成功false 表示请求失败
return res.noException();
// 当然在这里也可以写其它条件,比如 通过 res.getResult() 或 res.getContent() 获取业务数据
// 再根据业务数据判断是否成功
}
}

View File

@ -1,645 +0,0 @@
package com.ff.game.api.pp.impl;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import com.ff.base.constant.CacheConstants;
import com.ff.base.constant.Constants;
import com.ff.base.core.redis.RedisCache;
import com.ff.base.enums.*;
import com.ff.base.exception.base.ApiException;
import com.ff.base.exception.base.BaseException;
import com.ff.base.utils.DateUtils;
import com.ff.base.utils.JsonUtil;
import com.ff.base.utils.StringUtils;
import com.ff.base.utils.sign.Md5Utils;
import com.ff.game.api.IGamesService;
import com.ff.game.api.pp.client.PPClient;
import com.ff.game.api.pp.dto.*;
import com.ff.game.api.request.*;
import com.ff.game.domain.*;
import com.ff.game.service.IGameBettingDetailsService;
import com.ff.game.service.IGameExchangeMoneyService;
import com.ff.game.service.IGameFreeRecordService;
import com.ff.game.service.IGameService;
import com.ff.member.domain.Member;
import com.ff.member.service.IMemberService;
import com.ff.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* DG impl
*
* @author shi
* @date 2024/11/12
*/
@Service("PPService")
@Slf4j
public class GamesPPServiceImpl implements IGamesService {
@Resource
private RedisCache gRedisCache;
@Resource
private IGameService gameService;
@Resource
private IMemberService memberService;
@Resource
private IGameFreeRecordService gameFreeRecordService;
@Resource
private PPClient ppClient;
@Resource
private IGameBettingDetailsService gameBettingDetailsService;
@Resource
private IGameExchangeMoneyService gameExchangeMoneyService;
/**
*
*
* @param errorCode
* @return {@link Boolean }
*/
private Boolean getIsSuccess(String errorCode) {
ApiException.isTrue(!"7".equals(errorCode), ErrorCode.INSUFFICIENT_PLAYER_BALANCE.getCode());
return "0".equals(errorCode);
}
/**
*
*
* @param gamesBaseRequestDTO dto
* @return {@link String }
*/
private String getKey(GamesBaseRequestDTO gamesBaseRequestDTO) {
//取出对应的key跟密钥跟请求参数
String agentKey = gamesBaseRequestDTO.getAgentKey();
return Md5Utils.md5New(gamesBaseRequestDTO.getQuery() + agentKey);
}
/**
* ingress
*
* @param terminalTypes
* @return {@link Integer }
*/
public Integer convertToIngress(String terminalTypes) {
if (terminalTypes == null || terminalTypes.isEmpty()) {
return null;
}
boolean hasMobile = terminalTypes.contains("MOBILE");
boolean hasWeb = terminalTypes.contains("WEB");
if (hasMobile && hasWeb) {
return IngressType.PC_AND_MOBILE_WEB.getValue();
} else if (hasMobile) {
return IngressType.MOBILE_WEB.getValue();
} else if (hasWeb) {
return IngressType.PC_WEB.getValue();
} else {
return null;
}
}
/**
*
*
* @param createMemberRequestDTO dto
* @return {@link Boolean }
*/
@Override
public Boolean createMember(CreateMemberRequestDTO createMemberRequestDTO) {
log.info("GamesPPServiceImpl [createMember] 请求参数 {}", createMemberRequestDTO);
Map<String, Object> params = new TreeMap<>();
params.put("externalPlayerId", createMemberRequestDTO.getAccount());
params.put("secureLogin", createMemberRequestDTO.getAgentId());
params.put("currency", createMemberRequestDTO.getCurrency());
String query = JsonUtil.mapToQueryString(params);
createMemberRequestDTO.setQuery(query);
String key = this.getKey(createMemberRequestDTO);
params.put("hash", key);
PPUserAccountResponse member = ppClient.createMember(params);
if (this.getIsSuccess(member.getError())) {
return Boolean.TRUE;
}
//判断是否获取成功
return Boolean.FALSE;
}
/**
*
*
* @param memberInfoRequestDTO dto
* @return {@link MemberInfoResponseDTO }
*/
@Override
public MemberInfoResponseDTO getMemberInfo(MemberInfoRequestDTO memberInfoRequestDTO) {
log.info("GamesPPServiceImpl [loginWithoutRedirect] 请求参数 {}", memberInfoRequestDTO);
Map<String, Object> params = new TreeMap<>();
params.put("secureLogin", memberInfoRequestDTO.getAgentId());
params.put("externalPlayerId", memberInfoRequestDTO.getAccounts());
String query = JsonUtil.mapToQueryString(params);
memberInfoRequestDTO.setQuery(query);
String key = this.getKey(memberInfoRequestDTO);
params.put("hash", key);
PPPlayerAccountResponse memberInfo = ppClient.getMemberInfo(params);
if (this.getIsSuccess(memberInfo.getError())) {
return MemberInfoResponseDTO.builder().account(memberInfoRequestDTO.getAccounts())
.balance(memberInfo.getBalance())
.status(GameMemberStatus.UNKNOWN.getCode()).build();
}
throw new ApiException(ErrorCode.ACCOUNT_NOT_EXIST.getCode());
}
/**
*
*
* @param gamesLogin
* @return {@link String }
*/
@Override
public String loginWithoutRedirect(GamesLogin gamesLogin) {
log.info("GamesPPServiceImpl [loginWithoutRedirect] 请求参数 {}", gamesLogin);
Map<String, Object> params = new TreeMap<>();
params.put("secureLogin", gamesLogin.getAgentId());
params.put("externalPlayerId", gamesLogin.getAccount());
params.put("gameId", gamesLogin.getGameId());
params.put("language", gamesLogin.getLang());
if (!StringUtils.isEmpty(gamesLogin.getPlatform())) {
if ("web".equalsIgnoreCase(gamesLogin.getPlatform())) {
params.put("platform", "WEB");
} else {
params.put("platform", "MOBILE");
}
}
params.put("lobbyURL", gamesLogin.getHomeUrl());
String query = JsonUtil.mapToQueryString(params);
gamesLogin.setQuery(query);
String key = this.getKey(gamesLogin);
params.put("hash", key);
PPGameLaunchResponse ppGameLaunchResponse = ppClient.loginWithoutRedirect(params);
if (this.getIsSuccess(ppGameLaunchResponse.getError())) {
return ppGameLaunchResponse.getGameUrl();
} else {
throw new ApiException(ErrorCode.ACCOUNT_NOT_EXIST.getCode());
}
}
/**
*
*
* @param gamesBaseRequestDTO dto
* @return {@link String }
*/
@Transactional
@Override
public String getGameList(GamesBaseRequestDTO gamesBaseRequestDTO) {
List<PPGameResponseDTO.CasinoGame> gamesDatas = gRedisCache.getCacheList(CacheConstants.PP_GAMES);
if (!CollectionUtils.isEmpty(gamesDatas)) {
return CacheConstants.PP_GAMES;
}
Map<String, Object> params = new LinkedHashMap<>();
params.put("secureLogin", gamesBaseRequestDTO.getAgentId());
String query = JsonUtil.mapToQueryString(params);
gamesBaseRequestDTO.setQuery(query);
String key = this.getKey(gamesBaseRequestDTO);
params.put("hash", key);
PPGameResponseDTO gameList = ppClient.getGameList(params);
if (this.getIsSuccess(gameList.getError())) {
for (PPGameResponseDTO.CasinoGame apiGameInfoResponseDTO : gameList.getGameList()) {
Integer platformType = PPGameType.findSystemByCode(apiGameInfoResponseDTO.getGameTypeID());
//不支持的游戏跳过
if (ObjectUtils.isEmpty(platformType)) {
continue;
}
Integer ingress = convertToIngress(apiGameInfoResponseDTO.getPlatform());
//不需要的平台
if (ObjectUtils.isEmpty(ingress)) {
continue;
}
Game game = Game.builder()
.platformCode(GamePlatforms.PP.getCode())
.platformType(platformType)
.gameCode(apiGameInfoResponseDTO.getGameID())
.build();
List<Game> games = gameService.selectGameList(game);
//不存在这个游戏
if (CollectionUtils.isEmpty(games)) {
game.setIngress(ingress);
game.setGameSourceType(apiGameInfoResponseDTO.getGameTypeID());
game.setFreespin(Boolean.FALSE);
game.setDemoStatus(Boolean.FALSE);
game.setSortNo(gameService.selectMaxSortNo(platformType, GamePlatforms.PP.getCode()) + 1);
game.setGameName(apiGameInfoResponseDTO.getGameName());
game.setCreateBy("system");
game.setPlatformCode(GamePlatforms.PP.getCode());
game.setPlatformType(platformType);
game.setGameId(StringUtils.addSuffix(GamePlatforms.PP.getCode(), apiGameInfoResponseDTO.getGameID()));
List<NameInfo> nameInfos = new ArrayList<>();
nameInfos.add(new NameInfo(apiGameInfoResponseDTO.getGameName(), "en-US"));
game.setNameInfo(nameInfos);
gameService.insertGame(game);
} else {
game = games.get(0);
}
apiGameInfoResponseDTO.setSystemGameId(game.getGameId());
apiGameInfoResponseDTO.setSystemPlatformType(platformType);
}
gRedisCache.deleteObject(CacheConstants.PP_GAMES);
gRedisCache.setCacheList(CacheConstants.PP_GAMES, gameList.getGameList());
gRedisCache.expire(CacheConstants.PP_GAMES, 5L, TimeUnit.HOURS);
} else {
throw new BaseException(gameList.getDescription());
}
return CacheConstants.PP_GAMES;
}
/**
* id
*
* @param transactionIdRequestDTO iddto
* @return {@link String }
*/
@Override
public String getTransactionId(TransactionIdRequestDTO transactionIdRequestDTO) {
return GamePlatforms.PP.getCode() + IdUtil.getSnowflakeNextIdStr();
}
/**
* id
*
* @param exchangeTransferMoneyRequestDTO moeny dto
* @return {@link Long }
*/
@Override
@Transactional
public Long exchangeTransferByAgentId(ExchangeTransferMoneyRequestDTO exchangeTransferMoneyRequestDTO) {
log.info("GamesKMServiceImpl [exchangeTransferByAgentId] 请求参数 {}", exchangeTransferMoneyRequestDTO);
GameExchangeMoney exchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(exchangeTransferMoneyRequestDTO.getGameExchangeId());
BigDecimal amount = exchangeTransferMoneyRequestDTO.getAmount();
if (TransferType.ALL.getCode().equals(exchangeTransferMoneyRequestDTO.getTransferType())) {
// 获取第三方钱包余额
MemberInfoRequestDTO gamesBaseRequestDTO = MemberInfoRequestDTO.builder()
.accounts(exchangeTransferMoneyRequestDTO.getAccount())
.agentId(exchangeTransferMoneyRequestDTO.getAgentId())
.currency(exchangeTransferMoneyRequestDTO.getCurrency())
.agentKey(exchangeTransferMoneyRequestDTO.getAgentKey())
.build();
amount = this.getMemberInfo(gamesBaseRequestDTO).getBalance().negate();
}
Map<String, Object> params = new TreeMap<>();
params.put("secureLogin", exchangeTransferMoneyRequestDTO.getAgentId());
params.put("externalPlayerId", exchangeTransferMoneyRequestDTO.getAccount());
params.put("externalTransactionId", exchangeTransferMoneyRequestDTO.getTransactionId());
params.put("amount", amount);
String query = JsonUtil.mapToQueryString(params);
exchangeTransferMoneyRequestDTO.setQuery(query);
String key = this.getKey(exchangeTransferMoneyRequestDTO);
params.put("hash", key);
PPTransactionResponse transactionResponse = ppClient.exchangeTransfer(params);
//判断是否转移成功
if (this.getIsSuccess(transactionResponse.getError())) {
amount = amount.abs();
//更新数据
exchangeMoney.setBalance(amount);
exchangeMoney.setCoinBefore(NumberUtil.sub(amount, transactionResponse.getBalance()).abs());
exchangeMoney.setCoinAfter(transactionResponse.getBalance());
exchangeMoney.setCurrencyBefore(exchangeMoney.getCoinBefore());
exchangeMoney.setCurrencyAfter(exchangeMoney.getCoinAfter());
exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode());
exchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode());
exchangeMoney.setPartyTransactionId(transactionResponse.getTransactionId());
gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney);
} else {
exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode());
exchangeMoney.setStepStatus(GameExchangeStepStatus.FAILURE.getCode());
gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney);
log.error("GamesPPServiceImpl [exchangeTransferByAgentId] 金额转移失败,错误代码{},错误信息{}", transactionResponse.getError(), transactionResponse.getDescription());
throw new ApiException(ErrorCode.BALANCE_TRANSFER_FAILED.getCode());
}
return exchangeMoney.getId();
}
/**
*
*
* @param exchangeTransferMoneyRequestDTO dto
* @return {@link Boolean }
*/
@Override
public ExchangeTransferStatusResponseDTO exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) {
log.info("GamesPPServiceImpl [exchangeTransferStatus] 请求参数 {}", exchangeTransferMoneyRequestDTO);
GameExchangeMoney exchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(exchangeTransferMoneyRequestDTO.getGameExchangeMoneyId());
Map<String, Object> params = new TreeMap<>();
params.put("secureLogin", exchangeTransferMoneyRequestDTO.getAgentId());
params.put("externalTransactionId", StringUtils.isEmpty(exchangeMoney.getPartyTransactionId()) ? "0" : exchangeMoney.getPartyTransactionId());
params.put("externalPlayerId", exchangeTransferMoneyRequestDTO.getOrderId());
String query = JsonUtil.mapToQueryString(params);
exchangeTransferMoneyRequestDTO.setQuery(query);
String key = this.getKey(exchangeTransferMoneyRequestDTO);
params.put("hash", key);
PPTransactionStatusResponse ppTransactionStatusResponse = ppClient.exchangeTransferStatus(params);
if (this.getIsSuccess(ppTransactionStatusResponse.getError())) {
Integer status = StatusType.IN_PROGRESS.getValue();
if ("Success".equals(ppTransactionStatusResponse.getStatus())) {
status = StatusType.SUCCESS.getValue();
} else {
status = StatusType.FAILURE.getValue();
}
return ExchangeTransferStatusResponseDTO.builder()
.statusType(status)
.balance(ppTransactionStatusResponse.getAmount())
.coinAfter(ppTransactionStatusResponse.getBalance())
.build();
} else {
log.error("GamesPPServiceImpl [exchangeTransferStatus] 金额转移确认失败,错误代码{},错误信息{}", ppTransactionStatusResponse.getError(), ppTransactionStatusResponse.getDescription());
return ExchangeTransferStatusResponseDTO.builder()
.statusType(StatusType.FAILURE.getValue())
.build();
}
}
/**
*
*
* @param betRecordByTimeDTO dto
* @return {@link List }<{@link GameBettingDetails }>
*/
@Override
public Boolean getBetRecordByTime(BetRecordByTimeDTO betRecordByTimeDTO) {
Long timepoint = gRedisCache.getCacheObject(CacheConstants.PP_TIME_POINT);
if (ObjectUtils.isEmpty(timepoint)) {
timepoint = betRecordByTimeDTO.getStartTime();
}
//请求参数
log.info("GamesPPServiceImpl [getBetRecordByTime] 请求参数 {}", betRecordByTimeDTO);
Map<String, Object> params = new LinkedHashMap<>();
params.put("login", betRecordByTimeDTO.getAgentId());
params.put("password", betRecordByTimeDTO.getAgentKey());
params.put("timepoint", timepoint);
String result = ppClient.getBetRecordByTime(JsonUtil.mapToQueryString(params));
this.batchInsert(PPGameRoundRecord.parse(result), betRecordByTimeDTO);
//重新保存最新的时间
String[] lines = result.split("\n");
timepoint = Long.parseLong(lines[0].replace("timepoint=", ""));
gRedisCache.setCacheObject(CacheConstants.PP_TIME_POINT, timepoint);
return Boolean.TRUE;
}
/**
*
*
* @param betRecordByTimeDTO dto
* @return {@link Boolean }
*/
@Override
public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) {
//请求参数
log.info("GamesPPServiceImpl [getBetRecordByHistoryTime] 请求参数 {}", betRecordByTimeDTO);
long timepoint = betRecordByTimeDTO.getStartTime();
while (timepoint < betRecordByTimeDTO.getEndTime()) {
Map<String, Object> params = new LinkedHashMap<>();
params.put("login", betRecordByTimeDTO.getAgentId());
params.put("password", betRecordByTimeDTO.getAgentKey());
params.put("timepoint", timepoint);
String result = ppClient.getBetRecordByTime(JsonUtil.mapToQueryString(params));
this.batchInsert(PPGameRoundRecord.parse(result), betRecordByTimeDTO);
//重新保存最新的时间
String[] lines = result.split("\n");
timepoint = Long.parseLong(lines[0].replace("timepoint=", ""));
}
return Boolean.TRUE;
}
/**
*
*
* @param createFreeSpinRequest
* @return {@link Boolean }
*/
@Override
public Boolean createFreeSpin(CreateFreeSpinRequestDTO createFreeSpinRequest) {
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
}
/**
*
*
* @param getGameDetailRequestDTO dto
* @return {@link GetGameDetailResponseDTO }
*/
@Override
public GetGameDetailResponseDTO getGameDetail(GetGameDetailRequestDTO getGameDetailRequestDTO) {
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
}
/**
*
*
* @param kickMemberRequestDTO dto
* @return {@link Boolean }
*/
@Override
public Boolean kickMember(KickMemberRequestDTO kickMemberRequestDTO) {
log.info("GamesPPServiceImpl [kickMember] 请求参数 {}", kickMemberRequestDTO);
Map<String, Object> params = new TreeMap<>();
params.put("secureLogin", kickMemberRequestDTO.getAgentId());
params.put("externalPlayerId", kickMemberRequestDTO.getAccount());
String query = JsonUtil.mapToQueryString(params);
kickMemberRequestDTO.setQuery(query);
String key = this.getKey(kickMemberRequestDTO);
params.put("hash", key);
PPResponse kickMember = ppClient.kickMember(params);
if (this.getIsSuccess(kickMember.getError())) {
return Boolean.TRUE;
} else {
throw new ApiException(ErrorCode.KICK_OUT_AILED.getCode());
}
}
/**
*
*
* @param kickMemberAllDTO dto
* @return {@link Boolean }
*/
@Override
public Boolean kickMemberAll(KickMemberAllDTO kickMemberAllDTO) {
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
}
/**
* 使
*
* @param getFreeSpinDashflowRequestDTO dashflowdto
* @return {@link List }<{@link GameFreeRecord }>
*/
@Override
public List<GameFreeRecord> getFreeSpinDashflow(GetFreeSpinDashflowRequestDTO getFreeSpinDashflowRequestDTO) {
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
}
/**
*
*
* @param cancelFreeSpinRequestDTO
* @return {@link Boolean }
*/
@Override
public Boolean cancelFreeSpin(CancelFreeSpinRequestDTO cancelFreeSpinRequestDTO) {
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
}
@Override
public GameDemoLoginResponseDTO gameDemoLogin(GameDemoLoginRequestDTO gameDemoLoginRequestDTO) {
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
}
/**
*
*/
private synchronized void batchInsert(List<PPGameRoundRecord> report, GamesBaseRequestDTO gamesBaseRequestDTO) {
List<GameBettingDetails> gameBettingDetails = new ArrayList<>();
List<String> wagersIds = new ArrayList<>();
//数据转化
for (PPGameRoundRecord bean : report) {
GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder().platform(gamesBaseRequestDTO.getVendor()).data(bean).build());
if (!ObjectUtils.isEmpty(bettingDetails)) {
bettingDetails.setId(IdUtil.getSnowflakeNextId());
gameBettingDetails.add(bettingDetails);
}
wagersIds.add(String.valueOf(bean.getPlaySessionID()));
}
if (!CollectionUtils.isEmpty(gameBettingDetails)) {
//查询重复数据id
List<String> removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds, GamePlatforms.PP.getCode());
//用steam流清除list中与wagersIds集合相同的数据
gameBettingDetails = gameBettingDetails.stream()
.filter(detail -> !removeWagersIds.contains(detail.getWagersId()))
.collect(Collectors.toList());
if (!CollectionUtils.isEmpty(gameBettingDetails)) {
gameBettingDetailsService.batchInsert(gameBettingDetails);
}
}
}
/**
*
*
* @param gamesDataBuildDTO
* @return {@link GameBettingDetails }
*/
@Override
public GameBettingDetails dataBuild(GamesDataBuildDTO gamesDataBuildDTO) {
//转化类
PPGameRoundRecord resultBean = (PPGameRoundRecord) gamesDataBuildDTO.getData();
Member member = memberService.selectMemberByGameAccount(resultBean.getExtPlayerID());
if (ObjectUtils.isEmpty(member)) {
return null;
}
List<PPGameResponseDTO.CasinoGame> gamesDatas = gRedisCache.getCacheList(CacheConstants.PP_GAMES);
Map<String, PPGameResponseDTO.CasinoGame> dataDTOMap = gamesDatas.stream().collect(Collectors.toMap(
PPGameResponseDTO.CasinoGame::getGameID,
e -> e,
(existing, replacement) -> existing
));
PPGameResponseDTO.CasinoGame casinoGame = dataDTOMap.get(resultBean.getGameID());
BigDecimal payoffAmount = NumberUtil.sub(resultBean.getWin(), resultBean.getBet());
Integer gameStatus = GameStatus.FLAT.getCode();
if (payoffAmount.compareTo(BigDecimal.ZERO) > 0) {
gameStatus = GameStatus.WIN.getCode();
} else if (payoffAmount.compareTo(BigDecimal.ZERO) < 0) {
gameStatus = GameStatus.FAIL.getCode();
}
//数据构造
GameBettingDetails gameBettingDetails = GameBettingDetails.builder()
.tenantKey(member.getTenantKey())
//保存我们的币种id
.currencyCode(gamesDataBuildDTO.getPlatform().getOurCurrency(resultBean.getCurrency()))
.memberId(member.getId())
.gameCode(resultBean.getGameID())
.gameType(casinoGame.getSystemPlatformType())
.platformCode(GamePlatforms.PP.getInfo())
.gameId(casinoGame.getSystemGameId())
.gameName(casinoGame.getGameName())
.gameStatus(gameStatus)
.gameStatusType("F".equals(resultBean.getType()) ? 19 : 1)
.gameCurrencyCode(resultBean.getCurrency())
.account(resultBean.getExtPlayerID())
.wagersId(resultBean.getPlaySessionID())
.wagersTime(resultBean.getStartDate())
.betAmount(resultBean.getBet())
.payoffTime(resultBean.getEndDate())
.payoffAmount(payoffAmount.abs())
.settlementTime(resultBean.getEndDate())
.turnover(resultBean.getBet())
.settlementStatus(SettlementStatusEnum.COMPLETED.getCode())
.build();
gameBettingDetails.setCreateBy(Constants.SYSTEM);
gameBettingDetails.setCreateTime(DateUtils.getNowDate());
return gameBettingDetails;
}
}

View File

@ -0,0 +1,105 @@
package com.ff.game.api.pt.client;
import com.ff.base.exception.base.BaseException;
import org.apache.commons.io.IOUtils;
import javax.net.ssl.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
public class PTClient {
/**
* POST SSL
*
* @param url URL
* @param entityKey X_ENTITY_KEY
* @param params 使 URL
* @return
* @throws Exception
*/
public static String sendPostRequest(String url, String entityKey,String pwd, String params) {
try {
// 加载证书
KeyStore ks = KeyStore.getInstance("PKCS12");
Path path = Paths.get(System.getProperty("user.dir"), "pp_p12");
URL fileURL = new File(path.resolve("AGDRA_UAT.p12").toAbsolutePath().toString()).toURI().toURL();
File file = new File(fileURL.getFile());
try (FileInputStream fis = new FileInputStream(file)) {
ks.load(fis, pwd.toCharArray());
}
// 创建 KeyManagerFactory
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, pwd.toCharArray());
KeyManager[] kms = kmf.getKeyManagers();
// 创建 TrustManager 来绕过证书验证
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
// 创建 SSLContext
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kms, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
// 设置 HostnameVerifier 跳过主机名验证
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
// 创建请求连接
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestMethod("POST");
// 设置请求头
connection.setRequestProperty("X_ENTITY_KEY", entityKey);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
// 启用输入输出流
connection.setDoOutput(true);
// 写入请求体
try (OutputStream os = connection.getOutputStream()) {
byte[] input = params.getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}
// 获取响应
try (InputStream response = connection.getInputStream()) {
return IOUtils.toString(response, StandardCharsets.UTF_8);
} catch (IOException e) {
// 处理错误响应
try (InputStream errorStream = connection.getErrorStream()) {
return IOUtils.toString(errorStream, StandardCharsets.UTF_8);
}
} finally {
connection.disconnect();
}
} catch (Exception e) {
e.printStackTrace();
throw new BaseException("请求失败");
}
}
}

View File

@ -0,0 +1,27 @@
package com.ff.game.api.pt.dto;
import lombok.Data;
/**
* ptcreate
*
* @author shi
* @date 2025/03/29
*/
@Data
public class PTCreatePlayerResponse {
private Result result;
@Data
public static class Result {
private String result;
private String playername;
private String password;
private ExecutionTime executiontime;
@Data
public static class ExecutionTime {
private String webapi;
}
}
}

View File

@ -0,0 +1,51 @@
package com.ff.game.api.pt.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
* ptlogindto
*
* @author shi
* @date 2025/03/29
*/
@Data
public class PTMemberInfoResponse {
/**
*
*/
@JsonProperty("result")
private Result result;
@Data
public static class Result {
/**
*
*/
@JsonProperty("playername")
private String playerName;
/**
*
*/
@JsonProperty("bonusbalance")
private BigDecimal bonusBalance;
/**
*
*/
@JsonProperty("rc_balance")
private BigDecimal balance;
/**
* ISO
*/
@JsonProperty("currencycode")
private String currencyCode;
}
}

View File

@ -0,0 +1,20 @@
package com.ff.game.api.pt.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
/**
* pt线
*
* @author shi
* @date 2025/03/29
*/
@Data
public class PTMemberOnlineResponse {
/**
* 1 0
*/
@JsonProperty("result")
private Integer result;
}

View File

@ -0,0 +1,391 @@
package com.ff.game.api.pt.impl;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson2.JSON;
import com.ff.base.constant.CacheConstants;
import com.ff.base.constant.Constants;
import com.ff.base.core.redis.RedisCache;
import com.ff.base.enums.*;
import com.ff.base.exception.base.ApiException;
import com.ff.base.exception.base.BaseException;
import com.ff.base.system.service.ISysConfigService;
import com.ff.base.utils.DateUtils;
import com.ff.base.utils.JsonUtil;
import com.ff.base.utils.uuid.IdUtils;
import com.ff.config.KeyConfig;
import com.ff.game.api.IGamesService;
import com.ff.game.api.pt.client.PTClient;
import com.ff.game.api.pt.dto.*;
import com.ff.game.api.request.*;
import com.ff.game.api.xk.dto.*;
import com.ff.game.domain.*;
import com.ff.game.service.*;
import com.ff.member.domain.Member;
import com.ff.member.service.IMemberService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* PT impl
*
* @author shi
* @date 2024/11/12
*/
@Service("PTService")
@Slf4j
public class GamesPTServiceImpl implements IGamesService {
@Resource
private ISysConfigService configService;
@Resource
private RedisCache redisCache;
@Resource
private IGameExchangeMoneyService gameExchangeMoneyService;
@Resource
private IGameService gameService;
@Resource
private IMemberService memberService;
@Resource
private IGameFreeRecordService gameFreeRecordService;
@Resource
private KeyConfig keyConfig;
@Resource
private IGameBettingDetailsService gameBettingDetailsService;
/**
*
*
* @param errorCode
* @return {@link Boolean }
*/
private Boolean getIsSuccess(Integer errorCode) {
return 0 == errorCode;
}
/**
*
*
* @param url
* @param params
* @param gamesBaseRequestDTO dto
* @return {@link String }
*/
private String send(String url, Map<String, Object> params, GamesBaseRequestDTO gamesBaseRequestDTO) {
return PTClient.sendPostRequest(gamesBaseRequestDTO.getVendor().getUrlInfo().getUrl() + url, gamesBaseRequestDTO.getAgentKey(), gamesBaseRequestDTO.getAgentId(), JsonUtil.mapToQueryString(params));
}
/**
*
*
* @param createMemberRequestDTO dto
* @return {@link Boolean }
*/
@Override
public Boolean createMember(CreateMemberRequestDTO createMemberRequestDTO) {
log.info("GamesPTServiceImpl [createMember] 请求参数 {}", createMemberRequestDTO);
Map<String, Object> params = new LinkedHashMap<>();
params.put("playername", createMemberRequestDTO.getAccount());
params.put("currency", createMemberRequestDTO.getCurrency());
params.put("password", createMemberRequestDTO.getKeyInfo().getPassword());
String result = this.send("/player/create/", params, createMemberRequestDTO);
PTCreatePlayerResponse ptCreatePlayerResponse = JSON.parseObject(result, PTCreatePlayerResponse.class);
if (ObjectUtils.isEmpty(ptCreatePlayerResponse.getResult())) {
return Boolean.FALSE;
}
//判断是否获取成功
return Boolean.TRUE;
}
/**
*
*
* @param memberInfoRequestDTO dto
* @return {@link MemberInfoResponseDTO }
*/
@Override
public MemberInfoResponseDTO getMemberInfo(MemberInfoRequestDTO memberInfoRequestDTO) {
log.info("GamesPTServiceImpl [getMemberInfo] 请求参数 {}", memberInfoRequestDTO);
Map<String, Object> params = new LinkedHashMap<>();
params.put("playername", memberInfoRequestDTO.getAccounts());
String result = this.send("/player/balance/", params, memberInfoRequestDTO);
PTMemberInfoResponse memberInfoResponse = JSON.parseObject(result, PTMemberInfoResponse.class);
if (ObjectUtils.isEmpty(memberInfoResponse.getResult())) {
throw new ApiException(ErrorCode.ACCOUNT_NOT_EXIST.getCode());
}
PTMemberInfoResponse.Result results = memberInfoResponse.getResult();
//查询在线状态
params = new LinkedHashMap<>();
params.put("playername", memberInfoRequestDTO.getAccounts());
result = this.send("/player/online/", params, memberInfoRequestDTO);
PTMemberOnlineResponse ptMemberOnlineResponse = JSON.parseObject(result, PTMemberOnlineResponse.class);
//判断是否获取成功
return MemberInfoResponseDTO.builder().balance(results.getBalance()).status(ptMemberOnlineResponse.getResult() == 1 ? GameMemberStatus.ONLINE.getCode() : GameMemberStatus.OFFLINE.getCode()).build();
}
/**
*
*
* @param gamesLogin
* @return {@link String }
*/
@Override
public String loginWithoutRedirect(GamesLogin gamesLogin) {
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
}
/**
*
*
* @param gamesBaseRequestDTO dto
* @return {@link String }
*/
@Transactional
@Override
public String getGameList(GamesBaseRequestDTO gamesBaseRequestDTO) {
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
}
@Override
public String getTransactionId(TransactionIdRequestDTO transactionIdRequestDTO) {
return "";
}
/**
* id
*
* @param exchangeTransferMoneyRequestDTO moeny dto
* @return {@link Long }
*/
@Override
@Transactional
public Long exchangeTransferByAgentId(ExchangeTransferMoneyRequestDTO exchangeTransferMoneyRequestDTO) {
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
}
/**
*
*
* @param exchangeTransferMoneyRequestDTO dto
* @return {@link Boolean }
*/
@Override
public ExchangeTransferStatusResponseDTO exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) {
return null;
}
/**
*
*
* @param betRecordByTimeDTO dto
* @return {@link List }<{@link GameBettingDetails }>
*/
@Override
public Boolean getBetRecordByTime(BetRecordByTimeDTO betRecordByTimeDTO) {
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
}
/**
*
*
* @param betRecordByTimeDTO dto
* @return {@link Boolean }
*/
@Override
public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) {
return null;
}
/**
*
*
* @param createFreeSpinRequest
* @return {@link Boolean }
*/
@Override
public Boolean createFreeSpin(CreateFreeSpinRequestDTO createFreeSpinRequest) {
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
}
/**
*
*
* @param getGameDetailRequestDTO dto
* @return {@link GetGameDetailResponseDTO }
*/
@Override
public GetGameDetailResponseDTO getGameDetail(GetGameDetailRequestDTO getGameDetailRequestDTO) {
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
}
/**
*
*
* @param kickMemberRequestDTO dto
* @return {@link Boolean }
*/
@Override
public Boolean kickMember(KickMemberRequestDTO kickMemberRequestDTO) {
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
}
/**
*
*
* @param kickMemberAllDTO dto
* @return {@link Boolean }
*/
@Override
public Boolean kickMemberAll(KickMemberAllDTO kickMemberAllDTO) {
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
}
/**
* 使
*
* @param getFreeSpinDashflowRequestDTO dashflowdto
* @return {@link List }<{@link GameFreeRecord }>
*/
@Override
public List<GameFreeRecord> getFreeSpinDashflow(GetFreeSpinDashflowRequestDTO getFreeSpinDashflowRequestDTO) {
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
}
/**
*
*
* @param cancelFreeSpinRequestDTO
* @return {@link Boolean }
*/
@Override
public Boolean cancelFreeSpin(CancelFreeSpinRequestDTO cancelFreeSpinRequestDTO) {
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
}
@Override
public GameDemoLoginResponseDTO gameDemoLogin(GameDemoLoginRequestDTO gameDemoLoginRequestDTO) {
return null;
}
/**
*
*
* @param xkBetRecordResponseDTO xkdto
*/
private void batchInsert(XKBetRecordResponseDTO xkBetRecordResponseDTO) {
List<GameBettingDetails> gameBettingDetails = new ArrayList<>();
List<String> wagersIds = new ArrayList<>();
//数据组装
XKBetRecordResponseDTO.DataBean dataBean = xkBetRecordResponseDTO.getData();
//数据转化
for (XKBetRecordResponseDTO.DataBean.ResultBean bean : dataBean.getResult()) {
GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder().data(bean).build());
if (!ObjectUtils.isEmpty(bettingDetails)) {
bettingDetails.setId(IdUtil.getSnowflakeNextId());
gameBettingDetails.add(bettingDetails);
}
wagersIds.add(String.valueOf(bean.getWagersId()));
}
if (!CollectionUtils.isEmpty(gameBettingDetails)) {
//查询重复数据id
List<String> removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds,GamePlatforms.PT.getCode());
//用steam流清除list中与wagersIds集合相同的数据
gameBettingDetails = gameBettingDetails.stream()
.filter(detail -> !removeWagersIds.contains(detail.getWagersId()))
.collect(Collectors.toList());
if (!CollectionUtils.isEmpty(gameBettingDetails)) {
gameBettingDetailsService.batchInsert(gameBettingDetails);
}
}
}
/**
*
*
* @param gamesDataBuildDTO
* @return {@link GameBettingDetails }
*/
@Override
public GameBettingDetails dataBuild(GamesDataBuildDTO gamesDataBuildDTO) {
//转化类
XKBetRecordResponseDTO.DataBean.ResultBean resultBean = (XKBetRecordResponseDTO.DataBean.ResultBean) gamesDataBuildDTO.getData();
Member member = memberService.selectMemberByGameAccount(resultBean.getAccount());
if (ObjectUtils.isEmpty(member)) {
return null;
}
List<XKGamesDTO.DataBean> gamesDatas = redisCache.getCacheList(CacheConstants.XK_GAMES);
Map<String, XKGamesDTO.DataBean> dataDTOMap = gamesDatas.stream().collect(Collectors.toMap(XKGamesDTO.DataBean::getGameId, e -> e));
XKGamesDTO.DataBean gamesDataDTO = dataDTOMap.get(resultBean.getGameId());
BigDecimal payoffAmount = BigDecimal.ZERO;
if (GameStatus.WIN.getCode().equals(resultBean.getStatus())) {
payoffAmount = NumberUtil.sub(resultBean.getPayoffAmount(), resultBean.getTurnover());
} else if (GameStatus.FAIL.getCode().equals(resultBean.getStatus())) {
payoffAmount = NumberUtil.sub(resultBean.getPayoffAmount(), resultBean.getTurnover()).negate();
}
//数据构造
GameBettingDetails gameBettingDetails = GameBettingDetails.builder()
.tenantKey(member.getTenantKey())
//保存我们的币种id
.currencyCode(gamesDataBuildDTO.getSystemCurrencyCode())
.memberId(member.getId())
.gameCode(resultBean.getGameId())
.gameType(XKGameType.findSystemByCode(resultBean.getGameCategoryId()))
.platformCode(GamePlatforms.XK.getCode())
.gameId(gamesDataDTO.getSystemGameId())
.gameName(gamesDataDTO.getName())
.gameStatus(resultBean.getStatus())
.gameStatusType(resultBean.getType())
.gameCurrencyCode(resultBean.getAgentId())
.account(String.valueOf(resultBean.getAccount()))
.wagersId(String.valueOf(resultBean.getWagersId()))
.wagersTime(resultBean.getWagersTime())
.betAmount(resultBean.getBetAmount().abs())
.payoffTime(resultBean.getPayoffTime())
.payoffAmount(payoffAmount)
.settlementTime(resultBean.getSettlementTime())
.turnover(resultBean.getTurnover())
.orderNo(String.valueOf(resultBean.getRoundIndex()))
.settlementStatus(SettlementStatusEnum.COMPLETED.getCode())
.build();
gameBettingDetails.setCreateBy(Constants.SYSTEM);
gameBettingDetails.setCreateTime(DateUtils.getNowDate());
return gameBettingDetails;
}
}

View File

@ -99,9 +99,4 @@ public class GameExchangeMoney extends BaseEntity
* GameExchangeStepStatus
*/
private Integer stepStatus;
/**
* 使 id
*/
private String partyTransactionId;
}

View File

@ -61,9 +61,7 @@ public class PlatformServiceImpl implements IPlatformService {
Object key = entry.getKey();
// 设置数据源类型
DynamicDataSourceContextHolder.setDataSourceType(key.toString());
Platform platform = new Platform();
platform.setStopStatus(Boolean.FALSE);
List<Platform> list = selectList(platform);
List<Platform> list = selectList(new Platform());
for (Platform pp : list) {
redisCache.setCacheObject(getCacheKey(pp.getPlatformCode()), pp);
}

View File

@ -55,7 +55,7 @@ public class MemberServiceImpl implements IMemberService {
@Override
public synchronized String getMemberGameAccount(String platformCode,String tenantSn) {
String gameAccount = null;
if (GamePlatforms.DG.getInfo().equals(platformCode) || GamePlatforms.KM.getInfo().equals(platformCode)) {
if (GamePlatforms.DG.getInfo().equals(platformCode) || GamePlatforms.KM.getInfo().equals(platformCode)||GamePlatforms.PT.getInfo().equals(platformCode)) {
tenantSn=tenantSn.toUpperCase();
do {
gameAccount = RandomGeneratorUtils.generateRandomAccountUpper()+tenantSn;

View File

@ -0,0 +1,30 @@
Bag Attributes
localKeyID: A1 EA B4 FE 75 13 56 C4 8D 9A 45 97 9A 09 52 C5 3A 80 52 AF
Key Attributes: <No Attributes>
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAyX3zP0OnqujQYoCnXMr18fNnigqPNfW5o3UeafPlbk9+2iNW
vrdjIbvOxnHA7kca6PfUtWcws3HrFmt0KsfBRbhKh7Kf1z6c0+U2TtpMl923nhzf
FLTrB239joAwsBnkRjEhcqWqYWZXEnhLohH4x1eCYuWFQB2dWMJxaGRawa+llJ9e
rkyYWKzyCIkSBAtA/fxND4SqB7WftXzrPFf9z1P92nm8iKiEJm5xOM14b8bsAeyr
sTcXLfgH4NHBzOSghWeGlDLDF/Cpra1cB5zL6JjS8dEGHJ1XKZxJgwIlTOL6Q5O5
ElhCT4QnBhLxFHBC+2kmtgaRHZRyrcnXliU/6QIDAQABAoIBAQCL5qe+hXslcAFA
Y5PRGhsqo5aAglRtYvBCTk+PwYjLzuaFD4RrZ2mtQnmPz+vlhflpSKqoSb3G2pIg
PvupuIi5n/wfvCa/jPnXJo9OsMP9rjSP0/wQpI2L2xLyno8vtsqI8hQHRn/GoQhU
CrJ5FYFm55vgjvy2R9m4h0m28fcSA2YfQWZspsWf0VjzxNfYWJAu1PcR1oyzscMA
ts8fc/4+GIeSQlfl4B2wb0ZJk+z3Z/Cn+9Dzi3uCZrlm65qBAvQFuhPZzdr3odwE
9GLHAkFBU47XKDsBZNEesowstci57A5EL8EBrHiXX1hDc4bVhGbdq/nnrUcIV2T5
4/6sS7MBAoGBAPvl0GAgr73VG8N6a2dgH3tbeJk9qDHxc76he0+lvWi6mWYW56eN
MMTUYK8PJHKIio/im8vD2HMDKNKcIH0JYWfm8uGd1ZgsrCOwYuC/o9hiEim583e7
TuoibhB0oUqWiJrOlc5QS1AgZjUi0ZL/fDfFgYfZ1/Zb/l0sKq4F385fAoGBAMzF
/Wje6UNA09U7ftEAiwyGOJj1EfIWoEQrcdsxaRZrX9OnEgZakUqRtfT4i404faoq
OjsddQ9iyRxZAenHTrbzK2i4mszp2GVdsZgcjrAswUJcpDR97ov5HiOjEg+7dPiR
zrhunylAQ9fElZAUK4NHFNrhAJ1Vwh2wvRa/vYa3AoGAeq0Qj1A75nqb+9Zp6j2A
94WztQW3HSOXF/by4/Y2yYNe474x8YKshp9busXoHTNsL+jPsSvfBRw7zF4m4F4q
Jvztun0wodzXtMXZUdVjCSWx7MpXzS7WnuZHrhHu3zFys9n6UTD/jLVKsYQUhr+Q
EmVI0Q2BxMRGm7+/xWKs/YcCgYEAnc4iqNPIPXzTAquT4mshvSgeq7mI9+B55673
Ui00yAM9WPWSjXT0LNw3ti5oFQ+owB9EutPLp2zAgWkScV+YCKNDG7PQEARSMGPQ
/eFcEOaclJCiNpWp5RK5KEt+GsOitABhp34QiBCvd7NWcy8oDUYVC0yEVbuGGa1f
Ow3Od+cCgYEA9G7ZGzkA5pNKE0fKzdmN4+oPYB8BCnSPKf6z2Xvu8hDR4CuSlbXN
Nps4zrhs8v4u+2J+IXOgRgKJd+Culg4AdY5hcSrdbWOmebxWVEC+VzaXvTQTUF62
hSmlSD/hyKIxKMGbx6h74gQ86d7NgPHVefZPrYiAXPXHAj79WKA23LA=
-----END RSA PRIVATE KEY-----

Binary file not shown.

View File

@ -0,0 +1,36 @@
Bag Attributes
localKeyID: A1 EA B4 FE 75 13 56 C4 8D 9A 45 97 9A 09 52 C5 3A 80 52 AF
subject=/CN=KioskAPI ASIA-SHARED-PROD-UMS CRXUATTLE (CHG0110705)/O=Playtech Estonia/OU=Infra Operations/C=EE/ST=Tartumaa/L=Tartu/DC=2228591
issuer=/CN=Playtech Production API Auth CA - G1/OU=Security/O=Playtech PLC/C=IM
-----BEGIN CERTIFICATE-----
MIIFjDCCBHSgAwIBAgIINW/4hQUOxmkwDQYJKoZIhvcNAQELBQAwZjEtMCsGA1UE
AwwkUGxheXRlY2ggUHJvZHVjdGlvbiBBUEkgQXV0aCBDQSAtIEcxMREwDwYDVQQL
DAhTZWN1cml0eTEVMBMGA1UECgwMUGxheXRlY2ggUExDMQswCQYDVQQGEwJJTTAe
Fw0yNDA0MzAwMDAwMDBaFw0yNjAxMDUxMDAwMDBaMIG+MT0wOwYDVQQDDDRLaW9z
a0FQSSBBU0lBLVNIQVJFRC1QUk9ELVVNUyBDUlhVQVRUTEUgKENIRzAxMTA3MDUp
MRkwFwYDVQQKDBBQbGF5dGVjaCBFc3RvbmlhMRkwFwYDVQQLDBBJbmZyYSBPcGVy
YXRpb25zMQswCQYDVQQGEwJFRTERMA8GA1UECAwIVGFydHVtYWExDjAMBgNVBAcM
BVRhcnR1MRcwFQYKCZImiZPyLGQBGRYHMjIyODU5MTCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBAMl98z9Dp6ro0GKAp1zK9fHzZ4oKjzX1uaN1Hmnz5W5P
ftojVr63YyG7zsZxwO5HGuj31LVnMLNx6xZrdCrHwUW4Soeyn9c+nNPlNk7aTJfd
t54c3xS06wdt/Y6AMLAZ5EYxIXKlqmFmVxJ4S6IR+MdXgmLlhUAdnVjCcWhkWsGv
pZSfXq5MmFis8giJEgQLQP38TQ+Eqge1n7V86zxX/c9T/dp5vIiohCZucTjNeG/G
7AHsq7E3Fy34B+DRwczkoIVnhpQywxfwqa2tXAecy+iY0vHRBhydVymcSYMCJUzi
+kOTuRJYQk+EJwYS8RRwQvtpJrYGkR2Ucq3J15YlP+kCAwEAAaOCAeMwggHfMA4G
A1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAjAdBgNVHQ4EFgQUxW8U
91f9h5D0CJ89mAQ7STEigjQwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBQbE05j
cuUE9DORnQEwzjPKZ8dAoDCCAWgGA1UdHwSCAV8wggFbMIG4oEqgSIZGaHR0cDov
L3BraS5pbmZyYS5wdGVjL2NybC9QbGF5dGVjaF9Qcm9kdWN0aW9uX0FQSV9BdXRo
X0NBXy1fRzEuY3JsLmRlcqJqpGgwZjEtMCsGA1UEAwwkUGxheXRlY2ggUHJvZHVj
dGlvbiBBUEkgQXV0aCBDQSAtIEcxMREwDwYDVQQLDAhTZWN1cml0eTEVMBMGA1UE
CgwMUGxheXRlY2ggUExDMQswCQYDVQQGEwJJTTCBnaCBmqCBl4aBlGxkYXA6Ly9w
cm9kbGRhcC5pbmZyYS5wdGVjOjM4OS9jbj1QbGF5dGVjaCUyMFByb2R1Y3Rpb24l
MjBBUEklMjBBdXRoJTIwQ0ElMjAtJTIwRzEsb3U9Q1JMLG91PVBLSSxkYz1wbGF5
dGVjaCxkYz1jb20/Y2VydGlmaWNhdGVSZXZvY2F0aW9uTGlzdDtiaW5hcnkwDQYJ
KoZIhvcNAQELBQADggEBABozAUwJAIKNrjh/ZMjyq52u346zDjLP4imY+1ZGRPJG
8SY2GYosPOIpfYdFJ3UatC/EsNwr9XsKUsJ5MD0SjNgx3MgyPjCBWw6xunn1E9WX
OquLn74t49NP+He/oDTWGImWeaHIJcMwgU6TD6/ZPUuUhdeZCjDMYmJUuxmrZkL1
iNSu1jMqcIHCtuiKDbluuaUQtk+5eUFilJnJIQUVqqBr/XXG7GfQ6fq/c1GjJNqM
mgfEJEwPWdjeS5ynBSCE0AnocziyKpJg4RXPiXKgDVDfAscgF93JmnEIYYDtm+oU
0XhJZg1dKZtpOAM2IfCndP8VKHY0RTD2QZDg56p+9Kc=
-----END CERTIFICATE-----

View File

@ -0,0 +1 @@
A6ZCfYoycq5tDa5p