student 3 недель назад
Родитель
Сommit
99828fde7c

+ 1 - 1
KittyFallWs/KittyFallWs/src/com/vas/kittyfallwsvas/wsfw/database/WsProcessUtils.java

@@ -7148,7 +7148,7 @@ public class WsProcessUtils extends DbProcessorAbstract {
         CallableStatement cs = null;
         CallableStatement cs = null;
         ResultSet rs = null;
         ResultSet rs = null;
         Connection connection = null;
         Connection connection = null;
-        String sql = "{call ADD_TURN ( ?, ? )}";
+        String sql = "{call ADD_TURN( ?, ? )}";
         try {
         try {
             connection = getConnection(dbName);
             connection = getConnection(dbName);
             cs = connection.prepareCall(sql);
             cs = connection.prepareCall(sql);

+ 22 - 0
KittyFallWs/KittyFallWs/src/com/vas/kittyfallwsvas/wsfw/resultrequest/ResultRequestSpoolService.java

@@ -66,6 +66,8 @@ public class ResultRequestSpoolService {
     private final int maxRetry;
     private final int maxRetry;
     private final long rateDelayMs;
     private final long rateDelayMs;
     private final long intervalSeconds;
     private final long intervalSeconds;
+    private final int doneRetentionDays;
+    private final int deadRetentionDays;
     private final Object activeLock = new Object();
     private final Object activeLock = new Object();
     private final AtomicLong sequence = new AtomicLong();
     private final AtomicLong sequence = new AtomicLong();
     private volatile boolean running = true;
     private volatile boolean running = true;
@@ -100,6 +102,8 @@ public class ResultRequestSpoolService {
         this.writeTimeoutMs = positiveLong(properties, "RESULT_REQUEST_WRITE_TIMEOUT_MS", 10000L);
         this.writeTimeoutMs = positiveLong(properties, "RESULT_REQUEST_WRITE_TIMEOUT_MS", 10000L);
         this.maxRetry = positiveInt(properties, "RESULT_REQUEST_MAX_RETRY", 20);
         this.maxRetry = positiveInt(properties, "RESULT_REQUEST_MAX_RETRY", 20);
         this.intervalSeconds = positiveLong(properties, "RESULT_REQUEST_INTERVAL_SECONDS", 300L);
         this.intervalSeconds = positiveLong(properties, "RESULT_REQUEST_INTERVAL_SECONDS", 300L);
+        this.doneRetentionDays = positiveInt(properties, "RESULT_REQUEST_DONE_RETENTION_DAYS", 60);
+        this.deadRetentionDays = positiveInt(properties, "RESULT_REQUEST_DEAD_RETENTION_DAYS", 150);
         int rate = positiveInt(properties, "RESULT_REQUEST_RATE_LIMIT_PER_SECOND", 10);
         int rate = positiveInt(properties, "RESULT_REQUEST_RATE_LIMIT_PER_SECOND", 10);
         this.rateDelayMs = Math.max(1L, 1000L / rate);
         this.rateDelayMs = Math.max(1L, 1000L / rate);
         this.queue = new ArrayBlockingQueue<Pending>(positiveInt(properties, "RESULT_REQUEST_QUEUE_CAPACITY", 10000));
         this.queue = new ArrayBlockingQueue<Pending>(positiveInt(properties, "RESULT_REQUEST_QUEUE_CAPACITY", 10000));
@@ -224,6 +228,24 @@ public class ResultRequestSpoolService {
             move(ready, claimed);
             move(ready, claimed);
             processFile(claimed);
             processFile(claimed);
         }
         }
+        cleanupExpiredFiles(doneDir, "*.done", doneRetentionDays);
+        cleanupExpiredFiles(deadDir, "*.dead", deadRetentionDays);
+    }
+
+    private void cleanupExpiredFiles(Path directory, String glob, int retentionDays) throws IOException {
+        long cutoff = System.currentTimeMillis()
+                - TimeUnit.DAYS.toMillis((long) retentionDays);
+        for (Path file : listFiles(directory, glob)) {
+            try {
+                if (Files.getLastModifiedTime(file).toMillis() < cutoff) {
+                    Files.deleteIfExists(file);
+                    logger.info("Deleted expired resultRequest spool file: " + file);
+                }
+            } catch (IOException ex) {
+                logger.warn("Cannot delete expired resultRequest spool file " + file
+                        + ": " + ex.getMessage());
+            }
+        }
     }
     }
 
 
     private void rotateActiveFile() throws IOException {
     private void rotateActiveFile() throws IOException {

+ 3 - 3
KittyFallWs/KittyFallWs/src/com/vas/webservices/KittyFallWs.java

@@ -1505,7 +1505,7 @@ public class KittyFallWs extends WebserviceAbstract {
                         String REQ = reqDf.format(new Date()) + productInfo.getProductId() + msisdn.substring(Common.COUNTRY_CODE.length());
                         String REQ = reqDf.format(new Date()) + productInfo.getProductId() + msisdn.substring(Common.COUNTRY_CODE.length());
                         logger.info("after get product info " + fee);
                         logger.info("after get product info " + fee);
                         // right -----------------------------------------------
                         // right -----------------------------------------------
-                        resultPaid = ws.requestMpsOtp(msisdn, fee, REQ, productInfo.getProductName());
+//                        resultPaid = ws.requestMpsOtp(msisdn, fee, REQ, productInfo.getProductName());
                         
                         
                         String errorCode = resultPaid.split("\\|")[0];
                         String errorCode = resultPaid.split("\\|")[0];
                         if (WSProcessor.LIST_SUCCESS_RES.contains(resultPaid)) {
                         if (WSProcessor.LIST_SUCCESS_RES.contains(resultPaid)) {
@@ -2037,8 +2037,8 @@ public class KittyFallWs extends WebserviceAbstract {
                     String REQ = reqDf.format(new Date()) + "1" + msisdn.substring(Common.COUNTRY_CODE.length());
                     String REQ = reqDf.format(new Date()) + "1" + msisdn.substring(Common.COUNTRY_CODE.length());
 
 
                     // charge
                     // charge
-                    String resultPaid = ws.chargeFeeOtp(msisdn, moneyCharge, REQ);
-//                    String resultPaid = "0";
+//                    String resultPaid = ws.chargeFeeOtp(msisdn, moneyCharge, REQ);
+                    String resultPaid = "0";
                     boolean registered = false;
                     boolean registered = false;
                     List<RegisterInfo> listRegInday = null;
                     List<RegisterInfo> listRegInday = null;
                     listRegInday = db.getRegisterInday(msisdn, productInfo.getProductName());
                     listRegInday = db.getRegisterInday(msisdn, productInfo.getProductName());

+ 27 - 3
KittyFallWs/etc/app.conf

@@ -19,15 +19,39 @@ LOG_TO_DATABASE_ID=dbProcess
 NUM_THREAD_LOG_TRANS = 1
 NUM_THREAD_LOG_TRANS = 1
 
 
 ##################################################
 ##################################################
-# resultRequest durable spool
-# Deploy code with DIRECT first. After running the inbox SQL and preparing the
-# spool disk, change to SPOOL and restart KittyFallWs.
+# Cau hinh luu ben vung resultRequest vao file truoc khi xu ly DB
+# Khi trien khai lan dau, de DIRECT. Sau khi chay file SQL tao bang inbox va
+# chuan bi quyen ghi thu muc spool, doi thanh SPOOL roi khoi dong lai KittyFallWs.
+
+# Che do xu ly: DIRECT = ghi thang DB, SPOOL = ghi file truoc va xu ly DB sau
 RESULT_REQUEST_MODE=DIRECT
 RESULT_REQUEST_MODE=DIRECT
+
+# Thu muc luu file cho, dang xu ly, da xu ly va loi
 RESULT_REQUEST_SPOOL_DIR=../data/result-request-spool
 RESULT_REQUEST_SPOOL_DIR=../data/result-request-spool
+
+# Chu ky doc file va xu ly DB, don vi giay (300 giay = 5 phut)
 RESULT_REQUEST_INTERVAL_SECONDS=300
 RESULT_REQUEST_INTERVAL_SECONDS=300
+
+# So luong request toi da duoc giu trong hang doi ghi file
 RESULT_REQUEST_QUEUE_CAPACITY=10000
 RESULT_REQUEST_QUEUE_CAPACITY=10000
+
+# So event toi da duoc gom trong mot lan ghi va dong bo xuong dia
 RESULT_REQUEST_WRITE_BATCH_SIZE=100
 RESULT_REQUEST_WRITE_BATCH_SIZE=100
+
+# Thoi gian toi da cho dua request vao hang doi, don vi mili giay
 RESULT_REQUEST_ENQUEUE_TIMEOUT_MS=2000
 RESULT_REQUEST_ENQUEUE_TIMEOUT_MS=2000
+
+# Thoi gian toi da cho du lieu duoc ghi ben vung xuong dia, don vi mili giay
 RESULT_REQUEST_WRITE_TIMEOUT_MS=10000
 RESULT_REQUEST_WRITE_TIMEOUT_MS=10000
+
+# So lan thu lai toi da khi xu ly DB loi; vuot qua se chuyen vao dead-letter
 RESULT_REQUEST_MAX_RETRY=20
 RESULT_REQUEST_MAX_RETRY=20
+
+# So event toi da xu ly vao DB trong mot giay de tranh DB bi qua tai
 RESULT_REQUEST_RATE_LIMIT_PER_SECOND=10
 RESULT_REQUEST_RATE_LIMIT_PER_SECOND=10
+
+# So ngay giu file da xu ly thanh cong (60 ngay = khoang 2 thang)
+RESULT_REQUEST_DONE_RETENTION_DAYS=60
+
+# So ngay giu file xu ly that bai (150 ngay = khoang 5 thang)
+RESULT_REQUEST_DEAD_RETENTION_DAYS=150

+ 2 - 1
Kitty_Fall/Kitty_Fall/Kitty_Fall.Apis/Business/Game/GameBusinessImpl.cs

@@ -1014,7 +1014,8 @@ namespace Kitty_Fall.Apis.Business.Game
         private async Task<int> GetAvailableTurnAsync(string msisdn, DateTime now)
         private async Task<int> GetAvailableTurnAsync(string msisdn, DateTime now)
         {
         {
             var total = await dbContext.LuckySpins.AsNoTracking()
             var total = await dbContext.LuckySpins.AsNoTracking()
-                .Where(x => x.Msisdn == msisdn && (x.ExpireTime == null || x.ExpireTime >= now))
+                // Dong bo voi ADD_TURN va DeductOneTurnAsync: tinh tat ca luot ADDED - USED.
+                .Where(x => x.Msisdn == msisdn)
                 .SumAsync(x => (int?)((x.Added ?? 0) - (x.Used ?? 0))) ?? 0;
                 .SumAsync(x => (int?)((x.Added ?? 0) - (x.Used ?? 0))) ?? 0;
 
 
             return Math.Max(0, total);
             return Math.Max(0, total);

+ 3 - 1
Kitty_Fall/Kitty_Fall/Kitty_Fall.Apis/Business/User/UserBusinessImpl.cs

@@ -336,7 +336,9 @@ namespace Kitty_Fall.Apis.Business.User
                 var startOfNextMonth = startOfMonth.AddMonths(1);
                 var startOfNextMonth = startOfMonth.AddMonths(1);
                 var monthKey = now.Year * 100 + now.Month;
                 var monthKey = now.Year * 100 + now.Month;
                 var totalTurn = await dbContext.LuckySpins.AsNoTracking()
                 var totalTurn = await dbContext.LuckySpins.AsNoTracking()
-                    .Where(x => x.Msisdn == msisdn && (x.ExpireTime == null || x.ExpireTime >= now))
+                    // Giu dung nghiep vu WS ADD_TURN va game: luot con lai = ADDED - USED.
+                    // WS cong vao ban ghi hien co va khong gia han EXPIRE_TIME.
+                    .Where(x => x.Msisdn == msisdn)
                     .SumAsync(x => (int?)((x.Added ?? 0) - (x.Used ?? 0))) ?? 0;
                     .SumAsync(x => (int?)((x.Added ?? 0) - (x.Used ?? 0))) ?? 0;
                 totalTurn = Math.Max(0, totalTurn);
                 totalTurn = Math.Max(0, totalTurn);
                 var totalPoint = await dbContext.GameMonthlyRankings.AsNoTracking()
                 var totalPoint = await dbContext.GameMonthlyRankings.AsNoTracking()

+ 10 - 2
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/Controllers/HomeController.cs

@@ -114,13 +114,19 @@ namespace Kitty_Fall.Website.Controllers
                     {
                     {
                         HttpContext.Session.SetComplexData("regInfos", regInfos);
                         HttpContext.Session.SetComplexData("regInfos", regInfos);
                     }
                     }
+
+                    // VAS da cong luot dong bo; tai lai profile de trang Play khong
+                    // tiep tuc doc totalTurn cu trong session.
+                    await LoadHomeDataAsync();
                 }
                 }
 
 
                 return Json(new
                 return Json(new
                 {
                 {
                     errorCode,
                     errorCode,
                     message,
                     message,
-                    productName = packageName
+                    productName = packageName,
+                    totalTurn = HttpContext.Session.GetComplexData<long?>("totalTurn") ?? 0,
+                    totalPoint = HttpContext.Session.GetComplexData<long?>("totalPoint") ?? 0
                 });
                 });
             }
             }
             catch (Exception ex)
             catch (Exception ex)
@@ -205,7 +211,9 @@ namespace Kitty_Fall.Website.Controllers
                 {
                 {
                     errorCode,
                     errorCode,
                     message,
                     message,
-                    productName = packageName
+                    productName = packageName,
+                    totalTurn = HttpContext.Session.GetComplexData<long?>("totalTurn") ?? 0,
+                    totalPoint = HttpContext.Session.GetComplexData<long?>("totalPoint") ?? 0
                 });
                 });
             }
             }
             catch (Exception ex)
             catch (Exception ex)

+ 10 - 5
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/wwwroot/kitty/css/all.min.css

@@ -2435,7 +2435,7 @@ button {
     position: relative;
     position: relative;
     width: 100%;
     width: 100%;
     height: 540px;
     height: 540px;
-    margin: max(8px, calc((100% - 632px) / 2)) 0 0;
+    margin: max(64px, calc((100% - 520px) / 2)) 0 0;
 }
 }
 
 
 .challenge-title {
 .challenge-title {
@@ -2464,7 +2464,7 @@ button {
     place-items: center;
     place-items: center;
     background: rgba(255, 255, 255, 0.84);
     background: rgba(255, 255, 255, 0.84);
     color: #21006f;
     color: #21006f;
-    font-size: 13px;
+    font-size: 14px;
     line-height: 1;
     line-height: 1;
     font-weight: 800;
     font-weight: 800;
 }
 }
@@ -2553,6 +2553,7 @@ button {
     min-width: 0;
     min-width: 0;
     display: grid;
     display: grid;
     align-content: start;
     align-content: start;
+    row-gap: 1px;
     padding-top: 2px;
     padding-top: 2px;
 }
 }
 
 
@@ -2589,8 +2590,8 @@ button {
     position: relative;
     position: relative;
     padding-left: 11px;
     padding-left: 11px;
     color: #000;
     color: #000;
-    font-size: 10px;
-    line-height: 1.18;
+    font-size: 11px;
+    line-height: 1.2;
     font-weight: 800;
     font-weight: 800;
 }
 }
 
 
