mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-11-02 11:15:03 +03:00
fix(sub): convert far expiry dates to Jalali in constant time
gregorianToJalali walked the calendar one month at a time from a 2024
reference, so an expiry near the int64 limit (a node reports expiries
unchecked) cost seconds of CPU on every subscription fetch that renders
{{JALALI_EXPIRE_DATE}}. Jalali leap years repeat every 33 years, so
whole 33-year blocks are skipped before the walk.
This commit is contained in:
@@ -423,6 +423,13 @@ func gregorianToJalali(gy, gm, gd int) (jy, jm, jd int) {
|
||||
refJDN := 2460311
|
||||
days := int64(jdn - refJDN)
|
||||
jy, jm, jd = 1402, 10, 11
|
||||
// Leap years follow y % 33, so whole 33-year blocks are skipped: a node-reported expiry
|
||||
// can lie hundreds of millions of years away, and the walk below goes month by month.
|
||||
const jalaliCycleDays = 33*365 + 8
|
||||
if cycles := days / jalaliCycleDays; cycles != 0 {
|
||||
jy += int(cycles) * 33
|
||||
days -= cycles * jalaliCycleDays
|
||||
}
|
||||
|
||||
// Walk forward
|
||||
for days > 0 {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/xray"
|
||||
@@ -529,6 +530,8 @@ func TestGregorianToJalali(t *testing.T) {
|
||||
{2024, 1, 1, 1402, 10, 11},
|
||||
{2000, 3, 20, 1379, 1, 1},
|
||||
{1979, 2, 11, 1357, 11, 22},
|
||||
// 2124-01-01 lies three 33-year blocks and a year past the reference.
|
||||
{2124, 1, 1, 1502, 10, 11},
|
||||
}
|
||||
for _, c := range cases {
|
||||
jy, jm, jd := gregorianToJalali(c.gy, c.gm, c.gd)
|
||||
@@ -539,6 +542,19 @@ func TestGregorianToJalali(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// A node reports the expiry the remark renders, so a date hundreds of millions of years
|
||||
// out must not walk the calendar month by month on every subscription fetch.
|
||||
func TestGregorianToJalaliFarDatesTakeConstantTime(t *testing.T) {
|
||||
start := time.Now()
|
||||
if jy, _, _ := gregorianToJalali(292000000, 1, 1); jy < 290000000 {
|
||||
t.Fatalf("year 292000000 converted to Jalali year %d", jy)
|
||||
}
|
||||
_, _, _ = gregorianToJalali(-292000000, 1, 1)
|
||||
if took := time.Since(start); took > 100*time.Millisecond {
|
||||
t.Fatalf("converting far dates took %v", took)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJalaliExpireDateLabel(t *testing.T) {
|
||||
if got := jalaliExpireDateLabel(0); got != "" {
|
||||
t.Errorf("jalaliExpireDateLabel(0) = %q, want empty", got)
|
||||
|
||||
Reference in New Issue
Block a user