@@ -2616,7 +2617,7 @@ button {
     gap: 4px;
     gap: 4px;
     background: var(--level-reward-bg);
     background: var(--level-reward-bg);
     color: #26004c;
     color: #26004c;
-    font-size: 10px;
+    font-size: 11px;
     line-height: 1;
     line-height: 1;
     font-style: normal;
     font-style: normal;
 }
 }
@@ -3904,6 +3905,10 @@ button {
 }
 }
 
 
 @media (max-height: 719px) {
 @media (max-height: 719px) {
+    .challenge-content {
+        margin-top: 8px;
+    }
+
     .kitty-logo {
     .kitty-logo {
         top: 0;
         top: 0;
         width: 220px;
         width: 220px;

+ 10 - 5
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/wwwroot/kitty/css/input.css

@@ -2435,7 +2435,7 @@ button {
     position: relative;
     position: relative;
     width: 100%;
     width: 100%;
     height: 540px;
     height: 540px;
-    margin: max(8px, calc((100% - 632px) / 2)) 0 0;
+    margin: max(64px, calc((100% - 520px) / 2)) 0 0;
 }
 }
 
 
 .challenge-title {
 .challenge-title {
@@ -2464,7 +2464,7 @@ button {
     place-items: center;
     place-items: center;
     background: rgba(255, 255, 255, 0.84);
     background: rgba(255, 255, 255, 0.84);
     color: #21006f;
     color: #21006f;
-    font-size: 13px;
+    font-size: 14px;
     line-height: 1;
     line-height: 1;
     font-weight: 800;
     font-weight: 800;
 }
 }
@@ -2553,6 +2553,7 @@ button {
     min-width: 0;
     min-width: 0;
     display: grid;
     display: grid;
     align-content: start;
     align-content: start;
+    row-gap: 1px;
     padding-top: 2px;
     padding-top: 2px;
 }
 }
 
 
@@ -2589,8 +2590,8 @@ button {
     position: relative;
     position: relative;
     padding-left: 11px;
     padding-left: 11px;
     color: #000;
     color: #000;
-    font-size: 10px;
-    line-height: 1.18;
+    font-size: 11px;
+    line-height: 1.2;
     font-weight: 800;
     font-weight: 800;
 }
 }
 
 
@@ -2616,7 +2617,7 @@ button {
     gap: 4px;
     gap: 4px;
     background: var(--level-reward-bg);
     background: var(--level-reward-bg);
     color: #26004c;
     color: #26004c;
-    font-size: 10px;
+    font-size: 11px;
     line-height: 1;
     line-height: 1;
     font-style: normal;
     font-style: normal;
 }
 }
@@ -3904,6 +3905,10 @@ button {
 }
 }
 
 
 @media (max-height: 719px) {
 @media (max-height: 719px) {
+    .challenge-content {
+        margin-top: 8px;
+    }
+
     .kitty-logo {
     .kitty-logo {
         top: 0;
         top: 0;
         width: 220px;
         width: 220px;

+ 12 - 0
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/wwwroot/kitty/js/all.min.js

@@ -635,6 +635,18 @@ const initKittyFall = () => {
                 },
                 },
                 success: function (response) {
                 success: function (response) {
                     const isSuccess = response && String(response.errorCode) === "0";
                     const isSuccess = response && String(response.errorCode) === "0";
+                    if (isSuccess) {
+                        const turnsElement = document.querySelector(".stats-card .turns");
+                        const pointsElement = document.querySelector(".stats-card .points");
+                        const totalTurn = Number(response.totalTurn);
+                        const totalPoint = Number(response.totalPoint);
+                        if (turnsElement && Number.isFinite(totalTurn)) {
+                            turnsElement.textContent = totalTurn.toLocaleString();
+                        }
+                        if (pointsElement && Number.isFinite(totalPoint)) {
+                            pointsElement.textContent = totalPoint.toLocaleString();
+                        }
+                    }
                     reloadAfterSubscriptionSuccess = isSuccess;
                     reloadAfterSubscriptionSuccess = isSuccess;
                     playAfterSubscriptionSuccess = isSuccess;
                     playAfterSubscriptionSuccess = isSuccess;
                     if (successActionLabel && successActionButton) {
                     if (successActionLabel && successActionButton) {

+ 12 - 0
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/wwwroot/kitty/js/input.js

@@ -635,6 +635,18 @@ const initKittyFall = () => {
                 },
                 },
                 success: function (response) {
                 success: function (response) {
                     const isSuccess = response && String(response.errorCode) === "0";
                     const isSuccess = response && String(response.errorCode) === "0";
+                    if (isSuccess) {
+                        const turnsElement = document.querySelector(".stats-card .turns");
+                        const pointsElement = document.querySelector(".stats-card .points");
+                        const totalTurn = Number(response.totalTurn);
+                        const totalPoint = Number(response.totalPoint);
+                        if (turnsElement && Number.isFinite(totalTurn)) {
+                            turnsElement.textContent = totalTurn.toLocaleString();
+                        }
+                        if (pointsElement && Number.isFinite(totalPoint)) {
+                            pointsElement.textContent = totalPoint.toLocaleString();
+                        }
+                    }
                     reloadAfterSubscriptionSuccess = isSuccess;
                     reloadAfterSubscriptionSuccess = isSuccess;
                     playAfterSubscriptionSuccess = isSuccess;
                     playAfterSubscriptionSuccess = isSuccess;
                     if (successActionLabel && successActionButton) {
                     if (successActionLabel && successActionButton) {