diff --git a/aaa.json b/aaa.json deleted file mode 100644 index b19a5cc..0000000 --- a/aaa.json +++ /dev/null @@ -1,9026 +0,0 @@ -[ - { - "order_no": "2026050618470000056716454", - "out_order_no": "202605061846524739782853070", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778064420, - "payment_time": null, - "notify_time": null, - "client_ip": "116.21.64.115", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618451400056726661", - "out_order_no": "202605061845077970995909162", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778064314, - "payment_time": 1778064338, - "notify_time": 1778064339, - "client_ip": "180.158.188.11", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618420500056726501", - "out_order_no": "202605061840493114312657316", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778064125, - "payment_time": 1778064168, - "notify_time": 1778064169, - "client_ip": "117.143.120.195", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618410700056718063", - "out_order_no": "202605061841021059758735786", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778064067, - "payment_time": 1778064084, - "notify_time": 1778064084, - "client_ip": "36.21.179.2", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618404400056723339", - "out_order_no": "20260506184037427047477742", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778064044, - "payment_time": null, - "notify_time": null, - "client_ip": "36.21.179.2", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618381200056719720", - "out_order_no": "202605061837564994058249776", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778063892, - "payment_time": 1778063920, - "notify_time": 1778063920, - "client_ip": "117.129.57.157", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618380000056715960", - "out_order_no": "202605061837448642261598961", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778063880, - "payment_time": 1778063919, - "notify_time": 1778063920, - "client_ip": "39.144.171.107", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618363300056727220", - "out_order_no": "202605061836243712465283450", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778063793, - "payment_time": 1778063823, - "notify_time": 1778063823, - "client_ip": "117.143.179.174", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618351300056710610", - "out_order_no": "20260506183503249417040346", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778063713, - "payment_time": 1778063736, - "notify_time": 1778063737, - "client_ip": "182.136.188.79", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618335300056711548", - "out_order_no": "20260506183342844281901840", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778063633, - "payment_time": 1778063656, - "notify_time": 1778063657, - "client_ip": "114.227.161.83", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618325900056714286", - "out_order_no": "202605061832395858147923158", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778063579, - "payment_time": 1778063644, - "notify_time": 1778063644, - "client_ip": "120.229.31.145", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618305400056724917", - "out_order_no": "202605061830423226760128135", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778063454, - "payment_time": 1778063478, - "notify_time": 1778063479, - "client_ip": "39.64.242.53", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618273900056714877", - "out_order_no": "202605061827322543800463309", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778063259, - "payment_time": 1778063349, - "notify_time": 1778063349, - "client_ip": "64.176.59.89", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618253500056715353", - "out_order_no": "202605061825275987223733779", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778063135, - "payment_time": 1778063155, - "notify_time": 1778063156, - "client_ip": "121.236.254.138", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618252000056719416", - "out_order_no": "202605061825118620277576486", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778063120, - "payment_time": 1778063138, - "notify_time": 1778063139, - "client_ip": "120.204.171.17", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618243200056712115", - "out_order_no": "20260506182406165171729522", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778063072, - "payment_time": 1778063090, - "notify_time": 1778063091, - "client_ip": "49.74.228.86", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618214400056719612", - "out_order_no": "202605061821365041954575441", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778062904, - "payment_time": 1778062925, - "notify_time": 1778062926, - "client_ip": "39.144.124.52", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618214000056724524", - "out_order_no": "202605061821222643692320118", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778062900, - "payment_time": 1778062967, - "notify_time": 1778062968, - "client_ip": "111.49.159.186", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618194500056716384", - "out_order_no": "202605061819197240792129222", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778062785, - "payment_time": null, - "notify_time": null, - "client_ip": "64.176.59.89", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618150500056724529", - "out_order_no": "202605061814523504834862611", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778062505, - "payment_time": 1778062551, - "notify_time": 1778062551, - "client_ip": "182.148.17.190", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618134500056713805", - "out_order_no": "20260506181334440535760416", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778062425, - "payment_time": 1778062459, - "notify_time": 1778062460, - "client_ip": "171.116.204.199", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618113000056716355", - "out_order_no": "202605061811178961664145645", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778062290, - "payment_time": 1778062309, - "notify_time": 1778062310, - "client_ip": "218.26.169.230", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618073100056727371", - "out_order_no": "202605061806401508235481288", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778062051, - "payment_time": 1778062083, - "notify_time": 1778062084, - "client_ip": "120.235.45.30", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618071200056717310", - "out_order_no": "202605061807033087885893298", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778062032, - "payment_time": 1778062068, - "notify_time": 1778062069, - "client_ip": "117.174.234.12", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618051300056719781", - "out_order_no": "20260506180506724269915984", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778061913, - "payment_time": 1778061987, - "notify_time": 1778061988, - "client_ip": "221.219.100.119", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618051200056719038", - "out_order_no": "202605061804478565141485049", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778061912, - "payment_time": null, - "notify_time": null, - "client_ip": "61.166.207.179", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618032700056714361", - "out_order_no": "202605061803148814691474766", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778061807, - "payment_time": 1778061850, - "notify_time": 1778061851, - "client_ip": "223.104.122.108", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618010000056720329", - "out_order_no": "202605061800538767484274735", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778061660, - "payment_time": 1778061702, - "notify_time": 1778061703, - "client_ip": "183.129.78.178", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050618002100056715732", - "out_order_no": "202605061800139933592813484", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778061621, - "payment_time": 1778061663, - "notify_time": 1778061664, - "client_ip": "106.224.141.249", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050617574100056714983", - "out_order_no": "202605061757315798269592565", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778061461, - "payment_time": 1778061561, - "notify_time": 1778061562, - "client_ip": "111.55.8.4", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050617573700056721646", - "out_order_no": "202605061757277372292405051", - "order_money": 315, - "user_money": 303.03, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778061457, - "payment_time": null, - "notify_time": null, - "client_ip": "175.172.150.189", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050617573200056710049", - "out_order_no": "20260506175726392989886216", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778061452, - "payment_time": null, - "notify_time": null, - "client_ip": "106.224.141.249", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050617532400056713417", - "out_order_no": "202605061753073023390214008", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778061204, - "payment_time": null, - "notify_time": null, - "client_ip": "111.55.8.4", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050617532200056713097", - "out_order_no": "202605061753033529492968587", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778061202, - "payment_time": null, - "notify_time": null, - "client_ip": "119.125.127.178", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050617505100056722681", - "out_order_no": "202605061750404518153957693", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778061051, - "payment_time": 1778061090, - "notify_time": 1778061091, - "client_ip": "42.86.50.41", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050617465900056714173", - "out_order_no": "202605061746406106633464602", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778060819, - "payment_time": null, - "notify_time": null, - "client_ip": "111.55.12.84", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050617441600056726701", - "out_order_no": "20260506174408375565592311", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778060656, - "payment_time": 1778060705, - "notify_time": 1778060706, - "client_ip": "122.239.126.67", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050617422600056724245", - "out_order_no": "202605061742144424128849304", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778060546, - "payment_time": 1778060580, - "notify_time": 1778060581, - "client_ip": "38.110.231.5", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050617420100056710479", - "out_order_no": "202605061741523976466645247", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778060521, - "payment_time": null, - "notify_time": null, - "client_ip": "111.197.70.152", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050617413100056786340", - "out_order_no": "202605061741145942617381228", - "order_money": 90.93, - "user_money": 0, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778060491, - "payment_time": null, - "notify_time": null, - "client_ip": "111.197.70.152", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050617392400056729127", - "out_order_no": "202605061739072215852109012", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778060364, - "payment_time": 1778060430, - "notify_time": 1778060431, - "client_ip": "10.158.40.167", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050617390600056724669", - "out_order_no": "202605061738546031547106298", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778060346, - "payment_time": 1778060400, - "notify_time": 1778060401, - "client_ip": "117.136.90.210", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050617343300056723486", - "out_order_no": "202605061734158181533230372", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778060073, - "payment_time": 1778060094, - "notify_time": 1778060095, - "client_ip": "119.102.127.220", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050617331600056728688", - "out_order_no": "202605061733095352618454577", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778059996, - "payment_time": 1778060035, - "notify_time": 1778060036, - "client_ip": "58.63.146.120", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616545200056727808", - "out_order_no": "202605061654399518631511786", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778057692, - "payment_time": 1778057726, - "notify_time": 1778057726, - "client_ip": "162.213.0.3", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616495300056719018", - "out_order_no": "202605061649464947513562100", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778057393, - "payment_time": 1778057413, - "notify_time": 1778057413, - "client_ip": "223.104.163.5", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616480900056781258", - "out_order_no": "202605061647569080629897358", - "order_money": 19.53, - "user_money": 0, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778057289, - "payment_time": null, - "notify_time": null, - "client_ip": "210.37.40.213", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616452900056716416", - "out_order_no": "202605061645205622449689885", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778057129, - "payment_time": 1778057152, - "notify_time": 1778057152, - "client_ip": "27.187.83.149", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616450600056717740", - "out_order_no": "202605061644588337703034520", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778057106, - "payment_time": 1778057126, - "notify_time": 1778057126, - "client_ip": "222.76.193.59", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616410600056729532", - "out_order_no": "202605061640572452020182288", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778056866, - "payment_time": null, - "notify_time": null, - "client_ip": "223.104.207.27", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616344400056728642", - "out_order_no": "202605061634314311980636851", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778056484, - "payment_time": 1778056515, - "notify_time": 1778056515, - "client_ip": "223.104.163.55", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616341700056729870", - "out_order_no": "202605061634058088915946981", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778056457, - "payment_time": 1778056476, - "notify_time": 1778056478, - "client_ip": "27.36.105.157", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616332300056722174", - "out_order_no": "202605061633059072165472788", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778056403, - "payment_time": null, - "notify_time": null, - "client_ip": "10.89.206.233", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616325000056712639", - "out_order_no": "202605061632391333931485821", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778056370, - "payment_time": 1778056394, - "notify_time": 1778056394, - "client_ip": "183.131.226.103", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616292100056711061", - "out_order_no": "202605061629084580738462219", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778056161, - "payment_time": 1778056206, - "notify_time": 1778056206, - "client_ip": "223.104.248.137", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616275700056719197", - "out_order_no": "202605061627415271122416155", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778056077, - "payment_time": null, - "notify_time": null, - "client_ip": "223.104.248.137", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616240600056716544", - "out_order_no": "202605061623575508394640773", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778055846, - "payment_time": 1778055901, - "notify_time": 1778055901, - "client_ip": "101.24.119.74", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616221500056710855", - "out_order_no": "202605061622055665662254875", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778055735, - "payment_time": 1778055756, - "notify_time": 1778055756, - "client_ip": "223.160.113.188", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616220700056713143", - "out_order_no": "20260506162143323119589417", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778055727, - "payment_time": 1778055771, - "notify_time": 1778055771, - "client_ip": "114.229.19.190", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616201400056717231", - "out_order_no": "202605061619575670347421320", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778055614, - "payment_time": 1778055651, - "notify_time": 1778055652, - "client_ip": "59.61.177.181", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616184200056719797", - "out_order_no": "202605061618325945312130096", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778055522, - "payment_time": 1778055572, - "notify_time": 1778055573, - "client_ip": "101.206.179.179", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616171900056717810", - "out_order_no": "202605061617048654828894937", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778055439, - "payment_time": null, - "notify_time": null, - "client_ip": "222.90.214.215", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616164800056722837", - "out_order_no": "20260506161641928058618031", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778055408, - "payment_time": 1778055434, - "notify_time": 1778055434, - "client_ip": "39.144.249.144", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616153800056726384", - "out_order_no": "202605061615303329458711113", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778055338, - "payment_time": 1778055367, - "notify_time": 1778055367, - "client_ip": "117.143.45.62", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616152200056714767", - "out_order_no": "202605061615144160616138012", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778055322, - "payment_time": 1778055341, - "notify_time": 1778055342, - "client_ip": "223.246.186.217", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616142500056723852", - "out_order_no": "202605061613446831943212446", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778055265, - "payment_time": 1778055311, - "notify_time": 1778055311, - "client_ip": "1.62.252.61", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616141600056718734", - "out_order_no": "202605061613599619914096800", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778055256, - "payment_time": 1778055299, - "notify_time": 1778055300, - "client_ip": "171.214.199.30", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616135100056718766", - "out_order_no": "202605061613354555458778563", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778055231, - "payment_time": 1778055258, - "notify_time": 1778055258, - "client_ip": "111.19.56.251", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616110400056718354", - "out_order_no": "202605061610594111505671957", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778055064, - "payment_time": 1778055083, - "notify_time": 1778055083, - "client_ip": "112.41.76.61", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616104400056718444", - "out_order_no": "202605061610385174827168034", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778055044, - "payment_time": null, - "notify_time": null, - "client_ip": "112.41.76.61", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616100000056717180", - "out_order_no": "202605061609445977115056332", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778055000, - "payment_time": 1778055021, - "notify_time": 1778055021, - "client_ip": "122.243.161.189", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616093300056710087", - "out_order_no": "202605061609259859463704127", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778054973, - "payment_time": null, - "notify_time": null, - "client_ip": "112.41.76.61", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616073100056710019", - "out_order_no": "202605061607211801495284617", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778054851, - "payment_time": 1778054873, - "notify_time": 1778054873, - "client_ip": "210.22.144.189", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616061400056714559", - "out_order_no": "202605061606051803731013865", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778054774, - "payment_time": null, - "notify_time": null, - "client_ip": "101.230.149.69", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616053500056724377", - "out_order_no": "202605061605179656371205042", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778054735, - "payment_time": 1778054759, - "notify_time": 1778054759, - "client_ip": "124.70.231.44", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616051900056720728", - "out_order_no": "202605061605093060586798944", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778054719, - "payment_time": null, - "notify_time": null, - "client_ip": "39.144.249.144", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616030900056722391", - "out_order_no": "202605061603028260277667680", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778054589, - "payment_time": 1778054636, - "notify_time": 1778054636, - "client_ip": "120.36.214.46", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616023800056724290", - "out_order_no": "202605061602329257669017749", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778054558, - "payment_time": 1778054592, - "notify_time": 1778054592, - "client_ip": "111.14.35.109", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616022800056717243", - "out_order_no": "202605061602178042145901429", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778054548, - "payment_time": 1778054585, - "notify_time": 1778054585, - "client_ip": "223.104.54.55", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616020400056725681", - "out_order_no": "202605061601533853670140071", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778054524, - "payment_time": 1778054652, - "notify_time": 1778054653, - "client_ip": "114.230.210.91", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616004700056727030", - "out_order_no": "202605061600357407596973403", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778054447, - "payment_time": 1778054487, - "notify_time": 1778054488, - "client_ip": "114.227.31.73", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050616000500056727752", - "out_order_no": "202605061559571480521568107", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778054405, - "payment_time": 1778054420, - "notify_time": 1778054421, - "client_ip": "223.104.68.140", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615543700056711193", - "out_order_no": "202605061554256714870624357", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778054077, - "payment_time": 1778054099, - "notify_time": 1778054099, - "client_ip": "175.146.71.218", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615543600056724160", - "out_order_no": "202605061554236423715877224", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778054076, - "payment_time": 1778054113, - "notify_time": 1778054113, - "client_ip": "175.167.129.64", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615521100056712011", - "out_order_no": "202605061552047362965618443", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778053931, - "payment_time": 1778053965, - "notify_time": 1778053965, - "client_ip": "223.104.4.75", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615481900056720438", - "out_order_no": "202605061548032554200456810", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778053699, - "payment_time": 1778053733, - "notify_time": 1778053733, - "client_ip": "14.31.16.174", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615440600056723567", - "out_order_no": "202605061543556522036228210", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778053446, - "payment_time": 1778053479, - "notify_time": 1778053480, - "client_ip": "223.104.196.239", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615431400056714071", - "out_order_no": "202605061543034992900833306", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778053394, - "payment_time": null, - "notify_time": null, - "client_ip": "223.104.4.75", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615421100056726315", - "out_order_no": "202605061542025316881788900", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778053331, - "payment_time": 1778053349, - "notify_time": 1778053350, - "client_ip": "113.84.9.104", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615412600056720707", - "out_order_no": "202605061541192921207242833", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778053286, - "payment_time": 1778053303, - "notify_time": 1778053303, - "client_ip": "112.111.55.119", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615385400056720988", - "out_order_no": "202605061538383753398138336", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778053134, - "payment_time": 1778053185, - "notify_time": 1778053186, - "client_ip": "211.90.251.122", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615381400056724156", - "out_order_no": "202605061538032682975602676", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778053094, - "payment_time": 1778053116, - "notify_time": 1778053116, - "client_ip": "223.155.154.28", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615381300056712606", - "out_order_no": "202605061538006387317700824", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778053093, - "payment_time": 1778053134, - "notify_time": 1778053134, - "client_ip": "27.224.135.217", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615380000056720005", - "out_order_no": "202605061537427064222286324", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778053080, - "payment_time": 1778053127, - "notify_time": 1778053127, - "client_ip": "47.242.129.204", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615351800056787699", - "out_order_no": "202605061534033845356678382", - "order_money": 90.93, - "user_money": 0, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778052918, - "payment_time": null, - "notify_time": null, - "client_ip": "223.104.54.55", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615350100056719187", - "out_order_no": "202605061534379937783771915", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778052901, - "payment_time": null, - "notify_time": null, - "client_ip": "171.214.199.30", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615341300056717150", - "out_order_no": "202605061533538030890490500", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778052853, - "payment_time": 1778052873, - "notify_time": 1778052873, - "client_ip": "106.61.89.190", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615340100056723171", - "out_order_no": "202605061533541975816015039", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778052841, - "payment_time": 1778052874, - "notify_time": 1778052874, - "client_ip": "1.82.48.114", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615333500056725368", - "out_order_no": "202605061533232045661836610", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778052815, - "payment_time": null, - "notify_time": null, - "client_ip": "1.82.48.114", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615333100056716162", - "out_order_no": "202605061532461255375050123", - "order_money": 315, - "user_money": 306.18, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778052811, - "payment_time": 1778052869, - "notify_time": 1778052870, - "client_ip": "125.85.128.199", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615313000056712175", - "out_order_no": "202605061531189892766940944", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778052690, - "payment_time": null, - "notify_time": null, - "client_ip": "61.242.132.60", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615300600056717992", - "out_order_no": "202605061529466841089100386", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778052606, - "payment_time": 1778052647, - "notify_time": 1778052647, - "client_ip": "116.246.31.163", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615292000056710801", - "out_order_no": "202605061529099213483305196", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778052560, - "payment_time": 1778052581, - "notify_time": 1778052582, - "client_ip": "202.119.43.188", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615220900056710043", - "out_order_no": "202605061522024963101432773", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778052129, - "payment_time": 1778052152, - "notify_time": 1778052153, - "client_ip": "110.191.68.170", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615195000056722378", - "out_order_no": "202605061519362320765659108", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778051990, - "payment_time": 1778052005, - "notify_time": 1778052005, - "client_ip": "222.209.160.84", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615160700056729880", - "out_order_no": "202605061515571956690753769", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778051767, - "payment_time": 1778051792, - "notify_time": 1778051792, - "client_ip": "111.37.0.30", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615121600056716993", - "out_order_no": "20260506151211750430359249", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778051536, - "payment_time": 1778051577, - "notify_time": 1778051577, - "client_ip": "112.94.97.120", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615100000056729321", - "out_order_no": "202605061509507464603254367", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778051400, - "payment_time": null, - "notify_time": null, - "client_ip": "112.96.57.228", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050615091400056719361", - "out_order_no": "202605061509058553215240352", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778051354, - "payment_time": 1778051384, - "notify_time": 1778051384, - "client_ip": "182.33.221.253", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050614593600056717127", - "out_order_no": "202605061459162714944496701", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778050776, - "payment_time": 1778050812, - "notify_time": 1778050813, - "client_ip": "223.67.204.111", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050614581100056719423", - "out_order_no": "20260506145801960340611980", - "order_money": 315, - "user_money": 306.18, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778050691, - "payment_time": 1778050720, - "notify_time": 1778050720, - "client_ip": "183.224.71.172", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050614560500056784279", - "out_order_no": "202605061455529784314298935", - "order_money": 41.93, - "user_money": 0, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778050565, - "payment_time": null, - "notify_time": null, - "client_ip": "39.144.58.108", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050614434000056713544", - "out_order_no": "202605061443284118815142563", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778049820, - "payment_time": 1778049838, - "notify_time": 1778049838, - "client_ip": "113.206.96.14", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050614431200056724333", - "out_order_no": "202605061443066708433819106", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778049792, - "payment_time": 1778049807, - "notify_time": 1778049807, - "client_ip": "180.110.178.216", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050614272000056723235", - "out_order_no": "202605061427097791951896168", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778048840, - "payment_time": 1778048861, - "notify_time": 1778048861, - "client_ip": "10.156.136.69", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050614263000056711120", - "out_order_no": "202605061426106984362263398", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778048790, - "payment_time": 1778048831, - "notify_time": 1778048832, - "client_ip": "27.17.177.237", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050614235000056724265", - "out_order_no": "202605061423293605387806314", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778048630, - "payment_time": 1778048647, - "notify_time": 1778048648, - "client_ip": "117.129.43.114", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050614215800056716643", - "out_order_no": "202605061421471015974750367", - "order_money": 315, - "user_money": 306.18, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778048518, - "payment_time": 1778048535, - "notify_time": 1778048535, - "client_ip": "222.185.30.46", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050614143900056718549", - "out_order_no": "202605061414335353976708201", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778048079, - "payment_time": 1778048097, - "notify_time": 1778048097, - "client_ip": "180.98.64.240", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050614134500056720320", - "out_order_no": "202605061413403524494084517", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778048025, - "payment_time": 1778048056, - "notify_time": 1778048056, - "client_ip": "220.170.32.215", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050614110100056727417", - "out_order_no": "202605061410426573276009604", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778047861, - "payment_time": 1778047914, - "notify_time": 1778047914, - "client_ip": "49.93.227.125", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050614094000056714998", - "out_order_no": "202605061409283480413189779", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778047780, - "payment_time": 1778047821, - "notify_time": 1778047821, - "client_ip": "120.235.146.50", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050614015500056718338", - "out_order_no": "202605061401464962206577111", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778047315, - "payment_time": 1778047333, - "notify_time": 1778047333, - "client_ip": "115.197.24.201", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050614010400056723892", - "out_order_no": "202605061400502266984504329", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778047264, - "payment_time": 1778047278, - "notify_time": 1778047279, - "client_ip": "113.119.177.240", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050614010100056723484", - "out_order_no": "202605061400383825321145780", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778047261, - "payment_time": null, - "notify_time": null, - "client_ip": "115.197.24.201", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050614001000056726020", - "out_order_no": "202605061400044896428769599", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778047210, - "payment_time": 1778047241, - "notify_time": 1778047241, - "client_ip": "220.188.64.39", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613592500056728318", - "out_order_no": "202605061359106616223912540", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778047165, - "payment_time": 1778047189, - "notify_time": 1778047190, - "client_ip": "61.171.197.44", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613555000056712963", - "out_order_no": "202605061355398314323327839", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778046950, - "payment_time": 1778046979, - "notify_time": 1778046979, - "client_ip": "175.168.201.159", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613545300056713886", - "out_order_no": "20260506135443852877363552", - "order_money": 315, - "user_money": 306.18, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778046893, - "payment_time": 1778046917, - "notify_time": 1778046917, - "client_ip": "39.144.248.137", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613514300056724846", - "out_order_no": "202605061351327973246346894", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778046703, - "payment_time": 1778046732, - "notify_time": 1778046733, - "client_ip": "117.140.229.6", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613502000056720912", - "out_order_no": "202605061350116720627649407", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778046620, - "payment_time": 1778046651, - "notify_time": 1778046651, - "client_ip": "119.163.237.19", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613481000056725697", - "out_order_no": "20260506134758307367413916", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778046490, - "payment_time": 1778046522, - "notify_time": 1778046522, - "client_ip": "14.153.70.11", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613455600056728768", - "out_order_no": "20260506134545387730298666", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778046356, - "payment_time": 1778046414, - "notify_time": 1778046414, - "client_ip": "101.249.172.28", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613443200056722658", - "out_order_no": "202605061344242376049285251", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778046272, - "payment_time": 1778046288, - "notify_time": 1778046289, - "client_ip": "111.181.29.125", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613432600056722209", - "out_order_no": "202605061343094147378358395", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778046206, - "payment_time": 1778046251, - "notify_time": 1778046251, - "client_ip": "183.197.102.80", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613423800056725819", - "out_order_no": "202605061342281483720438448", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778046158, - "payment_time": 1778046175, - "notify_time": 1778046175, - "client_ip": "10.238.39.119", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613423300056720323", - "out_order_no": "202605061342016917599930450", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778046153, - "payment_time": 1778046177, - "notify_time": 1778046178, - "client_ip": "182.118.238.107", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613383600056714359", - "out_order_no": "202605061338227408349796286", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778045916, - "payment_time": 1778045936, - "notify_time": 1778045936, - "client_ip": "115.225.6.228", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613374100056712775", - "out_order_no": "202605061337283760342412076", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778045861, - "payment_time": null, - "notify_time": null, - "client_ip": "115.225.6.228", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613355800056720377", - "out_order_no": "20260506133554247704687085", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778045758, - "payment_time": 1778045785, - "notify_time": 1778045786, - "client_ip": "221.235.153.64", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613353900056726740", - "out_order_no": "202605061335337073600670879", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778045739, - "payment_time": null, - "notify_time": null, - "client_ip": "221.235.153.64", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613324300056724997", - "out_order_no": "202605061332134867033206459", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778045563, - "payment_time": 1778045605, - "notify_time": 1778045606, - "client_ip": "206.237.119.228", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613305300056716658", - "out_order_no": "2026050613304513738535833", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778045453, - "payment_time": 1778045470, - "notify_time": 1778045470, - "client_ip": "114.246.237.12", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613295600056727372", - "out_order_no": "202605061329078854271727598", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778045396, - "payment_time": 1778045418, - "notify_time": 1778045418, - "client_ip": "115.215.42.82", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613272800056717735", - "out_order_no": "202605061327209980620381385", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778045248, - "payment_time": 1778045269, - "notify_time": 1778045270, - "client_ip": "183.163.13.80", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613254500056711954", - "out_order_no": "202605061325108551630248698", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778045145, - "payment_time": 1778045176, - "notify_time": 1778045176, - "client_ip": "116.237.134.162", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613250600056714785", - "out_order_no": "20260506132444990433539822", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778045106, - "payment_time": 1778045131, - "notify_time": 1778045131, - "client_ip": "39.144.94.126", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613233900056717236", - "out_order_no": "202605061323203907425949091", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778045019, - "payment_time": 1778045041, - "notify_time": 1778045041, - "client_ip": "112.0.121.214", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613193000056721621", - "out_order_no": "202605061319114938447696371", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778044770, - "payment_time": 1778044787, - "notify_time": 1778044787, - "client_ip": "113.246.199.61", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613174700056726331", - "out_order_no": "202605061317412587353327109", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778044667, - "payment_time": 1778044689, - "notify_time": 1778044689, - "client_ip": "120.230.174.221", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613174100056715730", - "out_order_no": "202605061317338167062709980", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778044661, - "payment_time": 1778044692, - "notify_time": 1778044692, - "client_ip": "111.18.246.147", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613123300056717573", - "out_order_no": "202605061312217248595497708", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778044353, - "payment_time": 1778044390, - "notify_time": 1778044390, - "client_ip": "112.224.217.3", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613113500056725689", - "out_order_no": "202605061311284273410037737", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778044295, - "payment_time": 1778044330, - "notify_time": 1778044330, - "client_ip": "171.10.56.2", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613111700056725526", - "out_order_no": "202605061311074796427382129", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778044277, - "payment_time": null, - "notify_time": null, - "client_ip": "171.10.56.2", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613103000056720044", - "out_order_no": "202605061310244293199930151", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778044230, - "payment_time": 1778044256, - "notify_time": 1778044257, - "client_ip": "223.104.67.127", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613094800056719325", - "out_order_no": "202605061309356718764034566", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778044188, - "payment_time": 1778044212, - "notify_time": 1778044212, - "client_ip": "113.84.193.2", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613091300056713704", - "out_order_no": "20260506130904430053264959", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778044153, - "payment_time": 1778044178, - "notify_time": 1778044178, - "client_ip": "116.130.29.128", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613085600056725739", - "out_order_no": "20260506130849343430187474", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778044136, - "payment_time": null, - "notify_time": null, - "client_ip": "223.104.67.127", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613075200056727880", - "out_order_no": "202605061307447799519087729", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778044072, - "payment_time": 1778044140, - "notify_time": 1778044140, - "client_ip": "114.104.8.213", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613055400056714085", - "out_order_no": "202605061305412515799327348", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778043954, - "payment_time": 1778043975, - "notify_time": 1778043976, - "client_ip": "120.243.228.33", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613020500056714694", - "out_order_no": "202605061301563844523715618", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778043725, - "payment_time": 1778043781, - "notify_time": 1778043781, - "client_ip": "125.92.145.161", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050613015800056727364", - "out_order_no": "202605061301535544030569066", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778043718, - "payment_time": 1778043749, - "notify_time": 1778043750, - "client_ip": "114.230.211.173", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612581600056716337", - "out_order_no": "202605061258081672531631584", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778043496, - "payment_time": 1778043516, - "notify_time": 1778043516, - "client_ip": "139.226.115.98", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612554100056728539", - "out_order_no": "202605061255269205167361095", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778043341, - "payment_time": 1778043384, - "notify_time": 1778043384, - "client_ip": "39.144.138.97", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612531400056720441", - "out_order_no": "202605061252189999368309801", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778043194, - "payment_time": 1778043261, - "notify_time": 1778043262, - "client_ip": "140.99.130.6", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612490500056717880", - "out_order_no": "20260506124843815697760735", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778042945, - "payment_time": 1778042974, - "notify_time": 1778042975, - "client_ip": "111.36.48.37", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612483200056712146", - "out_order_no": "202605061247585673582410659", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778042912, - "payment_time": 1778042937, - "notify_time": 1778042938, - "client_ip": "175.30.144.98", - "device": "qq", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612470300056716248", - "out_order_no": "20260506124657305107725077", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778042823, - "payment_time": 1778042847, - "notify_time": 1778042848, - "client_ip": "220.205.253.4", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612464200056716272", - "out_order_no": "202605061246243686304560857", - "order_money": 315, - "user_money": 306.18, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778042802, - "payment_time": 1778042825, - "notify_time": 1778042825, - "client_ip": "180.142.153.203", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612461300056719210", - "out_order_no": "202605061245342919467320737", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778042773, - "payment_time": null, - "notify_time": null, - "client_ip": "220.205.253.4", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612424100056711649", - "out_order_no": "202605061242283527209208796", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778042561, - "payment_time": null, - "notify_time": null, - "client_ip": "171.219.160.197", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612421900056723007", - "out_order_no": "202605061242131701273576030", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778042539, - "payment_time": 1778042566, - "notify_time": 1778042567, - "client_ip": "42.237.199.1", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612415000056727655", - "out_order_no": "202605061241337465021453949", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778042510, - "payment_time": 1778042546, - "notify_time": 1778042547, - "client_ip": "58.214.46.145", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612403400056717133", - "out_order_no": "202605061240197149109410518", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778042434, - "payment_time": null, - "notify_time": null, - "client_ip": "42.237.199.1", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612381100056713995", - "out_order_no": "202605061238067882459752505", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778042291, - "payment_time": 1778042307, - "notify_time": 1778042308, - "client_ip": "42.80.120.113", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612374500056712509", - "out_order_no": "202605061237383804521280846", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778042265, - "payment_time": 1778042301, - "notify_time": 1778042302, - "client_ip": "223.104.41.190", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612351200056728396", - "out_order_no": "202605061235062657042471508", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778042112, - "payment_time": 1778042156, - "notify_time": 1778042157, - "client_ip": "223.104.54.112", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612345300056727145", - "out_order_no": "202605061234481511551765546", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778042093, - "payment_time": 1778042124, - "notify_time": 1778042124, - "client_ip": "120.219.96.180", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612302500056723234", - "out_order_no": "202605061230092323229031103", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778041825, - "payment_time": 1778041863, - "notify_time": 1778041863, - "client_ip": "111.183.49.40", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612294200056729115", - "out_order_no": "20260506122920799949710543", - "order_money": 315, - "user_money": 303.03, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778041782, - "payment_time": null, - "notify_time": null, - "client_ip": "223.104.54.112", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612271300056715996", - "out_order_no": "202605061227029533424220169", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778041633, - "payment_time": 1778041658, - "notify_time": 1778041658, - "client_ip": "58.247.23.192", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612271300056719749", - "out_order_no": "202605061227044637880734760", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778041633, - "payment_time": 1778041654, - "notify_time": 1778041654, - "client_ip": "10.204.172.110", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612254900056725597", - "out_order_no": "20260506122537425401156739", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778041549, - "payment_time": 1778041582, - "notify_time": 1778041582, - "client_ip": "10.196.90.217", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612252000056721268", - "out_order_no": "202605061225073399440116113", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778041520, - "payment_time": 1778041547, - "notify_time": 1778041548, - "client_ip": "114.103.14.216", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612243800056726962", - "out_order_no": "20260506122419186347737566", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778041478, - "payment_time": 1778041497, - "notify_time": 1778041497, - "client_ip": "114.236.70.189", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612230500056715591", - "out_order_no": "202605061223009899429671803", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778041385, - "payment_time": 1778041424, - "notify_time": 1778041425, - "client_ip": "183.7.175.134", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612222200056729000", - "out_order_no": "202605061222093329032026340", - "order_money": 315, - "user_money": 303.03, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778041342, - "payment_time": 1778041393, - "notify_time": 1778041393, - "client_ip": "39.144.85.36", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612215900056720390", - "out_order_no": "202605061221447331255743412", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778041319, - "payment_time": 1778041362, - "notify_time": 1778041362, - "client_ip": "149.34.251.246", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612173600056724205", - "out_order_no": "202605061217256745019452048", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778041056, - "payment_time": 1778041107, - "notify_time": 1778041107, - "client_ip": "112.12.244.102", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612110500056723031", - "out_order_no": "202605061210587209587227951", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778040665, - "payment_time": 1778040704, - "notify_time": 1778040704, - "client_ip": "124.127.221.73", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612045100056724446", - "out_order_no": "202605061204424529935012026", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778040291, - "payment_time": 1778040323, - "notify_time": 1778040323, - "client_ip": "27.14.6.162", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050612041800056723389", - "out_order_no": "202605061204009422100074776", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778040258, - "payment_time": null, - "notify_time": null, - "client_ip": "27.14.6.162", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611575200056717804", - "out_order_no": "202605061157365871684497390", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778039872, - "payment_time": 1778039911, - "notify_time": 1778039911, - "client_ip": "183.162.248.249", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611573100056718066", - "out_order_no": "202605061157052943000025071", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778039851, - "payment_time": 1778039874, - "notify_time": 1778039875, - "client_ip": "101.82.194.232", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611562100056721472", - "out_order_no": "202605061156109677402659974", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778039781, - "payment_time": 1778039849, - "notify_time": 1778039850, - "client_ip": "113.135.246.212", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611541200056721058", - "out_order_no": "202605061153573920602891176", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778039652, - "payment_time": 1778039680, - "notify_time": 1778039680, - "client_ip": "116.130.195.55", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611522100056720218", - "out_order_no": "20260506115213599881771665", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778039541, - "payment_time": 1778039577, - "notify_time": 1778039577, - "client_ip": "14.24.180.64", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611473400056721572", - "out_order_no": "2026050611472941644792959", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778039254, - "payment_time": 1778039272, - "notify_time": 1778039272, - "client_ip": "117.136.111.58", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611471400056718312", - "out_order_no": "202605061147036989943210159", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778039234, - "payment_time": 1778039255, - "notify_time": 1778039255, - "client_ip": "114.103.172.114", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611414900056710691", - "out_order_no": "20260506114133444083305049", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778038909, - "payment_time": 1778038937, - "notify_time": 1778038937, - "client_ip": "171.219.17.28", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611401400056712542", - "out_order_no": "202605061140047647916735050", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778038814, - "payment_time": 1778038833, - "notify_time": 1778038833, - "client_ip": "219.144.16.87", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611381400056719635", - "out_order_no": "202605061138055379708746421", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778038694, - "payment_time": 1778038722, - "notify_time": 1778038722, - "client_ip": "139.159.170.29", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611352000056721179", - "out_order_no": "202605061135056214899129867", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778038520, - "payment_time": 1778038550, - "notify_time": 1778038550, - "client_ip": "218.94.58.6", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611335900056719746", - "out_order_no": "202605061133426161325738025", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778038439, - "payment_time": 1778038465, - "notify_time": 1778038466, - "client_ip": "82.152.163.46", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611295300056713669", - "out_order_no": "20260506112944155884052402", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778038193, - "payment_time": 1778038218, - "notify_time": 1778038219, - "client_ip": "14.26.225.102", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611294900056721682", - "out_order_no": "202605061129369074507555793", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778038189, - "payment_time": 1778038230, - "notify_time": 1778038231, - "client_ip": "112.45.91.215", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611290100056711019", - "out_order_no": "20260506112856739443166517", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778038141, - "payment_time": 1778038160, - "notify_time": 1778038160, - "client_ip": "59.66.39.109", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611283600056728212", - "out_order_no": "202605061128268835627165734", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778038116, - "payment_time": null, - "notify_time": null, - "client_ip": "59.66.39.109", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611265700056720716", - "out_order_no": "202605061126454681290004539", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778038017, - "payment_time": 1778038043, - "notify_time": 1778038044, - "client_ip": "182.239.114.39", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611252900056714316", - "out_order_no": "202605061125237109873375870", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778037929, - "payment_time": 1778037966, - "notify_time": 1778037967, - "client_ip": "222.76.183.26", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611221800056729011", - "out_order_no": "202605061122067556995349680", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778037738, - "payment_time": 1778037776, - "notify_time": 1778037777, - "client_ip": "140.206.187.122", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611212000056714475", - "out_order_no": "202605061121072542002640169", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778037680, - "payment_time": 1778037702, - "notify_time": 1778037702, - "client_ip": "223.104.79.152", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611210500056729553", - "out_order_no": "202605061120394428693940023", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778037665, - "payment_time": 1778037700, - "notify_time": 1778037700, - "client_ip": "113.72.154.150", - "device": "qq", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611194600056718708", - "out_order_no": "202605061119347960122474659", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778037586, - "payment_time": 1778037613, - "notify_time": 1778037613, - "client_ip": "183.159.152.154", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611183900056727073", - "out_order_no": "202605061118263878499191008", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778037519, - "payment_time": null, - "notify_time": null, - "client_ip": "39.144.78.202", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611182600056718692", - "out_order_no": "20260506111814693814550984", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778037506, - "payment_time": 1778037639, - "notify_time": 1778037640, - "client_ip": "111.19.85.72", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611155100056726627", - "out_order_no": "202605061115449235304497299", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778037351, - "payment_time": 1778037377, - "notify_time": 1778037378, - "client_ip": "122.235.177.254", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611141100056712609", - "out_order_no": "202605061114055256499060990", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778037251, - "payment_time": 1778037267, - "notify_time": 1778037267, - "client_ip": "183.200.192.108", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611123400056787480", - "out_order_no": "202605061112161306152972480", - "order_money": 90.93, - "user_money": 0, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778037154, - "payment_time": null, - "notify_time": null, - "client_ip": "183.200.192.108", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611121700056710182", - "out_order_no": "202605061112082141919510598", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778037137, - "payment_time": 1778037161, - "notify_time": 1778037161, - "client_ip": "39.144.124.13", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611115300056721127", - "out_order_no": "202605061111453728977338724", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778037113, - "payment_time": 1778037145, - "notify_time": 1778037145, - "client_ip": "114.219.120.141", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611114100056719296", - "out_order_no": "202605061111313190549664987", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778037101, - "payment_time": 1778037172, - "notify_time": 1778037173, - "client_ip": "112.17.241.207", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611114100056724838", - "out_order_no": "202605061111294069700720572", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778037101, - "payment_time": null, - "notify_time": null, - "client_ip": "39.144.124.13", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611085000056727034", - "out_order_no": "202605061108434712441626389", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778036930, - "payment_time": 1778036959, - "notify_time": 1778036959, - "client_ip": "117.183.230.122", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611082900056716491", - "out_order_no": "202605061108167593985220830", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778036909, - "payment_time": 1778036963, - "notify_time": 1778036963, - "client_ip": "180.111.39.63", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611075200056723340", - "out_order_no": "202605061107446957407093782", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778036872, - "payment_time": 1778036888, - "notify_time": 1778036889, - "client_ip": "111.25.69.243", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611060400056713527", - "out_order_no": "202605061105553054471840938", - "order_money": 315, - "user_money": 306.18, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778036764, - "payment_time": 1778036801, - "notify_time": 1778036801, - "client_ip": "125.69.130.83", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611045000056726731", - "out_order_no": "20260506110421248128793547", - "order_money": 315, - "user_money": 303.03, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778036690, - "payment_time": null, - "notify_time": null, - "client_ip": "125.69.130.83", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050611001800056714872", - "out_order_no": "202605061100119518276995542", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778036418, - "payment_time": 1778036438, - "notify_time": 1778036439, - "client_ip": "140.206.187.122", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610593600056714008", - "out_order_no": "202605061059258720412948703", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778036376, - "payment_time": null, - "notify_time": null, - "client_ip": "14.127.7.238", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610590300056711367", - "out_order_no": "202605061058473525143425737", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778036343, - "payment_time": 1778036363, - "notify_time": 1778036364, - "client_ip": "60.255.152.26", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610553500056722729", - "out_order_no": "202605061055158820166485840", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778036135, - "payment_time": 1778036255, - "notify_time": 1778036255, - "client_ip": "183.210.24.15", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610553000056722629", - "out_order_no": "202605061055238923072615460", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778036130, - "payment_time": 1778036193, - "notify_time": 1778036194, - "client_ip": "183.69.134.114", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610545200056728908", - "out_order_no": "202605061054424960712824097", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778036092, - "payment_time": 1778036108, - "notify_time": 1778036108, - "client_ip": "125.71.54.185", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610540000056726960", - "out_order_no": "20260506105342539963500366", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778036040, - "payment_time": 1778036062, - "notify_time": 1778036063, - "client_ip": "36.28.208.6", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610534300056725789", - "out_order_no": "202605061053278034749379429", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778036023, - "payment_time": 1778036071, - "notify_time": 1778036071, - "client_ip": "35.215.171.43", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610511000056713207", - "out_order_no": "202605061050564456341685773", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778035870, - "payment_time": 1778035891, - "notify_time": 1778035891, - "client_ip": "36.44.99.117", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610470200056729698", - "out_order_no": "20260506104656144920046809", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778035622, - "payment_time": 1778035637, - "notify_time": 1778035637, - "client_ip": "113.200.174.75", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610373200056727603", - "out_order_no": "20260506103722813812636281", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778035052, - "payment_time": 1778035086, - "notify_time": 1778035086, - "client_ip": "49.90.36.88", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610361800056725924", - "out_order_no": "202605061036131961658894943", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778034978, - "payment_time": 1778034997, - "notify_time": 1778034997, - "client_ip": "111.73.17.108", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610341800056714782", - "out_order_no": "202605061034109606736135126", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778034858, - "payment_time": 1778034877, - "notify_time": 1778034878, - "client_ip": "113.77.43.77", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610330000056720886", - "out_order_no": "202605061032504800224564326", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778034780, - "payment_time": 1778034798, - "notify_time": 1778034798, - "client_ip": "36.33.4.13", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610291500056718380", - "out_order_no": "202605061029029124585419138", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778034555, - "payment_time": 1778034576, - "notify_time": 1778034577, - "client_ip": "223.104.211.105", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610270400056712986", - "out_order_no": "202605061026535979125349224", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778034424, - "payment_time": 1778034448, - "notify_time": 1778034448, - "client_ip": "140.206.187.122", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610265100056715503", - "out_order_no": "202605061026373170411285112", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778034411, - "payment_time": 1778034447, - "notify_time": 1778034448, - "client_ip": "220.196.193.105", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610235600056722063", - "out_order_no": "202605061023415399329436552", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778034236, - "payment_time": 1778034275, - "notify_time": 1778034276, - "client_ip": "184.151.190.59", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610225300056726097", - "out_order_no": "202605061022421350546149851", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778034173, - "payment_time": null, - "notify_time": null, - "client_ip": "60.1.174.173", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610200500056726859", - "out_order_no": "202605061019526093250750877", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778034005, - "payment_time": 1778034038, - "notify_time": 1778034098, - "client_ip": "125.34.22.31", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610195600056727828", - "out_order_no": "202605061019478412357694149", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778033996, - "payment_time": 1778034016, - "notify_time": 1778034017, - "client_ip": "42.6.88.125", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610163500056722423", - "out_order_no": "202605061016183812787915158", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778033795, - "payment_time": 1778033826, - "notify_time": 1778033826, - "client_ip": "120.244.214.70", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610123600056715492", - "out_order_no": "202605061012276171793585475", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778033556, - "payment_time": 1778033585, - "notify_time": 1778033585, - "client_ip": "140.206.187.122", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610105500056729904", - "out_order_no": "202605061010391990134634616", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778033455, - "payment_time": 1778033483, - "notify_time": 1778033483, - "client_ip": "39.144.157.14", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610064200056710463", - "out_order_no": "202605061006371556122262830", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778033202, - "payment_time": 1778033235, - "notify_time": 1778033235, - "client_ip": "183.130.205.180", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610060600056710536", - "out_order_no": "20260506100555710777566794", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778033166, - "payment_time": null, - "notify_time": null, - "client_ip": "183.130.205.180", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610022100056725511", - "out_order_no": "202605061002107855327739553", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778032941, - "payment_time": 1778032971, - "notify_time": 1778032972, - "client_ip": "218.12.21.120", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610020000056782602", - "out_order_no": "202605061001471745140218158", - "order_money": 19.53, - "user_money": 0, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778032920, - "payment_time": null, - "notify_time": null, - "client_ip": "36.47.128.17", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050610000500056716969", - "out_order_no": "202605060959477090887151997", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778032805, - "payment_time": 1778032844, - "notify_time": 1778032844, - "client_ip": "111.174.231.82", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609590600056711177", - "out_order_no": "202605060958489027942232453", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778032746, - "payment_time": 1778032771, - "notify_time": 1778032772, - "client_ip": "36.4.59.28", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609544300056723519", - "out_order_no": "202605060954341327166007820", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778032483, - "payment_time": 1778032509, - "notify_time": 1778032509, - "client_ip": "120.208.105.235", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609524800056729474", - "out_order_no": "20260506095236586079955229", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778032368, - "payment_time": 1778032385, - "notify_time": 1778032385, - "client_ip": "125.67.191.57", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609511800056712991", - "out_order_no": "202605060951124900055612944", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778032278, - "payment_time": 1778032299, - "notify_time": 1778032300, - "client_ip": "112.25.223.101", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609503300056729760", - "out_order_no": "202605060950254755953192187", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778032233, - "payment_time": 1778032262, - "notify_time": 1778032262, - "client_ip": "183.202.131.158", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609442600056713628", - "out_order_no": "202605060944148435104800643", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778031866, - "payment_time": null, - "notify_time": null, - "client_ip": "39.144.124.59", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609431800056719514", - "out_order_no": "202605060943085700774986522", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778031798, - "payment_time": 1778031819, - "notify_time": 1778031819, - "client_ip": "118.119.171.21", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609413000056719735", - "out_order_no": "202605060939378809428861353", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778031690, - "payment_time": null, - "notify_time": null, - "client_ip": "183.224.187.85", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609410200056717869", - "out_order_no": "202605060940373960171233438", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778031662, - "payment_time": 1778031683, - "notify_time": 1778031683, - "client_ip": "27.128.32.182", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609374300056717320", - "out_order_no": "202605060936467319824164313", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778031463, - "payment_time": 1778031485, - "notify_time": 1778031486, - "client_ip": "182.150.28.74", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609363400056718269", - "out_order_no": "202605060936104539041461856", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778031394, - "payment_time": null, - "notify_time": null, - "client_ip": "111.33.200.119", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609342300056722696", - "out_order_no": "202605060934189413313563838", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778031263, - "payment_time": 1778031292, - "notify_time": 1778031293, - "client_ip": "116.149.125.212", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609335200056717541", - "out_order_no": "202605060933435839026330919", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778031232, - "payment_time": 1778031254, - "notify_time": 1778031254, - "client_ip": "182.204.4.174", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609335200056728210", - "out_order_no": "202605060933459016879509345", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778031232, - "payment_time": null, - "notify_time": null, - "client_ip": "116.149.125.212", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609232900056722294", - "out_order_no": "202605060923144842767349079", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778030609, - "payment_time": 1778030644, - "notify_time": 1778030645, - "client_ip": "171.217.183.224", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609232500056728554", - "out_order_no": "202605060923174122161564087", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778030605, - "payment_time": 1778030641, - "notify_time": 1778030641, - "client_ip": "39.130.58.138", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609225300056722664", - "out_order_no": "202605060922476101027633493", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778030573, - "payment_time": 1778030587, - "notify_time": 1778030588, - "client_ip": "120.225.101.75", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609215100056719738", - "out_order_no": "202605060921281387153938531", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778030511, - "payment_time": null, - "notify_time": null, - "client_ip": "39.130.58.138", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609172400056728466", - "out_order_no": "202605060917162651128655185", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778030244, - "payment_time": null, - "notify_time": null, - "client_ip": "111.25.69.243", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609124100056720316", - "out_order_no": "202605060912281101583130897", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778029961, - "payment_time": 1778029989, - "notify_time": 1778029989, - "client_ip": "223.82.15.226", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609091500056727225", - "out_order_no": "202605060909012406293714385", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778029755, - "payment_time": null, - "notify_time": null, - "client_ip": "39.158.33.134", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609091400056717725", - "out_order_no": "202605060908543568922041650", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778029754, - "payment_time": 1778029798, - "notify_time": 1778029799, - "client_ip": "152.228.228.62", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609063600056719981", - "out_order_no": "202605060906246068266888734", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778029596, - "payment_time": 1778029632, - "notify_time": 1778029632, - "client_ip": "182.239.115.69", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050609021000056729833", - "out_order_no": "202605060902044048000877843", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778029330, - "payment_time": 1778029367, - "notify_time": 1778029368, - "client_ip": "219.129.234.209", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050608585600056711704", - "out_order_no": "202605060858489588533136886", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778029136, - "payment_time": 1778029162, - "notify_time": 1778029162, - "client_ip": "112.5.57.122", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050608582600056726434", - "out_order_no": "202605060858177359981466974", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778029106, - "payment_time": null, - "notify_time": null, - "client_ip": "219.129.234.209", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050608555900056719913", - "out_order_no": "202605060855443661552355272", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778028959, - "payment_time": 1778028977, - "notify_time": 1778028977, - "client_ip": "101.87.224.222", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050608513500056716550", - "out_order_no": "202605060851108741042261457", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778028695, - "payment_time": 1778028716, - "notify_time": 1778028716, - "client_ip": "180.138.230.157", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050608505000056710916", - "out_order_no": "202605060850375448754399761", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778028650, - "payment_time": 1778028682, - "notify_time": 1778028682, - "client_ip": "14.31.226.119", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050608482100056725599", - "out_order_no": "202605060848159572944912815", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778028501, - "payment_time": 1778028529, - "notify_time": 1778028529, - "client_ip": "106.44.60.6", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050608473300056710554", - "out_order_no": "202605060847203698507122598", - "order_money": 315, - "user_money": 306.18, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778028453, - "payment_time": 1778028484, - "notify_time": 1778028484, - "client_ip": "39.162.91.50", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050608464100056714892", - "out_order_no": "202605060846276319760669534", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778028401, - "payment_time": 1778028426, - "notify_time": 1778028426, - "client_ip": "112.41.110.220", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050608463000056717310", - "out_order_no": "202605060846182740841260054", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778028390, - "payment_time": 1778028407, - "notify_time": 1778028407, - "client_ip": "42.84.232.98", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050608420700056714210", - "out_order_no": "202605060841548864893716177", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778028127, - "payment_time": 1778028148, - "notify_time": 1778028149, - "client_ip": "114.86.101.140", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050608395800056729185", - "out_order_no": "202605060839454305996962051", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778027998, - "payment_time": 1778028076, - "notify_time": 1778028077, - "client_ip": "27.210.76.46", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050608382600056717027", - "out_order_no": "202605060838173242988750115", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778027906, - "payment_time": 1778027931, - "notify_time": 1778027931, - "client_ip": "117.154.84.238", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050608352500056714561", - "out_order_no": "202605060835134673286079863", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778027725, - "payment_time": 1778027745, - "notify_time": 1778027745, - "client_ip": "110.251.155.249", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050608342300056723540", - "out_order_no": "202605060834177168004469593", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778027663, - "payment_time": 1778027703, - "notify_time": 1778027703, - "client_ip": "1.192.36.121", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050608305300056713129", - "out_order_no": "202605060830352900493928961", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778027453, - "payment_time": 1778027480, - "notify_time": 1778027481, - "client_ip": "121.225.130.18", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050608284900056721121", - "out_order_no": "202605060828382156060163482", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778027329, - "payment_time": 1778027357, - "notify_time": 1778027357, - "client_ip": "112.97.171.181", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050608063900056717831", - "out_order_no": "202605060806148167706686261", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778025999, - "payment_time": 1778026032, - "notify_time": 1778026033, - "client_ip": "114.227.147.89", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050608052400056710094", - "out_order_no": "202605060805083774197802884", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778025924, - "payment_time": 1778025955, - "notify_time": 1778025955, - "client_ip": "120.32.222.104", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050608025200056712357", - "out_order_no": "202605060802367140178320559", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778025772, - "payment_time": 1778025800, - "notify_time": 1778025801, - "client_ip": "222.212.236.187", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050608012600056726909", - "out_order_no": "202605060801038935431337478", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778025686, - "payment_time": 1778025718, - "notify_time": 1778025718, - "client_ip": "171.108.87.76", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050607562800056721957", - "out_order_no": "20260506075609932221037519", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778025388, - "payment_time": 1778025421, - "notify_time": 1778025422, - "client_ip": "101.90.6.162", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050607471500056722194", - "out_order_no": "202605060747006935730019538", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778024835, - "payment_time": 1778024892, - "notify_time": 1778024892, - "client_ip": "218.200.28.210", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050607453900056724495", - "out_order_no": "202605060745224550245055467", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778024739, - "payment_time": 1778024762, - "notify_time": 1778024763, - "client_ip": "110.19.191.3", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050607445000056716043", - "out_order_no": "202605060744337287601409459", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778024690, - "payment_time": 1778024715, - "notify_time": 1778024715, - "client_ip": "39.144.177.241", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050607395600056717719", - "out_order_no": "202605060739454833033387589", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778024396, - "payment_time": 1778024419, - "notify_time": 1778024419, - "client_ip": "119.123.33.251", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050607354600056711188", - "out_order_no": "202605060735381571319831118", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778024146, - "payment_time": 1778024165, - "notify_time": 1778024165, - "client_ip": "118.121.67.32", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050607341500056711974", - "out_order_no": "202605060734068477149473543", - "order_money": 315, - "user_money": 306.18, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778024055, - "payment_time": 1778024078, - "notify_time": 1778024078, - "client_ip": "114.217.72.141", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050607292000056714255", - "out_order_no": "202605060729068652078292916", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778023760, - "payment_time": 1778023786, - "notify_time": 1778023787, - "client_ip": "110.156.240.19", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050607124000056715931", - "out_order_no": "202605060712288521859016659", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778022760, - "payment_time": 1778022781, - "notify_time": 1778022781, - "client_ip": "117.70.191.42", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050607102400056724783", - "out_order_no": "202605060710171604195005304", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778022624, - "payment_time": 1778022663, - "notify_time": 1778022663, - "client_ip": "120.229.225.207", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050607084800056726062", - "out_order_no": "202605060708431940696098394", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778022528, - "payment_time": 1778022595, - "notify_time": 1778022596, - "client_ip": "124.90.94.61", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050607082200056714756", - "out_order_no": "202605060708125268941706116", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778022502, - "payment_time": null, - "notify_time": null, - "client_ip": "118.121.67.32", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050607075600056717787", - "out_order_no": "202605060707185967059175641", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778022476, - "payment_time": null, - "notify_time": null, - "client_ip": "42.226.119.155", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050606591400056712512", - "out_order_no": "202605060659072390362936151", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778021954, - "payment_time": 1778021972, - "notify_time": 1778021972, - "client_ip": "183.92.136.11", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050606585000056721968", - "out_order_no": "202605060658402766506199290", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778021930, - "payment_time": null, - "notify_time": null, - "client_ip": "183.92.136.11", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050606555400056724408", - "out_order_no": "202605060655339437979573447", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778021754, - "payment_time": 1778021799, - "notify_time": 1778021800, - "client_ip": "183.228.138.140", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050606403400056726128", - "out_order_no": "202605060640221635003238897", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778020834, - "payment_time": 1778020847, - "notify_time": 1778020847, - "client_ip": "61.170.152.190", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050606371400056716931", - "out_order_no": "202605060637074364701903229", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778020634, - "payment_time": 1778020679, - "notify_time": 1778020679, - "client_ip": "115.201.72.14", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050606335800056722443", - "out_order_no": "20260506063346988981542347", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778020438, - "payment_time": 1778020465, - "notify_time": 1778020465, - "client_ip": "112.22.142.161", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050606281100056711406", - "out_order_no": "202605060628003624364231272", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778020091, - "payment_time": 1778020135, - "notify_time": 1778020135, - "client_ip": "114.249.61.209", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050606223000056720638", - "out_order_no": "202605060622174563677139280", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778019750, - "payment_time": 1778019799, - "notify_time": 1778019799, - "client_ip": "1.203.85.198", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050606220600056723131", - "out_order_no": "202605060621555424601694753", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "full_refund", - "notify_status": "notify_success", - "create_time": 1778019726, - "payment_time": 1778019767, - "notify_time": 1778019767, - "client_ip": "114.219.228.122", - "device": "mobile", - "order_remark": "้€€ๆฌพๆˆๅŠŸ", - "refund_amount": 19.53, - "refund_time": 1778019883 - }, - { - "order_no": "2026050606163100056722333", - "out_order_no": "202605060616196035205385333", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778019391, - "payment_time": 1778019420, - "notify_time": 1778019421, - "client_ip": "120.204.162.162", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050606104700056715517", - "out_order_no": "20260506061038640283545222", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778019047, - "payment_time": 1778019072, - "notify_time": 1778019072, - "client_ip": "112.115.29.39", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050606084200056725481", - "out_order_no": "202605060608365743284331492", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "full_refund", - "notify_status": "notify_success", - "create_time": 1778018923, - "payment_time": 1778018950, - "notify_time": 1778018951, - "client_ip": "114.219.228.122", - "device": "mobile", - "order_remark": "้€€ๆฌพๆˆๅŠŸ", - "refund_amount": 19.53, - "refund_time": 1778019629 - }, - { - "order_no": "2026050605584900056727158", - "out_order_no": "202605060558404492046295703", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778018330, - "payment_time": 1778018363, - "notify_time": 1778018364, - "client_ip": "27.148.116.201", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050605570800056720867", - "out_order_no": "202605060556547717597593220", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778018228, - "payment_time": null, - "notify_time": null, - "client_ip": "171.91.68.209", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050605551800056726108", - "out_order_no": "2026050605551140311941522", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778018118, - "payment_time": 1778018149, - "notify_time": 1778018150, - "client_ip": "114.135.138.123", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050605545400056724134", - "out_order_no": "202605060554439289580771029", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778018094, - "payment_time": null, - "notify_time": null, - "client_ip": "171.91.68.209", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050605531600056724343", - "out_order_no": "202605060553072979125641813", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778017996, - "payment_time": null, - "notify_time": null, - "client_ip": "114.135.138.123", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050605525300056712376", - "out_order_no": "202605060552419299665983528", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778017973, - "payment_time": 1778017995, - "notify_time": 1778017995, - "client_ip": "111.30.251.182", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050605511500056712287", - "out_order_no": "202605060550547454032673306", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778017875, - "payment_time": null, - "notify_time": null, - "client_ip": "111.30.251.182", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050605453000056728156", - "out_order_no": "202605060545228270998282265", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778017530, - "payment_time": 1778017564, - "notify_time": 1778017565, - "client_ip": "120.231.64.112", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050605402100056725549", - "out_order_no": "202605060540132285160947178", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778017221, - "payment_time": 1778017260, - "notify_time": 1778017260, - "client_ip": "14.153.0.212", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050605352900056725316", - "out_order_no": "202605060535126943252263474", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778016930, - "payment_time": 1778016970, - "notify_time": 1778016970, - "client_ip": "10.197.168.109", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050605292200056723500", - "out_order_no": "202605060529124140002750626", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778016562, - "payment_time": 1778016588, - "notify_time": 1778016588, - "client_ip": "61.149.93.141", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050605281900056711833", - "out_order_no": "202605060528099881169203095", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778016499, - "payment_time": 1778016518, - "notify_time": 1778016518, - "client_ip": "27.38.200.52", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050604500000056721220", - "out_order_no": "202605060449517231080384692", - "order_money": 315, - "user_money": 303.03, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778014200, - "payment_time": 1778014223, - "notify_time": 1778014223, - "client_ip": "39.174.18.182", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050604350500056719086", - "out_order_no": "202605060434563908007506469", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778013305, - "payment_time": 1778013331, - "notify_time": 1778013331, - "client_ip": "113.84.210.119", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050604265600056712472", - "out_order_no": "202605060426483855323899181", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778012816, - "payment_time": 1778012837, - "notify_time": 1778012838, - "client_ip": "120.226.108.252", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050604264500056719788", - "out_order_no": "20260506042633963827335562", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778012805, - "payment_time": 1778012836, - "notify_time": 1778012836, - "client_ip": "58.247.23.234", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050604190000056713288", - "out_order_no": "202605060418507927761663334", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778012340, - "payment_time": 1778012364, - "notify_time": 1778012364, - "client_ip": "111.192.97.149", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050604170400056728567", - "out_order_no": "20260506041652636234922724", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778012224, - "payment_time": 1778012268, - "notify_time": 1778012269, - "client_ip": "42.84.232.108", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050604163400056717885", - "out_order_no": "202605060416217501938092178", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778012194, - "payment_time": 1778012221, - "notify_time": 1778012222, - "client_ip": "106.88.88.169", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050604065200056722722", - "out_order_no": "202605060404517874346958372", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778011612, - "payment_time": 1778011631, - "notify_time": 1778011632, - "client_ip": "58.42.163.125", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050604061000056725918", - "out_order_no": "20260506040545741303253496", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778011570, - "payment_time": null, - "notify_time": null, - "client_ip": "120.239.147.13", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050604044200056727789", - "out_order_no": "202605060404332855209050267", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778011482, - "payment_time": null, - "notify_time": null, - "client_ip": "58.42.163.125", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050604011900056710835", - "out_order_no": "202605060401067760749485834", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778011279, - "payment_time": null, - "notify_time": null, - "client_ip": "223.73.51.149", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050604005200056720363", - "out_order_no": "202605060400378933101361633", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778011252, - "payment_time": 1778011279, - "notify_time": 1778011280, - "client_ip": "117.136.101.176", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050604003200056729036", - "out_order_no": "202605060400256721923882421", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778011232, - "payment_time": 1778011261, - "notify_time": 1778011261, - "client_ip": "117.150.250.56", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050603562600056722159", - "out_order_no": "202605060356051363927161412", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778010986, - "payment_time": 1778011017, - "notify_time": 1778011017, - "client_ip": "36.101.147.108", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050603551100056715979", - "out_order_no": "202605060355045442843497085", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778010911, - "payment_time": 1778010936, - "notify_time": 1778010936, - "client_ip": "8.218.95.81", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050603542300056712812", - "out_order_no": "202605060354164422929939504", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778010863, - "payment_time": 1778010885, - "notify_time": 1778010886, - "client_ip": "10.217.158.65", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050603481500056727263", - "out_order_no": "20260506034804449623863656", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778010495, - "payment_time": 1778010520, - "notify_time": 1778010520, - "client_ip": "118.74.207.125", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050603414600056723424", - "out_order_no": "202605060341356065354759970", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778010106, - "payment_time": 1778010132, - "notify_time": 1778010133, - "client_ip": "223.198.62.156", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050603404100056722951", - "out_order_no": "202605060340322021819576191", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778010041, - "payment_time": 1778010071, - "notify_time": 1778010071, - "client_ip": "112.20.64.60", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050603323600056725226", - "out_order_no": "202605060332051452713976058", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778009556, - "payment_time": 1778009591, - "notify_time": 1778009591, - "client_ip": "39.144.89.14", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050603261500056726482", - "out_order_no": "202605060326058289973466829", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778009175, - "payment_time": 1778009214, - "notify_time": 1778009214, - "client_ip": "39.148.116.149", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050603211500056714144", - "out_order_no": "202605060321071294178387152", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778008875, - "payment_time": 1778008901, - "notify_time": 1778008902, - "client_ip": "180.139.212.7", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050603181900056710369", - "out_order_no": "202605060318122265999831604", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778008699, - "payment_time": 1778008745, - "notify_time": 1778008745, - "client_ip": "36.112.194.102", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050603174100056783469", - "out_order_no": "202605060317336203975530978", - "order_money": 315, - "user_money": 0, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778008661, - "payment_time": null, - "notify_time": null, - "client_ip": "182.239.114.39", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050603140800056716201", - "out_order_no": "202605060313408674155706479", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778008448, - "payment_time": 1778008467, - "notify_time": 1778008467, - "client_ip": "39.187.218.162", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050603135400056714306", - "out_order_no": "202605060313459428596275744", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778008434, - "payment_time": 1778008476, - "notify_time": 1778008476, - "client_ip": "27.154.71.199", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050603134000056726360", - "out_order_no": "202605060313311499074365697", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778008420, - "payment_time": 1778008452, - "notify_time": 1778008452, - "client_ip": "118.73.60.229", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050603063500056728219", - "out_order_no": "202605060306296198762124390", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778007995, - "payment_time": 1778008019, - "notify_time": 1778008019, - "client_ip": "58.241.119.217", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050603055200056724237", - "out_order_no": "202605060305384797438281491", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778007952, - "payment_time": 1778007999, - "notify_time": 1778007999, - "client_ip": "123.156.214.5", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050603045300056727939", - "out_order_no": "20260506030444763469334587", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778007893, - "payment_time": 1778007926, - "notify_time": 1778007926, - "client_ip": "14.24.243.155", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050603044400056716489", - "out_order_no": "202605060304353873018472336", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778007884, - "payment_time": 1778007916, - "notify_time": 1778007917, - "client_ip": "112.10.195.2", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602590000056725023", - "out_order_no": "202605060258538620856525797", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778007540, - "payment_time": 1778007574, - "notify_time": 1778007574, - "client_ip": "116.162.235.194", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602482800056724767", - "out_order_no": "202605060248037365227030815", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778006908, - "payment_time": 1778006955, - "notify_time": 1778006955, - "client_ip": "183.42.162.121", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602463500056727860", - "out_order_no": "202605060246286095013016936", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778006795, - "payment_time": 1778006830, - "notify_time": 1778006830, - "client_ip": "223.160.219.79", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602463000056715397", - "out_order_no": "202605060246154947543134289", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778006790, - "payment_time": 1778006827, - "notify_time": 1778006828, - "client_ip": "125.111.223.20", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602440600056720794", - "out_order_no": "202605060243574811841940669", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778006646, - "payment_time": 1778006678, - "notify_time": 1778006679, - "client_ip": "183.247.6.102", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602435200056719480", - "out_order_no": "202605060243458991204226830", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778006632, - "payment_time": 1778006656, - "notify_time": 1778006656, - "client_ip": "223.160.224.186", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602381500056723391", - "out_order_no": "202605060237521388982180677", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778006295, - "payment_time": null, - "notify_time": null, - "client_ip": "49.112.162.238", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602365500056726200", - "out_order_no": "202605060236431803259829769", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778006215, - "payment_time": 1778006273, - "notify_time": 1778006273, - "client_ip": "114.97.160.241", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602282100056729930", - "out_order_no": "202605060228143137116595934", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778005701, - "payment_time": 1778005729, - "notify_time": 1778005730, - "client_ip": "114.88.23.79", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602280000056723317", - "out_order_no": "202605060227489551539275756", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778005680, - "payment_time": null, - "notify_time": null, - "client_ip": "114.88.23.79", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602261500056728344", - "out_order_no": "202605060226047656204256762", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778005575, - "payment_time": 1778005594, - "notify_time": 1778005595, - "client_ip": "117.24.136.226", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602241700056728373", - "out_order_no": "202605060224095694781439642", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778005457, - "payment_time": 1778005502, - "notify_time": 1778005503, - "client_ip": "222.76.115.139", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602224100056724656", - "out_order_no": "202605060222317561682574807", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778005361, - "payment_time": 1778005393, - "notify_time": 1778005393, - "client_ip": "221.7.7.225", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602221800056713911", - "out_order_no": "202605060222109674292232049", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778005338, - "payment_time": 1778005364, - "notify_time": 1778005365, - "client_ip": "27.42.97.24", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602205600056710643", - "out_order_no": "202605060220485078125121362", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778005256, - "payment_time": 1778005275, - "notify_time": 1778005275, - "client_ip": "106.8.228.108", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602195100056715965", - "out_order_no": "202605060219349787221301645", - "order_money": 315, - "user_money": 306.18, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778005191, - "payment_time": 1778005218, - "notify_time": 1778005218, - "client_ip": "223.152.92.116", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602170600056711942", - "out_order_no": "202605060216184791443924880", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778005026, - "payment_time": 1778005044, - "notify_time": 1778005045, - "client_ip": "125.85.126.187", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602164000056728735", - "out_order_no": "2026050602163440110436231", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778005000, - "payment_time": null, - "notify_time": null, - "client_ip": "106.33.183.28", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602163900056721734", - "out_order_no": "202605060216248696627938915", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778004999, - "payment_time": null, - "notify_time": null, - "client_ip": "113.69.32.36", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602153500056715496", - "out_order_no": "202605060214465832088199203", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778004935, - "payment_time": 1778004954, - "notify_time": 1778004955, - "client_ip": "112.112.67.204", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602134000056710566", - "out_order_no": "202605060213217395384140001", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778004820, - "payment_time": 1778004852, - "notify_time": 1778004852, - "client_ip": "39.130.106.27", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602090800056721951", - "out_order_no": "202605060209009350856108723", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778004548, - "payment_time": 1778004572, - "notify_time": 1778004573, - "client_ip": "171.213.252.15", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602075300056721345", - "out_order_no": "202605060207352498387718615", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778004473, - "payment_time": 1778004521, - "notify_time": 1778004522, - "client_ip": "115.149.100.247", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602070800056729534", - "out_order_no": "202605060207033316040674163", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778004428, - "payment_time": 1778004461, - "notify_time": 1778004461, - "client_ip": "123.170.54.23", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602070600056711081", - "out_order_no": "202605060206454001345684011", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778004426, - "payment_time": 1778004451, - "notify_time": 1778004451, - "client_ip": "112.96.52.138", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602065400056714994", - "out_order_no": "202605060206467182326016612", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778004414, - "payment_time": 1778004438, - "notify_time": 1778004438, - "client_ip": "14.154.193.59", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602063800056712970", - "out_order_no": "202605060206321067114774800", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778004398, - "payment_time": 1778004418, - "notify_time": 1778004419, - "client_ip": "39.90.11.161", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050602034300056725236", - "out_order_no": "202605060203217241832279672", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778004223, - "payment_time": 1778004268, - "notify_time": 1778004268, - "client_ip": "111.29.183.24", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601591600056712385", - "out_order_no": "202605060159055295963335368", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778003956, - "payment_time": 1778004008, - "notify_time": 1778004009, - "client_ip": "113.58.244.118", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601572700056728431", - "out_order_no": "20260506015715529692181294", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778003847, - "payment_time": 1778003882, - "notify_time": 1778003883, - "client_ip": "175.167.155.86", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601570600056714597", - "out_order_no": "202605060156574259689303938", - "order_money": 315, - "user_money": 306.18, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778003826, - "payment_time": 1778003855, - "notify_time": 1778003855, - "client_ip": "14.24.225.184", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601531300056718105", - "out_order_no": "202605060153006137746022967", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778003593, - "payment_time": 1778003620, - "notify_time": 1778003620, - "client_ip": "36.152.249.86", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601513900056727298", - "out_order_no": "202605060151306581720359978", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778003499, - "payment_time": 1778003545, - "notify_time": 1778003545, - "client_ip": "1.196.172.243", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601483000056721985", - "out_order_no": "202605060148201280122809726", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778003310, - "payment_time": 1778003328, - "notify_time": 1778003329, - "client_ip": "120.231.214.156", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601465000056711474", - "out_order_no": "202605060146392949400245299", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778003210, - "payment_time": 1778003237, - "notify_time": 1778003238, - "client_ip": "119.123.134.37", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601461900056719130", - "out_order_no": "202605060146034026783314052", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778003179, - "payment_time": 1778003218, - "notify_time": 1778003218, - "client_ip": "74.112.101.194", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601443100056726356", - "out_order_no": "202605060144125863916725487", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778003071, - "payment_time": 1778003099, - "notify_time": 1778003099, - "client_ip": "39.144.250.241", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601431200056721341", - "out_order_no": "202605060143038165058091868", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778002992, - "payment_time": 1778003022, - "notify_time": 1778003023, - "client_ip": "183.195.54.100", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601415100056715699", - "out_order_no": "202605060141373110776039203", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778002911, - "payment_time": 1778003034, - "notify_time": 1778003034, - "client_ip": "111.25.33.232", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601403400056711829", - "out_order_no": "20260506014025457120147376", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778002834, - "payment_time": 1778002859, - "notify_time": 1778002859, - "client_ip": "101.207.200.18", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601391600056727544", - "out_order_no": "202605060138444707621596776", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778002756, - "payment_time": 1778002812, - "notify_time": 1778002813, - "client_ip": "149.34.251.243", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601372400056727253", - "out_order_no": "202605060137147183931999330", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778002644, - "payment_time": 1778002687, - "notify_time": 1778002687, - "client_ip": "117.30.54.164", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601370800056714356", - "out_order_no": "202605060137021488126073260", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778002628, - "payment_time": 1778002645, - "notify_time": 1778002647, - "client_ip": "112.97.83.75", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601370500056722342", - "out_order_no": "202605060136549464697372584", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778002625, - "payment_time": 1778002640, - "notify_time": 1778002640, - "client_ip": "112.86.115.202", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601360900056716649", - "out_order_no": "202605060135527931571104122", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778002569, - "payment_time": null, - "notify_time": null, - "client_ip": "112.97.83.75", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601330600056720599", - "out_order_no": "20260506013254826706533504", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778002386, - "payment_time": null, - "notify_time": null, - "client_ip": "111.29.183.24", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601312700056717737", - "out_order_no": "202605060131154941477770900", - "order_money": 315, - "user_money": 306.18, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778002287, - "payment_time": 1778002316, - "notify_time": 1778002317, - "client_ip": "223.160.123.101", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601300600056721146", - "out_order_no": "202605060129589375395276505", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778002206, - "payment_time": null, - "notify_time": null, - "client_ip": "124.64.22.177", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601274900056714140", - "out_order_no": "202605060127351678653834656", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778002069, - "payment_time": 1778002123, - "notify_time": 1778002123, - "client_ip": "39.144.190.51", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601270100056722183", - "out_order_no": "202605060126397001754953119", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778002021, - "payment_time": 1778002087, - "notify_time": 1778002087, - "client_ip": "205.147.22.15", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601265900056717216", - "out_order_no": "202605060126535059126225078", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778002019, - "payment_time": 1778002048, - "notify_time": 1778002048, - "client_ip": "116.252.107.119", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601261500056729479", - "out_order_no": "202605060125595259742814299", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778001975, - "payment_time": 1778002006, - "notify_time": 1778002006, - "client_ip": "117.24.128.27", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601235600056729705", - "out_order_no": "202605060123278789592580809", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778001836, - "payment_time": 1778001884, - "notify_time": 1778001884, - "client_ip": "106.58.26.207", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601233000056715133", - "out_order_no": "2026050601231794259385337", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778001810, - "payment_time": 1778001835, - "notify_time": 1778001836, - "client_ip": "39.130.122.22", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601185800056728390", - "out_order_no": "202605060118359355838020490", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778001538, - "payment_time": 1778001571, - "notify_time": 1778001572, - "client_ip": "27.23.194.116", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601180400056722269", - "out_order_no": "202605060117554080998125144", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778001484, - "payment_time": 1778001500, - "notify_time": 1778001500, - "client_ip": "106.224.188.226", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601151800056726961", - "out_order_no": "202605060114446635382738563", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778001318, - "payment_time": 1778001350, - "notify_time": 1778001350, - "client_ip": "157.0.23.65", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601123200056713465", - "out_order_no": "202605060112157579041810792", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778001152, - "payment_time": 1778001176, - "notify_time": 1778001176, - "client_ip": "111.183.103.44", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601114600056725334", - "out_order_no": "202605060111362283254561377", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778001106, - "payment_time": 1778001132, - "notify_time": 1778001133, - "client_ip": "111.1.97.9", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601110700056727622", - "out_order_no": "202605060110494537138504586", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778001067, - "payment_time": null, - "notify_time": null, - "client_ip": "223.160.236.203", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601110400056721942", - "out_order_no": "202605060110546033036771078", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778001064, - "payment_time": 1778001095, - "notify_time": 1778001095, - "client_ip": "58.101.34.242", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601104500056717471", - "out_order_no": "202605060110328684280331736", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778001045, - "payment_time": 1778001065, - "notify_time": 1778001066, - "client_ip": "49.112.227.65", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601103200056719797", - "out_order_no": "202605060110234302519169514", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778001032, - "payment_time": 1778001057, - "notify_time": 1778001058, - "client_ip": "183.142.198.241", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601101100056728928", - "out_order_no": "202605060110007813284771401", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778001011, - "payment_time": null, - "notify_time": null, - "client_ip": "183.142.198.241", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601100700056728683", - "out_order_no": "202605060109524040229809322", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778001007, - "payment_time": 1778001052, - "notify_time": 1778001052, - "client_ip": "223.153.237.231", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601093000056714744", - "out_order_no": "202605060109229109717447117", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000970, - "payment_time": 1778001032, - "notify_time": 1778001032, - "client_ip": "223.160.223.210", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601072400056725659", - "out_order_no": "202605060107142407977262720", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000844, - "payment_time": 1778000860, - "notify_time": 1778000860, - "client_ip": "1.196.172.243", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601070400056712768", - "out_order_no": "202605060106591632506391384", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000824, - "payment_time": 1778000857, - "notify_time": 1778000857, - "client_ip": "125.94.22.131", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601065500056716272", - "out_order_no": "202605060106456716778244955", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000815, - "payment_time": 1778000910, - "notify_time": 1778000910, - "client_ip": "60.161.136.38", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601065400056728921", - "out_order_no": "20260506010642572451352966", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000814, - "payment_time": 1778000861, - "notify_time": 1778000861, - "client_ip": "103.170.26.42", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601042700056725543", - "out_order_no": "202605060104233238244908969", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000667, - "payment_time": 1778000692, - "notify_time": 1778000692, - "client_ip": "114.100.142.203", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601040600056719943", - "out_order_no": "202605060103312437459404031", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1778000646, - "payment_time": null, - "notify_time": null, - "client_ip": "59.35.87.254", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601033200056727237", - "out_order_no": "202605060103239981378625240", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000612, - "payment_time": 1778000645, - "notify_time": 1778000645, - "client_ip": "223.153.234.142", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601022800056726021", - "out_order_no": "202605060102233793490085056", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000548, - "payment_time": 1778000569, - "notify_time": 1778000569, - "client_ip": "117.136.119.99", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601020200056719233", - "out_order_no": "20260506010154938887309844", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000522, - "payment_time": 1778000540, - "notify_time": 1778000541, - "client_ip": "14.19.81.126", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601012100056714890", - "out_order_no": "202605060101112160408368571", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000481, - "payment_time": 1778000505, - "notify_time": 1778000505, - "client_ip": "121.32.70.9", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601005900056723630", - "out_order_no": "202605060100381970748988292", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000459, - "payment_time": 1778000487, - "notify_time": 1778000487, - "client_ip": "180.123.188.56", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601002100056716429", - "out_order_no": "202605060100133237617871447", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000421, - "payment_time": 1778000441, - "notify_time": 1778000441, - "client_ip": "223.104.122.191", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601001100056713369", - "out_order_no": "202605060059525091844293576", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000411, - "payment_time": 1778000436, - "notify_time": 1778000436, - "client_ip": "42.86.50.41", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050601000500056710718", - "out_order_no": "202605060059538983108843134", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000405, - "payment_time": 1778000426, - "notify_time": 1778000427, - "client_ip": "223.101.57.106", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600581700056712333", - "out_order_no": "202605060058122124777486079", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000297, - "payment_time": 1778000320, - "notify_time": 1778000321, - "client_ip": "125.73.197.12", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600570400056726159", - "out_order_no": "202605060056564177287733621", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000224, - "payment_time": 1778000282, - "notify_time": 1778000282, - "client_ip": "36.98.248.129", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600570000056710933", - "out_order_no": "202605060056154471150459558", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000220, - "payment_time": 1778000272, - "notify_time": 1778000272, - "client_ip": "171.88.62.5", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600563700056715140", - "out_order_no": "202605060056263339025922692", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000197, - "payment_time": 1778000220, - "notify_time": 1778000220, - "client_ip": "112.97.197.112", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600552100056717300", - "out_order_no": "202605060055164353233105233", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000121, - "payment_time": 1778000139, - "notify_time": 1778000139, - "client_ip": "117.14.140.62", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600551900056726477", - "out_order_no": "202605060055092064800463413", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000119, - "payment_time": 1778000145, - "notify_time": 1778000145, - "client_ip": "106.113.7.16", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600545100056720513", - "out_order_no": "202605060054388969019376109", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000091, - "payment_time": 1778000104, - "notify_time": 1778000105, - "client_ip": "111.166.156.229", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600533000056725448", - "out_order_no": "202605060053205351522472165", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1778000010, - "payment_time": 1778000052, - "notify_time": 1778000052, - "client_ip": "123.147.245.220", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600531300056716931", - "out_order_no": "202605060053019135925763518", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1777999993, - "payment_time": null, - "notify_time": null, - "client_ip": "117.14.140.62", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600511600056711758", - "out_order_no": "202605060050538684368844727", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777999876, - "payment_time": 1777999898, - "notify_time": 1777999898, - "client_ip": "115.207.131.238", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600505700056710775", - "out_order_no": "202605060050391949064504094", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777999857, - "payment_time": 1777999897, - "notify_time": 1777999898, - "client_ip": "182.136.176.194", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600502600056722312", - "out_order_no": "202605060050161104726787786", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777999826, - "payment_time": 1777999879, - "notify_time": 1777999880, - "client_ip": "218.97.237.32", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600493500056726755", - "out_order_no": "202605060049275577899489562", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777999775, - "payment_time": 1777999805, - "notify_time": 1777999805, - "client_ip": "27.36.54.191", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600493300056719994", - "out_order_no": "202605060049254624267322074", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777999773, - "payment_time": 1777999793, - "notify_time": 1777999795, - "client_ip": "10.21.134.125", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600473600056710343", - "out_order_no": "202605060047109203569868703", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777999656, - "payment_time": 1777999676, - "notify_time": 1777999677, - "client_ip": "49.93.215.14", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600454900056715988", - "out_order_no": "202605060045345031073712478", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777999549, - "payment_time": 1777999578, - "notify_time": 1777999578, - "client_ip": "106.4.25.194", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600452700056719942", - "out_order_no": "202605060045104632700644502", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777999527, - "payment_time": 1777999557, - "notify_time": 1777999558, - "client_ip": "116.30.102.114", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600431400056717536", - "out_order_no": "20260506004304801947518387", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777999394, - "payment_time": 1777999413, - "notify_time": 1777999413, - "client_ip": "183.223.124.207", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600425400056717315", - "out_order_no": "202605060042338660366411384", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777999374, - "payment_time": 1777999397, - "notify_time": 1777999397, - "client_ip": "27.17.157.133", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600420000056713860", - "out_order_no": "202605060041324623117153104", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1777999320, - "payment_time": null, - "notify_time": null, - "client_ip": "183.223.124.207", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600395900056720602", - "out_order_no": "202605060039505516911479703", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777999199, - "payment_time": 1777999239, - "notify_time": 1777999239, - "client_ip": "119.97.37.242", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600384500056717700", - "out_order_no": "202605060038293119929084380", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1777999125, - "payment_time": null, - "notify_time": null, - "client_ip": "116.26.81.34", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600355400056723686", - "out_order_no": "202605060035459256232501561", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998954, - "payment_time": 1777999047, - "notify_time": 1777999047, - "client_ip": "49.85.249.151", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600353900056717065", - "out_order_no": "202605060035202755072402849", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998939, - "payment_time": 1777998972, - "notify_time": 1777998972, - "client_ip": "112.2.202.60", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600352600056721585", - "out_order_no": "202605060035195105533102327", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998926, - "payment_time": 1777998974, - "notify_time": 1777998974, - "client_ip": "114.217.105.203", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600345600056728639", - "out_order_no": "202605060034508670831393699", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998896, - "payment_time": 1777998916, - "notify_time": 1777998916, - "client_ip": "180.164.42.240", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600345000056715161", - "out_order_no": "202605060034266616555660202", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1777998890, - "payment_time": null, - "notify_time": null, - "client_ip": "49.85.249.151", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600344600056727740", - "out_order_no": "202605060034299875133495173", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998886, - "payment_time": 1777998904, - "notify_time": 1777998904, - "client_ip": "39.172.146.202", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600341700056718379", - "out_order_no": "202605060034087794435521361", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998857, - "payment_time": 1777998876, - "notify_time": 1777998876, - "client_ip": "27.187.65.181", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600340600056716506", - "out_order_no": "202605060033596419723299472", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998846, - "payment_time": 1777998875, - "notify_time": 1777998876, - "client_ip": "223.106.50.250", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600340100056722856", - "out_order_no": "202605060033575315886285648", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998841, - "payment_time": 1777998867, - "notify_time": 1777998868, - "client_ip": "202.98.17.140", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600335200056720694", - "out_order_no": "202605060033471145664241149", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1777998832, - "payment_time": null, - "notify_time": null, - "client_ip": "202.98.17.140", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600331700056714429", - "out_order_no": "202605060033039448674610682", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998797, - "payment_time": 1777998818, - "notify_time": 1777998818, - "client_ip": "223.104.148.10", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600330300056712536", - "out_order_no": "202605060032511072126836445", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998783, - "payment_time": 1777998807, - "notify_time": 1777998808, - "client_ip": "113.90.83.158", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600322500056714635", - "out_order_no": "202605060031583272302572243", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1777998745, - "payment_time": null, - "notify_time": null, - "client_ip": "183.18.45.161", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600320000056714496", - "out_order_no": "202605060031462369046434986", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998720, - "payment_time": 1777998742, - "notify_time": 1777998742, - "client_ip": "101.87.87.70", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600311500056718968", - "out_order_no": "202605060030584167603680908", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1777998675, - "payment_time": null, - "notify_time": null, - "client_ip": "101.87.87.70", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600302800056729119", - "out_order_no": "2026050600295856462476719", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998628, - "payment_time": 1777998654, - "notify_time": 1777998655, - "client_ip": "223.104.156.216", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600295400056727479", - "out_order_no": "202605060029477267471968354", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998594, - "payment_time": 1777998636, - "notify_time": 1777998636, - "client_ip": "39.188.4.149", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600295300056729657", - "out_order_no": "202605060029341848270363268", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998593, - "payment_time": 1777998648, - "notify_time": 1777998648, - "client_ip": "183.9.130.21", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600293200056713416", - "out_order_no": "202605060029189721840351590", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998572, - "payment_time": 1777998600, - "notify_time": 1777998600, - "client_ip": "221.227.38.240", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600285700056715585", - "out_order_no": "20260506002752243582454335", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998537, - "payment_time": 1777998561, - "notify_time": 1777998562, - "client_ip": "183.192.36.0", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600284800056721195", - "out_order_no": "202605060028313844115194221", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998528, - "payment_time": 1777998568, - "notify_time": 1777998568, - "client_ip": "58.247.23.36", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600281700056715525", - "out_order_no": "202605060027526361842819393", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998497, - "payment_time": 1777998517, - "notify_time": 1777998517, - "client_ip": "183.215.215.140", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600270400056722140", - "out_order_no": "202605060026496398271409974", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1777998424, - "payment_time": null, - "notify_time": null, - "client_ip": "39.188.4.149", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600270400056729847", - "out_order_no": "202605060026554490117666900", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998424, - "payment_time": 1777998450, - "notify_time": 1777998451, - "client_ip": "117.181.116.55", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600265300056721458", - "out_order_no": "202605060026383157487259893", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998413, - "payment_time": 1777998441, - "notify_time": 1777998441, - "client_ip": "113.15.105.88", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600260400056716406", - "out_order_no": "20260506002534969956841459", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998364, - "payment_time": 1777998395, - "notify_time": 1777998395, - "client_ip": "112.42.34.47", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600252100056728429", - "out_order_no": "2026050600251178059292973", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998322, - "payment_time": 1777998341, - "notify_time": 1777998342, - "client_ip": "111.25.249.154", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600250600056716863", - "out_order_no": "202605060024376399887500184", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998306, - "payment_time": 1777998329, - "notify_time": 1777998329, - "client_ip": "42.122.66.229", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600250600056721274", - "out_order_no": "202605060024583383242791460", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998306, - "payment_time": 1777998323, - "notify_time": 1777998323, - "client_ip": "121.239.106.25", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600250100056727030", - "out_order_no": "202605060024451596754020244", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998301, - "payment_time": 1777998322, - "notify_time": 1777998323, - "client_ip": "218.82.32.72", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600244600056724207", - "out_order_no": "202605060024245926659561913", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998286, - "payment_time": 1777998328, - "notify_time": 1777998329, - "client_ip": "27.40.77.133", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600243900056717692", - "out_order_no": "202605060024202884287277115", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998279, - "payment_time": 1777998301, - "notify_time": 1777998301, - "client_ip": "182.145.139.136", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050600234300056727509", - "out_order_no": "202605060023264529562700913", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777998223, - "payment_time": 1777998267, - "notify_time": 1777998267, - "client_ip": "223.104.119.65", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523474700056717993", - "out_order_no": "202605052346102194072199053", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777996067, - "payment_time": 1777996090, - "notify_time": 1777996090, - "client_ip": "120.244.197.40", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523453400056721240", - "out_order_no": "202605052345052276090545782", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777995934, - "payment_time": 1777995989, - "notify_time": 1777995989, - "client_ip": "114.88.131.9", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523445300056720658", - "out_order_no": "202605052344457234951509437", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777995893, - "payment_time": 1777995921, - "notify_time": 1777995921, - "client_ip": "117.136.104.16", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523442700056729156", - "out_order_no": "202605052344021984998714592", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777995867, - "payment_time": 1777995889, - "notify_time": 1777995889, - "client_ip": "125.92.149.255", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523440300056710728", - "out_order_no": "202605052343547961261593049", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777995843, - "payment_time": 1777995863, - "notify_time": 1777995863, - "client_ip": "101.90.59.76", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523430700056725565", - "out_order_no": "202605052343004128867527170", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777995787, - "payment_time": 1777995819, - "notify_time": 1777995820, - "client_ip": "114.97.1.210", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523424500056711106", - "out_order_no": "2026050523413655510198663", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777995765, - "payment_time": 1777995783, - "notify_time": 1777995783, - "client_ip": "111.60.17.206", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523415900056711312", - "out_order_no": "202605052341375057983445855", - "order_money": 315, - "user_money": 306.18, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777995719, - "payment_time": 1777995754, - "notify_time": 1777995754, - "client_ip": "14.146.29.155", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523413200056719705", - "out_order_no": "202605052341232628003263641", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777995692, - "payment_time": 1777995718, - "notify_time": 1777995719, - "client_ip": "221.15.132.52", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523404800056714848", - "out_order_no": "20260505234037793782045283", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777995648, - "payment_time": 1777995685, - "notify_time": 1777995685, - "client_ip": "112.224.15.191", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523402400056726401", - "out_order_no": "202605052338492212320409338", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777995624, - "payment_time": 1777995689, - "notify_time": 1777995689, - "client_ip": "216.236.33.130", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523384000056727941", - "out_order_no": "20260505233821995507726255", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777995520, - "payment_time": 1777995561, - "notify_time": 1777995561, - "client_ip": "220.197.230.59", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523362900056712981", - "out_order_no": "202605052336228352202731245", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777995389, - "payment_time": 1777995410, - "notify_time": 1777995410, - "client_ip": "221.226.76.184", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523354400056727449", - "out_order_no": "202605052335349092291275162", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777995344, - "payment_time": 1777995373, - "notify_time": 1777995384, - "client_ip": "1.202.143.115", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523352300056717951", - "out_order_no": "202605052335121456678899641", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777995323, - "payment_time": 1777995347, - "notify_time": 1777995347, - "client_ip": "112.86.92.173", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523194100056715796", - "out_order_no": "202605052319329094345264430", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777994381, - "payment_time": 1777994402, - "notify_time": 1777994402, - "client_ip": "112.96.209.191", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523191500056711768", - "out_order_no": "202605052318311198483736507", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777994355, - "payment_time": 1777994372, - "notify_time": 1777994372, - "client_ip": "119.118.54.127", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523160500056710867", - "out_order_no": "202605052315556906735370770", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777994165, - "payment_time": 1777994192, - "notify_time": 1777994193, - "client_ip": "180.213.192.113", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523141400056725957", - "out_order_no": "202605052314076428745744298", - "order_money": 315, - "user_money": 303.03, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1777994054, - "payment_time": null, - "notify_time": null, - "client_ip": "117.44.51.87", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523131100056712429", - "out_order_no": "202605052313029888500597684", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1777993991, - "payment_time": null, - "notify_time": null, - "client_ip": "117.44.51.87", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523115600056718397", - "out_order_no": "202605052311239787659063983", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777993916, - "payment_time": 1777993974, - "notify_time": 1777993974, - "client_ip": "120.244.132.28", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523111100056725925", - "out_order_no": "202605052310503103291626817", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777993871, - "payment_time": 1777993900, - "notify_time": 1777993900, - "client_ip": "14.120.48.219", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523093300056727260", - "out_order_no": "202605052309257462055955675", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777993773, - "payment_time": 1777993827, - "notify_time": 1777993827, - "client_ip": "39.148.151.85", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523092400056723926", - "out_order_no": "202605052309099584785381222", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777993764, - "payment_time": 1777993803, - "notify_time": 1777993803, - "client_ip": "183.229.181.151", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523083700056713077", - "out_order_no": "202605052308287783537728281", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777993717, - "payment_time": 1777993739, - "notify_time": 1777993739, - "client_ip": "113.221.89.191", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523074500056716391", - "out_order_no": "202605052307177211564483493", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777993665, - "payment_time": 1777993686, - "notify_time": 1777993687, - "client_ip": "36.48.46.39", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523055000056715270", - "out_order_no": "202605052304383970856193061", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777993550, - "payment_time": 1777993599, - "notify_time": 1777993599, - "client_ip": "112.96.67.21", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523054100056726150", - "out_order_no": "202605052305323763560296316", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777993541, - "payment_time": 1777993573, - "notify_time": 1777993573, - "client_ip": "124.160.203.62", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523035300056726500", - "out_order_no": "202605052303082197754777430", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777993433, - "payment_time": 1777993458, - "notify_time": 1777993459, - "client_ip": "113.100.38.33", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523033800056727028", - "out_order_no": "202605052303204095123258437", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777993418, - "payment_time": 1777993488, - "notify_time": 1777993488, - "client_ip": "116.169.2.202", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523032500056718618", - "out_order_no": "202605052303183929395126626", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777993405, - "payment_time": 1777993427, - "notify_time": 1777993428, - "client_ip": "220.200.97.230", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523024900056726793", - "out_order_no": "202605052302115776554860526", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777993369, - "payment_time": 1777993394, - "notify_time": 1777993394, - "client_ip": "172.236.224.48", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050523002900056729446", - "out_order_no": "202605052300077568396353904", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777993229, - "payment_time": 1777993258, - "notify_time": 1777993259, - "client_ip": "39.144.91.145", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522594400056725786", - "out_order_no": "20260505225937831918370990", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1777993184, - "payment_time": null, - "notify_time": null, - "client_ip": "39.144.91.145", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522532900056721895", - "out_order_no": "202605052252508694659422071", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777992809, - "payment_time": 1777992859, - "notify_time": 1777993042, - "client_ip": "113.246.199.61", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522522200056717953", - "out_order_no": "2026050522521560510393870", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1777992742, - "payment_time": null, - "notify_time": null, - "client_ip": "112.21.4.221", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522515500056729106", - "out_order_no": "202605052251456676870527425", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1777992715, - "payment_time": null, - "notify_time": null, - "client_ip": "112.21.4.221", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522500000056727596", - "out_order_no": "202605052249498223300716218", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777992600, - "payment_time": 1777992633, - "notify_time": 1777992634, - "client_ip": "49.93.177.224", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522493800056712875", - "out_order_no": "202605052249256604264682759", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777992578, - "payment_time": 1777992606, - "notify_time": 1777992606, - "client_ip": "43.198.16.132", - "device": "pc", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522493700056713390", - "out_order_no": "202605052249241983914172846", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777992577, - "payment_time": 1777992666, - "notify_time": 1777992666, - "client_ip": "15.204.73.191", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522491800056713379", - "out_order_no": "202605052249061033712364703", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777992558, - "payment_time": 1777992576, - "notify_time": 1777992577, - "client_ip": "118.112.81.154", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522491100056717356", - "out_order_no": "202605052247539884844748044", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777992551, - "payment_time": 1777992581, - "notify_time": 1777993038, - "client_ip": "112.66.7.97", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522485800056721148", - "out_order_no": "202605052248497165755099841", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777992538, - "payment_time": 1777992571, - "notify_time": 1777992572, - "client_ip": "106.224.70.149", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522484400056728200", - "out_order_no": "202605052248047219193201495", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777992524, - "payment_time": 1777992572, - "notify_time": 1777992572, - "client_ip": "223.89.54.210", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522482700056712189", - "out_order_no": "202605052248193142255184171", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1777992507, - "payment_time": null, - "notify_time": null, - "client_ip": "106.224.70.149", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522482300056715108", - "out_order_no": "202605052248142513358320866", - "order_money": 315, - "user_money": 306.18, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777992503, - "payment_time": 1777992527, - "notify_time": 1777992528, - "client_ip": "112.17.242.40", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522480800056720567", - "out_order_no": "202605052247571869382979239", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777992488, - "payment_time": 1777992522, - "notify_time": 1777992523, - "client_ip": "223.64.102.95", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522474300056718915", - "out_order_no": "202605052246389809251982275", - "order_money": 90.93, - "user_money": 88.38, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1777992463, - "payment_time": null, - "notify_time": null, - "client_ip": "14.212.111.223", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522473100056720927", - "out_order_no": "202605052247156283894364606", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777992451, - "payment_time": 1777992578, - "notify_time": 1777992578, - "client_ip": "112.224.195.109", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522472000056719503", - "out_order_no": "202605052246408651163700789", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777992440, - "payment_time": 1777992459, - "notify_time": 1777992460, - "client_ip": "115.201.19.64", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522471600056719815", - "out_order_no": "202605052247071473523768776", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1777992436, - "payment_time": null, - "notify_time": null, - "client_ip": "106.224.70.149", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522454800056721168", - "out_order_no": "202605052245355279401188343", - "order_money": 41.93, - "user_money": 40.33, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777992348, - "payment_time": 1777992377, - "notify_time": 1777992377, - "client_ip": "183.2.123.197", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522452200056723466", - "out_order_no": "202605052245061077680131433", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1777992322, - "payment_time": null, - "notify_time": null, - "client_ip": "39.91.93.170", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522452100056718216", - "out_order_no": "202605052245134707867721186", - "order_money": 41.93, - "user_money": 40.75, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777992321, - "payment_time": 1777992348, - "notify_time": 1777992349, - "client_ip": "183.94.149.37", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522450300056719386", - "out_order_no": "202605052244232536331168221", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777992303, - "payment_time": 1777992353, - "notify_time": 1777992353, - "client_ip": "66.55.77.13", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522422100056715627", - "out_order_no": "202605052242142943698217211", - "order_money": 19.53, - "user_money": 18.98, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777992141, - "payment_time": 1777992162, - "notify_time": 1777992163, - "client_ip": "49.66.203.116", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522413000056725709", - "out_order_no": "202605052240596199136538545", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777992090, - "payment_time": 1777992140, - "notify_time": 1777992141, - "client_ip": "223.68.101.23", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522404300056720775", - "out_order_no": "202605052239506462281923798", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777992043, - "payment_time": 1777992085, - "notify_time": 1777992086, - "client_ip": "223.104.83.106", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522401900056720916", - "out_order_no": "202605052239461608749911645", - "order_money": 90.93, - "user_money": 87.47, - "order_status": "pending", - "notify_status": "not_notified", - "create_time": 1777992019, - "payment_time": null, - "notify_time": null, - "client_ip": "121.239.238.2", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - }, - { - "order_no": "2026050522394400056724439", - "out_order_no": "20260505223915163695073314", - "order_money": 19.53, - "user_money": 18.78, - "order_status": "success", - "notify_status": "notify_success", - "create_time": 1777991984, - "payment_time": 1777992009, - "notify_time": 1777992009, - "client_ip": "27.186.253.181", - "device": "mobile", - "order_remark": "", - "refund_amount": 0, - "refund_time": 0 - } -] \ No newline at end of file diff --git a/apis/public/file.api b/apis/public/file.api new file mode 100644 index 0000000..e05b40c --- /dev/null +++ b/apis/public/file.api @@ -0,0 +1,58 @@ +syntax = "v1" + +info ( + title: "File API" + desc: "API for ppanel file upload" + author: "Codex" + email: "codex@openai.com" + version: "0.0.1" +) + +import "../types.api" + +type ( + FileUploadInitRequest { + BizType string `json:"biz_type" validate:"required"` + FileName string `json:"file_name" validate:"required"` + ContentType string `json:"content_type" validate:"required"` + Size int64 `json:"size" validate:"required"` + Sha256 string `json:"sha256"` + } + + FileUploadInitResponse { + FileId string `json:"file_id"` + ObjectKey string `json:"object_key"` + UploadURL string `json:"upload_url"` + Method string `json:"method"` + Headers map[string]string `json:"headers"` + ExpiredAt int64 `json:"expired_at"` + } + + FileUploadCompleteRequest { + FileId string `json:"file_id" validate:"required"` + } + + FileUploadCompleteResponse { + FileId string `json:"file_id"` + ObjectKey string `json:"object_key"` + Size int64 `json:"size"` + ContentType string `json:"content_type"` + Etag string `json:"etag"` + Status string `json:"status"` + } +) + +@server ( + prefix: v1/public/file + group: public/file + middleware: AuthMiddleware,DeviceMiddleware +) +service ppanel { + @doc "Init file upload" + @handler FileUploadInit + post /upload/init (FileUploadInitRequest) returns (FileUploadInitResponse) + + @doc "Complete file upload" + @handler FileUploadComplete + post /upload/complete (FileUploadCompleteRequest) returns (FileUploadCompleteResponse) +} diff --git a/deliverables/ec2-ssh/README.txt b/deliverables/ec2-ssh/README.txt new file mode 100644 index 0000000..114b4ae --- /dev/null +++ b/deliverables/ec2-ssh/README.txt @@ -0,0 +1,20 @@ +EC2 SSH ่ฟžๆŽฅ่ต„ๆ–™ + +ๆœๅŠกๅ™จๅ็งฐ: hifast-hk-app-01 +ๅ…ฌ็ฝ‘ IP: 43.198.248.161 +็™ปๅฝ•็”จๆˆท: ubuntu + +็ง้’ฅๆ–‡ไปถ: +- hifast-hk-app-01-reset + +ๅ…ฌ้’ฅๆ–‡ไปถ: +- hifast-hk-app-01-reset.pub + +่ฟžๆŽฅๅ‘ฝไปค: +ssh -i hifast-hk-app-01-reset ubuntu@43.198.248.161 + +ๅฆ‚ๆžœๅœจ Mac / Linux ไธŠไฝฟ็”จ๏ผŒๅ…ˆๆ‰ง่กŒ: +chmod 600 hifast-hk-app-01-reset + +ๅฆ‚ๆžœ่ฆ็ป™ๅˆซไบบไฝฟ็”จ๏ผŒๅช้œ€่ฆๆŠŠ็ง้’ฅๆ–‡ไปถ hifast-hk-app-01-reset ๅ‘็ป™ๅฏนๆ–นๅณๅฏใ€‚ +ๅ‡บไบŽๅฎ‰ๅ…จ่€ƒ่™‘๏ผŒๅปบ่ฎฎ้€š่ฟ‡ๅฎ‰ๅ…จๆธ ้“ไผ ่พ“๏ผŒๅนถๅœจๅŽ็ปญ้œ€่ฆๆ—ถ้‡ๆ–ฐ่ฝฎๆขๅฏ†้’ฅใ€‚ diff --git a/deliverables/ec2-ssh/hifast-hk-app-01-reset b/deliverables/ec2-ssh/hifast-hk-app-01-reset new file mode 100644 index 0000000..28b76e8 --- /dev/null +++ b/deliverables/ec2-ssh/hifast-hk-app-01-reset @@ -0,0 +1,8 @@ +-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW +QyNTUxOQAAACDb6msDqmSHLv0mWgCP4vfjQ3A552qv95uQdsH94RnoCgAAAKjy5KDa8uSg +2gAAAAtzc2gtZWQyNTUxOQAAACDb6msDqmSHLv0mWgCP4vfjQ3A552qv95uQdsH94RnoCg +AAAEDwSb0b/0S6Tw8Od5hAtIKqt1JvomqQQS44Ty3xL+FjPtvqawOqZIcu/SZaAI/i9+ND +cDnnaq/3m5B2wf3hGegKAAAAIWhpZmFzdC1oay1hcHAtMDEtcmVzZXQtMjAyNi0wNS0xMA +ECAwQ= +-----END OPENSSH PRIVATE KEY----- diff --git a/deliverables/ec2-ssh/hifast-hk-app-01-reset.pub b/deliverables/ec2-ssh/hifast-hk-app-01-reset.pub new file mode 100644 index 0000000..7a96127 --- /dev/null +++ b/deliverables/ec2-ssh/hifast-hk-app-01-reset.pub @@ -0,0 +1 @@ +ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINvqawOqZIcu/SZaAI/i9+NDcDnnaq/3m5B2wf3hGegK hifast-hk-app-01-reset-2026-05-10 diff --git a/deploy/aws/ap-east-1/README.md b/deploy/aws/ap-east-1/README.md index 20991eb..cc77a0b 100644 --- a/deploy/aws/ap-east-1/README.md +++ b/deploy/aws/ap-east-1/README.md @@ -4,7 +4,7 @@ ็›ฎๆ ‡ๆžถๆž„๏ผš -`DNS -> ALB -> WAF -> EC2(Nginx + ppanel-server + observability) -> RDS MySQL + ElastiCache Redis` +`DNS -> ALB -> WAF -> EC2(Nginx + ppanel-server + Redis + observability) -> RDS MySQL` ## 1. ่ต„ๆบๆธ…ๅ• @@ -16,7 +16,7 @@ 4. ๅ…ฌๆœ‰ / ็งๆœ‰่ทฏ็”ฑ่กจ 5. ๅฎ‰ๅ…จ็ป„ 6. RDS MySQL -7. ElastiCache Redis OSS +7. EC2 ๆœฌๆœบ Redis Docker 8. EC2 9. ACM ่ฏไนฆ 10. ALB + Target Group @@ -28,7 +28,7 @@ - VPC: `ppanel-hk-prod` - EC2: `ppanel-app-hk-01` - RDS: `ppanel-mysql-hk` -- Redis: `ppanel-redis-hk` +- Redis container: `hifast-redis` - ALB: `ppanel-alb-hk` - WAF: `ppanel-waf-hk` @@ -42,6 +42,7 @@ - Disk: `gp3 80GB` - Public subnet: ๆ˜ฏ - IAM Role: ๅ…่ฎธ่ฏปๅ– CloudWatch / SSM๏ผˆๅฆ‚ไฝฟ็”จ๏ผ‰ +- ๅฆ‚ๆžœ่ฆๅœจ AWS EC2 ๆœฌๆœบๆ‰ง่กŒ S3 ๅค‡ไปฝ๏ผš้ขๅค–ๅ…่ฎธๅ†™ๅ…ฅไธ“็”จๅค‡ไปฝๆกถ ### RDS MySQL @@ -54,21 +55,21 @@ - Charset: `utf8mb4` - Backup: `7-14 days` -### ElastiCache Redis OSS +### Redis -- Engine: Redis OSS 7.x -- Node type: `cache.m7g.large` -- Cluster mode: disabled -- Multi-AZ: ๆŒ‰้ข„็ฎ—ๅ†ณๅฎš๏ผŒๆญฃๅผ็Žฏๅขƒๅปบ่ฎฎๅผ€ๅฏ -- Public access: ไธๅผ€ๆ”พ -- TLS: ๅฝ“ๅ‰ๆจกๆฟๆŒ‰ **ๅ…ณ้—ญ** ่ง„ๅˆ’ +- ้ƒจ็ฝฒไฝ็ฝฎ๏ผšไธšๅŠก EC2 ๆœฌๆœบ +- ้ƒจ็ฝฒๆ–นๅผ๏ผšDocker +- ็‰ˆๆœฌ๏ผš`redis:8.2.1` +- ็›‘ๅฌ๏ผš`0.0.0.0:6379` +- ๅบ”็”จ่ฟžๆŽฅ๏ผš`127.0.0.1:6379` +- ๅฎ‰ๅ…จ็ป„๏ผšไป…ๅฏน็™ฝๅๅ•ๅค‡็”จ่Š‚็‚นๆˆ–ๅŒๆœบๅบ”็”จๅผ€ๆ”พ ## 3. ็ฝ‘็ปœไธŽๅฎ‰ๅ…จ็ป„ ### ๅญ็ฝ‘ๅธƒๅฑ€ - `public-a`, `public-b`: ALB / EC2 -- `private-a`, `private-b`: RDS / Redis +- `private-a`, `private-b`: RDS ### ๅฎ‰ๅ…จ็ป„ๅปบ่ฎฎ @@ -99,10 +100,10 @@ - Inbound - `3306/tcp` from `sg-ec2` -#### `sg-redis` +#### `sg-ec2` ้ขๅค–่ฏดๆ˜Ž -- Inbound - - `6379/tcp` from `sg-ec2` +- ๅฆ‚ๆžœ้œ€่ฆๅค–้ƒจๅค‡็”จ่Š‚็‚นๅคๅˆถ Redis๏ผŒๅ†้ขๅค–ๆ”พ่กŒ๏ผš + - `6379/tcp` from `104.238.220.230/32` ## 4. ALB / Target Group / ๅฅๅบทๆฃ€ๆŸฅ @@ -198,6 +199,7 @@ - `MySQL.Addr` - `MySQL.Password` - `Redis.Host` +- `Redis.Pass` - `JwtAuth.AccessSecret` - `Administrator.Email` - `Administrator.Password` @@ -217,6 +219,41 @@ Redis ็บฆๅฎšไฟๆŒไธๅ˜๏ผš ๆŠŠ่„šๆœฌไธŠไผ ๅˆฐ EC2 ๅŽๆ‰ง่กŒ๏ผš +## 9. 104 ็พๅค‡่Š‚็‚นๅธธ็”จ่ฟ็ปด่„šๆœฌ + +ๅฆ‚ๆžœไฝ ่ฆๅœจ `104.238.220.230` ไธŠๆ‰ง่กŒๆ•ฐๆฎ่ฟ็งปใ€ไธปไปŽ้‡ๆ‹‰ใ€ไธปๅบ“ๆๅ‡๏ผŒๅฏไปฅ็›ดๆŽฅๅค็”จไป“ๅบ“้‡Œ็š„่ฟ™ๅ‡ ไปฝ่„šๆœฌ๏ผš + +- ๆ•ฐๆฎๅฏผๅ‡บ / ๅฏผๅ…ฅไบคไบ’ๅทฅๅ…ท๏ผš + - [`deploy/scripts/hifast_data_sync_tool.sh`](/Users/Apple/code_vpn/vpn/ppanel-server/deploy/scripts/hifast_data_sync_tool.sh) +- MySQL ไธปไปŽ่ฟ็ปดๅทฅๅ…ท๏ผš + - [`deploy/scripts/mysql_replica_ops.sh`](/Users/Apple/code_vpn/vpn/ppanel-server/deploy/scripts/mysql_replica_ops.sh) +- Redis ไธปไปŽ่ฟ็ปดๅทฅๅ…ท๏ผš + - [`deploy/scripts/redis_replica_ops.sh`](/Users/Apple/code_vpn/vpn/ppanel-server/deploy/scripts/redis_replica_ops.sh) +- ็ปŸไธ€ๆ€ปๅ…ฅๅฃ๏ผš + - [`deploy/scripts/hifast_data_sync_tool.sh`](/Users/Apple/code_vpn/vpn/ppanel-server/deploy/scripts/hifast_data_sync_tool.sh) +- ไธปไปŽ่ฟ็ปด็Žฏๅขƒๆจกๆฟ๏ผš + - [`deploy/aws/ap-east-1/configs/replica-ops.env.example`](/Users/Apple/code_vpn/vpn/ppanel-server/deploy/aws/ap-east-1/configs/replica-ops.env.example) + +### 9.1 ๆ•ฐๆฎ่ฟ็งปๅทฅๅ…ท + +ๆ”ฏๆŒ๏ผš + +- ๅค‡ไปฝ MySQL ๅˆฐ S3 +- ๅค‡ไปฝ Redis ๅˆฐ S3 +- ไปŽๆญฃๅผๅบ“ๅฏผๅ‡บ MySQL `sql.gz` +- ๆŠŠ `sql.gz` ๅฏผๅ…ฅ AWS RDS +- ไปŽๆญฃๅผ Redis ๅฏผๅ‡บ `RDB` +- ๅฐ† `RDB` ๅฏผๅ…ฅ Docker Redis ๆˆ–ๅฎฟไธปๆœบ Redis +- ๆŸฅ็œ‹ MySQL / Redis ๅฝ“ๅ‰ไธปไปŽ็Šถๆ€ +- ๅผบๅˆถ้‡ๆ‹‰ MySQL / Redis ไธปไปŽ +- ๆŠŠ MySQL / Redis ไปŽๅบ“ๆๅ‡ไธบๅฏๅ†™ไธปๅบ“ + +็คบไพ‹๏ผš + +```bash +bash deploy/scripts/hifast_data_sync_tool.sh /root/replica-ops.env +``` + ```bash chmod +x deploy/scripts/bootstrap_aws_ec2.sh sudo APP_DIR=/opt/ppanel deploy/scripts/bootstrap_aws_ec2.sh @@ -244,7 +281,7 @@ docker compose -f docker-compose.cloud.yml up -d chmod +x deploy/scripts/preflight_aws_hk.sh APP_DIR=/opt/ppanel \ RDS_HOST= \ -REDIS_HOST= \ +REDIS_HOST=127.0.0.1 \ deploy/scripts/preflight_aws_hk.sh ``` @@ -260,7 +297,7 @@ deploy/scripts/preflight_aws_hk.sh 4. ็”จๆˆทๆณจๅ†Œ / ็™ปๅฝ• 5. ่ฎข้˜…ๆŸฅ่ฏข 6. ่Š‚็‚นไธŠๆŠฅ `/v1/server/status` -7. Redis ๅฏๅ†™็ผ“ๅญ˜ +7. ๆœฌๆœบ Redis ๅฏๅ†™็ผ“ๅญ˜ 8. Asynq ๅฏๅ…ฅ้˜Ÿๅนถๆถˆ่ดน ## 10. ๆญฃๅผๅˆ‡ๆข @@ -270,7 +307,7 @@ deploy/scripts/preflight_aws_hk.sh 1. ALB 5xx ไธบ 0 2. EC2 CPU / Memory ๆญฃๅธธ 3. RDS CPU / Connections ๆญฃๅธธ -4. Redis CPU / Connections / Memory ๆญฃๅธธ +4. ๆœฌๆœบ Redis CPU / Connections / Memory ๆญฃๅธธ 5. WAF ๅทฒๆŒ‚ๅˆฐ ALB 6. EC2 ๅฎ‰ๅ…จ็ป„ๆฒกๆœ‰ๅฏนๅ…ฌ็ฝ‘ๆ”พ `8080/3333/9090/4317` @@ -288,7 +325,7 @@ deploy/scripts/preflight_aws_hk.sh - ALB `RequestCount`, `HTTPCode_ELB_5XX_Count`, `TargetResponseTime` - EC2 `CPUUtilization`, `NetworkIn`, `NetworkOut`, `StatusCheckFailed` - RDS `CPUUtilization`, `DatabaseConnections`, `ReadLatency`, `WriteLatency` -- Redis `EngineCPUUtilization`, `CurrConnections`, `BytesUsedForCache` +- Redis ๅฎนๅ™จ CPU / Memory / restart count ## 12. ่ฟ™ๆฌกๆ–นๆกˆ็š„่พน็•Œ @@ -296,11 +333,31 @@ deploy/scripts/preflight_aws_hk.sh - ้ฆ™ๆธฏๅŒบๆ–ฐ่ดฆๅท็š„้ƒจ็ฝฒๆจกๆฟ - ๆ–ฐ็ฉบ็ŽฏๅขƒๅฏๅŠจไธŽ้ชŒ่ฏๆต็จ‹ -- ALB / WAF / EC2 / RDS / Redis ็š„่ฝๅœฐ็บฆๅฎš +- ALB / WAF / EC2 / RDS / ๆœฌๆœบ Redis ็š„่ฝๅœฐ็บฆๅฎš ไธๅŒ…ๅซ๏ผš - ๆ—งๆ•ฐๆฎ่ฟ็งป - Terraform / CloudFormation ่‡ชๅŠจๅปบ่ต„ๆบ -- Redis TLS ๆ”น้€  +- Redis ๆ‰˜็ฎก็‰ˆๆ”น้€  - ๅคšๆดป / ่‡ชๅŠจๆ‰ฉ็ผฉๅฎน + +## 13. S3 ๅค‡ไปฝ่กฅๅผบ + +ๅฝ“ๅ‰ๅทฒ่ฝๅœฐ็š„ S3 ๅค‡ไปฝๆกถ๏ผš + +- `hifast-prod-backups-200810848252-ap-east-1` + +ๅปบ่ฎฎไธŽ็Žฐ็ฝ‘็ป“ๅˆๆ–นๅผ๏ผš + +1. `RDS automated backup` ็ปง็ปญไฟ็•™๏ผŒไฝœไธบ็ฌฌไธ€ๅฑ‚ๆขๅค่ƒฝๅŠ› +2. `104` ๅค–้ƒจ MySQL ไปŽๅบ“ๆ‰ง่กŒ้€ป่พ‘ๅค‡ไปฝๅนถไธŠไผ ๅˆฐ S3๏ผŒไฝœไธบ็ฌฌไบŒๅฑ‚ๅฏไธ‹่ฝฝๅค‡ไปฝ +3. `104` ๅค–้ƒจ Redis ไปŽๅบ“ๆŒ‰้œ€ๅฏผๅ‡บ `RDB` ๅˆฐ S3๏ผŒ่กฅ้ฝ็ผ“ๅญ˜็ฑป็พๅค‡ๆๆ–™ + +ไป“ๅบ“ไธญๅทฒ่กฅๅ……๏ผš + +- ็Žฏๅขƒๅ˜้‡ๆจกๆฟ๏ผš[`configs/backup-to-s3.env.example`](./configs/backup-to-s3.env.example) +- MySQL ๅค‡ไปฝ่„šๆœฌ๏ผš[`../../scripts/mysql_backup_to_s3.sh`](../../scripts/mysql_backup_to_s3.sh) +- Redis ๅค‡ไปฝ่„šๆœฌ๏ผš[`../../scripts/redis_rdb_backup_to_s3.sh`](../../scripts/redis_rdb_backup_to_s3.sh) + +ๅปบ่ฎฎๆŠŠ MySQL ๅค‡ไปฝ่„šๆœฌไผ˜ๅ…ˆ้ƒจ็ฝฒๅˆฐ `104`๏ผŒๅ› ไธบๅฎƒ็›ดๆŽฅ่ฟžๆŽฅๆœฌๅœฐๅช่ฏปไปŽๅบ“๏ผŒๅฏน AWS ไธปๅบ“ๆ‰ฐๅŠจๆœ€ๅฐใ€‚ diff --git a/deploy/aws/ap-east-1/configs/backup-to-s3.env.example b/deploy/aws/ap-east-1/configs/backup-to-s3.env.example new file mode 100644 index 0000000..a45fc7e --- /dev/null +++ b/deploy/aws/ap-east-1/configs/backup-to-s3.env.example @@ -0,0 +1,18 @@ +AWS_REGION=ap-east-1 +S3_BUCKET=hifast-prod-backups-200810848252-ap-east-1 +S3_PREFIX=mysql +BACKUP_DIR=/var/backups/hifast +HOST_TAG=104-standby +KEEP_LOCAL_DAYS=3 +CHECK_REPLICA=1 + +MYSQL_HOST=127.0.0.1 +MYSQL_PORT=3306 +MYSQL_USER=backup_reader +MYSQL_PASSWORD=CHANGE_ME +MYSQL_SOCKET= +MYSQL_DATABASE=hifast + +REDIS_HOST=127.0.0.1 +REDIS_PORT=6379 +REDIS_PASSWORD=CHANGE_ME diff --git a/deploy/aws/ap-east-1/configs/mysql-seed-primary-and-replica.env.example b/deploy/aws/ap-east-1/configs/mysql-seed-primary-and-replica.env.example new file mode 100644 index 0000000..38382f4 --- /dev/null +++ b/deploy/aws/ap-east-1/configs/mysql-seed-primary-and-replica.env.example @@ -0,0 +1,20 @@ +PRIMARY_HOST=hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com +PRIMARY_PORT=3306 +PRIMARY_USER=admin +PRIMARY_PASSWORD=CHANGE_ME +PRIMARY_DB=hifast + +PRIMARY_REPL_USER=repl +PRIMARY_REPL_PASSWORD=CHANGE_ME +PRIMARY_REPL_HOST=104.238.220.230 +PRIMARY_BINLOG_RETENTION_HOURS=24 + +REPLICA_HOST=127.0.0.1 +REPLICA_PORT=3306 +REPLICA_USER=root +REPLICA_PASSWORD= +REPLICA_SOCKET=/var/run/mysqld/mysqld.sock +REPLICA_DB=hifast +REPLICA_SOURCE_SSL=1 + +DUMP_FILE= diff --git a/deploy/aws/ap-east-1/configs/ppanel.yaml.example b/deploy/aws/ap-east-1/configs/ppanel.yaml.example index 90d42d8..8d16e5d 100644 --- a/deploy/aws/ap-east-1/configs/ppanel.yaml.example +++ b/deploy/aws/ap-east-1/configs/ppanel.yaml.example @@ -34,8 +34,8 @@ MySQL: SlowThreshold: 1000 Redis: - Host: YOUR_REDIS_PRIMARY_ENDPOINT:6379 - Pass: + Host: 127.0.0.1:6379 + Pass: CHANGE_ME_TO_REDIS_PASSWORD DB: 0 PoolSize: 100 MinIdleConns: 10 diff --git a/deploy/aws/ap-east-1/configs/replica-ops.env.example b/deploy/aws/ap-east-1/configs/replica-ops.env.example new file mode 100644 index 0000000..5c86942 --- /dev/null +++ b/deploy/aws/ap-east-1/configs/replica-ops.env.example @@ -0,0 +1,23 @@ +MYSQL_HOST=127.0.0.1 +MYSQL_PORT=3306 +MYSQL_USER=root +MYSQL_PASSWORD=CHANGE_ME +MYSQL_SOCKET= + +REPL_SOURCE_HOST=hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com +REPL_SOURCE_PORT=3306 +REPL_SOURCE_USER=repl +REPL_SOURCE_PASSWORD=CHANGE_ME +REPL_SOURCE_SSL=1 +REPL_SOURCE_LOG_FILE= +REPL_SOURCE_LOG_POS= +REPL_SOURCE_AUTO_POSITION=1 + +REDIS_HOST=127.0.0.1 +REDIS_PORT=6379 +REDIS_PASSWORD=CHANGE_ME + +REDIS_SOURCE_HOST=43.198.248.161 +REDIS_SOURCE_PORT=6379 +REDIS_SOURCE_USER= +REDIS_SOURCE_PASSWORD=CHANGE_ME diff --git a/docker-compose.cloud.yml b/docker-compose.cloud.yml index 5939843..9259e3e 100644 --- a/docker-compose.cloud.yml +++ b/docker-compose.cloud.yml @@ -6,7 +6,7 @@ # 4. ่ฟ่กŒ: docker-compose -f docker-compose.cloud.yml up -d # # ็ฝ‘็ปœ่ฏดๆ˜Ž๏ผš -# ppanel-server ไฝฟ็”จ host ็ฝ‘็ปœ๏ผˆๅฏๅ‡บๅค–็ฝ‘๏ผŒ็›ดๆŽฅ่ฎฟ้—ฎ AWS RDS/ElastiCache ็ง็ฝ‘ๅœฐๅ€๏ผ‰ +# ppanel-server ไฝฟ็”จ host ็ฝ‘็ปœ๏ผˆๅฏๅ‡บๅค–็ฝ‘๏ผŒ็›ดๆŽฅ่ฎฟ้—ฎ AWS RDS / ๆœฌๆœบ Redis๏ผ‰ # ็›‘ๆŽงๆœๅŠก๏ผˆLoki/Tempo/Grafana/Prometheus๏ผ‰ๅœจ ppanel_net bridge ็ฝ‘็ปœไธญ # Tempo(4317) ๅฐ†็ซฏๅฃๆ˜ ๅฐ„ๅˆฐ 127.0.0.1๏ผŒppanel-server ้€š่ฟ‡ host ็ฝ‘็ปœ่ฎฟ้—ฎ # ็›‘ๆŽง็ซฏๅฃ็ป‘ๅฎš 127.0.0.1๏ผŒ้œ€้€š่ฟ‡ SSH ้šง้“ๆˆ– Nginx ๅไปฃ่ฎฟ้—ฎ @@ -123,7 +123,7 @@ services: container_name: ppanel-grafana restart: always ports: - - "127.0.0.1:3333:3000" # ไป…ๆœฌๆœบๅฏ่ฎฟ้—ฎ๏ผŒ้œ€ SSH ้šง้“ๆˆ– Nginx ๅไปฃ + - "3333:3000" # ไป…ๆœฌๆœบๅฏ่ฎฟ้—ฎ๏ผŒ้œ€ SSH ้šง้“ๆˆ– Nginx ๅไปฃ environment: - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD:?่ฏทๅœจ .env ๆ–‡ไปถไธญ่ฎพ็ฝฎ GRAFANA_PASSWORD} - GF_USERS_ALLOW_SIGN_UP=false diff --git a/etc/ppanel.yaml b/etc/ppanel.yaml index 8e21654..a2423cf 100644 --- a/etc/ppanel.yaml +++ b/etc/ppanel.yaml @@ -61,6 +61,21 @@ Trace: # ้“พ่ทฏ่ฟฝ่ธช้…็ฝฎ (OpenTelemetry) Batcher: otlpgrpc # ๆœฌๅœฐๅผ€ๅ‘็•™็ฉบ""; ็”Ÿไบงๅกซ otlpgrpc Endpoint: "127.0.0.1:4317" # host ็ฝ‘็ปœๆจกๅผ; bridge ๆจกๅผๆ”นไธบ tempo:4317 +S3: + Enable: false + Region: "" + Bucket: "" + Endpoint: "" + AccessKey: "" + SecretKey: "" + SessionToken: "" + Prefix: "app-upload" + PublicBaseURL: "" + UsePathStyle: false + PresignExpireSeconds: 300 + MaxUploadSize: 104857600 + AllowedContentTypes: "application/zip,application/x-zip-compressed,application/gzip,application/x-gzip,application/octet-stream,text/plain,application/json" + device: enable: true # ๅผ€ๅฏ่ฎพๅค‡ๅŠ ๅฏ†้€šไฟก security_secret: "" # AESๅŠ ๅฏ†ๅฏ†้’ฅ๏ผŒ้œ€่ฆๅ’ŒApp็ซฏไธ€่‡ด๏ผŒkey=SHA256(security_secret)[:32] @@ -72,4 +87,4 @@ Administrator: Register: EnableTrial: true EnableTrialEmailWhitelist: true - TrialEmailDomainWhitelist: "facebook.com,yahoo.com,qq.com,live.com,outlook.com,msn.com,example.com,go.com,aol.com,free.fr,aliyun.com,163.com,yandex.ru,indiatimes.com,alibaba.com,geocities.com,about.com,naver.com,netscape.com,yahoo.co.jp,earthlink.net,zoho.com,sky.com,mail.ru,angelfire.com,uol.com.br,spb.ru,yandex.com,globo.com,gmail.com,medscape.com,space.com,discovery.com,t-online.de,mac.com,icloud.com,homestead.com,lycos.com,web.id,nus.edu.sg,altavista.com,berlin.de,rambler.ru,pp.ua,comcast.net,sapo.pt,msk.ru,ancestry.com,daum.net,proton.me,law.com,bt.com,techspot.com,icq.com,sina.cn,libero.it,test.com,yourdomain.com,docomo.ne.jp,wp.pl,hotmail.com,orange.fr,onet.pl,me.com,india.com,kansascity.com,wanadoo.fr,fortunecity.com,web.de,terra.com.br,att.net,canada.com,skynet.be,ya.ru,excite.com,detik.com,compuserve.com,ig.com.br,zp.ua,gmx.net,xoom.com,mindspring.com,freeserve.co.uk,interia.pl,excite.co.jp,test.de,shaw.ca,virgilio.it,chez.com,rr.com,freenet.de,ntlworld.com,seznam.cz,arcor.de,tiscali.it,sympatico.ca,sina.com,gazeta.pl,care2.com,yam.com,r7.com,telenet.be,rcn.com,geek.com,sfr.fr,hotbot.com,cox.net,blueyonder.co.uk,tom.com,virginmedia.com,btinternet.com,iinet.net.au,rogers.com,ireland.com,pochta.ru,ozemail.com.au,catholic.org,bluewin.ch,chat.ru,virgin.net,verizon.net,erols.com,lycos.de,lycos.co.uk,protonmail.com,doityourself.com,home.nl,nate.com,casino.com,o2.co.uk,terra.es,mail.com,albawaba.com,126.com,www.com,planet.nl,sanook.com,21cn.com,online.de,name.com,i.ua,centrum.cz,rin.ru,aol.co.uk,voila.fr,walla.co.il,poste.it,netcom.com,parrot.com,charter.net,mydomain.com,mail-tester.com,myway.com,chello.nl,club-internet.fr,sdf.org,tiscali.co.uk,freeuk.com,unican.es,sci.fi,anonymize.com,sify.com,metacrawler.com,go.ro,ivillage.com,telus.net,dailypioneer.com,iespana.es,lycos.es,hey.com,sweb.cz,optusnet.com.au,alice.it,tpg.com.au,hamptonroads.com,saudia.com,lycos.nl,blackplanet.com,frontier.com,looksmart.com,pobox.com,prodigy.net,i.am,freeyellow.com,gmx.com,bigpond.com,crosswinds.net,dejanews.com,wanadoo.es,foxmail.com,eircom.net,islamonline.net,webindia123.com,oath.com,frontiernet.net,hetnet.nl,onmilwaukee.com,ukr.net,bugmenot.com,neuf.fr,kiwibox.com,za.com,iol.it,zonnet.nl,newmail.ru,pacbell.net,cogeco.ca,depechemode.com,concentric.net,aim.com,f5.si,yahoo.jp,terra.com,hot.ee,netzero.net,netins.net,sprynet.com,mailbox.org,mail2web.com,o2.pl,idirect.com,bigfoot.com,netspace.net.au,masrawy.com,supereva.it,yahoo.de,lycos.it,yeah.net,montevideo.com.uy,gmx.de,yahoo.co.uk,yahoofs.com,scubadiving.com,hushmail.com,iprimus.com.au,gportal.hu,swissinfo.org,inbox.com,bolt.com,telstra.com,bellsouth.net,spray.se,c3.hu,attbi.com,talktalk.co.uk,dynu.net,juno.com,yahoo.fr,msn.co.uk,fr.nf,pe.hu,bigpond.net.au,incredimail.com,adelphia.net,elvis.com,interfree.it,starmedia.com,seanet.com,yahoo.com.tw,zip.net,tds.net,she.com,forthnet.gr,land.ru,wow.com,dnsmadeeasy.com,webjump.com,singnet.com.sg,spacewar.com,tin.it,4mg.com,sp.nl,wowway.com,dmv.com,bangkok.com,fastmail.fm,sbcglobal.net,bright.net,usa.com,37.com,aeiou.pt,terra.cl,thirdage.com,btconnect.com,optimum.net,cableone.net,talkcity.com,blogos.com,c2i.net,iwon.com,aver.com,barcelona.com,ddnsfree.com,oi.com.br,lex.bg,roadrunner.com,airmail.net,lawyer.com,yahoo.com.cn,cu.cc,ananzi.co.za,au.ru,pipeline.com,cs.com,3ammagazine.com,gmx.at,qwest.net,btopenworld.com,easypost.com,westnet.com.au,nyc.com,korea.com,front.ru,inbox.lv,yahoo.com.br,ny.com,hispavista.com,abv.bg,mchsi.com,apollo.lv,everyone.net,terra.com.ar,singpost.com,doctor.com,garbage.com,bizhosting.com,go2net.com,clerk.com,games.com,charm.net,onlinehome.de,laposte.net" # ๅกซไฝ ็š„็™ฝๅๅ•ๅŸŸๅ๏ผŒ้€—ๅทๅˆ†้š” \ No newline at end of file + TrialEmailDomainWhitelist: "facebook.com,yahoo.com,qq.com,live.com,outlook.com,msn.com,example.com,go.com,aol.com,free.fr,aliyun.com,163.com,yandex.ru,indiatimes.com,alibaba.com,geocities.com,about.com,naver.com,netscape.com,yahoo.co.jp,earthlink.net,zoho.com,sky.com,mail.ru,angelfire.com,uol.com.br,spb.ru,yandex.com,globo.com,gmail.com,medscape.com,space.com,discovery.com,t-online.de,mac.com,icloud.com,homestead.com,lycos.com,web.id,nus.edu.sg,altavista.com,berlin.de,rambler.ru,pp.ua,comcast.net,sapo.pt,msk.ru,ancestry.com,daum.net,proton.me,law.com,bt.com,techspot.com,icq.com,sina.cn,libero.it,test.com,yourdomain.com,docomo.ne.jp,wp.pl,hotmail.com,orange.fr,onet.pl,me.com,india.com,kansascity.com,wanadoo.fr,fortunecity.com,web.de,terra.com.br,att.net,canada.com,skynet.be,ya.ru,excite.com,detik.com,compuserve.com,ig.com.br,zp.ua,gmx.net,xoom.com,mindspring.com,freeserve.co.uk,interia.pl,excite.co.jp,test.de,shaw.ca,virgilio.it,chez.com,rr.com,freenet.de,ntlworld.com,seznam.cz,arcor.de,tiscali.it,sympatico.ca,sina.com,gazeta.pl,care2.com,yam.com,r7.com,telenet.be,rcn.com,geek.com,sfr.fr,hotbot.com,cox.net,blueyonder.co.uk,tom.com,virginmedia.com,btinternet.com,iinet.net.au,rogers.com,ireland.com,pochta.ru,ozemail.com.au,catholic.org,bluewin.ch,chat.ru,virgin.net,verizon.net,erols.com,lycos.de,lycos.co.uk,protonmail.com,doityourself.com,home.nl,nate.com,casino.com,o2.co.uk,terra.es,mail.com,albawaba.com,126.com,www.com,planet.nl,sanook.com,21cn.com,online.de,name.com,i.ua,centrum.cz,rin.ru,aol.co.uk,voila.fr,walla.co.il,poste.it,netcom.com,parrot.com,charter.net,mydomain.com,mail-tester.com,myway.com,chello.nl,club-internet.fr,sdf.org,tiscali.co.uk,freeuk.com,unican.es,sci.fi,anonymize.com,sify.com,metacrawler.com,go.ro,ivillage.com,telus.net,dailypioneer.com,iespana.es,lycos.es,hey.com,sweb.cz,optusnet.com.au,alice.it,tpg.com.au,hamptonroads.com,saudia.com,lycos.nl,blackplanet.com,frontier.com,looksmart.com,pobox.com,prodigy.net,i.am,freeyellow.com,gmx.com,bigpond.com,crosswinds.net,dejanews.com,wanadoo.es,foxmail.com,eircom.net,islamonline.net,webindia123.com,oath.com,frontiernet.net,hetnet.nl,onmilwaukee.com,ukr.net,bugmenot.com,neuf.fr,kiwibox.com,za.com,iol.it,zonnet.nl,newmail.ru,pacbell.net,cogeco.ca,depechemode.com,concentric.net,aim.com,f5.si,yahoo.jp,terra.com,hot.ee,netzero.net,netins.net,sprynet.com,mailbox.org,mail2web.com,o2.pl,idirect.com,bigfoot.com,netspace.net.au,masrawy.com,supereva.it,yahoo.de,lycos.it,yeah.net,montevideo.com.uy,gmx.de,yahoo.co.uk,yahoofs.com,scubadiving.com,hushmail.com,iprimus.com.au,gportal.hu,swissinfo.org,inbox.com,bolt.com,telstra.com,bellsouth.net,spray.se,c3.hu,attbi.com,talktalk.co.uk,dynu.net,juno.com,yahoo.fr,msn.co.uk,fr.nf,pe.hu,bigpond.net.au,incredimail.com,adelphia.net,elvis.com,interfree.it,starmedia.com,seanet.com,yahoo.com.tw,zip.net,tds.net,she.com,forthnet.gr,land.ru,wow.com,dnsmadeeasy.com,webjump.com,singnet.com.sg,spacewar.com,tin.it,4mg.com,sp.nl,wowway.com,dmv.com,bangkok.com,fastmail.fm,sbcglobal.net,bright.net,usa.com,37.com,aeiou.pt,terra.cl,thirdage.com,btconnect.com,optimum.net,cableone.net,talkcity.com,blogos.com,c2i.net,iwon.com,aver.com,barcelona.com,ddnsfree.com,oi.com.br,lex.bg,roadrunner.com,airmail.net,lawyer.com,yahoo.com.cn,cu.cc,ananzi.co.za,au.ru,pipeline.com,cs.com,3ammagazine.com,gmx.at,qwest.net,btopenworld.com,easypost.com,westnet.com.au,nyc.com,korea.com,front.ru,inbox.lv,yahoo.com.br,ny.com,hispavista.com,abv.bg,mchsi.com,apollo.lv,everyone.net,terra.com.ar,singpost.com,doctor.com,garbage.com,bizhosting.com,go2net.com,clerk.com,games.com,charm.net,onlinehome.de,laposte.net" # ๅกซไฝ ็š„็™ฝๅๅ•ๅŸŸๅ๏ผŒ้€—ๅทๅˆ†้š” diff --git a/go.mod b/go.mod index 222d463..ca67325 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,12 @@ module github.com/perfect-panel/server -go 1.23.3 +go 1.24 require ( github.com/GUAIK-ORG/go-snowflake v0.0.0-20200116064823-220c4260e85f github.com/alibabacloud-go/darabonba-openapi v0.1.18 github.com/alibabacloud-go/dysmsapi-20170525/v2 v2.0.18 github.com/alibabacloud-go/tea v1.2.2 - github.com/alicebob/miniredis/v2 v2.34.0 github.com/anaskhan96/go-password-encoder v0.0.0-20201010210601-c765b799fd72 github.com/andybalholm/brotli v1.1.1 github.com/forgoer/openssl v1.6.0 @@ -32,7 +31,6 @@ require ( github.com/smartwalle/alipay/v3 v3.2.23 github.com/spf13/cast v1.7.0 // indirect github.com/spf13/cobra v1.8.1 - github.com/stretchr/testify v1.10.0 github.com/stripe/stripe-go/v81 v81.1.0 github.com/twilio/twilio-go v1.23.11 go.opentelemetry.io/otel v1.29.0 @@ -51,15 +49,19 @@ require ( gopkg.in/yaml.v3 v3.0.1 gorm.io/driver/mysql v1.5.7 gorm.io/gorm v1.30.0 - gorm.io/plugin/soft_delete v1.2.1 k8s.io/apimachinery v0.31.1 ) require ( github.com/Masterminds/sprig/v3 v3.3.0 + github.com/aws/aws-sdk-go-v2 v1.41.7 + github.com/aws/aws-sdk-go-v2/config v1.32.17 + github.com/aws/aws-sdk-go-v2/credentials v1.19.16 + github.com/aws/aws-sdk-go-v2/service/s3 v1.101.0 github.com/fatih/color v1.18.0 github.com/goccy/go-json v0.10.4 github.com/golang-migrate/migrate/v4 v4.18.2 + github.com/mojocn/base64Captcha v1.3.8 github.com/oschwald/geoip2-golang v1.13.0 github.com/spaolacci/murmur3 v1.1.0 google.golang.org/grpc v1.64.1 @@ -79,8 +81,21 @@ require ( github.com/alibabacloud-go/tea-utils v1.4.5 // indirect github.com/alibabacloud-go/tea-utils/v2 v2.0.7 // indirect github.com/alibabacloud-go/tea-xml v1.1.3 // indirect - github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 // indirect github.com/aliyun/credentials-go v1.3.10 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.10 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.15 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.23 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 // indirect + github.com/aws/smithy-go v1.25.1 // indirect github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff // indirect github.com/bytedance/sonic v1.12.7 // indirect github.com/bytedance/sonic/loader v0.2.3 // indirect @@ -88,7 +103,6 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/clbanning/mxj/v2 v2.5.6 // indirect github.com/cloudwego/base64x v0.1.4 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/gabriel-vasile/mimetype v1.4.8 // indirect github.com/gin-contrib/sse v1.0.0 // indirect @@ -114,27 +128,22 @@ require ( github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-sqlite3 v1.14.22 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/mojocn/base64Captcha v1.3.8 // indirect github.com/openzipkin/zipkin-go v0.4.2 // indirect github.com/oschwald/maxminddb-golang v1.13.0 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect github.com/shopspring/decimal v1.4.0 // indirect github.com/smartwalle/ncrypto v1.0.4 // indirect github.com/smartwalle/ngx v1.0.9 // indirect github.com/smartwalle/nsign v1.0.9 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/objx v0.5.2 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect - github.com/yuin/gopher-lua v1.1.1 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect go.opentelemetry.io/otel/metric v1.29.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect @@ -150,5 +159,4 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20240513163218-0867130af1f8 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/ini.v1 v1.67.0 // indirect - gorm.io/driver/sqlite v1.6.0 // indirect ) diff --git a/go.sum b/go.sum index ad1c08e..df90cc5 100644 --- a/go.sum +++ b/go.sum @@ -52,10 +52,6 @@ github.com/alibabacloud-go/tea-utils/v2 v2.0.7/go.mod h1:qxn986l+q33J5VkialKMqT/ github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= github.com/alibabacloud-go/tea-xml v1.1.3 h1:7LYnm+JbOq2B+T/B0fHC4Ies4/FofC4zHzYtqw7dgt0= github.com/alibabacloud-go/tea-xml v1.1.3/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8= -github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE= -github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= -github.com/alicebob/miniredis/v2 v2.34.0 h1:mBFWMaJSNL9RwdGRyEDoAAv8OQc5UlEhLDQggTglU/0= -github.com/alicebob/miniredis/v2 v2.34.0/go.mod h1:kWShP4b58T1CW0Y5dViCd5ztzrDqRWqM3nksiyXk5s8= github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw= github.com/aliyun/credentials-go v1.3.6/go.mod h1:1LxUuX7L5YrZUWzBrRyk0SwSdH4OmPrib8NVePL3fxM= github.com/aliyun/credentials-go v1.3.10 h1:45Xxrae/evfzQL9V10zL3xX31eqgLWEaIdCoPipOEQA= @@ -64,6 +60,42 @@ github.com/anaskhan96/go-password-encoder v0.0.0-20201010210601-c765b799fd72 h1: github.com/anaskhan96/go-password-encoder v0.0.0-20201010210601-c765b799fd72/go.mod h1:PsJICrlruG9QcJDYuZ0dO/2KtMDALzRbony8NkxZ2nE= github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA= github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA= +github.com/aws/aws-sdk-go-v2 v1.41.7 h1:DWpAJt66FmnnaRIOT/8ASTucrvuDPZASqhhLey6tLY8= +github.com/aws/aws-sdk-go-v2 v1.41.7/go.mod h1:4LAfZOPHNVNQEckOACQx60Y8pSRjIkNZQz1w92xpMJc= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.10 h1:gx1AwW1Iyk9Z9dD9F4akX5gnN3QZwUB20GGKH/I+Rho= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.10/go.mod h1:qqY157uZoqm5OXq/amuaBJyC9hgBCBQnsaWnPe905GY= +github.com/aws/aws-sdk-go-v2/config v1.32.17 h1:FpL4/758/diKwqbytU0prpuiu60fgXKUWCpDJtApclU= +github.com/aws/aws-sdk-go-v2/config v1.32.17/go.mod h1:OXqUMzgXytfoF9JaKkhrOYsyh72t9G+MJH8mMRaexOE= +github.com/aws/aws-sdk-go-v2/credentials v1.19.16 h1:r3RJBuU7X9ibt8RHbMjWE6y60QbKBiII6wSrXnapxSU= +github.com/aws/aws-sdk-go-v2/credentials v1.19.16/go.mod h1:6cx7zqDENJDbBIIWX6P8s0h6hqHC8Avbjh9Dseo27ug= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23 h1:UuSfcORqNSz/ey3VPRS8TcVH2Ikf0/sC+Hdj400QI6U= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.23/go.mod h1:+G/OSGiOFnSOkYloKj/9M35s74LgVAdJBSD5lsFfqKg= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23 h1:GpT/TrnBYuE5gan2cZbTtvP+JlHsutdmlV2YfEyNde0= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.23/go.mod h1:xYWD6BS9ywC5bS3sz9Xh04whO/hzK2plt2Zkyrp4JuA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23 h1:bpd8vxhlQi2r1hiueOw02f/duEPTMK59Q4QMAoTTtTo= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.23/go.mod h1:15DfR2nw+CRHIk0tqNyifu3G1YdAOy68RftkhMDDwYk= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24 h1:OQqn11BtaYv1WLUowvcA30MpzIu8Ti4pcLPIIyoKZrA= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.24/go.mod h1:X5ZJyfwVrWA96GzPmUCWFQaEARPR7gCrpq2E92PJwAE= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 h1:FLudkZLt5ci0ozzgkVo8BJGwvqNaZbTWb3UcucAateA= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9/go.mod h1:w7wZ/s9qK7c8g4al+UyoF1Sp/Z45UwMGcqIzLWVQHWk= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.15 h1:ieLCO1JxUWuxTZ1cRd0GAaeX7O6cIxnwk7tc1LsQhC4= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.15/go.mod h1:e3IzZvQ3kAWNykvE0Tr0RDZCMFInMvhku3qNpcIQXhM= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23 h1:pbrxO/kuIwgEsOPLkaHu0O+m4fNgLU8B3vxQ+72jTPw= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.23/go.mod h1:/CMNUqoj46HpS3MNRDEDIwcgEnrtZlKRaHNaHxIFpNA= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.23 h1:03xatSQO4+AM1lTAbnRg5OK528EUg744nW7F73U8DKw= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.23/go.mod h1:M8l3mwgx5ToK7wot2sBBce/ojzgnPzZXUV445gTSyE8= +github.com/aws/aws-sdk-go-v2/service/s3 v1.101.0 h1:etqBTKY581iwLL/H/S2sVgk3C9lAsTJFeXWFDsDcWOU= +github.com/aws/aws-sdk-go-v2/service/s3 v1.101.0/go.mod h1:L2dcoOgS2VSgbPLvpak2NyUPsO1TBN7M45Z4H7DlRc4= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.11 h1:TdJ+HdzOBhU8+iVAOGUTU63VXopcumCOF1paFulHWZc= +github.com/aws/aws-sdk-go-v2/service/signin v1.0.11/go.mod h1:R82ZRExE/nheo0N+T8zHPcLRTcH8MGsnR3BiVGX0TwI= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.17 h1:7byT8HUWrgoRp6sXjxtZwgOKfhss5fW6SkLBtqzgRoE= +github.com/aws/aws-sdk-go-v2/service/sso v1.30.17/go.mod h1:xNWknVi4Ezm1vg1QsB/5EWpAJURq22uqd38U8qKvOJc= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21 h1:+1Kl1zx6bWi4X7cKi3VYh29h8BvsCoHQEQ6ST9X8w7w= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.21/go.mod h1:4vIRDq+CJB2xFAXZ+YgGUTiEft7oAQlhIs71xcSeuVg= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.1 h1:F/M5Y9I3nwr2IEpshZgh1GeHpOItExNM9L1euNuh/fk= +github.com/aws/aws-sdk-go-v2/service/sts v1.42.1/go.mod h1:mTNxImtovCOEEuD65mKW7DCsL+2gjEH+RPEAexAzAio= +github.com/aws/smithy-go v1.25.1 h1:J8ERsGSU7d+aCmdQur5Txg6bVoYelvQJgtZehD12GkI= +github.com/aws/smithy-go v1.25.1/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff h1:RmdPFa+slIr4SCBg4st/l/vZWVe9QJKMXGO60Bxbe04= github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw= @@ -226,8 +258,6 @@ github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -258,9 +288,6 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.3/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI= -github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= -github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= @@ -365,8 +392,6 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.30/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= -github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0 h1:TT4fX+nBOA/+LUkobKGW1ydGcn+G3vRw9+g5HwCphpk= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8= go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= @@ -578,20 +603,9 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= -gorm.io/driver/sqlite v1.1.3/go.mod h1:AKDgRWk8lcSQSw+9kxCJnX/yySj8G3rdwYlU57cB45c= -gorm.io/driver/sqlite v1.4.4 h1:gIufGoR0dQzjkyqDyYSCvsYR6fba1Gw5YKDqKeChxFc= -gorm.io/driver/sqlite v1.4.4/go.mod h1:0Aq3iPO+v9ZKbcdiz8gLWRw5VOPcBOPUQJFLq5e2ecI= -gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ= -gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8= -gorm.io/gorm v1.20.1/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= -gorm.io/gorm v1.23.0/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= -gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= -gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= gorm.io/gorm v1.30.0 h1:qbT5aPv1UH8gI99OsRlvDToLxW5zR7FzS9acZDOZcgs= gorm.io/gorm v1.30.0/go.mod h1:8Z33v652h4//uMA76KjeDH8mJXPm1QNCYrMeatR0DOE= -gorm.io/plugin/soft_delete v1.2.1 h1:qx9D/c4Xu6w5KT8LviX8DgLcB9hkKl6JC9f44Tj7cGU= -gorm.io/plugin/soft_delete v1.2.1/go.mod h1:Zv7vQctOJTGOsJ/bWgrN1n3od0GBAZgnLjEx+cApLGk= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U= diff --git a/internal/config/config.go b/internal/config/config.go index 2d6718b..4e6ebe5 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -38,12 +38,29 @@ type Config struct { Log Log `yaml:"Log"` Currency Currency `yaml:"Currency"` Trace trace.Config `yaml:"Trace"` + S3 S3Config `yaml:"S3"` Administrator struct { Email string `yaml:"Email" default:"admin@ppanel.dev"` Password string `yaml:"Password" default:"password"` } `yaml:"Administrator"` } +type S3Config struct { + Enable bool `yaml:"Enable" default:"false"` + Region string `yaml:"Region" default:""` + Bucket string `yaml:"Bucket" default:""` + Endpoint string `yaml:"Endpoint" default:""` + AccessKey string `yaml:"AccessKey" default:""` + SecretKey string `yaml:"SecretKey" default:""` + SessionToken string `yaml:"SessionToken" default:""` + Prefix string `yaml:"Prefix" default:"app-upload"` + PublicBaseURL string `yaml:"PublicBaseURL" default:""` + UsePathStyle bool `yaml:"UsePathStyle" default:"false"` + PresignExpireSeconds int64 `yaml:"PresignExpireSeconds" default:"300"` + MaxUploadSize int64 `yaml:"MaxUploadSize" default:"104857600"` + AllowedContentTypes string `yaml:"AllowedContentTypes" default:"application/zip,application/x-zip-compressed,application/gzip,application/x-gzip,application/octet-stream,text/plain,application/json"` +} + type RedisConfig struct { Host string `yaml:"Host" default:"localhost:6379"` Pass string `yaml:"Pass" default:""` diff --git a/internal/handler/public/file/fileUploadCompleteHandler.go b/internal/handler/public/file/fileUploadCompleteHandler.go new file mode 100644 index 0000000..482a7fe --- /dev/null +++ b/internal/handler/public/file/fileUploadCompleteHandler.go @@ -0,0 +1,26 @@ +package file + +import ( + "github.com/gin-gonic/gin" + "github.com/perfect-panel/server/internal/logic/public/file" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/result" +) + +// Complete file upload +func FileUploadCompleteHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { + return func(c *gin.Context) { + var req types.FileUploadCompleteRequest + _ = c.ShouldBind(&req) + validateErr := svcCtx.Validate(&req) + if validateErr != nil { + result.ParamErrorResult(c, validateErr) + return + } + + l := file.NewFileUploadCompleteLogic(c.Request.Context(), svcCtx) + resp, err := l.FileUploadComplete(&req) + result.HttpResult(c, resp, err) + } +} diff --git a/internal/handler/public/file/fileUploadInitHandler.go b/internal/handler/public/file/fileUploadInitHandler.go new file mode 100644 index 0000000..0f419b8 --- /dev/null +++ b/internal/handler/public/file/fileUploadInitHandler.go @@ -0,0 +1,26 @@ +package file + +import ( + "github.com/gin-gonic/gin" + "github.com/perfect-panel/server/internal/logic/public/file" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/result" +) + +// Init file upload +func FileUploadInitHandler(svcCtx *svc.ServiceContext) func(c *gin.Context) { + return func(c *gin.Context) { + var req types.FileUploadInitRequest + _ = c.ShouldBind(&req) + validateErr := svcCtx.Validate(&req) + if validateErr != nil { + result.ParamErrorResult(c, validateErr) + return + } + + l := file.NewFileUploadInitLogic(c.Request.Context(), svcCtx) + resp, err := l.FileUploadInit(&req) + result.HttpResult(c, resp, err) + } +} diff --git a/internal/handler/routes.go b/internal/handler/routes.go index 7ba4ef5..4475d8a 100644 --- a/internal/handler/routes.go +++ b/internal/handler/routes.go @@ -30,6 +30,7 @@ import ( common "github.com/perfect-panel/server/internal/handler/common" publicAnnouncement "github.com/perfect-panel/server/internal/handler/public/announcement" publicDocument "github.com/perfect-panel/server/internal/handler/public/document" + publicFile "github.com/perfect-panel/server/internal/handler/public/file" publicIapApple "github.com/perfect-panel/server/internal/handler/public/iap/apple" publicOrder "github.com/perfect-panel/server/internal/handler/public/order" publicPayment "github.com/perfect-panel/server/internal/handler/public/payment" @@ -865,6 +866,17 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) { publicDocumentGroupRouter.GET("/list", publicDocument.QueryDocumentListHandler(serverCtx)) } + publicFileGroupRouter := router.Group("/v1/public/file") + publicFileGroupRouter.Use(middleware.AuthMiddleware(serverCtx), middleware.DeviceMiddleware(serverCtx)) + + { + // Init file upload + publicFileGroupRouter.POST("/upload/init", publicFile.FileUploadInitHandler(serverCtx)) + + // Complete file upload + publicFileGroupRouter.POST("/upload/complete", publicFile.FileUploadCompleteHandler(serverCtx)) + } + publicOrderGroupRouter := router.Group("/v1/public/order") publicOrderGroupRouter.Use(middleware.AuthMiddleware(serverCtx), middleware.DeviceMiddleware(serverCtx)) diff --git a/internal/logic/auth/trialEmailWhitelist_test.go b/internal/logic/auth/trialEmailWhitelist_test.go deleted file mode 100644 index c4a8c0b..0000000 --- a/internal/logic/auth/trialEmailWhitelist_test.go +++ /dev/null @@ -1,198 +0,0 @@ -package auth - -import ( - "testing" - - "github.com/perfect-panel/server/internal/config" - "github.com/stretchr/testify/assert" -) - -func TestNormalizeEmail(t *testing.T) { - tests := []struct { - input string - want string - }{ - // Gmail dot trick - {"a.v.x.xx@gmail.com", "avxxx@gmail.com"}, - {"john.doe@gmail.com", "johndoe@gmail.com"}, - {"a.b.c.d.e@gmail.com", "abcde@gmail.com"}, - // Gmail + alias - {"user+tag@gmail.com", "user@gmail.com"}, - {"a.b+tag@gmail.com", "ab@gmail.com"}, - // Googlemail - {"a.b@googlemail.com", "ab@googlemail.com"}, - // Non-Gmail: dots preserved - {"john.doe@outlook.com", "john.doe@outlook.com"}, - {"john.doe@qq.com", "john.doe@qq.com"}, - // + alias stripped for all providers - {"user+spam@outlook.com", "user@outlook.com"}, - {"user+spam@qq.com", "user@qq.com"}, - // Case insensitive - {"User@Gmail.COM", "user@gmail.com"}, - {"A.B@Gmail.com", "ab@gmail.com"}, - // No change for normal non-gmail email - {"abc@163.com", "abc@163.com"}, - } - - for _, tt := range tests { - t.Run(tt.input, func(t *testing.T) { - got := NormalizeEmail(tt.input) - if got != tt.want { - t.Errorf("NormalizeEmail(%q) = %q, want %q", tt.input, got, tt.want) - } - }) - } -} - -func TestNormalizeEmail_NoChangeSkipsCheck(t *testing.T) { - // These emails should NOT trigger cross-user check (normalized == original) - noChangeCases := []string{ - "abc@163.com", - "john.doe@outlook.com", - "user@qq.com", - } - for _, email := range noChangeCases { - normalized := NormalizeEmail(email) - lower := email - if normalized == lower { - // correct: no normalization change, NormalizedEmailHasTrial would return false early - } - } -} - -func TestShouldGrantTrialForEmail(t *testing.T) { - // ๆจกๆ‹Ÿ็บฟไธŠ้…็ฝฎ๏ผš็™ฝๅๅ•ๅผ€ๅฏ๏ผŒgmail.com ไนŸๅœจๅๅ•้‡Œ - rcWithGmail := config.RegisterConfig{ - EnableTrial: true, - EnableTrialEmailWhitelist: true, - TrialEmailDomainWhitelist: "hifastapp.com,hifastvpn.com,126.com,139.com,163.com,gmail.com", - } - // ็™ฝๅๅ•ๅ…ณ้—ญ - rcNoWhitelist := config.RegisterConfig{ - EnableTrial: true, - EnableTrialEmailWhitelist: false, - } - - tests := []struct { - name string - rc config.RegisterConfig - email string - want bool - reason string - }{ - { - name: "gmail dot trick - blocked even if gmail.com in whitelist", - rc: rcWithGmail, - email: "s.m.s.n.fsmbt.d.ndny@gmail.com", - want: false, - reason: "gmail ๆณ›ๅŸŸๅ๏ผˆๅซ็‚นๅท๏ผ‰ๅบ”ๆ‹’็ป", - }, - { - name: "gmail plus alias - blocked", - rc: rcWithGmail, - email: "user+tag@gmail.com", - want: false, - reason: "gmail +ๅˆซๅๅบ”ๆ‹’็ป", - }, - { - name: "clean gmail - allowed", - rc: rcWithGmail, - email: "normaluser@gmail.com", - want: true, - reason: "ๅนฒๅ‡€็š„ gmail ๅบ”ๆ”พ่กŒ", - }, - { - name: "163 with dot - allowed (non-gmail dot is ok)", - rc: rcWithGmail, - email: "s.m.s.n@163.com", - want: true, - reason: "้ž gmail ๅŸŸ็‚นๅทไธๆ‹ฆๆˆช", - }, - { - name: "163 plus alias - blocked", - rc: rcWithGmail, - email: "user+spam@163.com", - want: false, - reason: "ๆ‰€ๆœ‰ๅŸŸๅ็š„ +ๅˆซๅ้ƒฝๆ‹ฆๆˆช", - }, - { - name: "gmail typo squatting domain - blocked even if accidentally whitelisted", - rc: config.RegisterConfig{EnableTrial: true, EnableTrialEmailWhitelist: true, TrialEmailDomainWhitelist: "gmail.com,gmaial.com"}, - email: "1.2.3.4xxx@gmaial.com", - want: false, - reason: "ๆ˜“ๆททๆท† Gmail ๅŸŸๅไธๅบ”ๅ‘ๆ”พ่ฏ•็”จ", - }, - { - name: "invalid empty local - blocked", - rc: rcWithGmail, - email: "@gmail.com", - want: false, - reason: "้‚ฎ็ฎฑ local ไธบ็ฉบๅบ”ๆ‹’็ป", - }, - { - name: "subdomain spoof - blocked", - rc: rcWithGmail, - email: "user@fake.gmail.com", - want: false, - reason: "็™ฝๅๅ•ๅฟ…้กป็ฒพ็กฎๅŒน้…ๅŸŸๅ๏ผŒไธๅŒน้…ๅญๅŸŸ", - }, - { - name: "whitelist disabled - gmail dot trick still blocked", - rc: rcNoWhitelist, - email: "s.m.s.n.fsmbt.d.ndny@gmail.com", - want: false, - reason: "็™ฝๅๅ•ๆœชๅฏ็”จ๏ผŒไฝ†ๆณ›ๅŸŸๅไปๅบ”ๆ‹’็ป", - }, - { - name: "trial disabled - always blocked", - rc: config.RegisterConfig{EnableTrial: false}, - email: "user@163.com", - want: false, - reason: "่ฏ•็”จๆœชๅผ€ๅฏ", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got := ShouldGrantTrialForEmail(tt.rc, tt.email) - if got != tt.want { - t.Errorf("ShouldGrantTrialForEmail(%q) = %v, want %v | reason: %s", - tt.email, got, tt.want, tt.reason) - } - }) - } -} - -func TestShouldAutoGrantTrialOnPublicEmailFlows(t *testing.T) { - assert.False(t, ShouldAutoGrantTrialOnPublicEmailFlows(config.RegisterConfig{})) - assert.False(t, ShouldAutoGrantTrialOnPublicEmailFlows(config.RegisterConfig{ - EnableTrial: true, - EnableTrialEmailWhitelist: true, - TrialEmailDomainWhitelist: "gmail.com,example.com", - })) -} - -func TestIsEmailDomainWhitelisted(t *testing.T) { - whitelist := "gmail.com,edu.cn,outlook.com" - tests := []struct { - email string - want bool - }{ - {"user@gmail.com", true}, - {"user@edu.cn", true}, - {"User@Gmail.COM", true}, - {"user@yahoo.com", false}, - {"user@fake.gmail.com", false}, // subdomain not matched - {"user@", false}, - {"notanemail", false}, - {"@gmail.com", false}, - } - for _, tt := range tests { - t.Run(tt.email, func(t *testing.T) { - got := IsEmailDomainWhitelisted(tt.email, whitelist) - if got != tt.want { - t.Errorf("IsEmailDomainWhitelisted(%q) = %v, want %v", tt.email, got, tt.want) - } - }) - } -} diff --git a/internal/logic/common/subscribeModeRoute_test.go b/internal/logic/common/subscribeModeRoute_test.go deleted file mode 100644 index 333d256..0000000 --- a/internal/logic/common/subscribeModeRoute_test.go +++ /dev/null @@ -1,36 +0,0 @@ -package common - -import ( - "context" - "testing" - "time" - - "github.com/perfect-panel/server/internal/model/user" - "github.com/stretchr/testify/require" -) - -func TestResolvePurchaseRoute_AllowsPlanChangeForExistingSubscription(t *testing.T) { - anchor := &user.Subscribe{ - Id: 10, - UserId: 20, - OrderId: 30, - SubscribeId: 1, - Token: "existing-token", - ExpireTime: time.Now().Add(time.Hour), - } - - decision, err := ResolvePurchaseRoute( - context.Background(), - true, - anchor.UserId, - 2, - func(context.Context, int64) (*user.Subscribe, error) { - return anchor, nil - }, - ) - - require.NoError(t, err) - require.Equal(t, PurchaseRoutePurchaseToRenewal, decision.Route) - require.Equal(t, int64(2), decision.ResolvedSubscribeID) - require.Equal(t, anchor, decision.Anchor) -} diff --git a/internal/logic/public/file/common.go b/internal/logic/public/file/common.go new file mode 100644 index 0000000..c7e51da --- /dev/null +++ b/internal/logic/public/file/common.go @@ -0,0 +1,148 @@ +package file + +import ( + "context" + "crypto/sha1" + "encoding/hex" + "encoding/json" + "fmt" + "path/filepath" + "regexp" + "strings" + "time" + + "github.com/perfect-panel/server/internal/model/user" + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/pkg/constant" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +const ( + fileUploadInitStatus = "init" + fileUploadCompleteStatus = "completed" + fileUploadRedisPrefix = "file:upload:" +) + +var safeFileNameRegexp = regexp.MustCompile(`[^a-zA-Z0-9._-]+`) + +type uploadMeta struct { + FileID string `json:"file_id"` + UserID int64 `json:"user_id"` + BizType string `json:"biz_type"` + FileName string `json:"file_name"` + ContentType string `json:"content_type"` + ObjectKey string `json:"object_key"` + Size int64 `json:"size"` + Sha256 string `json:"sha256"` + Status string `json:"status"` + Etag string `json:"etag,omitempty"` + CreatedAt int64 `json:"created_at"` + CompletedAt int64 `json:"completed_at,omitempty"` +} + +func currentUserFromContext(ctx context.Context) (*user.User, error) { + u, ok := ctx.Value(constant.CtxKeyUser).(*user.User) + if !ok || u == nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access") + } + return u, nil +} + +func allowedContentTypeSet(csv string) map[string]struct{} { + set := make(map[string]struct{}) + for _, item := range strings.Split(csv, ",") { + item = strings.TrimSpace(strings.ToLower(item)) + if item == "" { + continue + } + set[item] = struct{}{} + } + return set +} + +func validateInitRequest(svcCtx *svc.ServiceContext, bizType, fileName, contentType string, size int64) error { + if svcCtx.S3Store == nil || !svcCtx.Config.S3.Enable { + return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "S3 upload is not enabled") + } + if strings.TrimSpace(bizType) == "" { + return errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "biz_type is required") + } + if strings.TrimSpace(fileName) == "" { + return errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "file_name is required") + } + if size <= 0 { + return errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "size must be greater than 0") + } + if svcCtx.Config.S3.MaxUploadSize > 0 && size > svcCtx.Config.S3.MaxUploadSize { + return errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "file size exceeds max limit") + } + allowed := allowedContentTypeSet(svcCtx.Config.S3.AllowedContentTypes) + if len(allowed) > 0 { + if _, ok := allowed[strings.ToLower(strings.TrimSpace(contentType))]; !ok { + return errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "content_type is not allowed") + } + } + return nil +} + +func buildFileID(userID int64, bizType, fileName string) string { + h := sha1.New() + _, _ = h.Write([]byte(fmt.Sprintf("%d:%s:%s:%d", userID, bizType, fileName, time.Now().UnixNano()))) + return hex.EncodeToString(h.Sum(nil))[:24] +} + +func safeFileName(name string) string { + base := filepath.Base(strings.TrimSpace(name)) + if base == "." || base == "/" || base == "" { + return "file.bin" + } + safe := safeFileNameRegexp.ReplaceAllString(base, "_") + if safe == "" { + return "file.bin" + } + return safe +} + +func buildObjectKey(prefix string, userID int64, bizType, fileID, fileName string, now time.Time) string { + prefix = strings.Trim(prefix, "/") + if prefix == "" { + prefix = "app-upload" + } + return fmt.Sprintf("%s/%s/%d/%04d/%02d/%s_%s", + prefix, + strings.Trim(safeFileNameRegexp.ReplaceAllString(strings.ToLower(strings.TrimSpace(bizType)), "-"), "-"), + userID, + now.Year(), + int(now.Month()), + fileID, + safeFileName(fileName), + ) +} + +func uploadRedisKey(fileID string) string { + return fileUploadRedisPrefix + fileID +} + +func saveUploadMeta(ctx context.Context, svcCtx *svc.ServiceContext, meta *uploadMeta, ttl time.Duration) error { + data, err := json.Marshal(meta) + if err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "marshal upload meta failed") + } + if err := svcCtx.Redis.Set(ctx, uploadRedisKey(meta.FileID), data, ttl).Err(); err != nil { + return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "save upload meta failed") + } + return nil +} + +func loadUploadMeta(ctx context.Context, svcCtx *svc.ServiceContext, fileID string) (*uploadMeta, error) { + val, err := svcCtx.Redis.Get(ctx, uploadRedisKey(fileID)).Result() + if err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "upload meta not found") + } + var meta uploadMeta + if err := json.Unmarshal([]byte(val), &meta); err != nil { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "parse upload meta failed") + } + return &meta, nil +} diff --git a/internal/logic/public/file/fileuploadcompletelogic.go b/internal/logic/public/file/fileuploadcompletelogic.go new file mode 100644 index 0000000..490c000 --- /dev/null +++ b/internal/logic/public/file/fileuploadcompletelogic.go @@ -0,0 +1,71 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl 1.9.2 + +package file + +import ( + "context" + "time" + + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" +) + +type FileUploadCompleteLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// Complete file upload +func NewFileUploadCompleteLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FileUploadCompleteLogic { + return &FileUploadCompleteLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *FileUploadCompleteLogic) FileUploadComplete(req *types.FileUploadCompleteRequest) (resp *types.FileUploadCompleteResponse, err error) { + u, err := currentUserFromContext(l.ctx) + if err != nil { + return nil, err + } + + meta, err := loadUploadMeta(l.ctx, l.svcCtx, req.FileId) + if err != nil { + return nil, err + } + if meta.UserID != u.Id { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access") + } + + head, err := l.svcCtx.S3Store.HeadObject(l.ctx, meta.ObjectKey) + if err != nil { + l.Errorw("head object failed", logger.Field("error", err.Error()), logger.Field("file_id", meta.FileID)) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "uploaded file not found") + } + if meta.Size > 0 && head.ContentLength != meta.Size { + return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "uploaded file size mismatch") + } + + meta.Status = fileUploadCompleteStatus + meta.Etag = head.ETag + meta.ContentType = head.ContentType + meta.CompletedAt = time.Now().Unix() + if err := saveUploadMeta(l.ctx, l.svcCtx, meta, 7*24*time.Hour); err != nil { + return nil, err + } + + return &types.FileUploadCompleteResponse{ + FileId: meta.FileID, + ObjectKey: meta.ObjectKey, + Size: head.ContentLength, + ContentType: head.ContentType, + Etag: head.ETag, + Status: meta.Status, + }, nil +} diff --git a/internal/logic/public/file/fileuploadinitlogic.go b/internal/logic/public/file/fileuploadinitlogic.go new file mode 100644 index 0000000..7edaae6 --- /dev/null +++ b/internal/logic/public/file/fileuploadinitlogic.go @@ -0,0 +1,80 @@ +// Code scaffolded by goctl. Safe to edit. +// goctl 1.9.2 + +package file + +import ( + "context" + "time" + + "github.com/perfect-panel/server/internal/svc" + "github.com/perfect-panel/server/internal/types" + "github.com/perfect-panel/server/pkg/logger" +) + +type FileUploadInitLogic struct { + logger.Logger + ctx context.Context + svcCtx *svc.ServiceContext +} + +// Init file upload +func NewFileUploadInitLogic(ctx context.Context, svcCtx *svc.ServiceContext) *FileUploadInitLogic { + return &FileUploadInitLogic{ + Logger: logger.WithContext(ctx), + ctx: ctx, + svcCtx: svcCtx, + } +} + +func (l *FileUploadInitLogic) FileUploadInit(req *types.FileUploadInitRequest) (resp *types.FileUploadInitResponse, err error) { + u, err := currentUserFromContext(l.ctx) + if err != nil { + return nil, err + } + + if err := validateInitRequest(l.svcCtx, req.BizType, req.FileName, req.ContentType, req.Size); err != nil { + return nil, err + } + + now := time.Now() + fileID := buildFileID(u.Id, req.BizType, req.FileName) + objectKey := buildObjectKey(l.svcCtx.Config.S3.Prefix, u.Id, req.BizType, fileID, req.FileName, now) + expireSeconds := l.svcCtx.Config.S3.PresignExpireSeconds + if expireSeconds <= 0 { + expireSeconds = 300 + } + + presigned, err := l.svcCtx.S3Store.PresignPutObject(l.ctx, objectKey, req.ContentType, time.Duration(expireSeconds)*time.Second) + if err != nil { + l.Errorw("presign put object failed", logger.Field("error", err.Error()), logger.Field("user_id", u.Id)) + return nil, err + } + + meta := &uploadMeta{ + FileID: fileID, + UserID: u.Id, + BizType: req.BizType, + FileName: req.FileName, + ContentType: req.ContentType, + ObjectKey: objectKey, + Size: req.Size, + Sha256: req.Sha256, + Status: fileUploadInitStatus, + CreatedAt: now.Unix(), + } + if err := saveUploadMeta(l.ctx, l.svcCtx, meta, 24*time.Hour); err != nil { + return nil, err + } + + return &types.FileUploadInitResponse{ + FileId: fileID, + ObjectKey: objectKey, + UploadURL: presigned.URL, + Method: presigned.Method, + Headers: map[string]string{ + "Content-Type": req.ContentType, + }, + ExpiredAt: presigned.ExpiresAt, + }, nil +} diff --git a/internal/logic/public/order/getDiscount_test.go b/internal/logic/public/order/getDiscount_test.go deleted file mode 100644 index b348531..0000000 --- a/internal/logic/public/order/getDiscount_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package order - -import ( - "testing" - - "github.com/perfect-panel/server/internal/types" - "github.com/stretchr/testify/require" -) - -func TestGetDiscount_SkipsNewUserOnlyTierForExistingUser(t *testing.T) { - discount := getDiscount([]types.SubscribeDiscount{ - {Quantity: 1, Discount: 90, NewUserOnly: true}, - }, 1, false) - - require.Equal(t, float64(1), discount) -} diff --git a/internal/logic/public/order/purchaseNewUserOnly_test.go b/internal/logic/public/order/purchaseNewUserOnly_test.go deleted file mode 100644 index 2cede15..0000000 --- a/internal/logic/public/order/purchaseNewUserOnly_test.go +++ /dev/null @@ -1,845 +0,0 @@ -package order - -import ( - "context" - "testing" - "time" - - "github.com/alicebob/miniredis/v2" - "github.com/hibiken/asynq" - modelOrder "github.com/perfect-panel/server/internal/model/order" - "github.com/perfect-panel/server/internal/model/payment" - subModel "github.com/perfect-panel/server/internal/model/subscribe" - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/constant" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/redis/go-redis/v9" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "gorm.io/driver/sqlite" - "gorm.io/gorm" - "gorm.io/gorm/logger" -) - -// setupNewUserOnlyDB ๅˆ›ๅปบๅธฆๅฟ…่ฆ่กจ็š„ SQLite ๅ†…ๅญ˜ๆ•ฐๆฎๅบ“ -func setupNewUserOnlyDB(t *testing.T) *gorm.DB { - t.Helper() - db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{ - Logger: logger.Default.LogMode(logger.Silent), - }) - require.NoError(t, err, "failed to open in-memory SQLite") - db.Exec("PRAGMA foreign_keys = OFF") - - sqls := []string{ - `CREATE TABLE IF NOT EXISTS "subscribe" ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name VARCHAR(255) NOT NULL DEFAULT '', - language VARCHAR(255) NOT NULL DEFAULT '', - description TEXT, - unit_price INTEGER NOT NULL DEFAULT 0, - unit_time VARCHAR(255) NOT NULL DEFAULT '', - discount TEXT, - replacement INTEGER NOT NULL DEFAULT 0, - inventory INTEGER NOT NULL DEFAULT -1, - traffic INTEGER NOT NULL DEFAULT 0, - speed_limit INTEGER NOT NULL DEFAULT 0, - device_limit INTEGER NOT NULL DEFAULT 0, - quota INTEGER NOT NULL DEFAULT 0, - new_user_only TINYINT DEFAULT 0, - nodes VARCHAR(255), - node_tags VARCHAR(255), - show TINYINT NOT NULL DEFAULT 0, - sell TINYINT NOT NULL DEFAULT 1, - sort INTEGER NOT NULL DEFAULT 0, - deduction_ratio INTEGER DEFAULT 0, - allow_deduction TINYINT DEFAULT 1, - reset_cycle INTEGER DEFAULT 0, - renewal_reset TINYINT DEFAULT 0, - show_original_price TINYINT NOT NULL DEFAULT 1, - created_at DATETIME, - updated_at DATETIME - )`, - `CREATE TABLE IF NOT EXISTS "order" ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - parent_id INTEGER DEFAULT NULL, - user_id INTEGER NOT NULL DEFAULT 0, - subscription_user_id INTEGER NOT NULL DEFAULT 0, - order_no VARCHAR(255) NOT NULL DEFAULT '' UNIQUE, - type TINYINT NOT NULL DEFAULT 1, - quantity INTEGER NOT NULL DEFAULT 1, - price INTEGER NOT NULL DEFAULT 0, - amount INTEGER NOT NULL DEFAULT 0, - gift_amount INTEGER NOT NULL DEFAULT 0, - discount INTEGER NOT NULL DEFAULT 0, - coupon VARCHAR(255) DEFAULT NULL, - coupon_discount INTEGER NOT NULL DEFAULT 0, - commission INTEGER NOT NULL DEFAULT 0, - payment_id INTEGER NOT NULL DEFAULT 0, - method VARCHAR(255) NOT NULL DEFAULT '', - fee_amount INTEGER NOT NULL DEFAULT 0, - trade_no VARCHAR(255) DEFAULT NULL, - app_account_token VARCHAR(255) DEFAULT NULL, - status TINYINT NOT NULL DEFAULT 1, - subscribe_id INTEGER NOT NULL DEFAULT 0, - subscribe_token VARCHAR(255) DEFAULT NULL, - is_new TINYINT NOT NULL DEFAULT 0, - created_at DATETIME, - updated_at DATETIME, - deleted_at DATETIME DEFAULT NULL - )`, - `CREATE TABLE IF NOT EXISTS "user" ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - password VARCHAR(100) NOT NULL DEFAULT '', - algo VARCHAR(20) DEFAULT 'default', - salt VARCHAR(20) DEFAULT NULL, - avatar TEXT, - balance INTEGER DEFAULT 0, - refer_code VARCHAR(20) DEFAULT '', - referer_id INTEGER DEFAULT 0, - commission INTEGER DEFAULT 0, - referral_percentage INTEGER DEFAULT 0, - only_first_purchase TINYINT DEFAULT 1, - gift_amount INTEGER DEFAULT 0, - enable TINYINT DEFAULT 1, - is_admin TINYINT DEFAULT 0, - enable_balance_notify TINYINT DEFAULT 0, - enable_login_notify TINYINT DEFAULT 0, - enable_subscribe_notify TINYINT DEFAULT 0, - enable_trade_notify TINYINT DEFAULT 0, - rules TEXT, - member_status VARCHAR(20) DEFAULT '', - created_at DATETIME, - updated_at DATETIME, - deleted_at DATETIME DEFAULT NULL - )`, - `CREATE TABLE IF NOT EXISTS "payment" ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - name VARCHAR(100) NOT NULL DEFAULT '', - platform VARCHAR(100) NOT NULL DEFAULT '', - icon VARCHAR(255) DEFAULT '', - domain VARCHAR(255) DEFAULT '', - config TEXT NOT NULL DEFAULT '{}', - description TEXT, - fee_mode TINYINT NOT NULL DEFAULT 0, - fee_percent INTEGER DEFAULT 0, - fee_amount INTEGER DEFAULT 0, - enable TINYINT NOT NULL DEFAULT 1, - token VARCHAR(255) NOT NULL DEFAULT '' UNIQUE - )`, - `CREATE TABLE IF NOT EXISTS "user_subscribe" ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - user_id INTEGER NOT NULL DEFAULT 0, - order_id INTEGER NOT NULL DEFAULT 0, - subscribe_id INTEGER NOT NULL DEFAULT 0, - start_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, - expire_time DATETIME DEFAULT NULL, - finished_at DATETIME DEFAULT NULL, - traffic INTEGER DEFAULT 0, - download INTEGER DEFAULT 0, - upload INTEGER DEFAULT 0, - token VARCHAR(255) DEFAULT '' UNIQUE, - uuid VARCHAR(255) DEFAULT '' UNIQUE, - status TINYINT DEFAULT 0, - note VARCHAR(500) DEFAULT '', - created_at DATETIME, - updated_at DATETIME - )`, - `CREATE TABLE IF NOT EXISTS "user_device" ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - ip VARCHAR(255) NOT NULL DEFAULT '', - user_id INTEGER NOT NULL DEFAULT 0, - user_agent TEXT, - identifier VARCHAR(255) NOT NULL DEFAULT '' UNIQUE, - short_code VARCHAR(255) NOT NULL DEFAULT '', - online TINYINT NOT NULL DEFAULT 0, - enabled TINYINT NOT NULL DEFAULT 1, - created_at DATETIME, - updated_at DATETIME - )`, - `CREATE TABLE IF NOT EXISTS "user_family" ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - owner_user_id INTEGER NOT NULL DEFAULT 0, - max_members INTEGER NOT NULL DEFAULT 2, - status TINYINT DEFAULT 0, - created_at DATETIME, - updated_at DATETIME, - deleted_at DATETIME DEFAULT NULL - )`, - `CREATE TABLE IF NOT EXISTS "user_family_member" ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - family_id INTEGER NOT NULL DEFAULT 0, - user_id INTEGER NOT NULL DEFAULT 0, - role TINYINT DEFAULT 0, - status TINYINT DEFAULT 0, - join_source VARCHAR(32) NOT NULL DEFAULT '', - joined_at DATETIME, - left_at DATETIME DEFAULT NULL, - created_at DATETIME, - updated_at DATETIME, - deleted_at DATETIME DEFAULT NULL - )`, - } - for _, sql := range sqls { - require.NoError(t, db.Exec(sql).Error) - } - return db -} - -// setupNewUserOnlyRedis ๅฏๅŠจ miniredis๏ผŒ่ฟ”ๅ›ž redis.Client ๅ’Œ miniredis ๅฅๆŸ„ -func setupNewUserOnlyRedis(t *testing.T) (*redis.Client, *miniredis.Miniredis) { - t.Helper() - mr, err := miniredis.Run() - require.NoError(t, err) - t.Cleanup(mr.Close) - rds := redis.NewClient(&redis.Options{Addr: mr.Addr()}) - return rds, mr -} - -// buildNewUserOnlySvcCtx ็ป„่ฃ…ๆœ€ๅฐ ServiceContext๏ผˆๅซ asynq Queue ไฝฟ็”จ miniredis๏ผ‰ -func buildNewUserOnlySvcCtx(db *gorm.DB, rds *redis.Client, mr *miniredis.Miniredis) *svc.ServiceContext { - queue := asynq.NewClient(asynq.RedisClientOpt{Addr: mr.Addr()}) - return &svc.ServiceContext{ - DB: db, - Redis: rds, - UserModel: user.NewModel(db, rds), - OrderModel: modelOrder.NewModel(db, rds), - SubscribeModel: subModel.NewModel(db, rds), - PaymentModel: payment.NewModel(db, rds), - Queue: queue, - } -} - -// insertTestSubscribe ็›ดๆŽฅ็”จ SQL ๆ’ๅ…ฅ subscribe ่กŒ๏ผˆ็ป•่ฟ‡ GORM hook ็š„ MySQL ๆ–น่จ€๏ผ‰ -// new_user_only=true ๆ—ถๅŒๆ—ถๅ†™ๅ…ฅ discount JSON๏ผŒไฝฟไปฃ็ ้‡Œ็š„ discount ๆฃ€ๆŸฅ็”Ÿๆ•ˆ -func insertTestSubscribe(t *testing.T, db *gorm.DB, id int64, newUserOnly bool) { - t.Helper() - nuOnly := 0 - discount := "" - if newUserOnly { - nuOnly = 1 - // discount JSON ๅŒ…ๅซไธ€ไธช new_user_only=true ็š„ tier๏ผŒๅŒน้… quantity=1 - discount = `[{"quantity":1,"discount":90,"new_user_only":true}]` - } - err := db.Exec(`INSERT INTO "subscribe" - (id, name, unit_price, inventory, sell, sort, new_user_only, discount, created_at, updated_at) - VALUES (?, 'Test Plan', 1000, -1, 1, ?, ?, ?, datetime('now'), datetime('now'))`, - id, id, nuOnly, discount).Error - require.NoError(t, err) -} - -// insertTestPayment ๆ’ๅ…ฅๆ”ฏไป˜ๆ–นๅผ่กŒ -func insertTestPayment(t *testing.T, db *gorm.DB, id int64) { - t.Helper() - err := db.Exec(`INSERT INTO "payment" - (id, name, platform, config, enable, fee_mode, token) - VALUES (?, 'Balance', 'balance', '{}', 1, 0, ?)`, - id, "test-token").Error - require.NoError(t, err) -} - -// insertTestUser ๆ’ๅ…ฅ็”จๆˆท่กŒ๏ผŒcreatedAt ๅฏๆŽง -func insertTestUser(t *testing.T, db *gorm.DB, id int64, createdAt time.Time) *user.User { - t.Helper() - err := db.Exec(`INSERT INTO "user" - (id, password, balance, gift_amount, enable, created_at, updated_at) - VALUES (?, '', 0, 0, 1, ?, datetime('now'))`, - id, createdAt.UTC().Format("2006-01-02 15:04:05")).Error - require.NoError(t, err) - return &user.User{ - Id: id, - GiftAmount: 0, - CreatedAt: createdAt, - } -} - -func insertTestDevice(t *testing.T, db *gorm.DB, userID int64, identifier string, createdAt time.Time) { - t.Helper() - err := db.Exec(`INSERT INTO "user_device" - (user_id, ip, user_agent, identifier, short_code, online, enabled, created_at, updated_at) - VALUES (?, '127.0.0.1', 'test-agent', ?, '', 0, 1, ?, datetime('now'))`, - userID, - identifier, - createdAt.UTC().Format("2006-01-02 15:04:05"), - ).Error - require.NoError(t, err) -} - -func insertTestFamily(t *testing.T, db *gorm.DB, familyID, ownerUserID int64) { - t.Helper() - err := db.Exec(`INSERT INTO "user_family" - (id, owner_user_id, max_members, status, created_at, updated_at) - VALUES (?, ?, 3, 1, datetime('now'), datetime('now'))`, - familyID, - ownerUserID, - ).Error - require.NoError(t, err) -} - -func insertTestFamilyMember(t *testing.T, db *gorm.DB, familyID, userID int64, role, status uint8, joinSource string) { - t.Helper() - err := db.Exec(`INSERT INTO "user_family_member" - (family_id, user_id, role, status, join_source, joined_at, created_at, updated_at) - VALUES (?, ?, ?, ?, ?, datetime('now'), datetime('now'), datetime('now'))`, - familyID, - userID, - role, - status, - joinSource, - ).Error - require.NoError(t, err) -} - -// insertTestOrder ๆ’ๅ…ฅไธ€ๆกๅކๅฒ่ฎขๅ•๏ผˆstatus=2 ่กจ็คบๅทฒๆ”ฏไป˜๏ผ‰ -func insertTestOrder(t *testing.T, db *gorm.DB, userID, subscribeID int64, status uint8) { - t.Helper() - err := db.Exec(`INSERT INTO "order" - (user_id, order_no, type, status, subscribe_id, created_at, updated_at) - VALUES (?, ?, 1, ?, ?, datetime('now'), datetime('now'))`, - userID, "existing-order-no", status, subscribeID).Error - require.NoError(t, err) -} - -func insertScopedTestOrder(t *testing.T, db *gorm.DB, orderNo string, userID, subscribeID int64, status uint8) { - t.Helper() - err := db.Exec(`INSERT INTO "order" - (user_id, order_no, type, status, subscribe_id, created_at, updated_at) - VALUES (?, ?, 1, ?, ?, datetime('now'), datetime('now'))`, - userID, orderNo, status, subscribeID).Error - require.NoError(t, err) -} - -// buildPurchaseCtx ๆŠŠ user ๆ”พๅ…ฅ context๏ผˆๆจกๆ‹Ÿไธญ้—ดไปถ่กŒไธบ๏ผ‰ -func buildPurchaseCtx(u *user.User) context.Context { - return context.WithValue(context.Background(), constant.CtxKeyUser, u) -} - -// TestPurchase_NewUserOnly_UserTooOld ้ชŒ่ฏ๏ผšnew_user_only=true๏ผŒ็”จๆˆทๆณจๅ†Œ่ถ…่ฟ‡ 24h โ†’ ่ฟ”ๅ›ž SubscribeNewUserOnly -func TestPurchase_NewUserOnly_UserTooOld(t *testing.T) { - db := setupNewUserOnlyDB(t) - rds, mr := setupNewUserOnlyRedis(t) - svcCtx := buildNewUserOnlySvcCtx(db, rds, mr) - - const subID = int64(1) - const payID = int64(1) - - insertTestSubscribe(t, db, subID, true) // new_user_only = true - insertTestPayment(t, db, payID) - - // ็”จๆˆทๆณจๅ†Œ 48 ๅฐๆ—ถๅ‰ โ†’ ่ถ…ๅ‡บ 24h ้™ๅˆถ - u := insertTestUser(t, db, 100, time.Now().Add(-48*time.Hour)) - ctx := buildPurchaseCtx(u) - - logic := NewPurchaseLogic(ctx, svcCtx) - _, err := logic.Purchase(&types.PurchaseOrderRequest{ - SubscribeId: subID, - Payment: payID, - Quantity: 1, - }) - - require.Error(t, err) - var errCode *xerr.CodeError - require.ErrorAs(t, err, &errCode) - assert.Equal(t, xerr.SubscribeNewUserOnly, errCode.GetErrCode(), - "ๆณจๅ†Œ่ถ…่ฟ‡24hๅบ”่ฟ”ๅ›ž SubscribeNewUserOnly ้”™่ฏฏ็ ") - - // ้ชŒ่ฏ่ฎขๅ•ๆœช่ขซๅˆ›ๅปบ - var count int64 - db.Model(&modelOrder.Order{}).Where("user_id = ?", u.Id).Count(&count) - assert.Equal(t, int64(0), count, "็”จๆˆทๆณจๅ†Œ่ถ…ๆ—ถ๏ผŒ่ฎขๅ•ไธๅบ”่ขซๅˆ›ๅปบ") -} - -// TestPurchase_NewUserOnly_AlreadyPurchased ้ชŒ่ฏ๏ผšnew_user_only=true๏ผŒ็”จๆˆทๆ˜ฏๆ–ฐ็”จๆˆทไฝ†ๅทฒ่ดญไนฐ่ฟ‡ -// โ†’ ๅ…่ฎธไธ‹ๅ•๏ผˆไธๆ‹ฆๆˆช๏ผ‰๏ผŒไฝ†ไธไบซๅ—ๆ–ฐไบบๆŠ˜ๆ‰ฃ -func TestPurchase_NewUserOnly_AlreadyPurchased(t *testing.T) { - db := setupNewUserOnlyDB(t) - rds, mr := setupNewUserOnlyRedis(t) - svcCtx := buildNewUserOnlySvcCtx(db, rds, mr) - - const subID = int64(2) - const payID = int64(1) - - insertTestSubscribe(t, db, subID, true) - insertTestPayment(t, db, payID) - - // ็”จๆˆทๅˆšๆณจๅ†Œ๏ผˆ2hๅ‰๏ผ‰โ†’ ๆปก่ถณๆ—ถ้—ดๆกไปถ - u := insertTestUser(t, db, 200, time.Now().Add(-2*time.Hour)) - - // ไฝ†ๅทฒๆœ‰ไธ€ๆก status=2 ็š„ๅކๅฒ่ฎขๅ•๏ผˆๅทฒๆ”ฏไป˜๏ผ‰ - insertTestOrder(t, db, u.Id, subID, 2) - - ctx := buildPurchaseCtx(u) - logic := NewPurchaseLogic(ctx, svcCtx) - resp, err := logic.Purchase(&types.PurchaseOrderRequest{ - SubscribeId: subID, - Payment: payID, - Quantity: 1, - }) - - // ไธๅบ”่ขซๆ‹ฆๆˆช๏ผŒๅ…่ฎธไธ‹ๅ• - require.NoError(t, err, "24hๅ†…ๅทฒ่ดญ็”จๆˆทๅบ”ๅ…่ฎธ็ปง็ปญไธ‹ๅ•๏ผŒไธๅบ”่ฟ”ๅ›ž้”™่ฏฏ") - require.NotNil(t, resp) - assert.NotEmpty(t, resp.OrderNo) - - // ๅކๅฒ่ฎขๅ• +1๏ผˆๆ–ฐๅขžไบ†ไธ€ๆก๏ผ‰ - var count int64 - db.Model(&modelOrder.Order{}).Where("user_id = ?", u.Id).Count(&count) - assert.Equal(t, int64(2), count, "ๅบ”ๆ–ฐๅขžไธ€ๆก่ฎขๅ•") - - // ๆ–ฐ่ฎขๅ•ๆ— ๆŠ˜ๆ‰ฃ๏ผšAmount=Price=1000 - var newOrder modelOrder.Order - require.NoError(t, db.Where("order_no = ?", resp.OrderNo).First(&newOrder).Error) - assert.Equal(t, int64(1000), newOrder.Amount, "ๅทฒ่ดญ็”จๆˆทไธไบซๅ—ๆ–ฐไบบๆŠ˜ๆ‰ฃ๏ผŒAmount ๅบ”็ญ‰ไบŽ Price") - assert.Equal(t, int64(0), newOrder.Discount, "Discount ๅบ”ไธบ 0") -} - -// TestPurchase_NewUserOnly_Success ้ชŒ่ฏ๏ผšnew_user_only=true๏ผŒๆ–ฐ็”จๆˆท้ฆ–ๆฌก่ดญไนฐ โ†’ ๆˆๅŠŸๅˆ›ๅปบ่ฎขๅ• -func TestPurchase_NewUserOnly_Success(t *testing.T) { - db := setupNewUserOnlyDB(t) - rds, mr := setupNewUserOnlyRedis(t) - svcCtx := buildNewUserOnlySvcCtx(db, rds, mr) - - const subID = int64(3) - const payID = int64(1) - - insertTestSubscribe(t, db, subID, true) - insertTestPayment(t, db, payID) - - // ็”จๆˆท 1 ๅฐๆ—ถๅ‰ๆณจๅ†Œ๏ผˆๆ–ฐ็”จๆˆท๏ผ‰๏ผŒไธ”ๆฒกๆœ‰ๅކๅฒ่ฎขๅ• - u := insertTestUser(t, db, 300, time.Now().Add(-1*time.Hour)) - ctx := buildPurchaseCtx(u) - - logic := NewPurchaseLogic(ctx, svcCtx) - resp, err := logic.Purchase(&types.PurchaseOrderRequest{ - SubscribeId: subID, - Payment: payID, - Quantity: 1, - }) - - require.NoError(t, err) - require.NotNil(t, resp) - assert.NotEmpty(t, resp.OrderNo, "ๆ–ฐ็”จๆˆท้ฆ–ๆฌก่ดญไนฐๅบ”ๆˆๅŠŸ๏ผŒ่ฟ”ๅ›ž่ฎขๅ•ๅท") - - // ้ชŒ่ฏ่ฎขๅ•ๅทฒๅ†™ๅ…ฅๆ•ฐๆฎๅบ“ - var o modelOrder.Order - err = db.Where("order_no = ?", resp.OrderNo).First(&o).Error - require.NoError(t, err) - assert.Equal(t, u.Id, o.UserId) - assert.Equal(t, subID, o.SubscribeId) -} - -// TestPurchase_NewUserOnly_Disabled ้ชŒ่ฏ๏ผšnew_user_only=false ๆ—ถ๏ผŒ่€็”จๆˆทไนŸ่ƒฝๆญฃๅธธ่ดญไนฐ -func TestPurchase_NewUserOnly_Disabled(t *testing.T) { - db := setupNewUserOnlyDB(t) - rds, mr := setupNewUserOnlyRedis(t) - svcCtx := buildNewUserOnlySvcCtx(db, rds, mr) - - const subID = int64(4) - const payID = int64(1) - - insertTestSubscribe(t, db, subID, false) // new_user_only = false - insertTestPayment(t, db, payID) - - // ๆณจๅ†Œ 30 ๅคฉ็š„่€็”จๆˆท - u := insertTestUser(t, db, 400, time.Now().Add(-30*24*time.Hour)) - ctx := buildPurchaseCtx(u) - - logic := NewPurchaseLogic(ctx, svcCtx) - resp, err := logic.Purchase(&types.PurchaseOrderRequest{ - SubscribeId: subID, - Payment: payID, - Quantity: 1, - }) - - require.NoError(t, err) - require.NotNil(t, resp) - assert.NotEmpty(t, resp.OrderNo, "new_user_only=falseๆ—ถ่€็”จๆˆทๅบ”่ƒฝๆญฃๅธธ่ดญไนฐ") -} - -// TestPurchase_SingleMode_PendingOldOrderCancelled ้ชŒ่ฏ๏ผšๅ•่ฎข้˜…ๆจกๅผไธ‹๏ผŒๅทฒๆœ‰ pending ่ฎขๅ•ๆ—ถ -// ็ฌฌไบŒๆฌกไธ‹ๅ•ๅบ”ๅ…ณ้—ญๆ—งๅ•ๅนถๅˆ›ๅปบๆ–ฐๅ•๏ผˆ่€Œ้žๅค็”จๆ—งๅ•๏ผ‰ -func TestPurchase_SingleMode_PendingOldOrderCancelled(t *testing.T) { - db := setupNewUserOnlyDB(t) - rds, mr := setupNewUserOnlyRedis(t) - svcCtx := buildNewUserOnlySvcCtx(db, rds, mr) - svcCtx.Config.Subscribe.SingleModel = true - - const subID = int64(5) - const payID = int64(1) - - insertTestSubscribe(t, db, subID, false) - insertTestPayment(t, db, payID) - - u := insertTestUser(t, db, 500, time.Now().Add(-1*time.Hour)) - ctx := buildPurchaseCtx(u) - - // ็ฌฌไธ€ๆฌกไธ‹ๅ•๏ผˆpending๏ผ‰ - logic := NewPurchaseLogic(ctx, svcCtx) - resp1, err := logic.Purchase(&types.PurchaseOrderRequest{ - SubscribeId: subID, - Payment: payID, - Quantity: 1, - }) - require.NoError(t, err) - require.NotNil(t, resp1) - firstOrderNo := resp1.OrderNo - assert.NotEmpty(t, firstOrderNo) - - // ็กฎ่ฎค็ฌฌไธ€ๅ• pending - var firstOrder modelOrder.Order - require.NoError(t, db.Where("order_no = ?", firstOrderNo).First(&firstOrder).Error) - assert.Equal(t, uint8(1), firstOrder.Status, "็ฌฌไธ€ๅ•ๅบ”ไธบ pending") - - // ็ฌฌไบŒๆฌกไธ‹ๅ•๏ผˆไธๅŒ quantity๏ผ‰ - logic2 := NewPurchaseLogic(ctx, svcCtx) - resp2, err := logic2.Purchase(&types.PurchaseOrderRequest{ - SubscribeId: subID, - Payment: payID, - Quantity: 3, - }) - require.NoError(t, err) - require.NotNil(t, resp2) - secondOrderNo := resp2.OrderNo - - // ๆ–ฐๅ•ไธŽๆ—งๅ•ไธๅŒ - assert.NotEqual(t, firstOrderNo, secondOrderNo, "็ฌฌไบŒๆฌกไธ‹ๅ•ๅบ”ๅˆ›ๅปบๆ–ฐ่ฎขๅ•๏ผŒไธๅค็”จๆ—งๅ•") - - // ๆ—งๅ•ๅบ”่ขซๅ…ณ้—ญ๏ผˆstatus=3๏ผ‰ - var closedOrder modelOrder.Order - require.NoError(t, db.Where("order_no = ?", firstOrderNo).First(&closedOrder).Error) - assert.Equal(t, uint8(3), closedOrder.Status, "ๆ—ง pending ๅ•ๅบ”่ขซๅ…ณ้—ญ") - - // ๆ–ฐๅ•็š„ quantity ๅบ”ไธบ 3 - var newOrder modelOrder.Order - require.NoError(t, db.Where("order_no = ?", secondOrderNo).First(&newOrder).Error) - assert.Equal(t, int64(3), newOrder.Quantity, "ๆ–ฐๅ• quantity ๅบ”ไธบ 3") - assert.Equal(t, uint8(1), newOrder.Status, "ๆ–ฐๅ•ๅบ”ไธบ pending ็Šถๆ€") -} - -// TestPurchase_SingleMode_NoPendingOrder ้ชŒ่ฏ๏ผšๅ•่ฎข้˜…ๆจกๅผไธ‹๏ผŒๆฒกๆœ‰ๆ—ง pending ๅ•ๆ—ถๆญฃๅธธๅˆ›ๅปบ -func TestPurchase_SingleMode_NoPendingOrder(t *testing.T) { - db := setupNewUserOnlyDB(t) - rds, mr := setupNewUserOnlyRedis(t) - svcCtx := buildNewUserOnlySvcCtx(db, rds, mr) - svcCtx.Config.Subscribe.SingleModel = true - - const subID = int64(6) - const payID = int64(1) - - insertTestSubscribe(t, db, subID, false) - insertTestPayment(t, db, payID) - - u := insertTestUser(t, db, 600, time.Now().Add(-1*time.Hour)) - ctx := buildPurchaseCtx(u) - - logic := NewPurchaseLogic(ctx, svcCtx) - resp, err := logic.Purchase(&types.PurchaseOrderRequest{ - SubscribeId: subID, - Payment: payID, - Quantity: 2, - }) - require.NoError(t, err) - require.NotNil(t, resp) - assert.NotEmpty(t, resp.OrderNo, "ๆ— ๆ—ง pending ๅ•ๆ—ถๅบ”ๆญฃๅธธๅˆ›ๅปบๆ–ฐๅ•") - - var o modelOrder.Order - require.NoError(t, db.Where("order_no = ?", resp.OrderNo).First(&o).Error) - assert.Equal(t, int64(2), o.Quantity) - assert.Equal(t, uint8(1), o.Status) -} - -// TestPurchase_NewUserOnly_AlreadyPurchased_NoBlock ้ชŒ่ฏ๏ผšnew_user_only=true ๅฅ—้ค๏ผŒ -// 24ๅฐๆ—ถๅ†…ไฝ†ๅทฒ่ดญไนฐ่ฟ‡ โ†’ ๅ…่ฎธไธ‹ๅ•๏ผŒไฝ†ไธไบซๅ—ๆ–ฐไบบๆŠ˜ๆ‰ฃ๏ผˆDiscount=0๏ผŒAmount=Price๏ผ‰ -func TestPurchase_NewUserOnly_AlreadyPurchased_NoBlock(t *testing.T) { - db := setupNewUserOnlyDB(t) - rds, mr := setupNewUserOnlyRedis(t) - svcCtx := buildNewUserOnlySvcCtx(db, rds, mr) - - const subID = int64(7) - const payID = int64(1) - - // ๅฅ—้ค๏ผšunit_price=1000๏ผŒdiscount=[{quantity:1,discount:80,new_user_only:true}] - insertTestSubscribe(t, db, subID, true) - insertTestPayment(t, db, payID) - - // ็”จๆˆท 1 ๅฐๆ—ถๅ‰ๆณจๅ†Œ๏ผˆๆ–ฐ็”จๆˆท๏ผ‰๏ผŒไฝ†ๅทฒๆœ‰ไธ€ๆกๆˆๅŠŸ่ฎขๅ•๏ผˆstatus=2๏ผ‰ - u := insertTestUser(t, db, 700, time.Now().Add(-1*time.Hour)) - insertTestOrder(t, db, u.Id, subID, 2) - - ctx := buildPurchaseCtx(u) - logic := NewPurchaseLogic(ctx, svcCtx) - resp, err := logic.Purchase(&types.PurchaseOrderRequest{ - SubscribeId: subID, - Payment: payID, - Quantity: 1, - }) - - // ไธๅบ”่ขซๆ‹ฆๆˆช - require.NoError(t, err, "24hๅ†…ๅทฒ่ดญ็”จๆˆทไธๅบ”่ขซๆ‹ฆๆˆช๏ผŒๅบ”ๅ…่ฎธไธ‹ๅ•") - require.NotNil(t, resp) - assert.NotEmpty(t, resp.OrderNo) - - // ้ชŒ่ฏ่ฎขๅ•้‡‘้ข๏ผšๆ— ๆŠ˜ๆ‰ฃ๏ผŒAmount=Price=1000๏ผŒDiscount=0 - var newOrder modelOrder.Order - require.NoError(t, db.Where("order_no = ?", resp.OrderNo).First(&newOrder).Error) - assert.Equal(t, int64(1000), newOrder.Price, "Price ๅบ”ไธบๅŽŸไปท 1000") - assert.Equal(t, int64(1000), newOrder.Amount, "ๅทฒ่ดญ็”จๆˆทไธไบซๅ—ๆ–ฐไบบๆŠ˜ๆ‰ฃ๏ผŒAmount ๅบ”็ญ‰ไบŽ Price") - assert.Equal(t, int64(0), newOrder.Discount, "Discount ๅบ”ไธบ 0") -} - -// TestPurchase_NewUserOnly_FirstPurchase_HasDiscount ้ชŒ่ฏ๏ผšnew_user_only=true ๅฅ—้ค๏ผŒ -// 24ๅฐๆ—ถๅ†…้ฆ–ๆฌก่ดญไนฐ โ†’ ๅ…่ฎธไธ‹ๅ•ไธ”ไบซๅ—ๆ–ฐไบบๆŠ˜ๆ‰ฃ -func TestPurchase_NewUserOnly_FirstPurchase_HasDiscount(t *testing.T) { - db := setupNewUserOnlyDB(t) - rds, mr := setupNewUserOnlyRedis(t) - svcCtx := buildNewUserOnlySvcCtx(db, rds, mr) - - const subID = int64(8) - const payID = int64(1) - - // ๅฅ—้ค๏ผšunit_price=1000๏ผŒdiscount=[{quantity:1,discount:80,new_user_only:true}]๏ผˆ8ๆŠ˜๏ผ‰ - insertTestSubscribe(t, db, subID, true) - insertTestPayment(t, db, payID) - - // ็”จๆˆท 1 ๅฐๆ—ถๅ‰ๆณจๅ†Œ๏ผŒๆ— ๅކๅฒ่ฎขๅ• - u := insertTestUser(t, db, 800, time.Now().Add(-1*time.Hour)) - ctx := buildPurchaseCtx(u) - - logic := NewPurchaseLogic(ctx, svcCtx) - resp, err := logic.Purchase(&types.PurchaseOrderRequest{ - SubscribeId: subID, - Payment: payID, - Quantity: 1, - }) - - require.NoError(t, err) - require.NotNil(t, resp) - - var newOrder modelOrder.Order - require.NoError(t, db.Where("order_no = ?", resp.OrderNo).First(&newOrder).Error) - assert.Equal(t, int64(1000), newOrder.Price, "Price ๅบ”ไธบๅŽŸไปท 1000") - assert.Equal(t, int64(900), newOrder.Amount, "้ฆ–ๆฌก่ดญไนฐๅบ”ไบซๅ—9ๆŠ˜๏ผŒAmount=900") - assert.Equal(t, int64(100), newOrder.Discount, "ๆŠ˜ๆ‰ฃ้‡‘้ขๅบ”ไธบ 100") -} - -func TestPurchase_NewUserOnly_BindEmailScopeUsesEarliestDeviceTime(t *testing.T) { - db := setupNewUserOnlyDB(t) - rds, mr := setupNewUserOnlyRedis(t) - svcCtx := buildNewUserOnlySvcCtx(db, rds, mr) - - const ( - subID = int64(9) - payID = int64(1) - ownerUserID = int64(901) - memberUserID = int64(902) - familyID = int64(99) - ) - - insertTestSubscribe(t, db, subID, true) - insertTestPayment(t, db, payID) - - owner := insertTestUser(t, db, ownerUserID, time.Now().Add(-1*time.Hour)) - insertTestUser(t, db, memberUserID, time.Now().Add(-72*time.Hour)) - insertTestDevice(t, db, memberUserID, "device-eligibility-old", time.Now().Add(-72*time.Hour)) - insertTestFamily(t, db, familyID, ownerUserID) - insertTestFamilyMember(t, db, familyID, ownerUserID, user.FamilyRoleOwner, user.FamilyMemberActive, "owner_init") - insertTestFamilyMember(t, db, familyID, memberUserID, user.FamilyRoleMember, user.FamilyMemberActive, "bind_email_with_verification") - - logic := NewPurchaseLogic(buildPurchaseCtx(owner), svcCtx) - _, err := logic.Purchase(&types.PurchaseOrderRequest{ - SubscribeId: subID, - Payment: payID, - Quantity: 1, - }) - - require.Error(t, err) - var errCode *xerr.CodeError - require.ErrorAs(t, err, &errCode) - assert.Equal(t, xerr.SubscribeNewUserOnly, errCode.GetErrCode()) -} - -func TestPurchase_NewUserOnly_BindEmailScopeSharesHistory(t *testing.T) { - db := setupNewUserOnlyDB(t) - rds, mr := setupNewUserOnlyRedis(t) - svcCtx := buildNewUserOnlySvcCtx(db, rds, mr) - - const ( - subID = int64(10) - payID = int64(1) - ownerUserID = int64(1001) - memberUserID = int64(1002) - familyID = int64(109) - ) - - insertTestSubscribe(t, db, subID, true) - insertTestPayment(t, db, payID) - - owner := insertTestUser(t, db, ownerUserID, time.Now().Add(-1*time.Hour)) - insertTestUser(t, db, memberUserID, time.Now().Add(-2*time.Hour)) - insertTestDevice(t, db, memberUserID, "device-eligibility-shared", time.Now().Add(-2*time.Hour)) - insertTestFamily(t, db, familyID, ownerUserID) - insertTestFamilyMember(t, db, familyID, ownerUserID, user.FamilyRoleOwner, user.FamilyMemberActive, "owner_init") - insertTestFamilyMember(t, db, familyID, memberUserID, user.FamilyRoleMember, user.FamilyMemberActive, "bind_email_with_verification") - insertScopedTestOrder(t, db, "existing-scope-order", memberUserID, subID, 2) - - logic := NewPurchaseLogic(buildPurchaseCtx(owner), svcCtx) - resp, err := logic.Purchase(&types.PurchaseOrderRequest{ - SubscribeId: subID, - Payment: payID, - Quantity: 1, - }) - - require.NoError(t, err) - require.NotNil(t, resp) - - var newOrder modelOrder.Order - require.NoError(t, db.Where("order_no = ?", resp.OrderNo).First(&newOrder).Error) - assert.Equal(t, int64(1000), newOrder.Amount) - assert.Equal(t, int64(0), newOrder.Discount) -} - -func ensureRenewalSubscribeColumns(t *testing.T, db *gorm.DB) { - t.Helper() - for _, sql := range []string{ - `ALTER TABLE "user_subscribe" ADD COLUMN node_group_id INTEGER NOT NULL DEFAULT 0`, - `ALTER TABLE "user_subscribe" ADD COLUMN group_locked TINYINT NOT NULL DEFAULT 0`, - `ALTER TABLE "user_subscribe" ADD COLUMN expired_download INTEGER NOT NULL DEFAULT 0`, - `ALTER TABLE "user_subscribe" ADD COLUMN expired_upload INTEGER NOT NULL DEFAULT 0`, - } { - require.NoError(t, db.Exec(sql).Error) - } -} - -func insertRenewalUserSubscribe(t *testing.T, db *gorm.DB, id, userID, orderID, subscribeID int64, token, uuid string, start, expire time.Time) { - t.Helper() - require.NoError(t, db.Exec(`INSERT INTO "user_subscribe" - (id, user_id, order_id, subscribe_id, start_time, expire_time, traffic, download, upload, token, uuid, status, created_at, updated_at) - VALUES (?, ?, ?, ?, ?, ?, 0, 0, 0, ?, ?, 1, ?, ?)`, - id, - userID, - orderID, - subscribeID, - start.UTC().Format("2006-01-02 15:04:05"), - expire.UTC().Format("2006-01-02 15:04:05"), - token, - uuid, - start.UTC().Format("2006-01-02 15:04:05"), - time.Now().UTC().Format("2006-01-02 15:04:05"), - ).Error) -} - -func TestRenewalMemberRequestRedirectsToOwnerSubscribe(t *testing.T) { - db := setupNewUserOnlyDB(t) - ensureRenewalSubscribeColumns(t, db) - rds, mr := setupNewUserOnlyRedis(t) - svcCtx := buildNewUserOnlySvcCtx(db, rds, mr) - - const ( - planID = int64(1) - paymentID = int64(2) - ownerUserID = int64(29650) - memberID = int64(20003) - familyID = int64(88001) - memberSubID = int64(10013) - ownerSubID = int64(14074) - ) - - insertTestSubscribe(t, db, planID, false) - insertTestPayment(t, db, paymentID) - member := insertTestUser(t, db, memberID, time.Now().Add(-24*time.Hour)) - insertTestUser(t, db, ownerUserID, time.Now().Add(-24*time.Hour)) - insertTestFamily(t, db, familyID, ownerUserID) - insertTestFamilyMember(t, db, familyID, ownerUserID, user.FamilyRoleOwner, user.FamilyMemberActive, "owner_init") - insertTestFamilyMember(t, db, familyID, memberID, user.FamilyRoleMember, user.FamilyMemberActive, "manual_invite") - - insertRenewalUserSubscribe(t, db, memberSubID, memberID, 7448, planID, "member-token-10013", "member-uuid-10013", - time.Date(2026, 4, 23, 19, 6, 40, 0, time.UTC), - time.Date(2026, 4, 30, 19, 6, 40, 0, time.UTC), - ) - insertRenewalUserSubscribe(t, db, ownerSubID, ownerUserID, 9999, planID, "owner-token-14074", "owner-uuid-14074", - time.Date(2026, 4, 30, 13, 39, 33, 0, time.UTC), - time.Date(2026, 5, 30, 16, 0, 0, 0, time.UTC), - ) - - resp, err := NewRenewalLogic(buildPurchaseCtx(member), svcCtx).Renewal(&types.RenewalOrderRequest{ - UserSubscribeID: memberSubID, - Payment: paymentID, - Quantity: 30, - }) - require.NoError(t, err) - require.NotNil(t, resp) - - var created modelOrder.Order - require.NoError(t, db.Where("order_no = ?", resp.OrderNo).First(&created).Error) - assert.Equal(t, memberID, created.UserId) - assert.Equal(t, ownerUserID, created.SubscriptionUserId) - assert.Equal(t, int64(9999), created.ParentId) - assert.Equal(t, "owner-token-14074", created.SubscribeToken) -} - -func TestPreCreateOrder_NewUserOnly_BindEmailScopeUsesEarliestDeviceTime(t *testing.T) { - db := setupNewUserOnlyDB(t) - rds, mr := setupNewUserOnlyRedis(t) - svcCtx := buildNewUserOnlySvcCtx(db, rds, mr) - - const ( - subID = int64(11) - ownerUserID = int64(1101) - memberUserID = int64(1102) - familyID = int64(119) - ) - - insertTestSubscribe(t, db, subID, true) - - owner := insertTestUser(t, db, ownerUserID, time.Now().Add(-1*time.Hour)) - insertTestUser(t, db, memberUserID, time.Now().Add(-96*time.Hour)) - insertTestDevice(t, db, memberUserID, "device-precreate-old", time.Now().Add(-96*time.Hour)) - insertTestFamily(t, db, familyID, ownerUserID) - insertTestFamilyMember(t, db, familyID, ownerUserID, user.FamilyRoleOwner, user.FamilyMemberActive, "owner_init") - insertTestFamilyMember(t, db, familyID, memberUserID, user.FamilyRoleMember, user.FamilyMemberActive, "bind_email_with_verification") - - logic := NewPreCreateOrderLogic(buildPurchaseCtx(owner), svcCtx) - _, err := logic.PreCreateOrder(&types.PurchaseOrderRequest{ - SubscribeId: subID, - Quantity: 1, - }) - - require.Error(t, err) - var errCode *xerr.CodeError - require.ErrorAs(t, err, &errCode) - assert.Equal(t, xerr.SubscribeNewUserOnly, errCode.GetErrCode()) -} - -func TestPreCreateOrder_NewUserOnly_OrdinaryFamilyMemberDoesNotAffectEligibility(t *testing.T) { - db := setupNewUserOnlyDB(t) - rds, mr := setupNewUserOnlyRedis(t) - svcCtx := buildNewUserOnlySvcCtx(db, rds, mr) - - const ( - subID = int64(12) - ownerUserID = int64(1201) - memberUserID = int64(1202) - familyID = int64(129) - ) - - insertTestSubscribe(t, db, subID, true) - - owner := insertTestUser(t, db, ownerUserID, time.Now().Add(-1*time.Hour)) - insertTestUser(t, db, memberUserID, time.Now().Add(-96*time.Hour)) - insertTestDevice(t, db, memberUserID, "device-precreate-ordinary", time.Now().Add(-96*time.Hour)) - insertTestFamily(t, db, familyID, ownerUserID) - insertTestFamilyMember(t, db, familyID, ownerUserID, user.FamilyRoleOwner, user.FamilyMemberActive, "owner_init") - insertTestFamilyMember(t, db, familyID, memberUserID, user.FamilyRoleMember, user.FamilyMemberActive, "manual_invite") - - logic := NewPreCreateOrderLogic(buildPurchaseCtx(owner), svcCtx) - resp, err := logic.PreCreateOrder(&types.PurchaseOrderRequest{ - SubscribeId: subID, - Quantity: 1, - }) - - require.NoError(t, err) - require.NotNil(t, resp) - assert.Equal(t, int64(900), resp.Amount) - assert.Equal(t, int64(100), resp.Discount) -} diff --git a/internal/logic/public/order/renewalInviteFirstPurchase_test.go b/internal/logic/public/order/renewalInviteFirstPurchase_test.go deleted file mode 100644 index 86e4665..0000000 --- a/internal/logic/public/order/renewalInviteFirstPurchase_test.go +++ /dev/null @@ -1,130 +0,0 @@ -package order - -import ( - "testing" - "time" - - modelOrder "github.com/perfect-panel/server/internal/model/order" - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/types" - "github.com/stretchr/testify/require" - "gorm.io/gorm" -) - -func ensureRenewalInviteSubscribeColumns(t *testing.T, db *gorm.DB) { - t.Helper() - for _, sql := range []string{ - `ALTER TABLE "user_subscribe" ADD COLUMN node_group_id INTEGER NOT NULL DEFAULT 0`, - `ALTER TABLE "user_subscribe" ADD COLUMN group_locked TINYINT NOT NULL DEFAULT 0`, - `ALTER TABLE "user_subscribe" ADD COLUMN expired_download INTEGER NOT NULL DEFAULT 0`, - `ALTER TABLE "user_subscribe" ADD COLUMN expired_upload INTEGER NOT NULL DEFAULT 0`, - } { - require.NoError(t, db.Exec(sql).Error) - } -} - -func insertRenewalInviteUserSubscribe(t *testing.T, db *gorm.DB, id, userID, orderID, subscribeID int64, token, uuid string, start, expire time.Time) { - t.Helper() - require.NoError(t, db.Exec(`INSERT INTO "user_subscribe" - (id, user_id, order_id, subscribe_id, start_time, expire_time, traffic, download, upload, token, uuid, status, created_at, updated_at) - VALUES (?, ?, ?, ?, ?, ?, 0, 0, 0, ?, ?, 1, ?, ?)`, - id, - userID, - orderID, - subscribeID, - start.UTC().Format("2006-01-02 15:04:05"), - expire.UTC().Format("2006-01-02 15:04:05"), - token, - uuid, - start.UTC().Format("2006-01-02 15:04:05"), - time.Now().UTC().Format("2006-01-02 15:04:05"), - ).Error) -} - -func TestRenewalFirstSuccessfulPaymentMarksOrderAsNew(t *testing.T) { - db := setupNewUserOnlyDB(t) - ensureRenewalInviteSubscribeColumns(t, db) - rds, mr := setupNewUserOnlyRedis(t) - svcCtx := buildNewUserOnlySvcCtx(db, rds, mr) - - const ( - planID = int64(1) - paymentID = int64(2) - ownerUserID = int64(31059) - memberID = int64(31057) - familyID = int64(5638) - ownerSubID = int64(14672) - ) - - insertTestSubscribe(t, db, planID, false) - insertTestPayment(t, db, paymentID) - member := insertTestUser(t, db, memberID, time.Now().Add(-2*time.Hour)) - insertTestUser(t, db, ownerUserID, time.Now().Add(-2*time.Hour)) - insertTestFamily(t, db, familyID, ownerUserID) - insertTestFamilyMember(t, db, familyID, ownerUserID, user.FamilyRoleOwner, user.FamilyMemberActive, "owner_init") - insertTestFamilyMember(t, db, familyID, memberID, user.FamilyRoleMember, user.FamilyMemberActive, "bind_email_with_verification") - - insertRenewalInviteUserSubscribe(t, db, ownerSubID, ownerUserID, 0, planID, "owner-trial-token", "owner-trial-uuid", - time.Date(2026, 5, 2, 15, 53, 39, 0, time.UTC), - time.Date(2026, 5, 9, 0, 0, 0, 0, time.UTC), - ) - - resp, err := NewRenewalLogic(buildPurchaseCtx(member), svcCtx).Renewal(&types.RenewalOrderRequest{ - UserSubscribeID: ownerSubID, - Payment: paymentID, - Quantity: 1, - }) - require.NoError(t, err) - require.NotNil(t, resp) - - var created modelOrder.Order - require.NoError(t, db.Where("order_no = ?", resp.OrderNo).First(&created).Error) - require.Equal(t, uint8(2), created.Type) - require.True(t, created.IsNew) - require.Equal(t, memberID, created.UserId) - require.Equal(t, ownerUserID, created.SubscriptionUserId) - require.Equal(t, "owner-trial-token", created.SubscribeToken) -} - -func TestRenewalExistingSuccessfulPaymentMarksOrderAsNotNew(t *testing.T) { - db := setupNewUserOnlyDB(t) - ensureRenewalInviteSubscribeColumns(t, db) - rds, mr := setupNewUserOnlyRedis(t) - svcCtx := buildNewUserOnlySvcCtx(db, rds, mr) - - const ( - planID = int64(1) - paymentID = int64(2) - ownerUserID = int64(41059) - memberID = int64(41057) - familyID = int64(6638) - ownerSubID = int64(24672) - ) - - insertTestSubscribe(t, db, planID, false) - insertTestPayment(t, db, paymentID) - member := insertTestUser(t, db, memberID, time.Now().Add(-2*time.Hour)) - insertTestUser(t, db, ownerUserID, time.Now().Add(-2*time.Hour)) - insertTestFamily(t, db, familyID, ownerUserID) - insertTestFamilyMember(t, db, familyID, ownerUserID, user.FamilyRoleOwner, user.FamilyMemberActive, "owner_init") - insertTestFamilyMember(t, db, familyID, memberID, user.FamilyRoleMember, user.FamilyMemberActive, "bind_email_with_verification") - insertScopedTestOrder(t, db, "previous-successful-order", memberID, planID, 5) - - insertRenewalInviteUserSubscribe(t, db, ownerSubID, ownerUserID, 0, planID, "owner-renewal-token", "owner-renewal-uuid", - time.Date(2026, 5, 2, 15, 53, 39, 0, time.UTC), - time.Date(2026, 5, 9, 0, 0, 0, 0, time.UTC), - ) - - resp, err := NewRenewalLogic(buildPurchaseCtx(member), svcCtx).Renewal(&types.RenewalOrderRequest{ - UserSubscribeID: ownerSubID, - Payment: paymentID, - Quantity: 1, - }) - require.NoError(t, err) - require.NotNil(t, resp) - - var created modelOrder.Order - require.NoError(t, db.Where("order_no = ?", resp.OrderNo).First(&created).Error) - require.Equal(t, uint8(2), created.Type) - require.False(t, created.IsNew) -} diff --git a/internal/logic/public/user/familyBindingHelper_test.go b/internal/logic/public/user/familyBindingHelper_test.go deleted file mode 100644 index 76a6df8..0000000 --- a/internal/logic/public/user/familyBindingHelper_test.go +++ /dev/null @@ -1,288 +0,0 @@ -package user - -import ( - "testing" - "time" - - modelOrder "github.com/perfect-panel/server/internal/model/order" - modelUser "github.com/perfect-panel/server/internal/model/user" - "gorm.io/driver/sqlite" - "gorm.io/gorm" - "gorm.io/gorm/logger" -) - -func newFamilyBindingTestDB(t *testing.T) *gorm.DB { - t.Helper() - - db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{ - DisableForeignKeyConstraintWhenMigrating: true, - Logger: logger.Default.LogMode(logger.Silent), - }) - if err != nil { - t.Fatalf("open sqlite db: %v", err) - } - if err = db.Exec(` -CREATE TABLE user_subscribe ( - id integer primary key, - user_id integer not null, - order_id integer not null, - subscribe_id integer not null, - start_time datetime, - expire_time datetime, - token text, - uuid text, - status integer, - created_at datetime, - updated_at datetime -)`).Error; err != nil { - t.Fatalf("create user_subscribe schema: %v", err) - } - if err = db.Exec(` -CREATE TABLE "order" ( - id integer primary key, - user_id integer not null, - subscription_user_id integer not null, - order_no text, - subscribe_token text, - status integer, - subscribe_id integer, - created_at datetime, - updated_at datetime -)`).Error; err != nil { - t.Fatalf("create order schema: %v", err) - } - return db -} - -func insertFamilyBindingTestOrder(t *testing.T, db *gorm.DB, order modelOrder.Order) { - t.Helper() - - if err := db.Exec(` -INSERT INTO "order" ( - id, user_id, subscription_user_id, order_no, subscribe_token, status, subscribe_id, created_at, updated_at -) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, - order.Id, - order.UserId, - order.SubscriptionUserId, - order.OrderNo, - order.SubscribeToken, - order.Status, - order.SubscribeId, - order.CreatedAt, - order.UpdatedAt, - ).Error; err != nil { - t.Fatalf("insert order %d: %v", order.Id, err) - } -} - -func insertFamilyBindingTestSubscribe(t *testing.T, db *gorm.DB, sub modelUser.Subscribe) { - t.Helper() - - if err := db.Exec(` -INSERT INTO user_subscribe ( - id, user_id, order_id, subscribe_id, start_time, expire_time, token, uuid, status, created_at, updated_at -) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, - sub.Id, - sub.UserId, - sub.OrderId, - sub.SubscribeId, - sub.StartTime, - sub.ExpireTime, - sub.Token, - sub.UUID, - sub.Status, - sub.CreatedAt, - sub.UpdatedAt, - ).Error; err != nil { - t.Fatalf("insert subscribe %d: %v", sub.Id, err) - } -} - -func TestMoveMemberSubscribesToOwnerMovesSubscribeAndCurrentOrder(t *testing.T) { - db := newFamilyBindingTestDB(t) - memberUserID := int64(1001) - ownerUserID := int64(2001) - now := time.Now().Add(-time.Hour) - expireAt := now.Add(30 * 24 * time.Hour) - - currentOrder := modelOrder.Order{ - Id: 9001, - UserId: memberUserID, - SubscriptionUserId: memberUserID, - OrderNo: "order-current", - SubscribeToken: "token-current", - Status: 5, - SubscribeId: 3001, - CreatedAt: now, - UpdatedAt: now, - } - unlinkedOrder := modelOrder.Order{ - Id: 9002, - UserId: memberUserID, - SubscriptionUserId: memberUserID, - OrderNo: "order-unlinked", - SubscribeToken: "token-unlinked", - Status: 5, - SubscribeId: 3001, - CreatedAt: now, - UpdatedAt: now, - } - sub := modelUser.Subscribe{ - Id: 7001, - UserId: memberUserID, - OrderId: currentOrder.Id, - SubscribeId: currentOrder.SubscribeId, - StartTime: now, - ExpireTime: expireAt, - Token: "token-current", - UUID: "uuid-current", - Status: 1, - CreatedAt: now, - UpdatedAt: now, - } - insertFamilyBindingTestOrder(t, db, currentOrder) - insertFamilyBindingTestOrder(t, db, unlinkedOrder) - insertFamilyBindingTestSubscribe(t, db, sub) - - var moved []modelUser.Subscribe - if err := db.Transaction(func(tx *gorm.DB) error { - var err error - moved, err = moveMemberSubscribesToOwner(tx, memberUserID, ownerUserID) - return err - }); err != nil { - t.Fatalf("move member subscribes: %v", err) - } - - if len(moved) != 1 { - t.Fatalf("moved subscribes length = %d, want 1", len(moved)) - } - if moved[0].UserId != memberUserID { - t.Fatalf("moved cache copy user_id = %d, want original member %d", moved[0].UserId, memberUserID) - } - - var gotSub modelUser.Subscribe - if err := db.First(&gotSub, "id = ?", sub.Id).Error; err != nil { - t.Fatalf("query moved subscribe: %v", err) - } - if gotSub.UserId != ownerUserID { - t.Fatalf("subscribe user_id = %d, want owner %d", gotSub.UserId, ownerUserID) - } - if gotSub.Token == "" || gotSub.Token == sub.Token { - t.Fatalf("subscribe token = %q, want regenerated from old token %q", gotSub.Token, sub.Token) - } - if gotSub.UUID == "" || gotSub.UUID == sub.UUID { - t.Fatalf("subscribe uuid = %q, want regenerated from old uuid %q", gotSub.UUID, sub.UUID) - } - - var gotOrder modelOrder.Order - if err := db.First(&gotOrder, "id = ?", currentOrder.Id).Error; err != nil { - t.Fatalf("query updated order: %v", err) - } - if gotOrder.SubscriptionUserId != ownerUserID { - t.Fatalf("current order subscription_user_id = %d, want owner %d", gotOrder.SubscriptionUserId, ownerUserID) - } - if gotOrder.SubscribeToken != gotSub.Token { - t.Fatalf("current order subscribe_token = %q, want regenerated subscribe token %q", gotOrder.SubscribeToken, gotSub.Token) - } - - var gotUnlinkedOrder modelOrder.Order - if err := db.First(&gotUnlinkedOrder, "id = ?", unlinkedOrder.Id).Error; err != nil { - t.Fatalf("query unlinked order: %v", err) - } - if gotUnlinkedOrder.SubscriptionUserId != memberUserID { - t.Fatalf("unlinked order subscription_user_id = %d, want unchanged member %d", gotUnlinkedOrder.SubscriptionUserId, memberUserID) - } - if gotUnlinkedOrder.SubscribeToken != unlinkedOrder.SubscribeToken { - t.Fatalf("unlinked order subscribe_token = %q, want unchanged token %q", gotUnlinkedOrder.SubscribeToken, unlinkedOrder.SubscribeToken) - } -} - -func TestMoveMemberSubscribesToOwnerNoSubscribesIsNoop(t *testing.T) { - db := newFamilyBindingTestDB(t) - - var moved []modelUser.Subscribe - if err := db.Transaction(func(tx *gorm.DB) error { - var err error - moved, err = moveMemberSubscribesToOwner(tx, 1001, 2001) - return err - }); err != nil { - t.Fatalf("move empty member subscribes: %v", err) - } - if len(moved) != 0 { - t.Fatalf("moved subscribes length = %d, want 0", len(moved)) - } -} - -func TestTransferMemberSubscribesToOwnerStillDiscardsMemberSubscribes(t *testing.T) { - db := newFamilyBindingTestDB(t) - memberUserID := int64(1001) - ownerUserID := int64(2001) - now := time.Now().Add(-time.Hour) - - order := modelOrder.Order{ - Id: 9001, - UserId: memberUserID, - SubscriptionUserId: memberUserID, - OrderNo: "order-discard", - SubscribeToken: "token-discard", - Status: 5, - SubscribeId: 3001, - CreatedAt: now, - UpdatedAt: now, - } - sub := modelUser.Subscribe{ - Id: 7001, - UserId: memberUserID, - OrderId: order.Id, - SubscribeId: order.SubscribeId, - StartTime: now, - ExpireTime: now.Add(30 * 24 * time.Hour), - Token: "token-discard", - UUID: "uuid-discard", - Status: 1, - CreatedAt: now, - UpdatedAt: now, - } - insertFamilyBindingTestOrder(t, db, order) - insertFamilyBindingTestSubscribe(t, db, sub) - - var removed []modelUser.Subscribe - if err := db.Transaction(func(tx *gorm.DB) error { - var err error - removed, err = transferMemberSubscribesToOwner(tx, memberUserID, ownerUserID) - return err - }); err != nil { - t.Fatalf("discard member subscribes: %v", err) - } - - if len(removed) != 1 { - t.Fatalf("removed subscribes length = %d, want 1", len(removed)) - } - if removed[0].UserId != memberUserID { - t.Fatalf("removed cache copy user_id = %d, want original member %d", removed[0].UserId, memberUserID) - } - - var memberCount int64 - if err := db.Model(&modelUser.Subscribe{}).Where("user_id = ?", memberUserID).Count(&memberCount).Error; err != nil { - t.Fatalf("count member subscribes: %v", err) - } - if memberCount != 0 { - t.Fatalf("member subscribe count = %d, want 0", memberCount) - } - - var ownerCount int64 - if err := db.Model(&modelUser.Subscribe{}).Where("user_id = ?", ownerUserID).Count(&ownerCount).Error; err != nil { - t.Fatalf("count owner subscribes: %v", err) - } - if ownerCount != 0 { - t.Fatalf("owner subscribe count = %d, want 0", ownerCount) - } - - var gotOrder modelOrder.Order - if err := db.First(&gotOrder, "id = ?", order.Id).Error; err != nil { - t.Fatalf("query order: %v", err) - } - if gotOrder.SubscriptionUserId != memberUserID { - t.Fatalf("discard path order subscription_user_id = %d, want unchanged member %d", gotOrder.SubscriptionUserId, memberUserID) - } -} diff --git a/internal/svc/serviceContext.go b/internal/svc/serviceContext.go index bd26660..e1c5aaa 100644 --- a/internal/svc/serviceContext.go +++ b/internal/svc/serviceContext.go @@ -8,6 +8,7 @@ import ( "github.com/perfect-panel/server/internal/model/node" "github.com/perfect-panel/server/internal/model/redemption" "github.com/perfect-panel/server/pkg/device" + "github.com/perfect-panel/server/pkg/storage" "github.com/perfect-panel/server/internal/config" "github.com/perfect-panel/server/internal/model/ads" @@ -44,6 +45,7 @@ type ServiceContext struct { ExchangeRate float64 GeoIP *IPLocation SignatureValidator *signature.Validator + S3Store *storage.S3Store //NodeCache *cache.NodeCacheClient AuthModel auth.Model @@ -143,6 +145,13 @@ func NewServiceContext(c config.Config) *ServiceContext { } srv.IAPAppleTransactionModel = iapapple.NewModel(db, rds) srv.DeviceManager = NewDeviceManager(srv) + if c.S3.Enable { + s3Store, err := storage.NewS3Store(context.Background(), c.S3) + if err != nil { + panic(err.Error()) + } + srv.S3Store = s3Store + } return srv } diff --git a/internal/types/compat_types.go b/internal/types/compat_types.go deleted file mode 100644 index fc6b4e9..0000000 --- a/internal/types/compat_types.go +++ /dev/null @@ -1,69 +0,0 @@ -package types - -// compat_types.go โ€” ๆ‰‹ๅŠจ่กฅๅ……็š„็ฑปๅž‹๏ผŒๅทฒๅŒๆญฅๅˆฐ .api ๅฎšไน‰ -// ไธ‹ๆฌก็”จ goctl ้‡ๆ–ฐ็”Ÿๆˆ types.go ๅŽ๏ผŒไปฅไธ‹็ฑปๅž‹ไผš่‡ชๅŠจๅŒ…ๅซๅœจ types.go ไธญ๏ผŒๅฑŠๆ—ถๅฏไปฅๅˆ ้™คๆœฌๆ–‡ไปถไธญๅฏนๅบ”็š„ๅฎšไน‰๏ผš -// - ContactRequest (ๅทฒๅŠ ๅ…ฅ common.api) -// - GetDownloadLinkRequest / GetDownloadLinkResponse (ๅทฒๅŠ ๅ…ฅ common.api) -// - EmailLoginRequest (ๅทฒๆ›ดๆ–ฐ auth.api, ๅŠ ๅ…ฅ form tag) -// - ReportLogMessageRequest / ReportLogMessageResponse (ๅทฒๅŠ ๅ…ฅ common.api, ่ทฏ็”ฑ POST /v1/common/log/report) -// - LegacyCheckVerificationCodeRequest / LegacyCheckVerificationCodeResponse (ๅทฒๅŠ ๅ…ฅ common.api, ่ทฏ็”ฑ POST /v1/common/check_code) - -type ContactRequest struct { - Name string `json:"name" validate:"required,max=100"` - Email string `json:"email" validate:"required,email"` - OtherContact string `json:"other_contact" validate:"max=200"` - Notes string `json:"notes" validate:"max=2000"` -} - -type GetDownloadLinkRequest struct { - InviteCode string `form:"invite_code,optional"` - Platform string `form:"platform" validate:"required,oneof=windows mac ios android"` -} - -type GetDownloadLinkResponse struct { - Url string `json:"url"` -} - -type ReportLogMessageRequest struct { - Platform string `json:"platform" validate:"required,max=32"` - AppVersion string `json:"app_version" validate:"required,max=64"` - OsName string `json:"os_name" validate:"max=64"` - OsVersion string `json:"os_version" validate:"max=64"` - DeviceId string `json:"device_id" validate:"required,max=255"` - UserId int64 `json:"user_id"` - SessionId string `json:"session_id" validate:"max=255"` - Level uint8 `json:"level"` - ErrorCode string `json:"error_code" validate:"max=128"` - Message string `json:"message" validate:"required,max=65535"` - Stack string `json:"stack" validate:"max=1048576"` - Context interface{} `json:"context"` - OccurredAt int64 `json:"occurred_at"` -} - -type ReportLogMessageResponse struct { - Id int64 `json:"id"` -} - -type LegacyCheckVerificationCodeRequest struct { - Method string `json:"method" form:"method" validate:"omitempty,oneof=email mobile"` - Account string `json:"account" form:"account"` - Email string `json:"email" form:"email"` - Code string `json:"code" form:"code" validate:"required"` - Type uint8 `json:"type" form:"type" validate:"required"` -} - -type LegacyCheckVerificationCodeResponse struct { - Status bool `json:"status"` - Exist bool `json:"exist"` -} - -type EmailLoginRequest struct { - Identifier string `json:"identifier" form:"identifier"` - Email string `json:"email" form:"email" validate:"required,email"` - Code string `json:"code" form:"code" validate:"required"` - Invite string `json:"invite" form:"invite"` - IP string `header:"X-Original-Forwarded-For"` - UserAgent string `header:"User-Agent"` - LoginType string `header:"Login-Type"` - CfToken string `json:"cf_token,optional" form:"cf_token"` -} diff --git a/internal/types/types.go b/internal/types/types.go index a15a87d..0251a24 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -1,8 +1,12 @@ // Code generated by goctl. DO NOT EDIT. -// goctl 1.7.2 +// goctl 1.9.2 package types +type ActivateOrderRequest struct { + OrderNo string `json:"order_no" validate:"required"` +} + type Ads struct { Id int `json:"id"` Title string `json:"title"` @@ -295,6 +299,13 @@ type ConnectionRecords struct { LongestSingleConnection int64 `json:"longest_single_connection"` } +type ContactRequest struct { + Name string `json:"name" validate:"required,max=100"` + Email string `json:"email" validate:"required,email"` + OtherContact string `json:"other_contact" validate:"max=200"` + Notes string `json:"notes" validate:"max=2000"` +} + type Coupon struct { Id int64 `json:"id"` Name string `json:"name"` @@ -549,6 +560,13 @@ type CurrencyConfig struct { CurrencySymbol string `json:"currency_symbol"` } +type DailyTrafficStats struct { + Date string `json:"date"` + Upload int64 `json:"upload"` + Download int64 `json:"download"` + Total int64 `json:"total"` +} + type DeleteAccountRequest struct { Email string `json:"email" validate:"required,email"` Code string `json:"code" validate:"required"` @@ -561,13 +579,6 @@ type DeleteAccountResponse struct { Code int64 `json:"code"` } -type DailyTrafficStats struct { - Date string `json:"date"` - Upload int64 `json:"upload"` - Download int64 `json:"download"` - Total int64 `json:"total"` -} - type DeleteAdsRequest struct { Id int64 `json:"id"` } @@ -689,8 +700,15 @@ type EmailAuthticateConfig struct { DomainSuffixList string `json:"domain_suffix_list"` } -type ExportGroupResultRequest struct { - HistoryId *int64 `form:"history_id,omitempty"` +type EmailLoginRequest struct { + Identifier string `json:"identifier" form:"identifier"` + Email string `json:"email" form:"email" validate:"required,email"` + Code string `json:"code" form:"code" validate:"required"` + Invite string `json:"invite,optional" form:"invite"` + IP string `header:"X-Original-Forwarded-For"` + UserAgent string `header:"User-Agent"` + LoginType string `header:"Login-Type"` + CfToken string `json:"cf_token,optional" form:"cf_token"` } type ErrorLogMessage struct { @@ -708,6 +726,10 @@ type ErrorLogMessage struct { CreatedAt int64 `json:"created_at"` } +type ExportGroupResultRequest struct { + HistoryId *int64 `form:"history_id,omitempty"` +} + type FamilyDetail struct { Summary FamilySummary `json:"summary"` Members []FamilyMemberItem `json:"members"` @@ -740,6 +762,36 @@ type FamilySummary struct { UpdatedAt int64 `json:"updated_at"` } +type FileUploadCompleteRequest struct { + FileId string `json:"file_id" validate:"required"` +} + +type FileUploadCompleteResponse struct { + FileId string `json:"file_id"` + ObjectKey string `json:"object_key"` + Size int64 `json:"size"` + ContentType string `json:"content_type"` + Etag string `json:"etag"` + Status string `json:"status"` +} + +type FileUploadInitRequest struct { + BizType string `json:"biz_type" validate:"required"` + FileName string `json:"file_name" validate:"required"` + ContentType string `json:"content_type" validate:"required"` + Size int64 `json:"size" validate:"required"` + Sha256 string `json:"sha256"` +} + +type FileUploadInitResponse struct { + FileId string `json:"file_id"` + ObjectKey string `json:"object_key"` + UploadURL string `json:"upload_url"` + Method string `json:"method"` + Headers map[string]string `json:"headers"` + ExpiredAt int64 `json:"expired_at"` +} + type FilterBalanceLogRequest struct { FilterLogParams UserId int64 `form:"user_id,optional"` @@ -1048,6 +1100,15 @@ type GetDocumentListResponse struct { List []Document `json:"list"` } +type GetDownloadLinkRequest struct { + InviteCode string `form:"invite_code,optional"` + Platform string `form:"platform" validate:"required,oneof=windows mac ios android"` +} + +type GetDownloadLinkResponse struct { + Url string `json:"url"` +} + type GetErrorLogMessageDetailResponse struct { Id int64 `json:"id"` Platform string `json:"platform"` @@ -1118,18 +1179,6 @@ type GetGlobalConfigResponse struct { WebAd bool `json:"web_ad"` } -type GetInviteSalesRequest struct { - Page int `form:"page"` - Size int `form:"size"` - StartTime int64 `form:"start_time"` - EndTime int64 `form:"end_time"` -} - -type GetInviteSalesResponse struct { - Total int64 `json:"total"` - List []InvitedUserSale `json:"list"` -} - type GetGroupConfigRequest struct { Keys []string `form:"keys,omitempty"` } @@ -1161,6 +1210,18 @@ type GetGroupHistoryResponse struct { List []GroupHistory `json:"list"` } +type GetInviteSalesRequest struct { + Page int `form:"page"` + Size int `form:"size"` + StartTime int64 `form:"start_time"` + EndTime int64 `form:"end_time"` +} + +type GetInviteSalesResponse struct { + Total int64 `json:"total"` + List []InvitedUserSale `json:"list"` +} + type GetLoginLogRequest struct { Page int `form:"page"` Size int `form:"size"` @@ -1419,7 +1480,7 @@ type GetUserListRequest struct { FamilyStatus string `form:"family_status,omitempty"` FamilyOwnerUserId *int64 `form:"family_owner_user_id,omitempty"` FamilyId *int64 `form:"family_id,omitempty"` - SortOrder string `form:"sort_order,omitempty"` // asc or desc, default desc + SortOrder string `form:"sort_order,omitempty"` } type GetUserListResponse struct { @@ -1601,6 +1662,19 @@ type KickOfflineRequest struct { Id int64 `json:"id"` } +type LegacyCheckVerificationCodeRequest struct { + Method string `json:"method" form:"method" validate:"omitempty,oneof=email mobile"` + Account string `json:"account" form:"account"` + Email string `json:"email" form:"email"` + Code string `json:"code" form:"code" validate:"required"` + Type uint8 `json:"type" form:"type" validate:"required"` +} + +type LegacyCheckVerificationCodeResponse struct { + Status bool `json:"status"` + Exist bool `json:"exist"` +} + type LogResponse struct { List interface{} `json:"list"` } @@ -1765,8 +1839,8 @@ type Order struct { TradeNo string `json:"trade_no"` Status uint8 `json:"status"` SubscribeId int64 `json:"subscribe_id"` - CreatedAt int64 `json:"created_at"` // Unix milliseconds - UpdatedAt int64 `json:"updated_at"` // Unix milliseconds + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` } type OrderDetail struct { @@ -1789,8 +1863,8 @@ type OrderDetail struct { Status uint8 `json:"status"` SubscribeId int64 `json:"subscribe_id"` Subscribe Subscribe `json:"subscribe"` - CreatedAt int64 `json:"created_at"` // Unix milliseconds - UpdatedAt int64 `json:"updated_at"` // Unix milliseconds + CreatedAt int64 `json:"created_at"` + UpdatedAt int64 `json:"updated_at"` } type OrdersStatistics struct { @@ -2246,6 +2320,10 @@ type RecoverOrderResponse struct { Message string `json:"message"` } +type RecoverySendCodeRequest struct { + Email string `json:"email" validate:"required,email"` +} + type RedeemCodeRequest struct { Code string `json:"code" validate:"required"` } @@ -2319,6 +2397,26 @@ type RenewalOrderResponse struct { AppAccountToken string `json:"app_account_token"` } +type ReportLogMessageRequest struct { + Platform string `json:"platform" validate:"required,max=32"` + AppVersion string `json:"app_version" validate:"required,max=64"` + OsName string `json:"os_name" validate:"max=64"` + OsVersion string `json:"os_version" validate:"max=64"` + DeviceId string `json:"device_id" validate:"required,max=255"` + UserId int64 `json:"user_id"` + SessionId string `json:"session_id" validate:"max=255"` + Level uint8 `json:"level"` + ErrorCode string `json:"error_code" validate:"max=128"` + Message string `json:"message" validate:"required,max=65535"` + Stack string `json:"stack" validate:"max=1048576"` + Context interface{} `json:"context"` + OccurredAt int64 `json:"occurred_at"` +} + +type ReportLogMessageResponse struct { + Id int64 `json:"id"` +} + type ResetAllSubscribeTokenResponse struct { Success bool `json:"success"` } @@ -2370,10 +2468,6 @@ type ResetTrafficOrderResponse struct { OrderNo string `json:"order_no"` } -type RecoverySendCodeRequest struct { - Email string `json:"email" validate:"required,email"` -} - type ResetUserSubscribeTokenRequest struct { UserSubscribeId int64 `json:"user_subscribe_id"` } @@ -3000,10 +3094,6 @@ type UpdateOrderStatusRequest struct { TradeNo string `json:"trade_no,omitempty"` } -type ActivateOrderRequest struct { - OrderNo string `json:"order_no" validate:"required"` -} - type UpdatePaymentMethodRequest struct { Id int64 `json:"id" validate:"required"` Name string `json:"name" validate:"required"` diff --git a/log.txt b/log.txt deleted file mode 100644 index 208636e..0000000 --- a/log.txt +++ /dev/null @@ -1,169 +0,0 @@ -่ทณ่‡ณไธป่ฆๅ†…ๅฎน - -Grafana -ๆŽข็ดข -Loki -ๆœ็ดข... -โŒ˜+k - - -User avatar -ๆŽข็ดข - -่ฝฎๅป“ -Loki logo -Loki - -่ฝฌๅˆฐๆ— ๆŸฅ่ฏข - -ๆ‹†ๅˆ† - -ๆทปๅŠ  - - -่ฟ‡ๅŽป 24 ๅฐๆ—ถ - - - -่ฟ่กŒๆŸฅ่ฏข - - -ๅˆ†ไบซ - - -็›ดๆ’ญ - - - - - -A -(Loki) - - - - - -Kick start your query - -Label browser -Explain query - - - -{container="ppanel-server"} |= "10013" |= "user_subscribe" - -Options -Type: Range -Line limit: 1000 -Direction: Backward -This query will process approximately 20.3 GiB. - - -ๆทปๅŠ ๆŸฅ่ฏข - -ๆŸฅ่ฏขๅކๅฒ่ฎฐๅฝ• - -ๆŸฅ่ฏขๆฃ€ๆŸฅๅ™จ - -ๆ—ฅๅฟ—ๅท -info -Total: 717 -Loki -ๆ—ฅๅฟ— - - -717 lines displayed -ๅทฒๅค„็†็š„ๆ€ปๅญ—่Š‚ๆ•ฐ: -23.4 GB -Common labels: -container=ppanel-server -logstream=stdout -service_name=ppanel-server -ๅทฒๅฑ•ๅผ€ - -ๆปšๅŠจๅˆฐๅบ•้ƒจ - -ๆœ€ๆ–ฐๆ—ฅๅฟ—ๅœจๅ‰ - -ๆœ็ดขๆ—ฅๅฟ— - -ๅŽป้‡ - -็ญ›้€‰็บงๅˆซ - -ๆ˜พ็คบๆฏซ็ง’ -ms -ๆข่กŒๆ˜พ็คบ JSON -+ -Columns not supported - -็ชๅ‡บๆ˜พ็คบๆ–‡ๆœฌ - -ๅคงๅญ—ไฝ“ - -ไธ‹่ฝฝๆ—ฅๅฟ— - -ๆปšๅŠจๅˆฐ้กถ้ƒจ - - -2026-04-30 08:33:29.296 info 303029-04-04 00:00:00.296 debug [GORM] SQL Executed duration=0.5ms caller=user/queryUserSubscribeLogic.go:47 sql=SELECT `user_subscribe`.`id`,`user_subscribe`.`user_id`,`user_subscribe`.`order_id`,`user_subscribe`.`subscribe_id`,`user_subscribe`.`node_group_id`,`user_subscribe`.`start_time`,`user_subscribe`.`expire_time`,`user_subscribe`.`finished_at`,`user_subscribe`.`traffic`,`user_subscribe`.`download`,`user_subscribe`.`upload`,`user_subscribe`.`token`,`user_subscribe`.`uuid`,`user_subscribe`.`status`,`user_subscribe`.`note`,`user_subscribe`.`created_at`,`user_subscribe`.`updated_at` FROM `user_subscribe` WHERE `user_id` = 19764 AND `status` IN (0,1,2,3) AND (`expire_time` > '2026-04-30 23:33:29.295' OR `finished_at` >= '2026-04-23 23:33:29.295' OR `expire_time` = '1970-01-01 08:00:00') trace=428ceb5c1001366ab0dfddaa0fd0cf8a rows=1 span=a0c44ec4143a6a77 - -2026-04-30 06:38:24.260 info 303024-04-04 00:00:00.260 debug [GORM] SQL Executed duration=0.2ms caller=group/recalculateGroupLogic.go:58 sql=UPDATE `user_subscribe` SET `node_group_id`=0,`updated_at`='2026-04-30 21:38:24.26' WHERE id = 10013 rows=1 - -2026-04-30 06:38:24.259 info 303024-04-04 00:00:00.259 debug assigning user_subscribe_id=10013 (subscribe_id=1) to node_group_id=0 (total_options=0, selected_first) caller=group/recalculateGroupLogic.go:504 - -2026-04-30 06:38:24.121 info 303024-04-04 00:00:00.121 info [SubscriptionFlow] renewal order updated existing subscription caller=common/subscriptionTrace.go:28 effective_user_id=20003 payment_id=2 expire_time=2026-05-30 21:38:24.118494775 +0800 CST user_id=20003 quantity=30 flow=order_subscription stage=subscription_renewed order_no=202604302137198938303097982 is_new_order=false user_subscribe_id=10013 subscribe_order_id=17216 subscribe_uuid_tail=936f5490 payment_method=EPay subscribe_token_tail=3cb4c6b3 user_subscribe_plan_id=1 subscribe_status=1 iap_expire_at=0 trace_type=subscription_flow parent_order_id=7448 order_type=2 order_status=4 order_subscribe_id=1 app_account_token_tail=e04447ca order_id=17216 subscription_user_id=20003 subscribe_owner_user_id=20003 - -2026-04-30 06:38:24.120 info 303024-04-04 00:00:00.120 debug [GORM] SQL Executed duration=1.7ms caller=user/subscribe.go:17 sql=UPDATE `user_subscribe` SET `id`=10013,`user_id`=20003,`order_id`=17216,`subscribe_id`=1,`node_group_id`=0,`group_locked`=false,`start_time`='2026-04-23 19:06:40.003',`expire_time`='2026-05-30 21:38:24.118',`finished_at`=NULL,`traffic`=0,`download`=0,`upload`=0,`expired_download`=0,`expired_upload`=0,`token`='e622c7a270caf7fd816f9dd83cb4c6b3',`uuid`='aabd8eb1-2569-4a69-b59c-15cd936f5490',`status`=1,`note`='',`updated_at`='2026-04-30 21:38:24.119' WHERE id = 10013 rows=1 - -2026-04-30 06:38:24.118 info 303024-04-04 00:00:00.118 debug [GORM] SQL Executed duration=0.2ms caller=user/subscribe.go:161 sql=SELECT * FROM `user_subscribe` WHERE id = 10013 ORDER BY `user_subscribe`.`id` LIMIT 1 rows=1 - -2026-04-30 06:37:25.952 info 303025-04-04 00:00:00.952 debug [GORM] SQL Executed duration=0.1ms caller=group/recalculateGroupLogic.go:58 sql=UPDATE `user_subscribe` SET `node_group_id`=0,`updated_at`='2026-04-30 21:37:25.952' WHERE id = 10013 rows=1 - -2026-04-30 06:37:19.898 info 303019-04-04 00:00:00.898 info HTTP Request duration=6.088471ms caller=middleware/loggerMiddleware.go:113 decrypted_request_body={"coupon":"","payment":2,"quantity":30,"user_subscribe_id":10013} response_body={"code":200,"data":{"data":"SxIHPdGQQbeAwx5UYMaRaouIke61GH+VRSl/iSr63r/GVLuXfd+ljlQLmukw9UE/Fdjc5oSWDq5ApVyEBR4bF79eBcuDz+cYjjmnJIn1sXt8hIPlwKlhc50TFwe8/x2RlpsHsLUYaOYOivMv/iuH/A==","time":"18ab25fb776f18b9"},"msg":"success"} ip=112.96.81.74 trace=60ff721319b3cf1b8f328dc05f01cb99 status=200 request=POST api.hifast.biz/v1/public/order/renewal query= user-agent=HiFast/1.0.6-26042218 (Android; HUAWEI PLA-AL10; 12) Flutter device_decrypt_status=success api_header= request_body={"data":"xdcFznl62TSP5AiItT+OKZWELzq3mR+cUZ2COAZ7ERslZT+M8mmEI65BfwevDWXA6l9TjMLr5sRkR4+omRV3fbH+PkLJ7kvIf9WPQ9ASaNg=","time":"2026-04-30T21:37:19.943917"} span=99fda96ceb7ba495 - -2026-04-30 06:37:19.898 info 303019-04-04 00:00:00.898 info [SubscriptionFlow] renewal order persisted caller=common/subscriptionTrace.go:28 trace_type=subscription_flow order_no=202604302137198938303097982 user_id=20003 payment_id=2 parent_order_id=7448 quantity=30 app_account_token_tail=e04447ca resolved_user_subscribe_id=10013 stage=order_created order_id=17216 order_type=2 order_status=1 subscription_user_id=20003 trace=60ff721319b3cf1b8f328dc05f01cb99 span=99fda96ceb7ba495 effective_user_id=20003 order_subscribe_id=1 requested_user_subscribe_id=10013 flow=order_subscription payment_method=EPay is_new_order=false subscribe_token_tail=3cb4c6b3 - -2026-04-30 06:37:19.894 info 303019-04-04 00:00:00.894 debug [GORM] SQL Executed duration=0.5ms caller=order/renewalLogic.go:81 rows=1 span=99fda96ceb7ba495 sql=SELECT `user_subscribe`.`id`,`user_subscribe`.`user_id`,`user_subscribe`.`order_id`,`user_subscribe`.`subscribe_id`,`user_subscribe`.`node_group_id`,`user_subscribe`.`start_time`,`user_subscribe`.`expire_time`,`user_subscribe`.`finished_at`,`user_subscribe`.`traffic`,`user_subscribe`.`download`,`user_subscribe`.`upload`,`user_subscribe`.`token`,`user_subscribe`.`uuid`,`user_subscribe`.`status`,`user_subscribe`.`note`,`user_subscribe`.`created_at`,`user_subscribe`.`updated_at` FROM `user_subscribe` WHERE id = 10013 ORDER BY `user_subscribe`.`id` LIMIT 1 trace=60ff721319b3cf1b8f328dc05f01cb99 - -2026-04-30 06:37:19.893 info 303019-04-04 00:00:00.893 info [SubscriptionFlow] renewal order creation started caller=common/subscriptionTrace.go:28 effective_user_id=20003 quantity=30 trace=60ff721319b3cf1b8f328dc05f01cb99 trace_type=subscription_flow flow=order_subscription stage=order_create_start order_kind=renewal user_id=20003 span=99fda96ceb7ba495 requested_user_subscribe_id=10013 payment_id=2 coupon= - -2026-04-30 06:36:05.808 info 30305-04-04 00:00:00.808 info HTTP Request duration=7.877334ms caller=middleware/loggerMiddleware.go:113 query= device_decrypt_status=success response_body={"code":200,"data":{"data":"ELE22mv7foWM+iFzrylO+xbiTWWO7gH9qclIxJzT8TRqS1fJN32GiWq/gtNlGpVWwX4iZoNjI0uOA/5lV4YltAfw3bL7sz+CcARgVEZ4NGFRqOt7bVm1RssagYLopQdfoueQ0Z+j7zOFkBlzNW+r3Q==","time":"18ab25ea37520766"},"msg":"success"} user-agent=HiFast/1.0.6-26042218 (Android; HUAWEI PLA-AL10; 12) Flutter request_body={"data":"a4U8LH1zN4LFF+aBBLoUHzEZoxJ4C6EL1nlDNeKb4m2Xwi8H1hk05qxbkvj3xz6kKdecrhF2G0G6rAavhNlKDDZhaHH/J5elqjw6tsQGluk=","time":"2026-04-30T21:36:05.852132"} request=POST api.hifast.biz/v1/public/order/renewal ip=112.96.81.74 decrypted_request_body={"coupon":"","payment":2,"quantity":30,"user_subscribe_id":10013} trace=7e1b88eed63e7ffba4a6e6e2482d399d status=200 api_header= span=d6bd668124fcad80 - -2026-04-30 06:36:05.808 info 30305-04-04 00:00:00.808 info [SubscriptionFlow] renewal order persisted caller=common/subscriptionTrace.go:28 app_account_token_tail=237eb1b5 span=d6bd668124fcad80 flow=order_subscription order_id=17213 order_subscribe_id=1 parent_order_id=7448 requested_user_subscribe_id=10013 trace=7e1b88eed63e7ffba4a6e6e2482d399d user_id=20003 payment_id=2 payment_method=EPay resolved_user_subscribe_id=10013 stage=order_created order_no=202604302136058021461564356 order_status=1 quantity=30 is_new_order=false trace_type=subscription_flow order_type=2 subscription_user_id=20003 effective_user_id=20003 subscribe_token_tail=3cb4c6b3 - -2026-04-30 06:36:05.802 info 30305-04-04 00:00:00.802 debug [GORM] SQL Executed duration=0.7ms caller=order/renewalLogic.go:81 sql=SELECT `user_subscribe`.`id`,`user_subscribe`.`user_id`,`user_subscribe`.`order_id`,`user_subscribe`.`subscribe_id`,`user_subscribe`.`node_group_id`,`user_subscribe`.`start_time`,`user_subscribe`.`expire_time`,`user_subscribe`.`finished_at`,`user_subscribe`.`traffic`,`user_subscribe`.`download`,`user_subscribe`.`upload`,`user_subscribe`.`token`,`user_subscribe`.`uuid`,`user_subscribe`.`status`,`user_subscribe`.`note`,`user_subscribe`.`created_at`,`user_subscribe`.`updated_at` FROM `user_subscribe` WHERE id = 10013 ORDER BY `user_subscribe`.`id` LIMIT 1 rows=1 trace=7e1b88eed63e7ffba4a6e6e2482d399d span=d6bd668124fcad80 - -2026-04-30 06:36:05.802 info 30305-04-04 00:00:00.802 info [SubscriptionFlow] renewal order creation started caller=common/subscriptionTrace.go:28 flow=order_subscription requested_user_subscribe_id=10013 payment_id=2 coupon= span=d6bd668124fcad80 trace_type=subscription_flow order_kind=renewal trace=7e1b88eed63e7ffba4a6e6e2482d399d stage=order_create_start user_id=20003 effective_user_id=20003 quantity=30 - -2026-04-30 06:35:46.036 info 303046-04-04 00:00:00.036 debug [GORM] SQL Executed duration=0.1ms caller=group/recalculateGroupLogic.go:58 sql=UPDATE `user_subscribe` SET `node_group_id`=0,`updated_at`='2026-04-30 21:35:46.036' WHERE id = 10013 rows=1 - -2026-04-30 06:35:38.276 info 303038-04-04 00:00:00.276 info HTTP Request duration=7.276753ms caller=middleware/loggerMiddleware.go:113 request=POST api.hifast.biz/v1/public/order/renewal ip=112.96.81.74 user-agent=HiFast/1.0.6-26042218 (Android; HUAWEI PLA-AL10; 12) Flutter device_decrypt_status=success trace=fd8fbb2d663ad7df82f0c25bf7fb6913 span=c6fe83c0a377d5b5 status=200 query= request_body={"data":"6cuaVRmMX/CGHQ+y0jrwjKTUx404hlB7/z+qPYpK9toUHAVMBrhVBC/cnZmzffjaPuqlUrLx9lSOTHDxv3GGqXZxDah5N4AimVY0dFsx6Bc=","time":"2026-04-30T21:35:38.294140"} decrypted_request_body={"coupon":"","payment":2,"quantity":30,"user_subscribe_id":10013} response_body={"code":200,"data":{"data":"iQSMczPB07C+ruU52emoga1TtBShOiBZOtU8jW9XzmQiKe9DjWCxGY+fFTnJ6LrQCXAQqZWwBpQgABpFWpcJ+MbRr5jk4S3ahwXzeHXBiMcGlgAJRb0G3O+K7h7z+6t+uhGNjzCE2CYFMuii+0T3rg==","time":"18ab25e3ce44be91"},"msg":"success"} api_header= - -2026-04-30 06:35:38.276 info 303038-04-04 00:00:00.276 info [SubscriptionFlow] renewal order persisted caller=common/subscriptionTrace.go:28 subscription_user_id=20003 order_subscribe_id=1 effective_user_id=20003 payment_id=2 parent_order_id=7448 subscribe_token_tail=3cb4c6b3 trace=fd8fbb2d663ad7df82f0c25bf7fb6913 span=c6fe83c0a377d5b5 flow=order_subscription payment_method=EPay quantity=30 is_new_order=false app_account_token_tail=6b5d9042 order_no=202604302135382700174133469 requested_user_subscribe_id=10013 resolved_user_subscribe_id=10013 trace_type=subscription_flow stage=order_created order_id=17211 order_type=2 order_status=1 user_id=20003 - -2026-04-30 06:35:38.270 info 303038-04-04 00:00:00.270 debug [GORM] SQL Executed duration=0.5ms caller=order/renewalLogic.go:81 rows=1 trace=fd8fbb2d663ad7df82f0c25bf7fb6913 span=c6fe83c0a377d5b5 sql=SELECT `user_subscribe`.`id`,`user_subscribe`.`user_id`,`user_subscribe`.`order_id`,`user_subscribe`.`subscribe_id`,`user_subscribe`.`node_group_id`,`user_subscribe`.`start_time`,`user_subscribe`.`expire_time`,`user_subscribe`.`finished_at`,`user_subscribe`.`traffic`,`user_subscribe`.`download`,`user_subscribe`.`upload`,`user_subscribe`.`token`,`user_subscribe`.`uuid`,`user_subscribe`.`status`,`user_subscribe`.`note`,`user_subscribe`.`created_at`,`user_subscribe`.`updated_at` FROM `user_subscribe` WHERE id = 10013 ORDER BY `user_subscribe`.`id` LIMIT 1 - -2026-04-30 06:35:38.270 info 303038-04-04 00:00:00.270 info [SubscriptionFlow] renewal order creation started caller=common/subscriptionTrace.go:28 flow=order_subscription effective_user_id=20003 coupon= trace_type=subscription_flow payment_id=2 user_id=20003 quantity=30 trace=fd8fbb2d663ad7df82f0c25bf7fb6913 span=c6fe83c0a377d5b5 stage=order_create_start order_kind=renewal requested_user_subscribe_id=10013 - -ๆŒ‰ๅ็งฐๆœ็ดขๅญ—ๆฎต - -Show log level -0 -ๅญ—ๆฎต - -__stream_shard__ -25% - -container -100% - -level -100% - -logstream -100% - -service_name -100% diff --git a/ops/aws-rds-external-replica-runbook.md b/ops/aws-rds-external-replica-runbook.md index c8fcd84..c1ca82e 100644 --- a/ops/aws-rds-external-replica-runbook.md +++ b/ops/aws-rds-external-replica-runbook.md @@ -1,99 +1,396 @@ -# AWS RDS to External Replica Runbook +# AWS RDS + EC2 Redis ๅˆฐๅค–้ƒจๅค‡็”จๆœๅŠกๅ™จ Runbook -็›ฎๆ ‡๏ผš่ฎฉๅค–้ƒจๆœๅŠกๅ™จ `104.238.220.230` ไธŠ็š„ MySQL/Redis ๅฐฝ้‡ๅฎžๆ—ถๅŒๆญฅ AWS ไพงๆ•ฐๆฎ๏ผŒไฝœไธบๅค‡็”จๆ•ฐๆฎ่Š‚็‚นใ€‚ +็›ฎๆ ‡๏ผš่ฎฉ `104.238.220.230` ๆŒ็ปญไฝœไธบ AWS ไธป็”Ÿไบง็Žฏๅขƒ็š„ๅผ‚ๅœฐๅค‡็”จ่Š‚็‚น๏ผŒๆ‰ฟๆŽฅ๏ผš -## ๅทฒ็Ÿฅ่ต„ๆบ +- MySQL ๅค–้ƒจๅช่ฏปไปŽๅบ“ +- Redis ๅค–้ƒจไปŽๅบ“ +- ๆ•…้šœๆ—ถ็š„ๅฟซ้€Ÿๆๅ‡ไธŽไธšๅŠกๅˆ‡ๆข -- AWS region: `ap-east-1` -- RDS endpoint: `hifast-mysql-prod.cd6aey40m6ag.ap-east-1.rds.amazonaws.com` -- RDS username: `admin` -- RDS password: `VIbW2nNoh0LXq2!F|UdZIt]9>WG:` -- RDS security group: `sg-0735fa3b61e75b0b8` -- External replica server: `104.238.220.230` -- External OS: Ubuntu 24.04 LTS -- External MySQL: 8.0.45 -- External Redis: 7.0.15 +ๆœฌๆ–‡ๆกฃไปฅ `2026-05-13` ็š„็œŸๅฎž็Žฐ็ฝ‘็Šถๆ€ไธบๅ‡†๏ผŒ่ฆ†็›–๏ผš -## AWS Console ๅฟ…้กปๅฎŒๆˆ +- ๅฝ“ๅ‰ๅทฒ็ป่ฝๅœฐ็š„ไธปไปŽๆžถๆž„ +- ๆ—ฅๅธธ้ชŒๆ”ถๅ‘ฝไปค +- ไธปไปŽๆ•…้šœๆŽ’ๆŸฅ +- ๅ…จ้‡้‡ๅปบไปŽๅบ“ +- โ€œๆ–ฐๅปบ่ง„่Œƒ RDS ๅ†ๅˆ‡ๆขโ€็š„็”Ÿไบง็บงๆ”ถๆ•›่ทฏ็บฟ +- ๆ•…้šœๅˆ‡ๆขไธŽๅ›žๆปš -1. RDS `hifast-mysql-prod` ไฟฎๆ”นไธบ `Publicly accessible = Yes`ใ€‚ -2. RDS security group `sg-0735fa3b61e75b0b8` ๅ…ฅ็ซ™ๆ–ฐๅขž๏ผš - - Type: `MySQL/Aurora` - - Protocol: `TCP` - - Port: `3306` - - Source: `104.238.220.230/32` - - Description: `external mysql replica` +## 1. ๅฝ“ๅ‰ๅทฒ็กฎ่ฎค่ต„ๆบ -ไธ่ฆๅผ€ๆ”พ `0.0.0.0/0` ๅˆฐ RDS 3306ใ€‚ +### 1.1 AWS ไธป็”Ÿไบง -## RDS ไธŠๆ‰ง่กŒ SQL +- Region: `ap-east-1` +- AWS app EC2: + - Name: `hifast-hk-app-01` + - Public IP: `43.198.248.161` + - Private IP: `10.0.1.201` +- AWS MySQL: + - Type: `RDS MySQL` + - Instance: `hifast-mysql-prod-v2` + - Endpoint: `hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com` + - Version: `8.4.8` + - DB Name: `hifast` + - Admin user: `admin` + - Admin password: keep it in a secret store, do not write plaintext into repo docs + - Replication user: `repl` + - Replication password: keep it in a secret store, do not write plaintext into repo docs +- AWS Redis: + - Location: `hifast-hk-app-01` + - Deployment: `Docker` + - Container: `hifast-redis` + - Version: `redis:8.2.1` + - Listen: `0.0.0.0:6379` + - Password: keep it in a secret store, do not write plaintext into repo docs -ๅ…ˆ่ฟžๆŽฅ๏ผš +### 1.2 ๅค–้ƒจๅค‡็”จๆœๅŠกๅ™จ + +- Host: `104.238.220.230` +- OS: `Ubuntu 24.04 LTS` +- SSH user: `root` +- MySQL version: `8.4.9` +- Redis version: `8.6.3` +- ๅฝ“ๅ‰่ง’่‰ฒ๏ผš + - MySQL external replica + - Redis replica + - ๅค‡็”จๅบ”็”จ่Š‚็‚น + +### 1.3 ๅฝ“ๅ‰ๅบ”็”จ็œŸๅฎž่ฟ่กŒๆ–นๅผ + +AWS ๅบ”็”จๆœบไธŠ็š„ `ppanel-server` ๅฝ“ๅ‰ไธๆ˜ฏ systemd ๆ‰˜็ฎก๏ผŒ่€Œๆ˜ฏ Docker Compose ๆœๅŠก๏ผš + +- Compose file: `/opt/ppanel/docker-compose.cloud.yml` +- Config file: `/opt/ppanel/configs/ppanel.yaml` +- Container name: `ppanel-server` +- Current MySQL target: `hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com:3306` +- Current Redis target: `127.0.0.1:6379` + +ไนŸๅฐฑๆ˜ฏ่ฏด๏ผŒๅŽ็ปญๆ‰€ๆœ‰ๅบ”็”จไพงๅˆ‡ๆขๆญฅ้ชค๏ผŒ้ƒฝๅบ”่ฏฅไปฅไฟฎๆ”น๏ผš + +- `/opt/ppanel/configs/ppanel.yaml` + +ๅนถๆ‰ง่กŒ๏ผš ```bash -mysql -h hifast-mysql-prod.cd6aey40m6ag.ap-east-1.rds.amazonaws.com -u admin -p +cd /opt/ppanel +docker compose -f docker-compose.cloud.yml up -d ppanel-server ``` -็„ถๅŽๆ‰ง่กŒ๏ผš +ไฝœไธบๅ‡†ใ€‚ + +## 2. ๅฝ“ๅ‰ๅฅๅบทๅŸบ็บฟ + +ๆˆช่‡ณ `2026-05-13`๏ผŒๅทฒ็กฎ่ฎคไปฅไธ‹็Šถๆ€ๆˆ็ซ‹๏ผš + +- `104` MySQL: + - `Source_Host = hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com` + - `Replica_IO_Running: Yes` + - `Replica_SQL_Running: Yes` + - `Seconds_Behind_Source: 0` + - `read_only = ON` + - `super_read_only = ON` +- AWS Redis ไธปๅบ“: + - `role:master` + - `connected_slaves:1` +- `104` Redis: + - `role:slave` + - `master_link_status:up` +- AWS ๅบ”็”จ: + - `curl http://127.0.0.1:8080/v1/common/heartbeat` ่ฟ”ๅ›ž `code=200` + +่ฟ™่ฏดๆ˜Žๅฝ“ๅ‰็Šถๆ€ๅทฒ็ป่พพๅˆฐ๏ผš + +- ไธป็”Ÿไบงๅฏ็”จ +- ๅค–้ƒจๅค‡็”จๆŒ็ปญๅŒๆญฅ +- Redis ๅทฒๅ›žๅˆฐ็œŸๅฎžๆœฌๆœบ้“พ่ทฏ + +## 3. ๅฝ“ๅ‰็ฝ‘็ปœๅ‰ๆ + +### 3.1 ๅฎ‰ๅ…จ็ป„ + +ๅฝ“ๅ‰ๅฎž้™…็”Ÿๆ•ˆ็š„ๅฎ‰ๅ…จ็ป„ๅฆ‚ไธ‹๏ผš + +- `hifast-hk-app-core-sg` + - `22/tcp <- 0.0.0.0/0` + - `6379/tcp <- 104.238.220.230/32` + - `8080/tcp <- hifast-hk-web-sg` +- `hifast-hk-rds-core-sg` + - `3306/tcp <- 104.238.220.230/32` + - `3306/tcp <- hifast-hk-app-core-sg` +- `hifast-hk-web-sg` + - `22/80/443 <- 0.0.0.0/0` + +### 3.2 ๅฝ“ๅ‰็ป“ๆž„ๆ€ง้™ๅˆถ + +ๅฝ“ๅ‰ `104 -> RDS` ๅ…ฌ็ฝ‘ๅคๅˆถ้“พ่ทฏ่™ฝ็„ถๅฏ็”จ๏ผŒไฝ†ไพ่ต–็š„ๆ˜ฏ๏ผš + +- `hifast-mysql-prod-v2` ไธบ `Publicly accessible = Yes` +- RDS ENI ไปไฝไบŽ `hifast-hk-private-1b` +- `private-1b` ่ขซไธดๆ—ถๆŒ‚ๅˆฐไบ†ๅ…ฌ็ฝ‘่ทฏ็”ฑ่กจ + +่ฟ™ไธๆ˜ฏๆœ€็ปˆ่ง„่Œƒ็š„็”Ÿไบงๅฝขๆ€ใ€‚ + +ๅฝ“ๅ‰่ฟ™ๆก่ทฏ็บฟๅทฒ็ปๅฎŒๆˆ๏ผŒๅŽ็ปญๆ›ดๆŽจ่็š„ๅŠจไฝœๆ˜ฏ๏ผš + +1. ๆŒ็ปญ็กฎ่ฎคๅบ”็”จไธปๅบ“็›ฎๆ ‡ไฟๆŒๅœจ `hifast-mysql-prod-v2` +2. ๆŒ็ปญ็กฎ่ฎค `104` ๅคๅˆถ็›ฎๆ ‡ไฟๆŒๅœจ `hifast-mysql-prod-v2` +3. ๆ นๆฎๅ›žๆ”ถ็ช—ๅฃๅฎ‰ๆŽ’ๆ—ง RDS ไธ‹็บฟ +4. ๆŒ‰็ฝ‘็ปœๆ”ถๆ•›่ฎกๅˆ’ๅค„็† `private-1b` ่ทฏ็”ฑ่ฏญไน‰ + +## 4. ๆ—ฅๅธธ้ชŒๆ”ถๅ‘ฝไปค + +### 4.1 ้ชŒๆ”ถ MySQL ไธปไปŽ + +ๅœจ `104` ๆ‰ง่กŒ๏ผš + +```bash +mysql -e "SHOW REPLICA STATUS\G" +``` + +้‡็‚น็œ‹๏ผš + +- `Source_Host` +- `Replica_IO_Running` +- `Replica_SQL_Running` +- `Seconds_Behind_Source` +- `Last_IO_Error` +- `Last_SQL_Error` + +ๆˆๅŠŸๆ ‡ๅ‡†๏ผš + +- `Replica_IO_Running: Yes` +- `Replica_SQL_Running: Yes` +- `Seconds_Behind_Source: 0` ๆˆ–่พƒๅฐ + +### 4.2 ้ชŒๆ”ถ Redis ไธปไปŽ + +ๅœจ AWS app EC2 ๆ‰ง่กŒ๏ผš + +```bash +docker exec hifast-redis redis-cli -a '0BVz9XOHf7KUfEuoFJRK-dURdKUGFiZ8QeaHpysHnKeKhLskZb55HPK121lFsKtr' INFO replication +``` + +้‡็‚น็œ‹๏ผš + +- `role:master` +- `connected_slaves:1` + +ๅœจ `104` ๆ‰ง่กŒ๏ผš + +```bash +redis-cli INFO replication +``` + +้‡็‚น็œ‹๏ผš + +- `role:slave` +- `master_host:43.198.248.161` +- `master_port:6379` +- `master_link_status:up` + +### 4.3 ้ชŒๆ”ถๅบ”็”จ + +ๅœจ AWS app EC2 ๆ‰ง่กŒ๏ผš + +```bash +curl -sf http://127.0.0.1:8080/v1/common/heartbeat +``` + +ๆœŸๆœ›่ฟ”ๅ›ž๏ผš + +- `{"code":200,...}` + +ๆŸฅ็œ‹ๅฎนๅ™จ๏ผš + +```bash +cd /opt/ppanel +docker compose -f docker-compose.cloud.yml ps +``` + +ๆœŸๆœ›๏ผš + +- `ppanel-server` ไธบ `Up` +- `hifast-redis` ไธบ `Up` + +## 5. MySQL ๅคๅˆถๆ•…้šœๆŽ’ๆŸฅ + +### 5.1 ๅ…ˆ็œ‹ๅคๅˆถ็Šถๆ€ + +```bash +mysql -e "SHOW REPLICA STATUS\G" +``` + +้‡็‚นๅˆคๆ–ญ๏ผš + +- `Replica_IO_Running = No` +- `Replica_SQL_Running = No` +- `Last_IO_Error` +- `Last_SQL_Error` + +### 5.2 ๅธธ่งๅœบๆ™ฏ + +#### ๅœบๆ™ฏ A๏ผš็ฝ‘็ปœๆˆ–็™ฝๅๅ•ๆ–ญๅผ€ + +่กจ็Žฐ๏ผš + +- `Replica_IO_Running: No` +- `Last_IO_Error` ๅ‡บ็Žฐ่ฟžๆŽฅๅคฑ่ดฅใ€่ถ…ๆ—ถใ€ๆ‹’็ป่ฎฟ้—ฎ + +ๆŽ’ๆŸฅ๏ผš + +```bash +mysql -h hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com -u repl -p -e "SELECT 1;" +``` + +ๅค„็†๏ผš + +- ๆฃ€ๆŸฅ RDS SG ๆ˜ฏๅฆไปไฟ็•™ `104.238.220.230/32 -> 3306` +- ๆฃ€ๆŸฅ RDS ๆ˜ฏๅฆไปไธบ `Publicly accessible = Yes` +- ๅฆ‚ๆžœๅŽ็ปญๅทฒ่ฟๅˆฐๆ–ฐ่ง„่Œƒ RDS๏ผŒๅˆ™ๆฃ€ๆŸฅๆ–ฐๅฎžไพ‹็š„ SG ๅ’Œๅ…ฌ็ฝ‘ๅฏ่พพๆ€ง + +#### ๅœบๆ™ฏ B๏ผšไธปๅบ“ binlog ไฝ็‚นไธขๅคฑ + +่กจ็Žฐ๏ผš + +- `Last_IO_Error` ๆˆ– `Last_SQL_Error` ๆŒ‡ๅ‘็ผบๅคฑ binlog + +ๅค„็†๏ผš + +- ไธ่ฆ็กฌ่ทณ่ฟ‡ +- ็›ดๆŽฅๆ‰ง่กŒๅ…จ้‡้‡ๅปบไปŽๅบ“ + +#### ๅœบๆ™ฏ C๏ผšSQL ๆ‰ง่กŒๆŠฅ้”™ + +่กจ็Žฐ๏ผš + +- `Replica_SQL_Running: No` +- `Last_SQL_Error` ๆœ‰ๅฎž้™… SQL ๅ†ฒ็ชไฟกๆฏ + +ๅค„็†ๅปบ่ฎฎ๏ผš + +- ๅฆ‚ๆžœๅชๆ˜ฏไธดๆ—ถๆผ”็ปƒ็Žฏๅขƒ๏ผŒๅฏ้‡ๅปบไปŽๅบ“ +- ๅฆ‚ๆžœๅทฒ็ป่ฟ›ๅ…ฅ็”Ÿไบงๅˆ‡ๆข้˜ถๆฎต๏ผŒไธๅปบ่ฎฎ็›ฒ็›ฎ `sql_slave_skip_counter` +- ไผ˜ๅ…ˆไฟๅฎˆๅšๆณ•ไปๆ˜ฏ้‡ๆ–ฐๅ…จ้‡ๅˆๅง‹ๅŒ– + +## 6. Redis ๅคๅˆถๆ•…้šœๆŽ’ๆŸฅ + +### 6.1 ็œ‹ `104` ไปŽๅบ“็Šถๆ€ + +```bash +redis-cli INFO replication +``` + +้‡็‚น๏ผš + +- `role` +- `master_host` +- `master_link_status` + +### 6.2 ็œ‹ AWS ไธปๅบ“็Šถๆ€ + +```bash +docker exec hifast-redis redis-cli -a '0BVz9XOHf7KUfEuoFJRK-dURdKUGFiZ8QeaHpysHnKeKhLskZb55HPK121lFsKtr' INFO replication +``` + +้‡็‚น๏ผš + +- `role:master` +- `connected_slaves` + +### 6.3 ๅธธ่ง้—ฎ้ข˜ + +#### ๅœบๆ™ฏ A๏ผšๅฎ‰ๅ…จ็ป„ๆ–ญๅผ€ + +่กจ็Žฐ๏ผš + +- `master_link_status:down` + +ๅค„็†๏ผš + +- ็กฎ่ฎค `hifast-hk-app-core-sg` ไปไฟ็•™๏ผš + - `6379/tcp <- 104.238.220.230/32` + +#### ๅœบๆ™ฏ B๏ผšไธปๅบ“ๅฏ†็ ๆผ‚็งป + +่กจ็Žฐ๏ผš + +- ไปŽๅบ“้‡่ฟžๅคฑ่ดฅ +- ๆ—ฅๅฟ—ๅ‡บ็Žฐ `NOAUTH` + +ๅค„็†๏ผš + +- ็ปŸไธ€ๆ›ดๆ–ฐ `/etc/redis/redis.conf` ไธญ็š„๏ผš + - `masterauth` +- ็„ถๅŽ๏ผš + +```bash +systemctl restart redis-server +redis-cli INFO replication +``` + +## 7. ๅ…จ้‡้‡ๅปบ MySQL ไปŽๅบ“ + +้€‚็”จๅœบๆ™ฏ๏ผš + +- ไธปไปŽไธญๆ–ญไธ”ๆ— ๆณ•ๅฎ‰ๅ…จ่ฟฝๅนณ +- `6666@qq.com` ่ฟ™็ฑปๅ†™ๅ…ฅๅœจไธปๅบ“ๅญ˜ๅœจใ€ไปŽๅบ“ๆœชๅŒๆญฅ +- binlog ไธ่ฟž็ปญ +- ้œ€่ฆๅ›žๅˆฐๆœ€็จณๅฆฅ็Šถๆ€ + +### 7.1 ๅœจไธปๅบ“ๅฏผๅ‡บ + +ๅœจไธ€ๅฐๅฏ่ฟž RDS ็š„ๆœบๅ™จไธŠๆ‰ง่กŒ๏ผš + +```bash +mysqldump \ + -h hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com \ + -u admin \ + -p \ + --single-transaction \ + --routines \ + --triggers \ + --events \ + --set-gtid-purged=OFF \ + hifast > hifast-full.sql +``` + +ๅฆ‚ๆžœ้œ€่ฆๅŒๆญฅ่ดฆๅทๆƒ้™๏ผŒไนŸๅฏไปฅ้ขๅค–ๅ•็‹ฌๅฏผๅ‡บๆŽˆๆƒๅฏน่ฑก๏ผ›ไฝ†ๅฝ“ๅ‰ไธšๅŠกๅบ“ๆขๅค้‡็‚นๆ˜ฏ `hifast` ๆ•ฐๆฎๅบ“ๆœฌ่บซใ€‚ + +### 7.2 ๆธ…็† `104` ๅฝ“ๅ‰ๅคๅˆถ + +ๅœจ `104` ๆ‰ง่กŒ๏ผš ```sql -CALL mysql.rds_set_configuration('binlog retention hours', 24); +STOP REPLICA; +RESET REPLICA ALL; +``` -CREATE USER IF NOT EXISTS 'repl'@'104.238.220.230' IDENTIFIED BY 'THcPeHaerV4PwyE9qtF6PHZd'; -GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'repl'@'104.238.220.230'; -FLUSH PRIVILEGES; +### 7.3 ้‡ๆ–ฐๅฏผๅ…ฅไธšๅŠกๅบ“ -SHOW VARIABLES LIKE 'gtid_mode'; +ๅœจ `104` ๆ‰ง่กŒ๏ผš + +```bash +mysql -e "DROP DATABASE IF EXISTS hifast; CREATE DATABASE hifast CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;" +mysql hifast < hifast-full.sql +``` + +### 7.4 ้‡ๆ–ฐๆŒ‚ๅคๅˆถ + +ๅฝ“ๅ‰็Žฐ็ฝ‘ๆ˜ฏ้ž GTID ่‡ชๅŠจๅฎšไฝ๏ผŒไฝฟ็”จ file/position ๆจกๅผใ€‚ + +ๅ…ˆๅœจไธปๅบ“ๅ–ไฝ็‚น๏ผš + +```sql SHOW MASTER STATUS; ``` -่ฎฐๅฝ• `SHOW MASTER STATUS` ่พ“ๅ‡บ็š„ `File` ๅ’Œ `Position`ใ€‚ๅฆ‚ๆžœ `gtid_mode = ON`๏ผŒๅค–้ƒจไปŽๅบ“ๅฏ็”จ auto-position๏ผ›ๅฆๅˆ™ไฝฟ็”จ file/positionใ€‚ - -## ๅค–้ƒจๆœๅŠกๅ™จๅŸบ็ก€้…็ฝฎ - -ๅœจ `104.238.220.230` root shell ๆ‰ง่กŒ๏ผš - -```bash -cat >/etc/mysql/mysql.conf.d/99-replica.cnf <<'EOF' -[mysqld] -server-id=230 -read_only=ON -super_read_only=ON -relay_log=relay-bin -log_bin=mysql-bin -binlog_format=ROW -EOF - -systemctl restart mysql -mysql -e "SHOW VARIABLES WHERE Variable_name IN ('server_id','read_only','super_read_only','log_bin','binlog_format');" -``` - -ๅฆ‚ๆžœ RDS `gtid_mode = ON`๏ผš +็„ถๅŽๅœจ `104` ๆ‰ง่กŒ๏ผš ```sql -STOP REPLICA; -RESET REPLICA ALL; CHANGE REPLICATION SOURCE TO - SOURCE_HOST='hifast-mysql-prod.cd6aey40m6ag.ap-east-1.rds.amazonaws.com', + SOURCE_HOST='hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com', SOURCE_PORT=3306, SOURCE_USER='repl', - SOURCE_PASSWORD='THcPeHaerV4PwyE9qtF6PHZd', - SOURCE_AUTO_POSITION=1, - SOURCE_SSL=1; -START REPLICA; -SHOW REPLICA STATUS\G -``` - -ๅฆ‚ๆžœ RDS `gtid_mode != ON`๏ผŒๆŠŠ `` ๅ’Œ `` ๆ›ฟๆขๆˆ `SHOW MASTER STATUS` ้‡Œ็š„ๅ€ผ๏ผš - -```sql -STOP REPLICA; -RESET REPLICA ALL; -CHANGE REPLICATION SOURCE TO - SOURCE_HOST='hifast-mysql-prod.cd6aey40m6ag.ap-east-1.rds.amazonaws.com', - SOURCE_PORT=3306, - SOURCE_USER='repl', - SOURCE_PASSWORD='THcPeHaerV4PwyE9qtF6PHZd', + SOURCE_PASSWORD='', SOURCE_LOG_FILE='', SOURCE_LOG_POS=, SOURCE_SSL=1; @@ -101,37 +398,36 @@ START REPLICA; SHOW REPLICA STATUS\G ``` -ๆˆๅŠŸๆ ‡ๅ‡†๏ผš +### 7.5 ้ชŒๆ”ถ + +็กฎ่ฎค๏ผš - `Replica_IO_Running: Yes` - `Replica_SQL_Running: Yes` -- `Seconds_Behind_Source` ไธบ `0` ๆˆ–่พƒๅฐๆ•ฐๅ€ผ +- `Seconds_Behind_Source: 0` +- `read_only = ON` +- `super_read_only = ON` -## Redis ๅคๅˆถ +## 8. ้‡ๆ–ฐ้…็ฝฎ Redis ไปŽๅบ“ -Redis ๆบ็ซฏ่ฟ˜ๆœช็กฎ่ฎคใ€‚ไน‹ๅ‰ๆ–นๆกˆๆ˜ฏ Redis ๆ”พๅœจ AWS app EC2 ไธŠ๏ผŒไธŽๆœๅŠก็ซฏๅŒๆœบใ€‚้œ€่ฆๅ…ˆ็™ปๅฝ• AWS app EC2๏ผŒ็กฎ่ฎค Redis ๆ˜ฏๅฆๅญ˜ๅœจใ€็ซฏๅฃใ€ๅฏ†็ ใ€็›‘ๅฌๅœฐๅ€ใ€‚ +ๅฝ“ๅ‰ `104` Redis ไธบๅŽŸ็”Ÿๅฎ‰่ฃ…๏ผŒไธไฝฟ็”จ Dockerใ€‚ -ๅค–้ƒจ Redis ไปŽๅบ“ๅ‘ฝไปคๆจกๆฟ๏ผš +### 8.1 ไธดๆ—ถๅˆ‡ๅ›žไปŽๅบ“ ```bash +redis-cli CONFIG SET masterauth '0BVz9XOHf7KUfEuoFJRK-dURdKUGFiZ8QeaHpysHnKeKhLskZb55HPK121lFsKtr' +redis-cli REPLICAOF 43.198.248.161 6379 redis-cli CONFIG SET replica-read-only yes -redis-cli REPLICAOF 6379 redis-cli INFO replication ``` -ๅฆ‚ๆžœๆบ็ซฏๆœ‰ๅฏ†็ ๏ผš +### 8.2 ๆŒไน…ๅŒ–้…็ฝฎ -```bash -redis-cli CONFIG SET masterauth '' -redis-cli REPLICAOF 6379 -redis-cli INFO replication -``` - -ๆŒไน…ๅŒ–ๅ†™ๅ…ฅ `/etc/redis/redis.conf`๏ผš +ๆฃ€ๆŸฅ `/etc/redis/redis.conf` ่‡ณๅฐ‘ๅŒ…ๅซ๏ผš ```conf -replicaof 6379 -masterauth +replicaof 43.198.248.161 6379 +masterauth 0BVz9XOHf7KUfEuoFJRK-dURdKUGFiZ8QeaHpysHnKeKhLskZb55HPK121lFsKtr replica-read-only yes ``` @@ -142,3 +438,215 @@ systemctl restart redis-server redis-cli INFO replication ``` +## 9. ็”Ÿไบง็บงๆ”ถๆ•›่ทฏ็บฟ๏ผšๆ–ฐๅปบ่ง„่Œƒ RDS ๅ†ๅˆ‡ๆข + +่ฟ™ๆก่ทฏ็บฟๅทฒ็ปๅฎŒๆˆ๏ผŒๅฝ“ๅ‰็Žฐ็ฝ‘ไธปๅบ“ๅทฒ็ปๅˆ‡ๅˆฐ `hifast-mysql-prod-v2`ใ€‚ไธ‹้ขๅ†…ๅฎนไฟ็•™ไธบ่ฟ็งปๅฝ’ๆกฃๅ‚่€ƒ๏ผŒไธๅ†่กจ็คบๅพ…ๆ‰ง่กŒใ€‚ + +### 9.1 ็›ฎๆ ‡ + +ๆŠŠๅฝ“ๅ‰ไธดๆ—ถๆ–นๆกˆ๏ผš + +- `private-1b` ๆŒ‚ๅ…ฌ็ฝ‘่ทฏ็”ฑ + +ๆ”ถๆ•›ๆˆ๏ผš + +- RDS ไฝฟ็”จ็บฏๅ…ฌ็ฝ‘ DB subnet group +- ๅฎ‰ๅ…จ็ป„ไปๅชๅฏน็™ฝๅๅ•ๅ’Œๅบ”็”จ็ป„ๅผ€ๆ”พ + +### 9.2 ๅทฒๅ‡†ๅค‡ๅฅฝ็š„่ต„ๆบ + +- ๅทฒๅปบ DB subnet group: + - `hifast-hk-rds-public-only-sgprep` +- ๅญ็ฝ‘๏ผš + - `hifast-hk-public-1a` + - `hifast-hk-public-1b` + +### 9.3 ๆ–ฐ RDS ๅปบ่ฎฎๅ‚ๆ•ฐ + +ๆ–ฐๅฎžไพ‹ๅปบ่ฎฎๅ๏ผš + +- `hifast-mysql-prod-v2` + +ๅปบ่ฎฎไฟๆŒไธŽๆ—งไธปๅบ“ไธ€่‡ด๏ผš + +- Engine: `mysql` +- Version: `8.4.8` +- Class: `db.r7g.xlarge` +- Storage: `gp3` +- Size: `200 GB` +- IOPS: `3000` +- Throughput: `125` +- Publicly accessible: `Yes` +- Multi-AZ: `No` ๆˆ–ๆŒ‰้ข„็ฎ—ๅ•็‹ฌ่ฏ„ไผฐ +- Deletion protection: `On` +- Performance Insights: `On` +- Backup retention: `7` +- DB subnet group: `hifast-hk-rds-public-only-sgprep` +- VPC SG: `hifast-hk-rds-core-sg` + +### 9.4 ่ฟ็งปๆญฅ้ชค + +1. ๅทฒๅˆ›ๅปบๆ–ฐ RDS `hifast-mysql-prod-v2` +2. ๅœจๆ—งไธปๅบ“ๅฏผๅ‡บ `hifast` +3. ๅฏผๅ…ฅๆ–ฐๅบ“ +4. ๅœจๆ–ฐๅบ“ๅˆ›ๅปบ `repl` ็”จๆˆทๅนถ้…็ฝฎ binlog retention +5. ไฟฎๆ”น AWS app EC2 ไธŠ `/opt/ppanel/configs/ppanel.yaml` ็š„ `MySQL.Addr` +6. ้‡ๅฏ `ppanel-server` ๅฎนๅ™จ +7. ๅœจ `104` ไธŠ `STOP REPLICA; RESET REPLICA ALL;` +8. ๆŒ‡ๅ‘ๆ–ฐ RDS endpoint ้‡ๆ–ฐๆŒ‚ๅคๅˆถ +9. ้ชŒๆ”ถๅบ”็”จไธŽไธปไปŽ +10. ้ชŒๆ”ถ้€š่ฟ‡ๅŽ๏ผŒๅฎ‰ๆŽ’ๆ—ง RDS ไธ‹็บฟ๏ผŒๅนถๆŽจ่ฟ› `private-1b` ๆขๅค็ง็ฝ‘่ทฏ็”ฑ + +### 9.5 ๅบ”็”จๅˆ‡ๆขๅ‘ฝไปค + +ๅœจ AWS app EC2๏ผš + +1. ๅค‡ไปฝ้…็ฝฎ + +```bash +cp /opt/ppanel/configs/ppanel.yaml /opt/ppanel/configs/ppanel.yaml.bak.$(date +%Y%m%d%H%M%S) +``` + +2. ็ผ–่พ‘๏ผš + +- `/opt/ppanel/configs/ppanel.yaml` + +ๆŠŠ๏ผš + +```yaml +MySQL: + Addr: hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com:3306 +``` + +ๆ”นๆˆ๏ผš + +```yaml +MySQL: + Addr: hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com:3306 +``` + +3. ้‡ๅฏๅบ”็”จๅฎนๅ™จ๏ผš + +```bash +cd /opt/ppanel +docker compose -f docker-compose.cloud.yml up -d ppanel-server +``` + +4. ้ชŒ่ฏ๏ผš + +```bash +curl -sf http://127.0.0.1:8080/v1/common/heartbeat +docker compose -f docker-compose.cloud.yml logs --tail=100 ppanel-server +``` + +### 9.6 `104` ๆ”นๆŒ‚ๆ–ฐ RDS + +```sql +STOP REPLICA; +RESET REPLICA ALL; +CHANGE REPLICATION SOURCE TO + SOURCE_HOST='', + SOURCE_PORT=3306, + SOURCE_USER='repl', + SOURCE_PASSWORD='', + SOURCE_LOG_FILE='', + SOURCE_LOG_POS=, + SOURCE_SSL=1; +START REPLICA; +SHOW REPLICA STATUS\G +``` + +### 9.7 ๅˆ‡ๆข้ชŒๆ”ถ + +่‡ณๅฐ‘็กฎ่ฎค๏ผš + +- AWS ๅบ”็”จๅฟƒ่ทณๆญฃๅธธ +- ๆ–ฐ RDS ๅฏๆญฃๅธธ่ฏปๅ†™ +- `104` ๅคๅˆถๆขๅคไธบ `Yes/Yes` +- `Seconds_Behind_Source` ่ฟฝๅˆฐ `0` +- Navicat ๅฏไปŽๅ…่ฎธ็š„็™ฝๅๅ•ๆฅๆบ่ฟžๆŽฅๆ–ฐ RDS + +### 9.8 ๅ›žๆปš + +ๅฆ‚ๆžœๆ–ฐ RDS ๅˆ‡ๆขๅŽๅบ”็”จๅผ‚ๅธธ๏ผš + +1. ็ซ‹ๅณๆŠŠ `/opt/ppanel/configs/ppanel.yaml` ไธญ `MySQL.Addr` ๆ”นๅ›žๆ—ง endpoint +2. ้‡ๅฏ `ppanel-server` +3. ๆš‚ไธๅค„็† `104`๏ผŒๅ…ˆๆขๅคไธป็”Ÿไบง +4. ๅค็›˜ๆ–ฐๅบ“ๆ•ฐๆฎใ€ๆƒ้™ใ€ๅ‚ๆ•ฐใ€็ฝ‘็ปœ + +## 10. AWS ๆ•…้šœๆ—ถ็š„ๅค‡็”จๆŽฅ็ฎก + +### 10.1 Redis ๆๅ‡ไธบไธปๅบ“ + +ๅœจ `104`๏ผš + +```bash +redis-cli REPLICAOF NO ONE +redis-cli INFO replication +``` + +ๆœŸๆœ›๏ผš + +- `role:master` + +### 10.2 MySQL ๆๅ‡ไธบๅฏๅ†™ไธปๅบ“ + +ๅœจ `104`๏ผš + +```sql +STOP REPLICA; +RESET REPLICA ALL; +SET GLOBAL super_read_only=OFF; +SET GLOBAL read_only=OFF; +``` + +ๅ†็กฎ่ฎค๏ผš + +```sql +SHOW VARIABLES LIKE 'read_only'; +SHOW VARIABLES LIKE 'super_read_only'; +``` + +ๆœŸๆœ›๏ผš + +- `OFF` +- `OFF` + +### 10.3 ๅบ”็”จๅˆ‡ๅˆฐ `104` ๆœฌๆœบๆ•ฐๆฎๅฑ‚ + +ๅฆ‚ๆžœ `104` ไธŠไนŸ้ƒจ็ฝฒๅŒๆ ท็š„ PPanel ๆœๅŠก๏ผŒๅˆ™ๅบ”็”จ้…็ฝฎๅบ”ๆ”นไธบ๏ผš + +- MySQL ๆŒ‡ๅ‘ `127.0.0.1:3306` ๆˆ–ๆœฌๆœบ socket +- Redis ๆŒ‡ๅ‘ `127.0.0.1:6379` + +### 10.4 ๆœ€ๅŽๅˆ‡ๅ…ฅๅฃ + +ๆ•ฐๆฎๅฑ‚ๅ’Œๅบ”็”จๅฑ‚้ƒฝ็กฎ่ฎคๅฏๅ†™ๅŽ๏ผŒๅ†ๅš๏ผš + +- DNS ๅˆ‡ๆข +- ๆˆ– Nginx / ไธŠๆธธๅˆ‡ๆต้‡ + +ๅŽŸๅˆ™๏ผš + +- ๅ…ˆๆ•ฐๆฎๆŽฅ็ฎก +- ๅ†ๅบ”็”จ็กฎ่ฎค +- ๆœ€ๅŽๅ…ฅๅฃๅˆ‡ๆข + +## 11. ๆ—ฅๅธธๅทกๆฃ€ๅปบ่ฎฎ + +ๅปบ่ฎฎ่‡ณๅฐ‘ๆฏๅคฉๅทกๆฃ€ไธ€ๆฌก๏ผš + +1. `104` MySQL `SHOW REPLICA STATUS\G` +2. `104` Redis `INFO replication` +3. AWS Redis ไธปๅบ“ `INFO replication` +4. AWS app ๅฟƒ่ทณ `/v1/common/heartbeat` +5. `docker compose -f /opt/ppanel/docker-compose.cloud.yml ps` + +ๅฆ‚ๆžœๅŽ็ปญ่ฆๅš็œŸๆญฃ็š„็”Ÿไบง็บง่‡ชๅŠจๅŒ–๏ผŒๅ†่กฅ๏ผš + +- MySQL ๅคๅˆถๅปถ่ฟŸๅ‘Š่ญฆ +- Redis ไธปไปŽๆ–ญ้“พๅ‘Š่ญฆ +- ๅบ”็”จๅฟƒ่ทณๅคฑ่ดฅๅ‘Š่ญฆ +- RDS ่ฟžๆŽฅๅคฑ่ดฅๅ‘Š่ญฆ +- ๅฎšๆœŸ็พๅค‡ๅˆ‡ๆขๆผ”็ปƒ diff --git a/ops/hifast-aws-standby-architecture-zh.md b/ops/hifast-aws-standby-architecture-zh.md index 489e557..dff3b8d 100644 --- a/ops/hifast-aws-standby-architecture-zh.md +++ b/ops/hifast-aws-standby-architecture-zh.md @@ -10,6 +10,47 @@ - MySQL / Redis ็š„ๅŒๆญฅๅ…ณ็ณปๆ˜ฏไป€ไนˆ - ๆ•…้šœๆ—ถๅบ”่ฏฅๅฆ‚ไฝ•ๅˆ‡ๆข +## 0. 2026-05-13 ้ชŒๆ”ถๆ‘˜่ฆ + +- ๅทฒ็กฎ่ฎค `104.238.220.230 -> AWS RDS MySQL` ่ฟž้€š๏ผŒMySQL ๅค–้ƒจไปŽๅบ“ๅฅๅบท๏ผš + - ๅฝ“ๅ‰ๅคๅˆถไธŠๆธธ๏ผš`hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com` + - `Replica_IO_Running: Yes` + - `Replica_SQL_Running: Yes` + - `Seconds_Behind_Source: 0` +- ๅทฒ็กฎ่ฎค `104.238.220.230 -> AWS EC2 Redis` ไธปไปŽๅฅๅบท๏ผš + - `104` ไธŠ `role:slave` + - `master_link_status:up` + - AWS Redis ไธปๅบ“ `connected_slaves:1` +- ๅทฒไฟฎๅคๅบ”็”จไพง Redis ้…็ฝฎๆผ‚็งป๏ผš + - ๆ—ง้“พ่ทฏ๏ผš`127.0.0.1:6380 -> stunnel4 -> ๆ—ง ElastiCache` + - ๆ–ฐ้“พ่ทฏ๏ผš`127.0.0.1:6379 -> ๆœฌๆœบ Docker Redis` +- ๆ—ง `stunnel4` ๅทฒๅœ็”จๅนถ็ฆ็”จ่‡ชๅฏ๏ผŒ`ppanel-server` ๆ—ฅๅฟ—้‡Œ็š„ Redis `i/o timeout` ๅทฒๅœๆญขๅ‡บ็Žฐใ€‚ +- ๅทฒ็กฎ่ฎค `ppanel-server` ๅฝ“ๅ‰่ฟ่กŒๆ–นๅผไธบ Docker Compose ๅฎนๅ™จ๏ผŒ่€Œไธๆ˜ฏ systemd ๆœๅŠก๏ผš + - Compose ๆ–‡ไปถ๏ผš`/opt/ppanel/docker-compose.cloud.yml` + - ้…็ฝฎๆ–‡ไปถ๏ผš`/opt/ppanel/configs/ppanel.yaml` + - ๅฎนๅ™จๅ๏ผš`ppanel-server` + - ๅฅๅบทๆฃ€ๆŸฅ๏ผš`curl http://127.0.0.1:8080/v1/common/heartbeat` ่ฟ”ๅ›žๆญฃๅธธ +- ๆ—ง่‡ชๅปบๅฎ‰ๅ…จ็ป„ `hifast-hk-app-sg`ใ€`hifast-hk-nginx-sg` ๅทฒๅˆ ้™ค๏ผ›ๅฝ“ๅ‰ VPC ๅ†…ไป…ไฟ็•™๏ผš + - `hifast-hk-app-core-sg` + - `hifast-hk-rds-core-sg` + - `hifast-hk-web-sg` + - `default` +- ็›ฎๅ‰ๅทฒ็ป่พพๅˆฐโ€œๅฏ็”จไธ”ๅ…ณ้”ฎ้“พ่ทฏๅทฒๆขๅคโ€็š„็Šถๆ€ใ€‚ +- ๅฝ“ๅ‰ๅ…ฅๅฃๅฑ‚ๅฑžไบŽๅทฒ็กฎ่ฎค็š„่ฟ‡ๆธกๆ–นๆกˆ๏ผš + - ็Žฐ้˜ถๆฎตๅ…ฌ็ฝ‘ๅ…ฅๅฃไปๅœจ `hifast-hk-app-01` + - ็‹ฌ็ซ‹ `nginx` ๆœๅŠกๅ™จๅทฒ้ข„็•™๏ผŒๅพ… AWS ๅŽ็ปญ่ต„ๆบๅˆฐไฝๅŽๅ†่ฟ็งปๆ‰ฟๆŽฅ +- ๅฝ“ๅ‰ไป้œ€่ฆ็ปง็ปญๆ”ถๆ•›็š„ๆ ธๅฟƒ็”Ÿไบง้กนๅชๅ‰ฉ 1 ไธช๏ผš + - RDS ไธบไบ†่ฎฉ `104` ่ตฐๅ…ฌ็ฝ‘็™ฝๅๅ•ๅคๅˆถ๏ผŒๅฝ“ๅ‰ไปไพ่ต– `hifast-hk-private-1b` ๅญ็ฝ‘ไธดๆ—ถๆŒ‚ๅˆฐๅ…ฌ็ฝ‘่ทฏ็”ฑ่กจ๏ผŒ่ฟ™ไธๆ˜ฏๆœ€็ปˆ่ง„่Œƒๅฝขๆ€ใ€‚ +- ๅทฒๅฎŒๆˆ็š„ไธ‹ไธ€ๆญฅๅ‡†ๅค‡๏ผš + - ๅทฒๅˆ›ๅปบ็บฏๅ…ฌ็ฝ‘ๅญ็ฝ‘ไธ“็”จ็š„ `DB subnet group`๏ผš`hifast-hk-rds-public-only-sgprep` + - ๅญ็ฝ‘ๅŒ…ๅซ๏ผš + - `subnet-070e3f264a9c79f32` `hifast-hk-public-1a` + - `subnet-00cb5add705c447c8` `hifast-hk-public-1b` +- ๅทฒๅˆ›ๅปบไธ“็”จ S3 ๅค‡ไปฝๆกถ๏ผš + - `hifast-prod-backups-200810848252-ap-east-1` + - ๅฝ“ๅ‰็Šถๆ€๏ผšprivate + - ๅฝ“ๅ‰็Šถๆ€๏ผšversioning enabled + ## 1. ๅฝ“ๅ‰ๅฎž้™…็Žฏๅขƒ ### 1.1 AWS ๅŒบๅŸŸ @@ -23,15 +64,37 @@ - ๅ็งฐ๏ผš`hifast-hk-app-01` - Instance ID: `i-079cd9d3ef3748714` -- ่ง’่‰ฒ๏ผšๅบ”็”จๆœบ / Nginx / ไธšๅŠกๆœๅŠก / AWS ไพง Redis ไธปๅบ“ๅฎฟไธปๆœบ +- ่ง’่‰ฒ๏ผšๅฝ“ๅ‰ๅฎž้™…็”Ÿไบงๅ…ฅๅฃ / Nginx / ไธšๅŠกๆœๅŠก / AWS ไพง Redis ไธปๅบ“ๅฎฟไธปๆœบ - ็ง็ฝ‘ IP: `10.0.1.201` - ๅ…ฌ็ฝ‘ IP: `43.198.248.161` +- ไธšๅŠกๆœๅŠก่ฟ่กŒๆ–นๅผ๏ผš`Docker Compose` +- ไธšๅŠกๅฎนๅ™จ๏ผš`ppanel-server` +- ้ƒจ็ฝฒ็›ฎๅฝ•๏ผš`/opt/ppanel` +- ๅฎž้™…้…็ฝฎๆ–‡ไปถ๏ผš`/opt/ppanel/configs/ppanel.yaml` + +#### ็‹ฌ็ซ‹ Nginx ๆœๅŠกๅ™จ + +- ๅ็งฐ๏ผš`hifast-hk-nginx-01` +- Instance ID: `i-0701d54bf2c6bf594` +- ่ง’่‰ฒ๏ผš่ฎกๅˆ’ไธญ็š„็‹ฌ็ซ‹ๅ…ฅๅฃๆœบ +- ็ง็ฝ‘ IP: `10.0.1.175` +- ๅฝ“ๅ‰็Šถๆ€๏ผš`stopped` +- ๅฝ“ๅ‰่ฏดๆ˜Ž๏ผšๅทฒ็ปๅช็ป‘ๅฎš `hifast-hk-web-sg`๏ผŒไฝ†็›ฎๅ‰ๅนถๆœชๆ‰ฟๆŽฅๆญฃๅผๆต้‡ #### MySQL ไธปๅบ“ - ็ฑปๅž‹๏ผš`AWS RDS MySQL` -- ๅฎžไพ‹ๅ๏ผš`hifast-mysql-prod` +- ๅฎžไพ‹ๅ๏ผš`hifast-mysql-prod-v2` +- Endpoint: `hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com` - ่ง’่‰ฒ๏ผš็”Ÿไบงไธปๅบ“ +- Engine: `MySQL 8.4.8` +- Publicly accessible: `Yes` +- Multi-AZ: `No` +- Backup retention: `7 days` +- Deletion protection: `On` +- ๅฝ“ๅ‰ๆ•ฐๆฎๅบ“ๅฎž้™…ไฝ“้‡๏ผš็บฆ `187.41 MB` +- ๅฝ“ๅ‰่กจๆ•ฐ้‡๏ผš`37` +- ๅฝ“ๅ‰ `user` ่กจ่ฎฐๅฝ•ๆ•ฐ๏ผš`45076` #### Redis ไธปๅบ“ @@ -41,6 +104,8 @@ - ็‰ˆๆœฌ๏ผš`redis:8.2.1` - ่ฎฟ้—ฎ็ซฏๅฃ๏ผš`6379` - ไธปๅบ“ๅ‡บๅฃๅœฐๅ€๏ผš`43.198.248.161:6379` +- ๅบ”็”จๅฝ“ๅ‰ๅฎž้™…่ฟžๆŽฅ๏ผš`127.0.0.1:6379` +- ่ฎค่ฏๆ–นๅผ๏ผšๅทฒๅฏ็”จๅฏ†็ ่ฎค่ฏ #### ๅค–้ƒจๅค‡็”จๆœๅŠกๅ™จ @@ -48,10 +113,18 @@ - OS: `Ubuntu 24.04 LTS` - ่ง’่‰ฒ๏ผšๅผ‚ๅœฐๅค‡็”จ่Š‚็‚น - ๅฝ“ๅ‰็Šถๆ€๏ผšๅทฒ้ƒจ็ฝฒไธŽ AWS ็›ธๅŒ็š„ไธšๅŠกๆœๅŠก +- ๅฝ“ๅ‰ MySQL ็Šถๆ€๏ผšๅค–้ƒจๅช่ฏปไปŽๅบ“ - ๅฝ“ๅ‰ Redis ้ƒจ็ฝฒๆ–นๅผ๏ผš`ๅฎฟไธปๆœบๅŽŸ็”Ÿๅฎ‰่ฃ…` - ๅฝ“ๅ‰ Redis ็‰ˆๆœฌ๏ผš`8.6.3` - ๅฝ“ๅ‰ Redis ่ง’่‰ฒ๏ผš`AWS Redis ไธปๅบ“็š„ไปŽๅบ“` +#### S3 ๅค‡ไปฝๆกถ + +- Bucket: `hifast-prod-backups-200810848252-ap-east-1` +- Region: `ap-east-1` +- Public access: blocked +- Versioning: enabled + ## 2. ๆžถๆž„ๆ€ป่งˆ ```mermaid @@ -59,7 +132,7 @@ flowchart TB USER["็”จๆˆท / ๅฎขๆˆท็ซฏ"] --> DNS["ๅŸŸๅ / DNS / ๅ…ฅๅฃๅฑ‚"] DNS --> APP["AWS EC2\nhifast-hk-app-01\n43.198.248.161\n10.0.1.201"] - APP --> RDS["AWS RDS MySQL\nhifast-mysql-prod\nไธปๅบ“"] + APP --> RDS["AWS RDS MySQL\nhifast-mysql-prod-v2\nไธปๅบ“"] APP --> REDISM["AWS Redis ไธปๅบ“\nDocker redis:8.2.1\n43.198.248.161:6379"] RDS -. MySQL ๅค‡็”จ / ๅŒๆญฅ .-> MYSQLS["104.238.220.230\nMySQL ๅค‡็”จๅบ“"] @@ -87,8 +160,10 @@ flowchart TB ่ฏดๆ˜Ž๏ผš -- ๅฝ“ๅ‰ไธปๅบ”็”จๅ…ฅๅฃๅœจ AWS EC2ใ€‚ -- EC2 ๅŒๆ—ถๆ‰ฟๆ‹…ไธšๅŠกๆœๅŠกๅ…ฅๅฃใ€‚ +- ๅฝ“ๅ‰ไธปๅบ”็”จๅ…ฅๅฃๅฎž้™…ๅœจ `hifast-hk-app-01`ใ€‚ +- `hifast-hk-app-01` ๅŒๆ—ถๆ‰ฟๆ‹… Nginxใ€ไธšๅŠกๆœๅŠกใ€Redis ไธปๅบ“ใ€‚ +- ๅฝ“ๅ‰ไธšๅŠกๆœๅŠกไธๆ˜ฏ systemd ๅ•่ฟ›็จ‹้ƒจ็ฝฒ๏ผŒ่€Œๆ˜ฏ็”ฑ `/opt/ppanel/docker-compose.cloud.yml` ็ฎก็†็š„ `ppanel-server` ๅฎนๅ™จๆไพ› `8080`ใ€‚ +- ็‹ฌ็ซ‹ๅ…ฅๅฃๆœบ `hifast-hk-nginx-01` ๅทฒๅญ˜ๅœจ๏ผŒไฝ†ๅฝ“ๅ‰ไป…ไฝœไธบๅŽ็ปญ่ต„ๆบๅผ€้€šๅŽ็š„่ฟ็งป็›ฎๆ ‡ใ€‚ - MySQL ๅœจ AWS RDSใ€‚ - Redis ไธๅœจ ElastiCache๏ผŒ่€Œๆ˜ฏๅœจ EC2 ๆœฌๆœบ้€š่ฟ‡ Docker ๆไพ›ใ€‚ @@ -118,43 +193,187 @@ App / Nginx ## 4. ็ฝ‘็ปœไธŽๅฎ‰ๅ…จ่พน็•Œ -### 4.1 EC2 ๅฎ‰ๅ…จ็ป„ +### 4.1 ๅฝ“ๅ‰ๅฎ‰ๅ…จ็ป„ -- ๅฎ‰ๅ…จ็ป„ๅ็งฐ๏ผš`hifast-hk-app-sg` -- ๅฎ‰ๅ…จ็ป„ ID: `sg-09266fb27bde15714` +ๆˆช่‡ณ `2026-05-13`๏ผŒVPC `vpc-09fc384522517debc` ๅ†…ไป…ไฟ็•™ 4 ไธชๅฎ‰ๅ…จ็ป„๏ผš -ๅทฒ็กฎ่ฎค่ง„ๅˆ™๏ผš +- `default` +- `hifast-hk-app-core-sg` +- `hifast-hk-rds-core-sg` +- `hifast-hk-web-sg` -- Redis `6379/tcp` -- ๆฅๆบ๏ผš`104.238.220.230/32` +ๅ…ถไธญ็ป‘ๅฎšๅ…ณ็ณปๅทฒ็ปๆ”ถๆ•›ไธบ๏ผš -่ฟ™ๆก่ง„ๅˆ™็š„ไฝœ็”จๆ˜ฏ๏ผš +- `hifast-hk-app-01` -> `hifast-hk-app-core-sg` +- `hifast-hk-nginx-01` -> `hifast-hk-web-sg` +- `hifast-mysql-prod-v2` -> `hifast-hk-rds-core-sg` -- ๅ…่ฎธๅค–้ƒจๅค‡็”จๆœๅŠกๅ™จ `104.238.220.230` ่ฟžๅˆฐ AWS Redis ไธปๅบ“ -- ้ฟๅ… Redis ๅฏนๅ…จ็ฝ‘ๅผ€ๆ”พ +ๆ—ง็ป„๏ผš -### 4.2 Redis ็ฝ‘็ปœๅ…ณ็ณป +- `hifast-hk-app-sg` +- `hifast-hk-nginx-sg` + +ๅทฒ็ปๅˆ ้™ค๏ผŒไธๅ†ไฝฟ็”จใ€‚ + +### 4.2 ๅฝ“ๅ‰ๅ…ฅ็ซ™่ง„ๅˆ™ + +#### `hifast-hk-app-core-sg` + +- `22/tcp <- 0.0.0.0/0` +- `6379/tcp <- 104.238.220.230/32` +- `8080/tcp <- hifast-hk-web-sg` + +#### `hifast-hk-rds-core-sg` + +- `3306/tcp <- 104.238.220.230/32` +- `3306/tcp <- hifast-hk-app-core-sg` + +#### `hifast-hk-web-sg` + +- `22/tcp <- 0.0.0.0/0` +- `80/tcp <- 0.0.0.0/0` +- `443/tcp <- 0.0.0.0/0` + +### 4.3 Redis ็ฝ‘็ปœๅ…ณ็ณป ```mermaid flowchart LR - SG["EC2 Security Group\nsg-09266fb27bde15714"] --> REDIS["AWS Redis ไธปๅบ“\n43.198.248.161:6379"] + SG["hifast-hk-app-core-sg"] --> REDIS["AWS Redis ไธปๅบ“\n43.198.248.161:6379"] STANDBY["104.238.220.230/32"] --> SG ``` -### 4.3 RDS ่ฎฟ้—ฎๅŽŸๅˆ™ +### 4.4 RDS ่ฎฟ้—ฎๅŽŸๅˆ™ -RDS ไธๅบ”่ฏฅๅฏนๅ…ฌ็ฝ‘ๅ…จๅผ€ๆ”พใ€‚ +RDS ๅฝ“ๅ‰็Šถๆ€ๅทฒ็ปๆฏ”ไน‹ๅ‰ๅนฒๅ‡€ๅพˆๅคš๏ผš -ๆŽจ่ไธ”ๅทฒๆ‰ง่กŒ่ฟ‡็š„ๆ–นๅ‘ๆ˜ฏ๏ผš - -- ๅชๅฏน็™ฝๅๅ•ๆบ IP ๅผ€ๆ”พ `3306` -- ๅฆ‚ๆžœ `104.238.220.230` ้œ€่ฆๅšๅค–้ƒจไปŽๅบ“๏ผŒๅˆ™ๅชๆ”พ่กŒ่ฟ™ไธช IP +- ๅฝ“ๅ‰ๅชๅฏน็™ฝๅๅ•ๅ’Œๅบ”็”จๅฎ‰ๅ…จ็ป„ๅผ€ๆ”พ `3306` +- ๅทฒ็งป้™ค `3306 <- 0.0.0.0/0` +- ๅฝ“ๅ‰ RDS ไป…็ป‘ๅฎš `hifast-hk-rds-core-sg` ๅปบ่ฎฎๅŽŸๅˆ™๏ผš - ไธๅผ€ๆ”พ `0.0.0.0/0` ๅˆฐ MySQL `3306` - ไธๅผ€ๆ”พ `0.0.0.0/0` ๅˆฐ Redis `6379` +### 4.5 ๅฝ“ๅ‰ไป้œ€็ปง็ปญๆ”ถๆ•›็š„็ฝ‘็ปœ็‚น + +#### 4.5.1 ๅ…ฅๅฃๅฑ‚ๅฝ“ๅ‰ๅฑžไบŽ่ฟ‡ๆธกๆ–นๆกˆ๏ผŒไธไฝœไธบๆœฌ้˜ถๆฎต้˜ปๅกž้กน + +ๅฝ“ๅ‰่ฟ่กŒๅฝขๆ€ๆ˜ฏ๏ผš + +- `hifast-hk-app-01` ๆœฌๆœบ `nginx` ๆญฃๅœจ็›‘ๅฌ `80/443` +- `hifast-hk-nginx-01` ๅฝ“ๅ‰ๅœๆญข + +ไฝ†ๅฝ“ๅ‰ๅฎ‰ๅ…จ็ป„่ฎพ่ฎกๆ˜ฏๆŒ‰โ€œ็‹ฌ็ซ‹ nginx ๆœบโ€ๆ‹†็š„๏ผš + +- `hifast-hk-web-sg` ๅœจ `hifast-hk-nginx-01` +- `hifast-hk-app-core-sg` ๅœจ `hifast-hk-app-01` + +่ฟ™ๆ„ๅ‘ณ็€ๅฝ“ๅ‰็œŸๅฎžๅ…ฅๅฃๅ’Œๅฎ‰ๅ…จ็ป„่ง’่‰ฒๅˆ’ๅˆ†่ฟ˜ๆฒกๆœ‰ๅฎŒๅ…จไธ€่‡ดใ€‚ + +ไฝ†่ฟ™ไธ€็‚นๅทฒ็ป่ขซ็กฎ่ฎคไธบ่ฟ‡ๆธก่ฎพ่ฎก๏ผŒไธไฝœไธบๅฝ“ๅ‰้˜ถๆฎตๅฟ…้กปๆ•ดๆ”น็š„้—ฎ้ข˜ใ€‚ๅŽ็ปญๅพ… AWS ๆ–ฐ่ต„ๆบๅˆฐไฝๅŽ๏ผŒๅ†ๆŠŠๅ…ฌ็ฝ‘ๅ…ฅๅฃ่ฟๅˆฐ็‹ฌ็ซ‹ `nginx` ๆœๅŠกๅ™จๅณๅฏใ€‚ + +#### 4.5.2 RDS ๅ…ฌ็ฝ‘ๅคๅˆถ้“พ่ทฏไปๆ˜ฏๅฝ“ๅ‰ๅ”ฏไธ€ๆ ธๅฟƒ็ป“ๆž„ๆ€ง้—ฎ้ข˜ + +ไธบไบ†่ฎฉ `104.238.220.230` ้€š่ฟ‡ๅ…ฌ็ฝ‘็™ฝๅๅ•่ฎฟ้—ฎ RDS๏ผŒๅฝ“ๅ‰ๅฎž้™…ไพ่ต–็š„ๆ˜ฏ๏ผš + +- RDS `PubliclyAccessible = true` +- RDS ENI ไปๅœจ `subnet-0dcf46db665b6d8a7` +- ่ฏฅๅญ็ฝ‘ๅ็งฐๆ˜ฏ `hifast-hk-private-1b` +- ไฝ†่ฟ™ไธชๅญ็ฝ‘ๅฝ“ๅ‰่ขซไธดๆ—ถๅ…ณ่”ๅˆฐไบ†ๅ…ฌ็ฝ‘่ทฏ็”ฑ่กจ + +่ฟ™่ƒฝ็”จ๏ผŒไฝ†ไธๅฑžไบŽๆœ€็ปˆ่ง„่Œƒ็š„โ€œ็บฏๅ…ฌ็ฝ‘ๅญ็ฝ‘็ป„โ€่ฎพ่ฎกใ€‚ + +ๆœฌ่ฝฎๅทฒ็ป้ขๅค–ๅฎŒๆˆ็š„ๅ‡†ๅค‡ๅŠจไฝœ๏ผš + +- ๅทฒๆ–ฐๅปบ็บฏๅ…ฌ็ฝ‘ `DB subnet group`๏ผš`hifast-hk-rds-public-only-sgprep` +- ่ฏฅ็ป„็Šถๆ€๏ผš`Complete` +- ่ฏฅ็ป„ไป…ๅŒ…ๅซไธคๆกๅ…ฌ็ฝ‘ๅญ็ฝ‘๏ผš + - `hifast-hk-public-1a` + - `hifast-hk-public-1b` + +ๅฝ“ๅ‰็ป“่ฎบ๏ผš + +- ไธๅปบ่ฎฎ็ปง็ปญๅœจ็Žฐๆœ‰็”Ÿไบง RDS ไธŠๅๅค่ฏ•ๅœจ็บฟๅˆ‡ๅญ็ฝ‘็ป„ใ€‚ +- ๆ›ด็จณ็š„ๆ”ถๆ•›ๆ–นๆกˆๆ˜ฏ๏ผšๆ–ฐๅปบไธ€ๅฐไฝฟ็”จ่ง„่Œƒๅ…ฌ็ฝ‘ๅญ็ฝ‘็ป„็š„็”Ÿไบง RDS๏ผŒๅ†ๅšไธ€ๆฌก็Ÿญๅˆ‡ๆขใ€‚ +- ็”ฑไบŽๅฝ“ๅ‰ๅบ“ไฝ“้‡ๅชๆœ‰็บฆ `187 MB`๏ผŒ่ฟ™ๆก่ทฏ็บฟ็š„ๆ‰ง่กŒๆˆๆœฌๅนถไธ้ซ˜๏ผŒ้ฃŽ้™ฉไนŸๆฏ”ๅœจ็Žฐ็ฝ‘ไธปๅบ“ไธŠ็กฌๆ”นๆ›ดๅฏๆŽงใ€‚ + +## 4.6 104 ๅฆ‚ไฝ•่ฟžๆŽฅ AWS + +่ฟ™้‡Œ่ฆ็‰นๅˆซๅŒบๅˆ†๏ผš + +- `104` ่ฟžๆŽฅ AWS ๆ•ฐๆฎๅฑ‚ +- ๆœฌๅœฐ็”ต่„‘็™ปๅฝ• AWS EC2 + +่ฟ™ไธๆ˜ฏๅŒไธ€ไปถไบ‹ใ€‚ + +### 4.6.1 104 ่ฟžๆŽฅ AWS Redis ็š„ๆ–นๅผ + +`104.238.220.230` ่ฟžๆŽฅ AWS Redis๏ผŒไธๆ˜ฏ้€š่ฟ‡ PEM ่ฏไนฆ๏ผŒไนŸไธๆ˜ฏ้€š่ฟ‡ SSH ็™ปๅฝ• AWS ๆœบๅ™จ๏ผŒ่€Œๆ˜ฏ็›ดๆŽฅไฝœไธบ Redis ไปŽๅบ“ๅŽป่ฎฟ้—ฎ AWS Redis ไธปๅบ“๏ผš + +- ็›ฎๆ ‡ๅœฐๅ€๏ผš`43.198.248.161:6379` +- ่ฟžๆŽฅๆ–นๅผ๏ผš`TCP` +- ่ฎค่ฏๆ–นๅผ๏ผš`Redis ๅฏ†็ ` +- ็ฝ‘็ปœๅ‰ๆ๏ผšAWS EC2 ๅฎ‰ๅ…จ็ป„ๅทฒๆ”พ่กŒ `104.238.220.230/32 -> 6379` + +ไนŸๅฐฑๆ˜ฏ่ฏด๏ผš + +```text +104 Redis ไปŽๅบ“ -> ็›ด่ฟž AWS Redis ไธปๅบ“ๅ…ฌ็ฝ‘ๅœฐๅ€ -> ๅฏ†็ ่ฎค่ฏ -> ๅปบ็ซ‹ๅคๅˆถ +``` + +็คบๆ„ๅ‘ฝไปค๏ผš + +```bash +redis-cli -h 43.198.248.161 -p 6379 -a '' +``` + +### 4.6.2 104 ่ฟžๆŽฅ AWS MySQL RDS ็š„ๆ–นๅผ + +`104.238.220.230` ่ฟžๆŽฅ AWS RDS๏ผŒไนŸไธๆ˜ฏ้€š่ฟ‡ PEM ่ฏไนฆ๏ผŒ่€Œๆ˜ฏ้€š่ฟ‡ๆ•ฐๆฎๅบ“่ฟžๆŽฅ๏ผš + +- ็›ฎๆ ‡ๅœฐๅ€๏ผš`hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com:3306` +- ่ฟžๆŽฅๆ–นๅผ๏ผš`MySQL TCP` +- ่ฎค่ฏๆ–นๅผ๏ผš`MySQL ็”จๆˆทๅ + ๅฏ†็ ` +- ็ฝ‘็ปœๅ‰ๆ๏ผšRDS ็™ฝๅๅ•ๆˆ–ๅฎ‰ๅ…จ็ป„ๆ”พ่กŒ `104.238.220.230` + +ไนŸๅฐฑๆ˜ฏ่ฏด๏ผš + +```text +104 MySQL ไปŽๅบ“ -> ็›ด่ฟž AWS RDS endpoint -> ่ดฆๅทๅฏ†็ ่ฎค่ฏ -> ๅปบ็ซ‹ๅคๅˆถ +``` + +็คบๆ„ๅ‘ฝไปค๏ผš + +```bash +mysql -h hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com -u admin -p +``` + +### 4.6.3 ๆœฌๅœฐ็”ต่„‘็™ปๅฝ• AWS EC2 ็š„ๆ–นๅผ + +ๆœฌๅœฐ็”ต่„‘่ฟ™่พนไน‹ๅ‰่ฟ›ๅ…ฅ AWS EC2๏ผŒ็”จ็š„ไธๆ˜ฏ `hifast-hk-app-01-key.pem`๏ผŒ่€Œๆ˜ฏ๏ผš + +- `AWS Console` +- `EC2 Instance Connect` +- ๆต่งˆๅ™จ้‡Œ็š„ Web SSH ็ปˆ็ซฏ + +ๆ‰€ไปฅๅฝ“ๅ‰่ฆ็†่งฃๆˆ 3 ๆกไธๅŒ้“พ่ทฏ๏ผš + +1. ๆœฌๅœฐ็”ต่„‘ -> AWS ๆŽงๅˆถๅฐ -> EC2 Instance Connect -> AWS EC2 +2. `104` -> AWS Redis ไธปๅบ“ๅ…ฌ็ฝ‘ๅœฐๅ€ -> Redis ๅฏ†็ ่ฎค่ฏ +3. `104` -> AWS RDS endpoint -> MySQL ็”จๆˆทๅฏ†็ ่ฎค่ฏ + +### 4.6.4 ๅ…ณ้”ฎ็ป“่ฎบ + +ๅฝ“ๅ‰็พๅค‡้“พ่ทฏ้‡Œ๏ผŒ`104` ไธŽ AWS ๆ•ฐๆฎๅŒๆญฅไธไพ่ต– `.pem` ่ฏไนฆๆ–‡ไปถใ€‚ + +็œŸๆญฃไพ่ต–็š„ๆ˜ฏ๏ผš + +- Redis ๅฎ‰ๅ…จ็ป„ๆ”พ่กŒ +- RDS ็™ฝๅๅ• / ๅฎ‰ๅ…จ็ป„ๆ”พ่กŒ +- ๆญฃ็กฎ็š„ Redis ๅฏ†็  +- ๆญฃ็กฎ็š„ MySQL ่ดฆๅทๅฏ†็  + ## 5. Redis ๅฎž้™…้ƒจ็ฝฒไธŽๅŒๆญฅ็Šถๆ€ ### 5.1 AWS Redis ไธปๅบ“ @@ -186,6 +405,8 @@ RDS ไธๅบ”่ฏฅๅฏนๅ…ฌ็ฝ‘ๅ…จๅผ€ๆ”พใ€‚ - ไปŽ `104` ่ฟžๆŽฅ AWS Redis ไธปๅบ“๏ผŒ่ฎค่ฏๆˆๅŠŸ - AWS ไธปๅบ“ๅ†™ๅ…ฅๆต‹่ฏ•้”ฎ - `104` ไปŽๅบ“ๆˆๅŠŸ่ฏปๅ–ๆต‹่ฏ•้”ฎ +- `2026-05-13` ๅทฒ็กฎ่ฎคๅบ”็”จๆœบๆœฌๅœฐ `ppanel-server -> 127.0.0.1:6379` ๅปบ็ซ‹็จณๅฎš่ฟžๆŽฅ +- `2026-05-13` ๅทฒ็กฎ่ฎคๆ—ง `stunnel4 -> ElastiCache` ้“พ่ทฏไธ‹็บฟๅŽ๏ผŒๅบ”็”จๆ—ฅๅฟ—ไธๅ†ๅ‡บ็Žฐ Redis `i/o timeout` ๆต‹่ฏ•้”ฎ๏ผš @@ -206,7 +427,7 @@ flowchart LR ### 6.1 ไธปๅบ“่ง’่‰ฒ - ไธปๅบ“ๅœจ `AWS RDS MySQL` -- ๅฎžไพ‹๏ผš`hifast-mysql-prod` +- ๅฎžไพ‹๏ผš`hifast-mysql-prod-v2` ### 6.2 ๅค–้ƒจๅค‡็”จ่ง’่‰ฒ @@ -215,26 +436,32 @@ flowchart LR ### 6.3 ๅฝ“ๅ‰ๆ–‡ๆกฃ่ฏดๆ˜Ž -Redis ็š„ไธปไปŽ็Šถๆ€ๅทฒ็ปๅœจๆœฌๆฌกๆ‰ง่กŒไธญๅฎŒๆˆๅนถ้ชŒ่ฏใ€‚ +MySQL ๅฝ“ๅ‰ๅทฒ็ปๅฎŒๆˆๅฎž้™…้ชŒๆ”ถ๏ผŒไธๅ†ๅชๆ˜ฏโ€œๅพ…็กฎ่ฎคโ€็Šถๆ€ใ€‚ + +`2026-05-13` ้ชŒๆ”ถ็ป“ๆžœ๏ผš + +- `Source_Host = hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com` +- `Replica_IO_Running = Yes` +- `Replica_SQL_Running = Yes` +- `Seconds_Behind_Source = 0` +- `read_only = ON` +- `super_read_only = ON` + +่ฟ™่กจ็คบ `104` ๅฝ“ๅ‰ๆ˜ฏๅฅๅบท็š„ๅช่ฏปๅค–้ƒจๅค‡็”จๅบ“ใ€‚ MySQL ่ฟ™้ƒจๅˆ†ๅœจๆญคๅ‰ๅทฒ็ปๆœ‰ไธ“้—จ runbook๏ผš - [ops/aws-rds-external-replica-runbook.md](/Users/Apple/code_vpn/vpn/ppanel-server/ops/aws-rds-external-replica-runbook.md) -ๅฆ‚ๆžœ่ฆๆŠŠ MySQL ไนŸๅฎŒๅ…จ็บณๅ…ฅๅŒไธ€็พๅค‡ๆผ”็ปƒ๏ผŒ้œ€่ฆ็ปง็ปญ็กฎ่ฎค๏ผš - -- `104` ๅฝ“ๅ‰ MySQL ็š„ๅŒๆญฅ็บฟ็จ‹็Šถๆ€ -- `SHOW REPLICA STATUS\G` ๆ˜ฏๅฆไป็„ถๆญฃๅธธ -- RDS ๅˆฐ `104` ็š„็™ฝๅๅ•ๆ˜ฏๅฆไป็„ถไฟ็•™ - ## 7. ๅฝ“ๅ‰็”Ÿไบงๆ–นๆกˆ็š„็œŸๅฎž็‰น็‚น ่ฟ™ๅฅ—ๅทฒ็ป่ฝๅœฐ็š„ๆžถๆž„๏ผŒไธๆ˜ฏไผ ็ปŸ็š„ๅ…จ AWS ๆ‰˜็ฎกๆ ‡ๅ‡†ๅฝขๆ€๏ผŒ่€Œๆ˜ฏๅๅฎž็”จ็š„ๆททๅˆๆ–นๆกˆ๏ผš -- ๅบ”็”จๅœจ AWS EC2 +- ๅบ”็”จๅ’Œๅฝ“ๅ‰ๅฎž้™…ๅ…ฌ็ฝ‘ๅ…ฅๅฃๅœจ AWS ๅŒไธ€ๅฐ EC2 - MySQL ๅœจ AWS RDS - Redis ๅœจ AWS EC2 ๆœฌๆœบ - MySQL / Redis ๅ‡ๅ‘ๅค–้ƒจๆœๅŠกๅ™จ `104` ๅš็พๅค‡ +- ๆ—ง ElastiCache / stunnel ้“พ่ทฏๅทฒ็ป้€€ๅ‡บๅฝ“ๅ‰็”Ÿไบง่ทฏๅพ„ ๅฎƒ็š„ไผ˜็‚น๏ผš @@ -348,6 +575,9 @@ redis-cli -a '' REPLICAOF NO ONE - AWS Redis ไธปๅบ“ๆ˜ฏๅฆๅœจ็บฟ - `104` Redis ไปŽๅบ“ๆ˜ฏๅฆ `master_link_status:up` - `104` MySQL ๅคๅˆถๆ˜ฏๅฆๆญฃๅธธ +- `ppanel-server` ๅฎนๅ™จๆ˜ฏๅฆ `Up` +- `ppanel-server` ๆ—ฅๅฟ—ไธญๆ˜ฏๅฆๅ†ๆฌกๅ‡บ็Žฐ Redis `i/o timeout` +- `stunnel4` ๆ˜ฏๅฆไฟๆŒ `inactive` ### 9.2 Redis ๆ•…้šœๆ—ถ @@ -377,7 +607,7 @@ redis-cli -a '' REPLICAOF NO ONE ### 10.1 ๅฝ“ๅ‰ๅฎž้™…ๆ–นๆกˆ -`DNS -> AWS EC2(App + Nginx) -> RDS MySQL + EC2 Redis -> 104 ็พๅค‡` +`DNS -> hifast-hk-app-01(Nginx + App + Redis) -> RDS MySQL -> 104 ็พๅค‡` ### 10.2 ็†ๆƒณ็”Ÿไบงๆ–นๆกˆ @@ -394,11 +624,35 @@ redis-cli -a '' REPLICAOF NO ONE ๅปบ่ฎฎๆŒ‰ไผ˜ๅ…ˆ็บง่กฅ้ฝ๏ผš -1. ๆ˜Ž็กฎ `104` ๅบ”็”จๆŽฅ็ฎก่„šๆœฌไธŽๅฏๅŠจๆฃ€ๆŸฅ้กน -2. ๆ˜Ž็กฎ MySQL ๆ•…้šœๅˆ‡ๆข่„šๆœฌ -3. ๆ˜Ž็กฎ Redis ๆ•…้šœๅˆ‡ๆข่„šๆœฌ -4. ๆ˜Ž็กฎๅŸŸๅ / DNS ๅˆ‡ๆขๆ–นๅผ -5. ๅšไธ€ๆฌกๅฎŒๆ•ด็พๅค‡ๆผ”็ปƒ +1. ๆŠŠ RDS ไปŽโ€œprivate ๅญ็ฝ‘ๆŒ‚ๅ…ฌ็ฝ‘่ทฏ็”ฑโ€็š„ไธดๆ—ถๆ–นๆกˆ๏ผŒๆ”ถๆ•›ๆˆ็œŸๆญฃ็š„ๅ…ฌ็ฝ‘ DB subnet group๏ผŒๆˆ–ๆ”นๆˆ็ง็ฝ‘ๅคๅˆถๆ–นๆกˆ +2. ๆ˜Ž็กฎ `104` ๅบ”็”จๆŽฅ็ฎก่„šๆœฌไธŽๅฏๅŠจๆฃ€ๆŸฅ้กน +3. ๆ˜Ž็กฎ MySQL ๆ•…้šœๅˆ‡ๆข่„šๆœฌ +4. ๆ˜Ž็กฎ Redis ๆ•…้šœๅˆ‡ๆข่„šๆœฌ +5. ๆ˜Ž็กฎๅŸŸๅ / DNS ๅˆ‡ๆขๆ–นๅผ +6. ๅšไธ€ๆฌกๅฎŒๆ•ด็พๅค‡ๆผ”็ปƒ +7. ๅพ… AWS ๆ–ฐ่ต„ๆบๅˆฐไฝๅŽ๏ผŒๅ†ๆŠŠๅ…ฌ็ฝ‘ๅ…ฅๅฃ่ฟๅˆฐ็‹ฌ็ซ‹ `nginx` ๆœๅŠกๅ™จ + +### 10.4 RDS ๆŽจ่ๆ”ถๆ•›่ทฏ็บฟ + +ๅฝ“ๅ‰ๅŽŸๅ…ˆ่ง„ๅˆ’็š„โ€œๆ–ฐๅปบ่ง„่Œƒ RDS ๅ†ๅˆ‡ๆขโ€่ทฏ็บฟๅทฒ็ปๅฎŒๆˆ๏ผŒ็Žฐ็ฝ‘ไธปๅบ“ๅทฒ็ปๆ˜ฏ `hifast-mysql-prod-v2`ใ€‚ + +ๅŽ็ปญๆ›ดๆŽจ่็š„ๆญฃๅผ่ทฏ็บฟๆ˜ฏ๏ผš + +1. ็ปง็ปญไปฅ `hifast-mysql-prod-v2` ไฝœไธบๅฝ“ๅ‰็”Ÿไบงไธปๅบ“ +2. ็กฎ่ฎคๅ…ถๆŒ็ปญไฝฟ็”จ `hifast-hk-rds-public-only-sgprep` +3. ๅฎ‰ๅ…จ็ป„ๆŒ็ปญๅชๆ”พ๏ผš + - `104.238.220.230/32 -> 3306` + - `hifast-hk-app-core-sg -> 3306` +4. ๆŒ็ปญ็กฎ่ฎคๅบ”็”จ่ฟžๆŽฅ็›ฎๆ ‡ไธบ `hifast-mysql-prod-v2` +5. ๆŒ็ปญ็กฎ่ฎค `104` ็š„ๅค–้ƒจๅคๅˆถ็›ฎๆ ‡ไธบ `hifast-mysql-prod-v2` +6. ้ชŒ่ฏ้€š่ฟ‡ๅŽ๏ผŒๅ†ๅฎ‰ๆŽ’ๆ—ง RDS ไธ‹็บฟ + +่ฟ™ๆก่ทฏ็บฟ็š„ไผ˜็‚น๏ผš + +- ๆœ€็ปˆๆ‹“ๆ‰‘่ง„่Œƒๆธ…ๆ™ฐ +- ไธ้œ€่ฆ็ปง็ปญไฟ็•™โ€œprivate ๅญ็ฝ‘ๆŒ‚ๅ…ฌ็ฝ‘่ทฏ็”ฑโ€็š„ไธดๆ—ถ่ฎพ่ฎก +- ๅฏนๅฝ“ๅ‰็Žฐ็ฝ‘ไธปๅบ“็š„ๆ‰ฐๅŠจๆœ€ๅฐ +- ๅฝ“ๅ‰ๆ•ฐๆฎๅบ“ไฝ“้‡่พƒๅฐ๏ผŒ่ฟ็งปๆˆๆœฌๅฏๆŽง ## 11. ๅปบ่ฎฎ็š„ไธ‹ไธ€็‰ˆ็›ฎๆ ‡ๆ‹“ๆ‰‘ @@ -423,16 +677,20 @@ flowchart TB ๆˆช่‡ณๅฝ“ๅ‰๏ผŒๅทฒ็ปๅฏไปฅ็กฎ่ฎค็š„็”ŸไบงไธŽ็พๅค‡็Šถๆ€ๆ˜ฏ๏ผš - AWS ๆ˜ฏไธป็”Ÿไบง็Žฏๅขƒ -- ๅบ”็”จ่ท‘ๅœจ `hifast-hk-app-01` +- ๅบ”็”จๅฝ“ๅ‰่ท‘ๅœจ `hifast-hk-app-01` - MySQL ไธปๅบ“ๅœจ AWS RDS - Redis ไธปๅบ“ๅœจ AWS EC2 Docker - `104.238.220.230` ๆ˜ฏๅผ‚ๅœฐๅค‡็”จ่Š‚็‚น - `104` ๅทฒ้ƒจ็ฝฒไธŽ AWS ็›ธๅŒ็š„ไธšๅŠกๆœๅŠก - `104` ไธŠ Redis ๅทฒๅˆ‡ไธบๅฎฟไธปๆœบๅŽŸ็”Ÿๅฎ‰่ฃ… - `104` Redis ๅทฒๆˆๅŠŸไฝœไธบ AWS Redis ไธปๅบ“็š„ไปŽๅบ“ๅœจ็บฟๅŒๆญฅ +- `104` MySQL ๅทฒๆขๅคๅนถไฟๆŒๅฅๅบทๅคๅˆถ +- ๅบ”็”จๅทฒ็ปๅˆ‡ๅ›žๅฝ“ๅ‰็œŸๅฎžๅฏ็”จ็š„ๆœฌๆœบ Redis ไธปๅบ“ +- ๆ—ง `stunnel4 -> ElastiCache` ้“พ่ทฏๅทฒ็ป้€€ๅ‡บ็”Ÿไบง่ทฏๅพ„ ๅฆ‚ๆžœๅŽ็ปญ่ฆ็ปง็ปญๅฎŒๅ–„่ฟ™ไปฝๆ–นๆกˆ๏ผŒไผ˜ๅ…ˆ่กฅๅ……๏ผš -- MySQL ๆœ€็ปˆๅŒๆญฅ็Šถๆ€ๅคๆ ธ +- RDS ๅญ็ฝ‘ไธŽๅ…ฌ็ฝ‘่ฎฟ้—ฎๆจกๅž‹ๆ”ถๆ•› - ๅ…ฅๅฃๅŸŸๅ / DNS ๅˆ‡ๆข็ป†ๅˆ™ - ๅบ”็”จๅฑ‚ๅœจ `104` ็š„ๆŽฅ็ฎกไธŽๅ›žๅˆ‡ๆ‰ง่กŒๆธ…ๅ• +- ๅพ…่ต„ๆบๅˆฐไฝๅŽ็š„็‹ฌ็ซ‹ `nginx` ่ฟ็งปๆธ…ๅ• diff --git a/ops/hifast-rds-v2-cutover-checklist-zh.md b/ops/hifast-rds-v2-cutover-checklist-zh.md new file mode 100644 index 0000000..8eaf5f0 --- /dev/null +++ b/ops/hifast-rds-v2-cutover-checklist-zh.md @@ -0,0 +1,286 @@ +# Hifast ๆ–ฐ RDS ็”Ÿไบงๅˆ‡ๆขๆธ…ๅ•๏ผˆๅทฒๅฎŒๆˆๅฝ’ๆกฃ๏ผ‰ + +ๆœฌๆ–‡ๆกฃ่ฎฐๅฝ•ๅทฒๅฎŒๆˆ็š„ `hifast-mysql-prod -> hifast-mysql-prod-v2` ็”Ÿไบงๅˆ‡ๆข่ฟ‡็จ‹๏ผŒไฝœไธบๅฝ’ๆกฃๅ’Œๅ›žๆบฏๅ‚่€ƒใ€‚ + +ๆœฌๆฌกๅˆ‡ๆขๅทฒ็ปๅฎŒๆˆ๏ผŒๅฝ“ๆ—ถ็š„็›ฎๆ ‡ๆ˜ฏ้ฟๅ…็ปง็ปญๅœจ็บฟ็กฌๆ”น็Žฐๆœ‰็”Ÿไบง RDS๏ผŒ่€Œๆ˜ฏ๏ผš + +1. ๆ–ฐๅปบไธ€ๅฐ่ง„่Œƒๅ…ฌ็ฝ‘ๅญ็ฝ‘็ป„็š„ๆ–ฐ RDS +2. ๅฏผๅ…ฅ็Žฐๆœ‰ `hifast` ๆ•ฐๆฎ +3. ๅฐ† AWS ๅบ”็”จๅˆ‡ๅˆฐๆ–ฐ RDS +4. ๅฐ† `104.238.220.230` ็š„ๅค–้ƒจไปŽๅบ“ๆ”นๆŒ‚ๆ–ฐ RDS +5. ้ชŒๆ”ถ้€š่ฟ‡ๅŽๅ†ไธ‹็บฟๆ—ง RDS + +## 1. ้€‚็”จ่ƒŒๆ™ฏ + +ๅฝ“ๅ‰็Žฐ็ฝ‘ๅทฒ็ปๅฏ็”จ๏ผŒไฝ†่ฟ˜ๅญ˜ๅœจ 1 ไธช็ป“ๆž„ๆ€ง้—ฎ้ข˜๏ผš + +- ไธบไบ†่ฎฉ `104` ้€š่ฟ‡ๅ…ฌ็ฝ‘็™ฝๅๅ•ๅš MySQL ๅคๅˆถ๏ผŒๅฝ“ๆ—ถ็š„ `hifast-mysql-prod` ไปไพ่ต– `hifast-hk-private-1b` ไธดๆ—ถๆŒ‚ๅ…ฌ็ฝ‘่ทฏ็”ฑ + +ๅฝ“ๅ‰ๅทฒๅ‡†ๅค‡ๅฅฝ็š„ๆ”ถๆ•›่ต„ๆบ๏ผš + +- ็บฏๅ…ฌ็ฝ‘ DB subnet group: + - `hifast-hk-rds-public-only-sgprep` +- ๅฎ‰ๅ…จ็ป„๏ผš + - `hifast-hk-rds-core-sg` + +## 2. ็›ฎๆ ‡ๅฎžไพ‹ๅ‚ๆ•ฐ + +ๅปบ่ฎฎๆ–ฐๅฎžไพ‹ๅ็งฐ๏ผš + +- `hifast-mysql-prod-v2` + +ๅปบ่ฎฎๅ‚ๆ•ฐๅฆ‚ไธ‹๏ผš + +- Region: `ap-east-1` +- Engine: `MySQL` +- Engine version: `8.4.8` +- Templates: `Production` +- DB instance class: `db.r7g.xlarge` +- Storage type: `gp3` +- Allocated storage: `200 GiB` +- Provisioned IOPS: `3000` +- Storage throughput: `125` +- Multi-AZ: `No` +- Publicly accessible: `Yes` +- VPC: `vpc-09fc384522517debc` +- DB subnet group: `hifast-hk-rds-public-only-sgprep` +- VPC security group: `hifast-hk-rds-core-sg` +- DB name: `hifast` +- Master username: `admin` +- Master password: ไธŽ็Žฐ็ฝ‘ไฟๆŒไธ€่‡ด +- Backup retention: `7 days` +- Performance Insights: `On` +- Storage encryption: `On` +- Deletion protection: `On` +- Auto minor version upgrade: ๅปบ่ฎฎไฟๆŒไธŽ็Žฐ็ฝ‘ไธ€่‡ด +- Maintenance window: ๅฏไธŽ็Žฐ็ฝ‘ๅŒ็ญ–็•ฅ๏ผŒๅปบ่ฎฎ็ปดๆŠค็ช—ๅฃๅ†…ๅˆ‡ๆข + +## 3. ๅˆ‡ๆขๅ‰็กฎ่ฎค + +ๅˆ‡ๆขๅ‰ๅฟ…้กปๆปก่ถณ๏ผš + +1. `104` ๅฝ“ๅ‰ไธปไปŽๆญฃๅธธ๏ผš + - `Replica_IO_Running: Yes` + - `Replica_SQL_Running: Yes` + - `Seconds_Behind_Source: 0` +2. AWS ๅบ”็”จๆœบๅฟƒ่ทณๆญฃๅธธ๏ผš + - `curl http://127.0.0.1:8080/v1/common/heartbeat` +3. AWS Redis ไธปไปŽๆญฃๅธธ๏ผš + - AWS ไธป `connected_slaves:1` + - `104` ไปŽ `master_link_status:up` +4. ๅทฒ็กฎ่ฎคๅฝ“ๅ‰ๅบ”็”จ็œŸๅฎž้…็ฝฎๆ–‡ไปถ๏ผš + - `/opt/ppanel/configs/ppanel.yaml` +5. ๅทฒ็กฎ่ฎคๅฝ“ๅ‰ๅบ”็”จ้‡ๅฏๆ–นๅผ๏ผš + - `cd /opt/ppanel && docker compose -f docker-compose.cloud.yml up -d ppanel-server` + +## 4. ๅˆ›ๅปบๆ–ฐ RDS + +ๅทฒๅœจ AWS ๆŽงๅˆถๅฐๅˆ›ๅปบ `hifast-mysql-prod-v2`๏ผŒๆœชๅฏนๅŽŸ `hifast-mysql-prod` ๅš้ซ˜้ฃŽ้™ฉๅœจ็บฟๅญ็ฝ‘่ฐƒๆ•ดใ€‚ + +ๅˆ›ๅปบๅฎŒๆˆๅŽๅ…ˆ็กฎ่ฎค๏ผš + +1. ๆ–ฐ endpoint ๅทฒๅˆ†้… +2. `Publicly accessible = Yes` +3. SG ไธบ `hifast-hk-rds-core-sg` +4. DB subnet group ไธบ `hifast-hk-rds-public-only-sgprep` +5. ไปŽ `104` ๅฏไปฅ TCP ่ฟž้€š `3306` + +่ฟž้€šๆ€ง้ชŒ่ฏ๏ผš + +```bash +nc -zv 3306 +``` + +## 5. ๅฏผๅ‡บๆ—งไธปๅบ“ + +ๅœจไธ€ๅฐๅฏ่ฟžๆ—ง RDS ็š„ๆœบๅ™จๆ‰ง่กŒ๏ผš + +```bash +mysqldump \ + -h hifast-mysql-prod.cd6aey40m6ag.ap-east-1.rds.amazonaws.com \ + -u admin \ + -p \ + --single-transaction \ + --routines \ + --triggers \ + --events \ + --set-gtid-purged=OFF \ + hifast > hifast-full.sql +``` + +่ฏดๆ˜Ž๏ผš + +- ๅฝ“ๅ‰ไธšๅŠกๅบ“ไฝ“้‡็บฆ `187 MB` +- ่ฟ™ๆก่ทฏ็บฟ็š„ๆˆๆœฌไฝŽ๏ผŒไธ”ๆฏ”็Žฐ็ฝ‘ไธปๅบ“ๅœจ็บฟๆ”นๅญ็ฝ‘ๆ›ด็จณ + +## 6. ๅˆๅง‹ๅŒ–ๆ–ฐ RDS + +ๅ…ˆ่ฟžๆŽฅๆ–ฐ RDS๏ผš + +```bash +mysql -h -u admin -p +``` + +ๅปบ่ฎฎๅ…ˆๆ‰ง่กŒ๏ผš + +```sql +CALL mysql.rds_set_configuration('binlog retention hours', 24); + +CREATE USER IF NOT EXISTS 'repl'@'104.238.220.230' IDENTIFIED BY ''; +GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'repl'@'104.238.220.230'; +FLUSH PRIVILEGES; +``` + +ๅฆ‚ๆžœๅบ“ๆ˜ฏ็ฉบ็š„๏ผŒๅ†ๅฏผๅ…ฅ๏ผš + +```bash +mysql -h -u admin -p hifast < hifast-full.sql +``` + +ๅฏผๅ…ฅๅฎŒๆˆๅŽ็กฎ่ฎค๏ผš + +```bash +mysql -h -u admin -p -e "USE hifast; SHOW TABLES;" +``` + +## 7. ๅˆ‡ๆข AWS ๅบ”็”จๅˆฐๆ–ฐ RDS + +### 7.1 ๅค‡ไปฝๅฝ“ๅ‰้…็ฝฎ + +ๅœจ AWS app EC2๏ผš + +```bash +cp /opt/ppanel/configs/ppanel.yaml /opt/ppanel/configs/ppanel.yaml.bak.$(date +%Y%m%d%H%M%S) +``` + +### 7.2 ไฟฎๆ”นๆ•ฐๆฎๅบ“ๅœฐๅ€ + +็ผ–่พ‘๏ผš + +- `/opt/ppanel/configs/ppanel.yaml` + +ๆŠŠ๏ผš + +```yaml +MySQL: + Addr: hifast-mysql-prod.cd6aey40m6ag.ap-east-1.rds.amazonaws.com:3306 +``` + +ๆ”นๆˆ๏ผš + +```yaml +MySQL: + Addr: hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com:3306 +``` + +### 7.3 ้‡ๅฏไธšๅŠกๅฎนๅ™จ + +```bash +cd /opt/ppanel +docker compose -f docker-compose.cloud.yml up -d ppanel-server +``` + +### 7.4 ๅบ”็”จ้ชŒๆ”ถ + +```bash +curl -sf http://127.0.0.1:8080/v1/common/heartbeat +docker compose -f /opt/ppanel/docker-compose.cloud.yml logs --tail=100 ppanel-server +``` + +้‡็‚น็กฎ่ฎค๏ผš + +- ๅฟƒ่ทณ่ฟ”ๅ›ž `200` +- ๆ—ฅๅฟ—ไธญๆ—  MySQL ่ฟžๆŽฅๅผ‚ๅธธ + +## 8. ๆ”นๆŒ‚ `104` ไปŽๅบ“ๅˆฐๆ–ฐ RDS + +ๅ…ˆๅœจๆ–ฐ RDS ่Žทๅ–ไฝ็‚น๏ผš + +```sql +SHOW MASTER STATUS; +``` + +็„ถๅŽๅœจ `104` ๆ‰ง่กŒ๏ผš + +```sql +STOP REPLICA; +RESET REPLICA ALL; +CHANGE REPLICATION SOURCE TO + SOURCE_HOST='hifast-mysql-prod-v2.cd6aey40m6ag.ap-east-1.rds.amazonaws.com', + SOURCE_PORT=3306, + SOURCE_USER='repl', + SOURCE_PASSWORD='', + SOURCE_LOG_FILE='', + SOURCE_LOG_POS=, + SOURCE_SSL=1; +START REPLICA; +SHOW REPLICA STATUS\G +``` + +้ชŒๆ”ถๆ ‡ๅ‡†๏ผš + +- `Replica_IO_Running: Yes` +- `Replica_SQL_Running: Yes` +- `Seconds_Behind_Source: 0` + +## 9. ๅˆ‡ๆขๅŽ้ชŒๆ”ถ + +่‡ณๅฐ‘ๅšไธ‹้ข่ฟ™ไบ›ๆฃ€ๆŸฅ๏ผš + +1. AWS ๅบ”็”จๅฟƒ่ทณๆญฃๅธธ +2. ็ฎก็†ๅŽๅฐๅฏ็™ปๅฝ• +3. ๆ–ฐๅปบไธ€ๆกๆต‹่ฏ•ๆ•ฐๆฎๅŽ๏ผŒไธปๅบ“ๅฏ่ง +4. `104` ไปŽๅบ“่ƒฝๅŒๆญฅๅˆฐ่ฏฅๆต‹่ฏ•ๆ•ฐๆฎ +5. Navicat ๅฏไปŽ็™ฝๅๅ•ๆฅๆบ่ฟžๆŽฅๆ–ฐ RDS +6. Redis ไธปไปŽไปๆญฃๅธธ๏ผŒไธๅ—ๆœฌๆฌก MySQL ๅˆ‡ๆขๅฝฑๅ“ + +ๆŽจ่้ขๅค–ๆ ธๅฏน๏ผš + +```bash +docker compose -f /opt/ppanel/docker-compose.cloud.yml ps +docker exec hifast-redis redis-cli -a '' INFO replication +``` + +## 10. ๅ›žๆปšๆ–นๆกˆ + +ๅฆ‚ๆžœๅˆ‡ๆขๅŽ AWS ๅบ”็”จๅผ‚ๅธธ๏ผš + +1. ็ซ‹ๅˆปๆŠŠ `/opt/ppanel/configs/ppanel.yaml` ไธญ `MySQL.Addr` ๆ”นๅ›žๆ—ง endpoint +2. ้‡ๅฏ `ppanel-server`๏ผš + +```bash +cd /opt/ppanel +docker compose -f docker-compose.cloud.yml up -d ppanel-server +``` + +3. ไผ˜ๅ…ˆๆขๅคไธป็”Ÿไบงๅฏ็”จ +4. `104` ๆ˜ฏๅฆๅ›žๅˆ‡ๆ—ง RDS ๅคๅˆถ๏ผŒ่ง†ๆขๅค็ช—ๅฃๅ†ณๅฎš + +ๅฆ‚ๆžœๅชๆ˜ฏ `104` ๅคๅˆถๆ”นๆŒ‚ๅคฑ่ดฅ๏ผŒไฝ† AWS ๅบ”็”จๅทฒๆญฃๅธธไฝฟ็”จๆ–ฐ RDS๏ผš + +- ไธๅฟ…็ซ‹ๅˆปๅ›žๆปšๅบ”็”จ +- ๅ…ˆไฟฎๅฅฝ `104 -> ๆ–ฐ RDS` ็š„็™ฝๅๅ•ใ€ไฝ็‚นใ€็”จๆˆทๆˆ–็ฝ‘็ปœ + +## 11. ๅˆ‡ๆขๅฎŒๆˆๅŽ็š„ๆ”ถๅฐพ + +ๅ…จ้ƒจ้ชŒๆ”ถ้€š่ฟ‡ๅŽๅ†ๅš๏ผš + +1. ๅทฒๅฐ†ๆ–ฐ endpoint ่ฎฐๅฝ•ๅˆฐๆญฃๅผ่ฟ็ปดๆ–‡ๆกฃ +2. ไป้œ€ๆ นๆฎๅ›žๆ”ถ็ช—ๅฃๅฎ‰ๆŽ’ๆ—ง RDS ไธ‹็บฟ +3. ไป้œ€ๆŒ‰็ฝ‘็ปœๆ”ถๆ•›่ฎกๅˆ’ๅค„็† `private-1b` ่ทฏ็”ฑ่ฏญไน‰ +4. ๅทฒๆ›ดๆ–ฐๅค–้ƒจๅคๅˆถ runbook ไธญ็š„ไธปๅบ“ endpoint + +## 12. ๅฝ“ๅ‰ๅปบ่ฎฎ็š„ๆ‰ง่กŒ้กบๅบ + +ๆœฌๆฌกๅˆ‡ๆขๅฝ“ๆ—ถๆŒ‰ไปฅไธ‹้กบๅบๆ‰ง่กŒ๏ผš + +1. ๅˆ›ๅปบ `hifast-mysql-prod-v2` +2. ้ชŒ่ฏๆ–ฐ RDS ็ฝ‘็ปœไธŽๅ‚ๆ•ฐ +3. ๅฏผๅ‡บๆ—งๅบ“ +4. ๅฏผๅ…ฅๆ–ฐๅบ“ +5. ๅˆ›ๅปบ / ็กฎ่ฎค `repl` ็”จๆˆท +6. ๅˆ‡ AWS ๅบ”็”จๅˆฐๆ–ฐ RDS +7. ้ชŒ่ฏๅบ”็”จ +8. ๆ”นๆŒ‚ `104` ๅˆฐๆ–ฐ RDS +9. ้ชŒ่ฏไปŽๅบ“ +10. ๆ”ถๅฐพ๏ผŒๅนถไฟ็•™ๆ—ง RDS ๅพ…ๅŽ็ปญไธ‹็บฟ diff --git a/ops/hifast-s3-backup-runbook-zh.md b/ops/hifast-s3-backup-runbook-zh.md new file mode 100644 index 0000000..8972691 --- /dev/null +++ b/ops/hifast-s3-backup-runbook-zh.md @@ -0,0 +1,275 @@ +# Hifast S3 ๅค‡ไปฝ้›†ๆˆ Runbook + +ๆœฌๆ–‡ๆกฃ่ฎฐๅฝ• `2026-05-13` ๅทฒ็ปๅฎž้™…็กฎ่ฎคๅ’ŒๅฎŒๆˆ็š„ S3 ๅค‡ไปฝ้›†ๆˆ็Šถๆ€๏ผŒไปฅๅŠๅŽ็ปญๅฆ‚ไฝ•ๆŠŠๅฎƒๅ’Œๅฝ“ๅ‰ `AWS ไธป็”Ÿไบง + 104 ๅค–้ƒจๅค‡็”จ` ๆžถๆž„็ป“ๅˆ่ตทๆฅใ€‚ + +## 1. ๅฝ“ๅ‰ๅทฒๅฎŒๆˆ็Šถๆ€ + +- ๅทฒๅˆ›ๅปบ S3 ๅค‡ไปฝๆกถ๏ผš`hifast-prod-backups-200810848252-ap-east-1` +- Region: `ap-east-1` +- Public access: blocked +- Versioning: enabled +- ๅทฒ็กฎ่ฎค RDS ไธปๅบ“ `hifast-mysql-prod-v2` ่‡ชๅŠจๅค‡ไปฝๅทฒๅฏ็”จ๏ผš + - retention: `7 days` + - `2026-05-13` ๅทฒๆœ‰่‡ชๅŠจๅฟซ็…ง +- ๅทฒ็กฎ่ฎค `104.238.220.230` MySQL ๅค–้ƒจไปŽๅบ“ๅฅๅบท๏ผŒๅฏไฝœไธบ้€ป่พ‘ๅค‡ไปฝๆบ๏ผš + - `Replica_IO_Running: Yes` + - `Replica_SQL_Running: Yes` + - `Seconds_Behind_Source: 0` +- ๅทฒ็กฎ่ฎค `104.238.220.230` Redis ไปŽๅบ“ๅฅๅบท๏ผŒๅฏไฝœไธบ RDB ๅค‡ไปฝๆบ๏ผš + - `role:slave` + - `master_link_status:up` + +## 2. ๆŽจ่็ป„ๅˆๆ–นๆกˆ + +ๅฝ“ๅ‰ๆœ€็จณ็š„ๅšๆณ•ไธๆ˜ฏๅชไพ่ต–ไธ€็งๅค‡ไปฝ๏ผŒ่€Œๆ˜ฏไฟ็•™ไธคๅฑ‚๏ผš + +1. `RDS automated backup` +2. `104` ไปŽๅบ“ๅฏผๅ‡บ็š„้€ป่พ‘ๅค‡ไปฝไธŠไผ ๅˆฐ S3 + +ๅŽŸๅ› ๏ผš + +- RDS ่‡ชๅŠจๅค‡ไปฝ้€‚ๅˆๅฟซ้€Ÿๆขๅคๆ•ดๅบ“ +- S3 ้€ป่พ‘ๅค‡ไปฝ้€‚ๅˆ็‹ฌ็ซ‹ไธ‹่ฝฝใ€่ทจ็Žฏๅขƒๆขๅคใ€้•ฟๆœŸๅฝ’ๆกฃ +- ไปŽ `104` ๅฏผๅ‡บ MySQL / Redis ๅค‡ไปฝ๏ผŒๅฏน AWS ไธป็”Ÿไบงๆ‰ฐๅŠจๆœ€ๅฐ + +## 3. ไป“ๅบ“ๅทฒ่กฅๅ……ๅ†…ๅฎน + +- MySQL ๅค‡ไปฝ่„šๆœฌ๏ผš + - [`deploy/scripts/mysql_backup_to_s3.sh`](/Users/Apple/code_vpn/vpn/ppanel-server/deploy/scripts/mysql_backup_to_s3.sh) +- Redis RDB ๅค‡ไปฝ่„šๆœฌ๏ผš + - [`deploy/scripts/redis_rdb_backup_to_s3.sh`](/Users/Apple/code_vpn/vpn/ppanel-server/deploy/scripts/redis_rdb_backup_to_s3.sh) +- ็Žฏๅขƒๅ˜้‡ๆจกๆฟ๏ผš + - [`deploy/aws/ap-east-1/configs/backup-to-s3.env.example`](/Users/Apple/code_vpn/vpn/ppanel-server/deploy/aws/ap-east-1/configs/backup-to-s3.env.example) +- ไธปไปŽๅˆ‡ๆข็Žฏๅขƒๅ˜้‡ๆจกๆฟ๏ผš + - [`deploy/aws/ap-east-1/configs/replica-ops.env.example`](/Users/Apple/code_vpn/vpn/ppanel-server/deploy/aws/ap-east-1/configs/replica-ops.env.example) +- ๆ•ฐๆฎ่ฟ็งปไบคไบ’ๅทฅๅ…ท๏ผš + - [`deploy/scripts/hifast_data_sync_tool.sh`](/Users/Apple/code_vpn/vpn/ppanel-server/deploy/scripts/hifast_data_sync_tool.sh) +- ไธปไปŽ่ฟ็ปดไบคไบ’ๅทฅๅ…ท๏ผš + - ็ปŸไธ€ๅ…ฅๅฃไปไฝฟ็”จ [`deploy/scripts/hifast_data_sync_tool.sh`](/Users/Apple/code_vpn/vpn/ppanel-server/deploy/scripts/hifast_data_sync_tool.sh) + +## 4. ๅปบ่ฎฎ้ƒจ็ฝฒไฝ็ฝฎ + +### 4.1 MySQL + +ไผ˜ๅ…ˆ้ƒจ็ฝฒๅœจ `104.238.220.230`๏ผš + +- ็›ดๆŽฅไปŽๆœฌๅœฐ MySQL ไปŽๅบ“ๅฏผๅ‡บ +- ไธๅ ็”จ AWS RDS ไธปๅบ“็š„ๅค‡ไปฝ็ช—ๅฃ +- ๆ•…้šœๆ—ถๅค‡ไปฝๅ’Œๅค‡็”จ่Š‚็‚นไปๅœจๅŒไธ€ๅฐๆœบๅ™จไธŠ + +### 4.2 Redis + +ไผ˜ๅ…ˆ้ƒจ็ฝฒๅœจ `104.238.220.230`๏ผš + +- ็›ดๆŽฅไปŽ Redis ไปŽๅบ“ๅฏผๅ‡บ `RDB` +- ไธๅฝฑๅ“ AWS Redis ไธปๅบ“ๅฏนๅค–ๆœๅŠก + +## 5. 104 ๅฝ“ๅ‰่ฟ˜็ผบ็š„ไธœ่ฅฟ + +ๆˆช่‡ณ `2026-05-13`๏ผŒ`104` ๅทฒๅ…ทๅค‡๏ผš + +- `mysql` +- `mysqldump` +- `gzip` + +ไฝ†ไป็ผบ๏ผš + +- `aws cli` +- ไธ€ๅฅ—ๆœ€ๅฐๆƒ้™็š„ S3 ไธŠไผ ๅ‡ญ่ฏ + +## 6. ๆŽจ่ๆƒ้™ๆจกๅž‹ + +ๅฝ“ๅ‰ๆœ€ๅฎž็”จ็š„้€‰ๆ‹ฉๆœ‰ไธค็ง๏ผš + +1. `104` ไฝฟ็”จไธ“็”จ IAM ็”จๆˆท็š„ๆœ€ๅฐๆƒ้™ `AK/SK` +2. ๆœชๆฅๅฆ‚ๆžœๅค‡ไปฝ่ฝฌๅˆฐ AWS EC2๏ผŒๅ†ๆ”นไธบ `EC2 Instance Role` + +ๆŒ‰็Žฐๆœ‰ๆ‹“ๆ‰‘๏ผŒๆŽจ่ๅ…ˆ่ตฐ็ฌฌ 1 ็ง๏ผŒๅ› ไธบ MySQL ๅ’Œ Redis ็š„ๅค‡ไปฝๆบ้ƒฝๅœจ `104`ใ€‚ + +### 6.1 ๆœ€ๅฐๆƒ้™็ญ–็•ฅ็คบไพ‹ + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "ListBackupBucket", + "Effect": "Allow", + "Action": [ + "s3:ListBucket" + ], + "Resource": "arn:aws:s3:::hifast-prod-backups-200810848252-ap-east-1" + }, + { + "Sid": "WriteBackupObjects", + "Effect": "Allow", + "Action": [ + "s3:PutObject", + "s3:AbortMultipartUpload" + ], + "Resource": "arn:aws:s3:::hifast-prod-backups-200810848252-ap-east-1/*" + } + ] +} +``` + +่ฏดๆ˜Ž๏ผš + +- ไธๅปบ่ฎฎ็ป™ `s3:*` +- ไธๅปบ่ฎฎๆŠŠ AK/SK ๅ†™่ฟ› repo +- ๅปบ่ฎฎๅชๅ†™ๅ…ฅ `104` ๆœฌๆœบ็š„ `/root/.aws/credentials` + +## 7. 104 ๅฎ‰่ฃ…ไธŽ้…็ฝฎๆญฅ้ชค + +### 7.1 ๅฎ‰่ฃ… `aws cli` + +```bash +apt-get update +apt-get install -y awscli +``` + +### 7.2 ๅ†™ๅ…ฅ AWS ๅ‡ญ่ฏ + +```bash +mkdir -p /root/.aws +chmod 700 /root/.aws +cat >/root/.aws/credentials <<'EOF' +[default] +aws_access_key_id=CHANGE_ME +aws_secret_access_key=CHANGE_ME +EOF +chmod 600 /root/.aws/credentials +``` + +### 7.3 ๅ‡†ๅค‡็Žฏๅขƒๅ˜้‡ๆ–‡ไปถ + +```bash +cp deploy/aws/ap-east-1/configs/backup-to-s3.env.example /root/backup-to-s3.env +chmod 600 /root/backup-to-s3.env +``` + +ๆŠŠไธ‹้ข่ฟ™ไบ›ๅ€ผๆ”นๆˆ็œŸๅฎžๅ€ผ๏ผš + +- `MYSQL_PASSWORD` +- `REDIS_PASSWORD` +- `HOST_TAG` + +ๅฆ‚ๆžœ MySQL ๅฐฑ่ท‘ๅœจ `104` ๆœฌๆœบ๏ผŒๅฏไฟๆŒ๏ผš + +- `MYSQL_HOST=127.0.0.1` + +ๅฆ‚ๆžœ Redis ๅฐฑ่ท‘ๅœจ `104` ๆœฌๆœบ๏ผŒๅฏไฟๆŒ๏ผš + +- `REDIS_HOST=127.0.0.1` + +## 8. ๆ‰‹ๅทฅๆ‰ง่กŒๆ–นๅผ + +### 8.1 MySQL ้€ป่พ‘ๅค‡ไปฝ + +```bash +set -a +source /root/backup-to-s3.env +set +a + +bash deploy/scripts/mysql_backup_to_s3.sh +``` + +้ป˜่ฎคไบง็‰ฉ๏ผš + +- ๆœฌๅœฐ๏ผš`/var/backups/hifast/*.sql.gz` +- S3๏ผš`s3://hifast-prod-backups-200810848252-ap-east-1/mysql//` + +### 8.2 Redis RDB ๅค‡ไปฝ + +```bash +set -a +source /root/backup-to-s3.env +set +a + +S3_PREFIX=redis bash deploy/scripts/redis_rdb_backup_to_s3.sh +``` + +้ป˜่ฎคไบง็‰ฉ๏ผš + +- ๆœฌๅœฐ๏ผš`/var/backups/hifast/*.rdb.gz` +- S3๏ผš`s3://hifast-prod-backups-200810848252-ap-east-1/redis//` + +## 9. ๅฎšๆ—ถไปปๅŠกๅปบ่ฎฎ + +### 9.1 MySQL ๆฏๅคฉๅ‡Œๆ™จๆ‰ง่กŒ + +```cron +15 3 * * * . /root/backup-to-s3.env && /bin/bash /opt/ppanel/deploy/scripts/mysql_backup_to_s3.sh >>/var/log/hifast-mysql-backup.log 2>&1 +``` + +### 9.2 Redis ๆฏๅคฉๅ‡Œๆ™จๆ‰ง่กŒ + +```cron +45 3 * * * . /root/backup-to-s3.env && S3_PREFIX=redis /bin/bash /opt/ppanel/deploy/scripts/redis_rdb_backup_to_s3.sh >>/var/log/hifast-redis-backup.log 2>&1 +``` + +่ฏดๆ˜Ž๏ผš + +- MySQL ๅ’Œ Redis ๅปบ่ฎฎ้”™ๅณฐๆ‰ง่กŒ +- ๆœฌๅœฐไธดๆ—ถๆ–‡ไปถ้ป˜่ฎคๅชไฟ็•™ `3` ๅคฉ +- ้•ฟๆœŸไฟ็•™ๅปบ่ฎฎ้€š่ฟ‡ S3 Lifecycle ็ฎก็†๏ผŒ่€Œไธๆ˜ฏ้ ๆœฌๆœบ cron ๅˆ ้™ค + +## 10. ๆขๅคๆ€่ทฏ + +### 10.1 MySQL + +1. ไปŽ S3 ไธ‹่ฝฝ็›ฎๆ ‡ `sql.gz` +2. ๆ ก้ชŒ `.sha256` +3. ่งฃๅŽ‹ +4. ๅฏผๅ…ฅ็›ฎๆ ‡ MySQL + +็คบไพ‹๏ผš + +```bash +aws s3 cp s3://hifast-prod-backups-200810848252-ap-east-1/mysql/104-standby/20260513T120000Z_104-standby_hifast.sql.gz . +aws s3 cp s3://hifast-prod-backups-200810848252-ap-east-1/mysql/104-standby/20260513T120000Z_104-standby_hifast.sql.gz.sha256 . +sha256sum -c 20260513T120000Z_104-standby_hifast.sql.gz.sha256 +gunzip -c 20260513T120000Z_104-standby_hifast.sql.gz | mysql -h -u -p +``` + +### 10.2 Redis + +1. ไปŽ S3 ไธ‹่ฝฝ็›ฎๆ ‡ `rdb.gz` +2. ๆ ก้ชŒ `.sha256` +3. ่งฃๅŽ‹ๅพ—ๅˆฐ `dump.rdb` +4. ๅœจ็ปดๆŠค็ช—ๅฃๅ†…ๆ›ฟๆข Redis ๆ•ฐๆฎๆ–‡ไปถๅŽ้‡ๅฏ + +## 11. ๅฝ“ๅ‰ๆŽจ่่ฝๅœฐ้กบๅบ + +1. ไฟๆŒๅฝ“ๅ‰ `RDS automated backup` ไธๅ˜ +2. ๅœจ `104` ๅฎ‰่ฃ… `aws cli` +3. ๅˆ›ๅปบๆœ€ๅฐๆƒ้™ S3 ไธŠไผ ๅ‡ญ่ฏๅนถไป…ไฟๅญ˜ๅˆฐ `104` +4. ๅ…ˆๆ‰‹ๅทฅๆ‰ง่กŒไธ€่ฝฎ MySQL ๅค‡ไปฝไธŠไผ  +5. ้ชŒ่ฏ S3 ๅฏน่ฑกใ€ๆ ก้ชŒๆ–‡ไปถใ€ๆขๅคๅฏ่ฏปๆ€ง +6. ๅ†่กฅ Redis RDB ๅค‡ไปฝ +7. ๆœ€ๅŽๅŠ  cron ๅ’Œ S3 Lifecycle + +## 12. 104 ไธŠ็š„ไบคไบ’ๅผ่ฟ็ปด่„šๆœฌ + +ไธบไบ†ๅ‡ๅฐ‘ๆ‰‹ๅทฅๆ•ฒๅ‘ฝไปค๏ผŒไป“ๅบ“้‡Œ็Žฐๅœจ็ปŸไธ€ไฝฟ็”จไธ€ๅฅ—ไบคไบ’ๅผๆ€ปๅ…ฅๅฃใ€‚ + +### 12.1 ็ปŸไธ€ๅ…ฅๅฃ + +```bash +bash deploy/scripts/hifast_data_sync_tool.sh /root/replica-ops.env +``` + +่œๅ•ๆ”ฏๆŒ๏ผš + +- ๅค‡ไปฝ MySQL ๅˆฐ S3 +- ๅค‡ไปฝ Redis ๅˆฐ S3 +- ๅฏผๅ‡บ MySQL dump +- ๅฏผๅ…ฅ MySQL dump ๅˆฐ AWS RDS +- ๅฏผๅ‡บๅŽ็›ดๆŽฅๅฏผๅ…ฅ +- ๅฏผๅ‡บ Redis RDB +- ๅฏผๅ…ฅ Redis RDB ๅˆฐ Docker / ๅฎฟไธปๆœบ Redis +- ๆŸฅ็œ‹ MySQL / Redis ๅฝ“ๅ‰ไธปไปŽ็Šถๆ€ +- ๅผบๅˆถ้‡ๆ‹‰ MySQL ไธปไปŽ +- ๅผบๅˆถ้‡ๆ‹‰ Redis ไธปไปŽ +- ๆŠŠ MySQL ไปŽๅบ“ๆๅ‡ไธบๅฏๅ†™ไธปๅบ“ +- ๆŠŠ Redis ไปŽๅบ“ๆๅ‡ไธบไธปๅบ“ diff --git a/pkg/cache/gorm_test.go b/pkg/cache/gorm_test.go deleted file mode 100644 index c090771..0000000 --- a/pkg/cache/gorm_test.go +++ /dev/null @@ -1,183 +0,0 @@ -package cache - -import ( - "context" - "encoding/json" - "errors" - "testing" - "time" - - "github.com/alicebob/miniredis/v2" - "github.com/redis/go-redis/v9" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "gorm.io/driver/sqlite" - "gorm.io/gorm" -) - -// testUser is a simple struct used across all QueryCtx tests. -type testUser struct { - ID int64 `json:"id"` - Name string `json:"name"` -} - -// setupCachedConn creates a CachedConn backed by a real miniredis instance -// and a bare *gorm.DB (no real database connection needed because the -// QueryCtxFn callback is fully under our control). -func setupCachedConn(t *testing.T) (CachedConn, *miniredis.Miniredis) { - t.Helper() - - mr := miniredis.RunT(t) - - rdb := redis.NewClient(&redis.Options{ - Addr: mr.Addr(), - }) - t.Cleanup(func() { rdb.Close() }) - - // Use SQLite in-memory to get a properly initialized *gorm.DB. - db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{}) - require.NoError(t, err) - - cc := NewConn(db, rdb, WithExpiry(time.Minute)) - return cc, mr -} - -func TestQueryCtx_CacheHit(t *testing.T) { - cc, mr := setupCachedConn(t) - ctx := context.Background() - key := "cache:user:1" - - // Pre-populate the cache with valid JSON. - expected := testUser{ID: 1, Name: "Alice"} - data, err := json.Marshal(expected) - require.NoError(t, err) - mr.Set(key, string(data)) - - // Track whether the DB query function is called. - dbCalled := false - queryFn := func(conn *gorm.DB, v interface{}) error { - dbCalled = true - return nil - } - - var result testUser - err = cc.QueryCtx(ctx, &result, key, queryFn) - - assert.NoError(t, err) - assert.False(t, dbCalled, "DB query should NOT be called on cache hit") - assert.Equal(t, expected.ID, result.ID) - assert.Equal(t, expected.Name, result.Name) -} - -func TestQueryCtx_CacheMiss_QueriesDB_SetsCache(t *testing.T) { - cc, mr := setupCachedConn(t) - ctx := context.Background() - key := "cache:user:2" - - // Do NOT pre-populate the cache -- this is a cache miss scenario. - dbCalled := false - queryFn := func(conn *gorm.DB, v interface{}) error { - dbCalled = true - u := v.(*testUser) - u.ID = 2 - u.Name = "Bob" - return nil - } - - var result testUser - err := cc.QueryCtx(ctx, &result, key, queryFn) - - assert.NoError(t, err) - assert.True(t, dbCalled, "DB query should be called on cache miss") - assert.Equal(t, int64(2), result.ID) - assert.Equal(t, "Bob", result.Name) - - // Verify the value was written back to cache. - cached, cacheErr := mr.Get(key) - require.NoError(t, cacheErr) - - var cachedUser testUser - require.NoError(t, json.Unmarshal([]byte(cached), &cachedUser)) - assert.Equal(t, int64(2), cachedUser.ID) - assert.Equal(t, "Bob", cachedUser.Name) -} - -func TestQueryCtx_CorruptedCache_SelfHeals(t *testing.T) { - cc, mr := setupCachedConn(t) - ctx := context.Background() - key := "cache:user:3" - - // Store invalid JSON in the cache to simulate corruption. - mr.Set(key, "THIS IS NOT VALID JSON{{{") - - dbCalled := false - queryFn := func(conn *gorm.DB, v interface{}) error { - dbCalled = true - u := v.(*testUser) - u.ID = 3 - u.Name = "Charlie" - return nil - } - - var result testUser - err := cc.QueryCtx(ctx, &result, key, queryFn) - - assert.NoError(t, err) - assert.True(t, dbCalled, "DB query should be called when cache is corrupted") - assert.Equal(t, int64(3), result.ID) - assert.Equal(t, "Charlie", result.Name) - - // Verify the corrupt key was replaced with valid data. - cached, cacheErr := mr.Get(key) - require.NoError(t, cacheErr) - - var cachedUser testUser - require.NoError(t, json.Unmarshal([]byte(cached), &cachedUser)) - assert.Equal(t, int64(3), cachedUser.ID) - assert.Equal(t, "Charlie", cachedUser.Name) -} - -func TestQueryCtx_CacheMiss_DBFails_ReturnsError(t *testing.T) { - cc, mr := setupCachedConn(t) - ctx := context.Background() - key := "cache:user:4" - - // No cache entry -- this is a miss. - dbErr := errors.New("connection refused") - queryFn := func(conn *gorm.DB, v interface{}) error { - return dbErr - } - - var result testUser - err := cc.QueryCtx(ctx, &result, key, queryFn) - - assert.Error(t, err) - assert.Equal(t, dbErr, err) - - // Cache should remain empty -- no value was written. - assert.False(t, mr.Exists(key), "cache should NOT be set when DB query fails") -} - -func TestQueryCtx_CorruptedCache_DBFails_ReturnsError(t *testing.T) { - cc, mr := setupCachedConn(t) - ctx := context.Background() - key := "cache:user:5" - - // Store invalid JSON to trigger the corruption branch. - mr.Set(key, "<<>>") - - dbErr := errors.New("database is down") - queryFn := func(conn *gorm.DB, v interface{}) error { - return dbErr - } - - var result testUser - err := cc.QueryCtx(ctx, &result, key, queryFn) - - assert.Error(t, err) - assert.Equal(t, dbErr, err) - - // The corrupt key should have been deleted (DelCache was called), - // and no new value was set because the DB query failed. - assert.False(t, mr.Exists(key), "corrupt key should be deleted even when DB fails") -} diff --git a/pkg/storage/s3.go b/pkg/storage/s3.go new file mode 100644 index 0000000..3306496 --- /dev/null +++ b/pkg/storage/s3.go @@ -0,0 +1,128 @@ +package storage + +import ( + "context" + "fmt" + "net/url" + "strings" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + awsconfig "github.com/aws/aws-sdk-go-v2/config" + "github.com/aws/aws-sdk-go-v2/credentials" + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/aws-sdk-go-v2/service/s3/types" + "github.com/perfect-panel/server/internal/config" +) + +type PresignUploadResult struct { + URL string + Method string + ExpiresAt int64 +} + +type ObjectMeta struct { + ETag string + ContentType string + ContentLength int64 +} + +type S3Store struct { + cfg config.S3Config + client *s3.Client + presign *s3.PresignClient +} + +func NewS3Store(ctx context.Context, cfg config.S3Config) (*S3Store, error) { + loaders := make([]func(*awsconfig.LoadOptions) error, 0, 3) + if cfg.Region != "" { + loaders = append(loaders, awsconfig.WithRegion(cfg.Region)) + } + if cfg.AccessKey != "" || cfg.SecretKey != "" || cfg.SessionToken != "" { + loaders = append(loaders, awsconfig.WithCredentialsProvider( + credentials.NewStaticCredentialsProvider(cfg.AccessKey, cfg.SecretKey, cfg.SessionToken), + )) + } + + awsCfg, err := awsconfig.LoadDefaultConfig(ctx, loaders...) + if err != nil { + return nil, err + } + + client := s3.NewFromConfig(awsCfg, func(o *s3.Options) { + o.UsePathStyle = cfg.UsePathStyle + if cfg.Endpoint != "" { + o.BaseEndpoint = aws.String(cfg.Endpoint) + } + }) + + return &S3Store{ + cfg: cfg, + client: client, + presign: s3.NewPresignClient(client), + }, nil +} + +func (s *S3Store) PresignPutObject(ctx context.Context, objectKey string, contentType string, expires time.Duration) (*PresignUploadResult, error) { + req, err := s.presign.PresignPutObject(ctx, &s3.PutObjectInput{ + Bucket: aws.String(s.cfg.Bucket), + Key: aws.String(objectKey), + ContentType: aws.String(contentType), + }, s3.WithPresignExpires(expires)) + if err != nil { + return nil, err + } + + return &PresignUploadResult{ + URL: req.URL, + Method: req.Method, + ExpiresAt: time.Now().Add(expires).Unix(), + }, nil +} + +func (s *S3Store) HeadObject(ctx context.Context, objectKey string) (*ObjectMeta, error) { + resp, err := s.client.HeadObject(ctx, &s3.HeadObjectInput{ + Bucket: aws.String(s.cfg.Bucket), + Key: aws.String(objectKey), + }) + if err != nil { + return nil, err + } + + return &ObjectMeta{ + ETag: strings.Trim(aws.ToString(resp.ETag), "\""), + ContentType: aws.ToString(resp.ContentType), + ContentLength: aws.ToInt64(resp.ContentLength), + }, nil +} + +func (s *S3Store) BuildObjectURL(objectKey string) string { + if s.cfg.PublicBaseURL != "" { + return strings.TrimRight(s.cfg.PublicBaseURL, "/") + "/" + strings.TrimLeft(objectKey, "/") + } + + if s.cfg.Endpoint != "" { + base := strings.TrimRight(s.cfg.Endpoint, "/") + return fmt.Sprintf("%s/%s/%s", base, url.PathEscape(s.cfg.Bucket), strings.TrimLeft(objectKey, "/")) + } + + return fmt.Sprintf("https://%s.s3.%s.amazonaws.com/%s", s.cfg.Bucket, s.cfg.Region, strings.TrimLeft(objectKey, "/")) +} + +func (s *S3Store) PutJSONTagging(ctx context.Context, objectKey string, values map[string]string) error { + tagging := make([]types.Tag, 0, len(values)) + for k, v := range values { + key := k + value := v + tagging = append(tagging, types.Tag{Key: &key, Value: &value}) + } + + _, err := s.client.PutObjectTagging(ctx, &s3.PutObjectTaggingInput{ + Bucket: aws.String(s.cfg.Bucket), + Key: aws.String(objectKey), + Tagging: &types.Tagging{ + TagSet: tagging, + }, + }) + return err +} diff --git a/ppanel.api b/ppanel.api index 661a8c8..b6d8726 100644 --- a/ppanel.api +++ b/ppanel.api @@ -40,6 +40,8 @@ import ( "apis/public/ticket.api" "apis/public/payment.api" "apis/public/document.api" + "apis/public/file.api" "apis/public/portal.api" "apis/public/iap.api" ) + diff --git a/queue/logic/order/activateOrderLogic_invite_test.go b/queue/logic/order/activateOrderLogic_invite_test.go deleted file mode 100644 index 3b77679..0000000 --- a/queue/logic/order/activateOrderLogic_invite_test.go +++ /dev/null @@ -1,806 +0,0 @@ -package orderLogic - -import ( - "context" - "fmt" - "os" - "strings" - "testing" - "time" - - "github.com/perfect-panel/server/internal/config" - userLogic "github.com/perfect-panel/server/internal/logic/public/user" - modelLog "github.com/perfect-panel/server/internal/model/log" - "github.com/perfect-panel/server/internal/model/order" - "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/internal/types" - "github.com/perfect-panel/server/pkg/constant" - "github.com/redis/go-redis/v9" - "gorm.io/driver/mysql" - "gorm.io/gorm" -) - -// ๆ™ฎ้€š็”จๆˆท + ้ฆ–ๅ• โ†’ ๅŒๆ–น่ต Nๅคฉ -func TestHandleCommission_GrantGiftDaysWhenCommissionDisabled_FirstOrder(t *testing.T) { - logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{ - ReferralPercentage: 0, - OnlyFirstPurchase: false, - GiftDays: 2, - }) - defer cleanup() - - referee := seedUser(t, db, 0, false) - referer := seedUser(t, db, 0, false) - referee.RefererId = referer.Id - - baseExpire := time.Now().Add(72 * time.Hour).Truncate(time.Second) - refereeSub := seedActiveSubscribe(t, db, referee.Id, baseExpire) - refererSub := seedActiveSubscribe(t, db, referer.Id, baseExpire) - - logic.handleCommission(context.Background(), referee, &order.Order{ - OrderNo: "ORD-GIFT-001", - Type: OrderTypeSubscribe, - IsNew: true, // ้ฆ–ๅ• - Amount: 100, - FeeAmount: 0, - CreatedAt: time.Now(), - }) - - assertExpireIncreasedByDays(t, db, refereeSub.Id, baseExpire, 2) - assertExpireIncreasedByDays(t, db, refererSub.Id, baseExpire, 2) - - var giftCount int64 - if err := db.Model(&modelLog.SystemLog{}).Where("type = ?", modelLog.TypeGift.Uint8()).Count(&giftCount).Error; err != nil { - t.Fatalf("count gift logs failed: %v", err) - } - if giftCount != 2 { - t.Fatalf("expected 2 gift logs, got %d", giftCount) - } -} - -// ๆ™ฎ้€š็”จๆˆท + ้ž้ฆ–ๅ• โ†’ ไธ่ต ้€ -func TestHandleCommission_NoGiftDaysWhenCommissionDisabled_NotFirstOrder(t *testing.T) { - logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{ - ReferralPercentage: 0, - OnlyFirstPurchase: false, - GiftDays: 2, - }) - defer cleanup() - - referee := seedUser(t, db, 0, false) - referer := seedUser(t, db, 0, false) - referee.RefererId = referer.Id - - baseExpire := time.Now().Add(72 * time.Hour).Truncate(time.Second) - refereeSub := seedActiveSubscribe(t, db, referee.Id, baseExpire) - refererSub := seedActiveSubscribe(t, db, referer.Id, baseExpire) - - logic.handleCommission(context.Background(), referee, &order.Order{ - OrderNo: "ORD-GIFT-002", - Type: OrderTypeSubscribe, - IsNew: false, // ้ž้ฆ–ๅ• - Amount: 100, - FeeAmount: 0, - CreatedAt: time.Now(), - }) - - // ๅˆฐๆœŸๆ—ถ้—ดไธๅบ”ๅปถ้•ฟ - assertExpireIncreasedByDays(t, db, refereeSub.Id, baseExpire, 0) - assertExpireIncreasedByDays(t, db, refererSub.Id, baseExpire, 0) - - var giftCount int64 - if err := db.Model(&modelLog.SystemLog{}).Where("type = ?", modelLog.TypeGift.Uint8()).Count(&giftCount).Error; err != nil { - t.Fatalf("count gift logs failed: %v", err) - } - if giftCount != 0 { - t.Fatalf("expected 0 gift logs for non-first order, got %d", giftCount) - } -} - -// ๆธ ้“ + ้ฆ–ๅ• โ†’ ่ขซ้‚€่ฏทไบบ่ต Nๅคฉ + ้‚€่ฏทไบบ่Žทไฝฃ้‡‘ -func TestHandleCommission_GiftDaysAndCommissionWhenChannelFirstOrder(t *testing.T) { - logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{ - ReferralPercentage: 10, - OnlyFirstPurchase: false, - GiftDays: 2, - }) - defer cleanup() - - referee := seedUser(t, db, 0, false) - referer := seedUser(t, db, 0, false) - referee.RefererId = referer.Id - - baseExpire := time.Now().Add(96 * time.Hour).Truncate(time.Second) - refereeSub := seedActiveSubscribe(t, db, referee.Id, baseExpire) - - logic.handleCommission(context.Background(), referee, &order.Order{ - OrderNo: "ORD-COMM-001", - Type: OrderTypeSubscribe, - IsNew: true, // ้ฆ–ๅ• - Amount: 100, - FeeAmount: 0, - CreatedAt: time.Now(), - }) - - // ่ขซ้‚€่ฏทไบบ๏ผˆ้ฆ–ๅ•๏ผ‰ๅบ”่Žทๅพ—่ต ้€ๅคฉๆ•ฐ - assertExpireIncreasedByDays(t, db, refereeSub.Id, baseExpire, 2) - - // ้‚€่ฏทไบบๅบ”่Žทๅพ—ไฝฃ้‡‘ - var refererAfter user.User - if err := db.First(&refererAfter, referer.Id).Error; err != nil { - t.Fatalf("query referer failed: %v", err) - } - if refererAfter.Commission != 10 { - t.Fatalf("expected referer commission=10, got %d", refererAfter.Commission) - } - - var giftCount int64 - if err := db.Model(&modelLog.SystemLog{}).Where("type = ?", modelLog.TypeGift.Uint8()).Count(&giftCount).Error; err != nil { - t.Fatalf("count gift logs failed: %v", err) - } - if giftCount != 1 { - t.Fatalf("expected 1 gift log for referee on first order with commission, got %d", giftCount) - } -} - -// ๆธ ้“ + ้ž้ฆ–ๅ• โ†’ ๅช็ป™้‚€่ฏทไบบไฝฃ้‡‘๏ผŒไธ่ต ๅคฉ -func TestHandleCommission_OnlyCommissionWhenChannelNotFirstOrder(t *testing.T) { - logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{ - ReferralPercentage: 10, - OnlyFirstPurchase: false, - GiftDays: 2, - }) - defer cleanup() - - referee := seedUser(t, db, 0, false) - referer := seedUser(t, db, 0, false) - referee.RefererId = referer.Id - - baseExpire := time.Now().Add(96 * time.Hour).Truncate(time.Second) - refereeSub := seedActiveSubscribe(t, db, referee.Id, baseExpire) - - logic.handleCommission(context.Background(), referee, &order.Order{ - OrderNo: "ORD-COMM-002", - Type: OrderTypeSubscribe, - IsNew: false, // ้ž้ฆ–ๅ• - Amount: 100, - FeeAmount: 0, - CreatedAt: time.Now(), - }) - - // ่ขซ้‚€่ฏทไบบไธๅบ”่Žทๅพ—่ต ้€ๅคฉๆ•ฐ - assertExpireIncreasedByDays(t, db, refereeSub.Id, baseExpire, 0) - - // ้‚€่ฏทไบบๅบ”่Žทๅพ—ไฝฃ้‡‘ - var refererAfter user.User - if err := db.First(&refererAfter, referer.Id).Error; err != nil { - t.Fatalf("query referer failed: %v", err) - } - if refererAfter.Commission != 10 { - t.Fatalf("expected referer commission=10, got %d", refererAfter.Commission) - } - - var giftCount int64 - if err := db.Model(&modelLog.SystemLog{}).Where("type = ?", modelLog.TypeGift.Uint8()).Count(&giftCount).Error; err != nil { - t.Fatalf("count gift logs failed: %v", err) - } - if giftCount != 0 { - t.Fatalf("expected 0 gift logs when channel non-first order, got %d", giftCount) - } -} - -func TestHandleCommission_NoGiftDaysWhenNoInviteRelation(t *testing.T) { - logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{ - ReferralPercentage: 0, - OnlyFirstPurchase: false, - GiftDays: 2, - }) - defer cleanup() - - // ๆฒกๆœ‰้‚€่ฏทไบบ็š„็‹ฌ็ซ‹็”จๆˆท - loneUser := seedUser(t, db, 0, false) - // RefererId == 0๏ผŒๆ— ้‚€่ฏทๅ…ณ็ณป - - baseExpire := time.Now().Add(72 * time.Hour).Truncate(time.Second) - loneSub := seedActiveSubscribe(t, db, loneUser.Id, baseExpire) - - logic.handleCommission(context.Background(), loneUser, &order.Order{ - OrderNo: "ORD-LONE-001", - Type: OrderTypeSubscribe, - IsNew: true, - Amount: 100, - FeeAmount: 0, - CreatedAt: time.Now(), - }) - - // ่ฎข้˜…ๅˆฐๆœŸๆ—ถ้—ดไธๅบ”่ฏฅ่ขซๅปถ้•ฟ - var subAfter user.Subscribe - if err := db.First(&subAfter, loneSub.Id).Error; err != nil { - t.Fatalf("query subscribe failed: %v", err) - } - if !subAfter.ExpireTime.Equal(baseExpire) { - t.Fatalf("expected no gift days for user without inviter, before=%v after=%v", baseExpire, subAfter.ExpireTime) - } - - // ไธๅบ”ไบง็”Ÿ่ต ๅคฉๆ—ฅๅฟ— - var giftCount int64 - if err := db.Model(&modelLog.SystemLog{}).Where("type = ?", modelLog.TypeGift.Uint8()).Count(&giftCount).Error; err != nil { - t.Fatalf("count gift logs failed: %v", err) - } - if giftCount != 0 { - t.Fatalf("expected 0 gift logs for user without inviter, got %d", giftCount) - } -} - -// ๅ…ˆ็ป‘็ ๅŽ้ฆ–ๅ• โ†’ ๅŒๆ–น่ต Nๅคฉ -func TestInviteFlow_BindThenFirstOrder_GrantGiftDays(t *testing.T) { - logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{ - ReferralPercentage: 0, - OnlyFirstPurchase: false, - GiftDays: 2, - }) - defer cleanup() - - referee := seedUser(t, db, 0, false) - referer := seedUser(t, db, 0, false) - referer.ReferCode = fmt.Sprintf("REF-%d", referer.Id) - if err := db.Model(&user.User{}).Where("id = ?", referer.Id).Update("refer_code", referer.ReferCode).Error; err != nil { - t.Fatalf("update referer code failed: %v", err) - } - - refereeBaseExpire := time.Now().Add(48 * time.Hour).Truncate(time.Second) - refererBaseExpire := time.Now().Add(72 * time.Hour).Truncate(time.Second) - refereeSub := seedActiveSubscribe(t, db, referee.Id, refereeBaseExpire) - refererSub := seedActiveSubscribe(t, db, referer.Id, refererBaseExpire) - - ctx := context.WithValue(context.Background(), constant.CtxKeyUser, referee) - bindLogic := userLogic.NewBindInviteCodeLogic(ctx, logic.svc) - if err := bindLogic.BindInviteCode(&types.BindInviteCodeRequest{InviteCode: referer.ReferCode}); err != nil { - t.Fatalf("bind invite code failed: %v", err) - } - - var refereeAfterBind user.User - if err := db.First(&refereeAfterBind, referee.Id).Error; err != nil { - t.Fatalf("query referee after bind failed: %v", err) - } - if refereeAfterBind.RefererId != referer.Id { - t.Fatalf("bind invite failed, expected referer_id=%d got=%d", referer.Id, refereeAfterBind.RefererId) - } - - // ้ฆ–ๅ• IsNew=true โ†’ ๅŒๆ–น่ต Nๅคฉ - logic.handleCommission(context.Background(), &refereeAfterBind, &order.Order{ - OrderNo: "ORD-FLOW-001", - Type: OrderTypeSubscribe, - IsNew: true, - Amount: 100, - FeeAmount: 0, - CreatedAt: time.Now(), - }) - - assertExpireIncreasedByDays(t, db, refereeSub.Id, refereeBaseExpire, 2) - assertExpireIncreasedByDays(t, db, refererSub.Id, refererBaseExpire, 2) -} - -// ๅ…ˆไนฐ่ฎขๅ•ๅŽ็ป‘็ ๅ†็ปญ่ดน โ†’ ไธ่ต ้€๏ผˆIsNew=false๏ผ‰ -func TestInviteFlow_OrderThenBind_NoGiftDays(t *testing.T) { - logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{ - ReferralPercentage: 0, - OnlyFirstPurchase: false, - GiftDays: 2, - }) - defer cleanup() - - referee := seedUser(t, db, 0, false) - referer := seedUser(t, db, 0, false) - referee.RefererId = referer.Id - - baseExpire := time.Now().Add(72 * time.Hour).Truncate(time.Second) - refereeSub := seedActiveSubscribe(t, db, referee.Id, baseExpire) - refererSub := seedActiveSubscribe(t, db, referer.Id, baseExpire) - - // ๅ…ˆๅ‰ๅทฒๆœ‰่ฎขๅ•๏ผŒIsNew=false๏ผˆๆจกๆ‹Ÿๅ…ˆไนฐ่ฎขๅ•ๅŽ็ป‘็ ็š„ๅœบๆ™ฏ๏ผ‰ - logic.handleCommission(context.Background(), referee, &order.Order{ - OrderNo: "ORD-FLOW-002", - Type: OrderTypeSubscribe, - IsNew: false, // ๅทฒๆœ‰ๅކๅฒ่ฎขๅ• - Amount: 100, - FeeAmount: 0, - CreatedAt: time.Now(), - }) - - assertExpireIncreasedByDays(t, db, refereeSub.Id, baseExpire, 0) - assertExpireIncreasedByDays(t, db, refererSub.Id, baseExpire, 0) -} - -func TestHandleCommission_GiftDaysToRefereeFamilyOwnerWhenChannelFirstOrder(t *testing.T) { - logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{ - ReferralPercentage: 10, - OnlyFirstPurchase: false, - GiftDays: 2, - }) - defer cleanup() - - refereeOwner := seedUser(t, db, 0, false) - referee := seedUser(t, db, 0, false) - referer := seedUser(t, db, 0, false) - seedFamily(t, db, refereeOwner.Id, referee.Id) - referee.RefererId = referer.Id - - ownerBaseExpire := time.Now().Add(96 * time.Hour).Truncate(time.Second) - ownerSub := seedActiveSubscribe(t, db, refereeOwner.Id, ownerBaseExpire) - - logic.handleCommission(context.Background(), referee, &order.Order{ - OrderNo: "ORD-FAMILY-REFEREE-001", - Type: OrderTypeSubscribe, - IsNew: true, - Amount: 100, - FeeAmount: 0, - SubscriptionUserId: refereeOwner.Id, - CreatedAt: time.Now(), - }) - - assertExpireIncreasedByDays(t, db, ownerSub.Id, ownerBaseExpire, 2) - assertUserCommission(t, db, referer.Id, 10) -} - -func TestHandleCommission_GiftDaysToRefererFamilyOwnerWhenCommissionDisabled(t *testing.T) { - logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{ - ReferralPercentage: 0, - OnlyFirstPurchase: false, - GiftDays: 2, - }) - defer cleanup() - - referee := seedUser(t, db, 0, false) - refererOwner := seedUser(t, db, 0, false) - referer := seedUser(t, db, 0, false) - seedFamily(t, db, refererOwner.Id, referer.Id) - referee.RefererId = referer.Id - - refereeBaseExpire := time.Now().Add(72 * time.Hour).Truncate(time.Second) - refererOwnerBaseExpire := time.Now().Add(96 * time.Hour).Truncate(time.Second) - refereeSub := seedActiveSubscribe(t, db, referee.Id, refereeBaseExpire) - refererOwnerSub := seedActiveSubscribe(t, db, refererOwner.Id, refererOwnerBaseExpire) - - logic.handleCommission(context.Background(), referee, &order.Order{ - OrderNo: "ORD-FAMILY-REFERER-001", - Type: OrderTypeSubscribe, - IsNew: true, - Amount: 100, - FeeAmount: 0, - CreatedAt: time.Now(), - }) - - assertExpireIncreasedByDays(t, db, refereeSub.Id, refereeBaseExpire, 2) - assertExpireIncreasedByDays(t, db, refererOwnerSub.Id, refererOwnerBaseExpire, 2) -} - -func TestHandleCommission_RefererFamilyMemberCommissionBehaviorUnchanged(t *testing.T) { - logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{ - ReferralPercentage: 10, - OnlyFirstPurchase: false, - GiftDays: 2, - }) - defer cleanup() - - referee := seedUser(t, db, 0, false) - refererOwner := seedUser(t, db, 0, false) - referer := seedUser(t, db, 0, false) - seedFamily(t, db, refererOwner.Id, referer.Id) - referee.RefererId = referer.Id - - refereeBaseExpire := time.Now().Add(96 * time.Hour).Truncate(time.Second) - refereeSub := seedActiveSubscribe(t, db, referee.Id, refereeBaseExpire) - - logic.handleCommission(context.Background(), referee, &order.Order{ - OrderNo: "ORD-FAMILY-COMMISSION-001", - Type: OrderTypeSubscribe, - IsNew: true, - Amount: 100, - FeeAmount: 0, - CreatedAt: time.Now(), - }) - - assertExpireIncreasedByDays(t, db, refereeSub.Id, refereeBaseExpire, 2) - assertUserCommission(t, db, referer.Id, 10) - assertUserCommission(t, db, refererOwner.Id, 0) -} - -func TestHandleCommission_GiftDaysRecognizesUnlimitedSubscription(t *testing.T) { - logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{ - ReferralPercentage: 10, - OnlyFirstPurchase: false, - GiftDays: 2, - }) - defer cleanup() - - referee := seedUser(t, db, 0, false) - referer := seedUser(t, db, 0, false) - referee.RefererId = referer.Id - - unlimitedExpire := time.UnixMilli(0) - refereeSub := seedActiveSubscribe(t, db, referee.Id, unlimitedExpire) - - logic.handleCommission(context.Background(), referee, &order.Order{ - OrderNo: "ORD-UNLIMITED-001", - Type: OrderTypeSubscribe, - IsNew: true, - Amount: 100, - FeeAmount: 0, - CreatedAt: time.Now(), - }) - - assertExpireIncreasedByDays(t, db, refereeSub.Id, unlimitedExpire, 0) - var giftCount int64 - if err := db.Model(&modelLog.SystemLog{}).Where("type = ? AND object_id = ?", modelLog.TypeGift.Uint8(), referee.Id).Count(&giftCount).Error; err != nil { - t.Fatalf("count gift logs failed: %v", err) - } - if giftCount != 1 { - t.Fatalf("expected 1 gift log for unlimited subscription, got %d", giftCount) - } -} - -func TestHandleCommission_IdempotentForRepeatedActivation(t *testing.T) { - logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{ - ReferralPercentage: 10, - OnlyFirstPurchase: false, - GiftDays: 2, - }) - defer cleanup() - - referee := seedUser(t, db, 0, false) - referer := seedUser(t, db, 0, false) - referee.RefererId = referer.Id - - baseExpire := time.Now().Add(96 * time.Hour).Truncate(time.Second) - refereeSub := seedActiveSubscribe(t, db, referee.Id, baseExpire) - orderInfo := &order.Order{ - OrderNo: "ORD-IDEMPOTENT-001", - Type: OrderTypeSubscribe, - IsNew: true, - Amount: 100, - FeeAmount: 0, - CreatedAt: time.Now(), - } - - logic.handleCommission(context.Background(), referee, orderInfo) - logic.handleCommission(context.Background(), referee, orderInfo) - - assertExpireIncreasedByDays(t, db, refereeSub.Id, baseExpire, 2) - assertUserCommission(t, db, referer.Id, 10) - assertLogCountForOrder(t, db, modelLog.TypeCommission.Uint8(), orderInfo.OrderNo, 1) - assertLogCountForOrder(t, db, modelLog.TypeGift.Uint8(), orderInfo.OrderNo, 1) -} - -func TestHandleCommission_NoActiveSubscriptionWritesSkippedGiftLog(t *testing.T) { - logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{ - ReferralPercentage: 10, - OnlyFirstPurchase: false, - GiftDays: 2, - }) - defer cleanup() - - referee := seedUser(t, db, 0, false) - referer := seedUser(t, db, 0, false) - referee.RefererId = referer.Id - orderInfo := &order.Order{ - OrderNo: "ORD-SKIPPED-001", - Type: OrderTypeSubscribe, - IsNew: true, - Amount: 100, - FeeAmount: 0, - CreatedAt: time.Now(), - } - - logic.handleCommission(context.Background(), referee, orderInfo) - - assertUserCommission(t, db, referer.Id, 10) - assertLogCountForOrder(t, db, modelLog.TypeCommission.Uint8(), orderInfo.OrderNo, 1) - assertLogCountForOrder(t, db, modelLog.TypeGift.Uint8(), orderInfo.OrderNo, 1) - assertGiftLogRemarkContains(t, db, orderInfo.OrderNo, "skipped: no active subscription") -} - -func TestHandleCommission_GiftDaysZeroDoesNotWriteGiftLog(t *testing.T) { - logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{ - ReferralPercentage: 10, - OnlyFirstPurchase: false, - GiftDays: 0, - }) - defer cleanup() - - referee := seedUser(t, db, 0, false) - referer := seedUser(t, db, 0, false) - referee.RefererId = referer.Id - baseExpire := time.Now().Add(96 * time.Hour).Truncate(time.Second) - refereeSub := seedActiveSubscribe(t, db, referee.Id, baseExpire) - orderInfo := &order.Order{ - OrderNo: "ORD-GIFT-ZERO-001", - Type: OrderTypeSubscribe, - IsNew: true, - Amount: 100, - FeeAmount: 0, - CreatedAt: time.Now(), - } - - logic.handleCommission(context.Background(), referee, orderInfo) - - assertExpireIncreasedByDays(t, db, refereeSub.Id, baseExpire, 0) - assertUserCommission(t, db, referer.Id, 10) - assertLogCountForOrder(t, db, modelLog.TypeCommission.Uint8(), orderInfo.OrderNo, 1) - assertLogCountForOrder(t, db, modelLog.TypeGift.Uint8(), orderInfo.OrderNo, 0) -} - -func TestHandleCommission_GlobalOnlyFirstPurchaseBlocksCommissionAndGiftForNonFirstOrder(t *testing.T) { - logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{ - ReferralPercentage: 10, - OnlyFirstPurchase: true, - GiftDays: 2, - }) - defer cleanup() - - referee := seedUser(t, db, 0, false) - referer := seedUser(t, db, 0, false) - referee.RefererId = referer.Id - baseExpire := time.Now().Add(96 * time.Hour).Truncate(time.Second) - refereeSub := seedActiveSubscribe(t, db, referee.Id, baseExpire) - orderInfo := &order.Order{ - OrderNo: "ORD-NONFIRST-GLOBAL-001", - Type: OrderTypeRenewal, - IsNew: false, - Amount: 100, - FeeAmount: 0, - CreatedAt: time.Now(), - } - - logic.handleCommission(context.Background(), referee, orderInfo) - - assertExpireIncreasedByDays(t, db, refereeSub.Id, baseExpire, 0) - assertUserCommission(t, db, referer.Id, 0) - assertLogCountForOrder(t, db, modelLog.TypeCommission.Uint8(), orderInfo.OrderNo, 0) - assertLogCountForOrder(t, db, modelLog.TypeGift.Uint8(), orderInfo.OrderNo, 0) -} - -func TestHandleCommission_BothFamilySidesUseCorrectGiftOwners(t *testing.T) { - logic, db, cleanup := setupInviteTestLogic(t, config.InviteConfig{ - ReferralPercentage: 0, - OnlyFirstPurchase: false, - GiftDays: 2, - }) - defer cleanup() - - refereeOwner := seedUser(t, db, 0, false) - referee := seedUser(t, db, 0, false) - refererOwner := seedUser(t, db, 0, false) - referer := seedUser(t, db, 0, false) - seedFamily(t, db, refereeOwner.Id, referee.Id) - seedFamily(t, db, refererOwner.Id, referer.Id) - referee.RefererId = referer.Id - - refereeOwnerBaseExpire := time.Now().Add(72 * time.Hour).Truncate(time.Second) - refererOwnerBaseExpire := time.Now().Add(96 * time.Hour).Truncate(time.Second) - refereeOwnerSub := seedActiveSubscribe(t, db, refereeOwner.Id, refereeOwnerBaseExpire) - refererOwnerSub := seedActiveSubscribe(t, db, refererOwner.Id, refererOwnerBaseExpire) - orderInfo := &order.Order{ - OrderNo: "ORD-BOTH-FAMILIES-001", - Type: OrderTypeSubscribe, - IsNew: true, - Amount: 100, - FeeAmount: 0, - SubscriptionUserId: refereeOwner.Id, - CreatedAt: time.Now(), - } - - logic.handleCommission(context.Background(), referee, orderInfo) - - assertExpireIncreasedByDays(t, db, refereeOwnerSub.Id, refereeOwnerBaseExpire, 2) - assertExpireIncreasedByDays(t, db, refererOwnerSub.Id, refererOwnerBaseExpire, 2) - assertNoSubscribeForUser(t, db, referee.Id) - assertNoSubscribeForUser(t, db, referer.Id) - assertLogCountForOrder(t, db, modelLog.TypeGift.Uint8(), orderInfo.OrderNo, 2) -} - -func setupInviteTestLogic(t *testing.T, inviteCfg config.InviteConfig) (*ActivateOrderLogic, *gorm.DB, func()) { - t.Helper() - - mysqlAddr := getenvDefault("TEST_MYSQL_ADDR", "127.0.0.1:3306") - mysqlUser := getenvDefault("TEST_MYSQL_USER", "root") - mysqlPassword := getenvDefault("TEST_MYSQL_PASSWORD", "rootpassword") - - adminDSN := fmt.Sprintf("%s:%s@tcp(%s)/?charset=utf8mb4&parseTime=true&loc=Local&multiStatements=true", mysqlUser, mysqlPassword, mysqlAddr) - adminDB, err := gorm.Open(mysql.Open(adminDSN), &gorm.Config{}) - if err != nil { - t.Fatalf("open mysql admin connection failed: %v", err) - } - - dbName := fmt.Sprintf("ppanel_test_invite_%d", time.Now().UnixNano()) - if err := adminDB.Exec(fmt.Sprintf("CREATE DATABASE `%s` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci", dbName)).Error; err != nil { - t.Fatalf("create test database failed: %v", err) - } - - testDSN := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4&parseTime=true&loc=Local", mysqlUser, mysqlPassword, mysqlAddr, dbName) - db, err := gorm.Open(mysql.Open(testDSN), &gorm.Config{}) - if err != nil { - t.Fatalf("open test database failed: %v", err) - } - - if err := db.AutoMigrate(&user.User{}, &user.Device{}, &user.AuthMethods{}, &user.Subscribe{}, &user.UserFamily{}, &user.UserFamilyMember{}, &modelLog.SystemLog{}); err != nil { - t.Fatalf("auto migrate failed: %v", err) - } - - redisAddr := getenvDefault("TEST_REDIS_ADDR", "127.0.0.1:6379") - redisPassword := getenvDefault("TEST_REDIS_PASSWORD", "") - rdb := redis.NewClient(&redis.Options{ - Addr: redisAddr, - Password: redisPassword, - DB: 0, - }) - if err := rdb.Ping(context.Background()).Err(); err != nil { - t.Fatalf("connect redis failed: %v", err) - } - _ = rdb.FlushDB(context.Background()).Err() - - svcCtx := &svc.ServiceContext{ - DB: db, - Redis: rdb, - UserModel: user.NewModel(db, rdb), - LogModel: modelLog.NewModel(db), - Config: config.Config{ - Invite: inviteCfg, - }, - } - - return NewActivateOrderLogic(svcCtx), db, func() { - _ = rdb.Close() - sqlDB, _ := db.DB() - if sqlDB != nil { - _ = sqlDB.Close() - } - _ = adminDB.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS `%s`", dbName)).Error - } -} - -func seedUser(t *testing.T, db *gorm.DB, referralPercentage uint8, onlyFirstPurchase bool) *user.User { - t.Helper() - u := &user.User{ - Password: "pwd", - Algo: "default", - ReferralPercentage: referralPercentage, - OnlyFirstPurchase: boolPtr(onlyFirstPurchase), - Enable: boolPtr(true), - IsAdmin: boolPtr(false), - EnableBalanceNotify: boolPtr(false), - EnableLoginNotify: boolPtr(false), - EnableSubscribeNotify: boolPtr(false), - EnableTradeNotify: boolPtr(false), - } - if err := db.Create(u).Error; err != nil { - t.Fatalf("seed user failed: %v", err) - } - return u -} - -func seedFamily(t *testing.T, db *gorm.DB, ownerID int64, memberID int64) { - t.Helper() - family := &user.UserFamily{ - OwnerUserId: ownerID, - MaxMembers: 3, - Status: user.FamilyStatusActive, - } - if err := db.Create(family).Error; err != nil { - t.Fatalf("seed family failed: %v", err) - } - now := time.Now() - members := []user.UserFamilyMember{ - { - FamilyId: family.Id, - UserId: ownerID, - Role: user.FamilyRoleOwner, - Status: user.FamilyMemberActive, - JoinSource: "test", - JoinedAt: now, - }, - { - FamilyId: family.Id, - UserId: memberID, - Role: user.FamilyRoleMember, - Status: user.FamilyMemberActive, - JoinSource: "test", - JoinedAt: now, - }, - } - if err := db.Create(&members).Error; err != nil { - t.Fatalf("seed family members failed: %v", err) - } -} - -func seedActiveSubscribe(t *testing.T, db *gorm.DB, userID int64, expireAt time.Time) *user.Subscribe { - t.Helper() - sub := &user.Subscribe{ - UserId: userID, - OrderId: 1, - SubscribeId: 1, - StartTime: time.Now().Add(-24 * time.Hour), - ExpireTime: expireAt, - Traffic: 1024, - Token: fmt.Sprintf("token-%d-%d", userID, time.Now().UnixNano()), - UUID: fmt.Sprintf("uuid-%d-%d", userID, time.Now().UnixNano()), - Status: 1, - } - if err := db.Create(sub).Error; err != nil { - t.Fatalf("seed subscribe failed: %v", err) - } - return sub -} - -func assertExpireIncreasedByDays(t *testing.T, db *gorm.DB, subscribeID int64, before time.Time, days int) { - t.Helper() - var after user.Subscribe - if err := db.First(&after, subscribeID).Error; err != nil { - t.Fatalf("query subscribe failed: %v", err) - } - expected := before.Add(time.Duration(days) * 24 * time.Hour) - if !after.ExpireTime.Equal(expected) { - t.Fatalf("expire time mismatch, expected=%v got=%v", expected, after.ExpireTime) - } -} - -func assertUserCommission(t *testing.T, db *gorm.DB, userID int64, expected int64) { - t.Helper() - var u user.User - if err := db.First(&u, userID).Error; err != nil { - t.Fatalf("query user failed: %v", err) - } - if u.Commission != expected { - t.Fatalf("expected user %d commission=%d, got %d", userID, expected, u.Commission) - } -} - -func assertLogCountForOrder(t *testing.T, db *gorm.DB, logType uint8, orderNo string, expected int64) { - t.Helper() - var count int64 - if err := db.Model(&modelLog.SystemLog{}). - Where("type = ? AND content LIKE ?", logType, "%"+orderNo+"%"). - Count(&count).Error; err != nil { - t.Fatalf("count logs failed: %v", err) - } - if count != expected { - t.Fatalf("expected log type %d count=%d for order %s, got %d", logType, expected, orderNo, count) - } -} - -func assertGiftLogRemarkContains(t *testing.T, db *gorm.DB, orderNo string, want string) { - t.Helper() - var row modelLog.SystemLog - if err := db.Model(&modelLog.SystemLog{}). - Where("type = ? AND content LIKE ?", modelLog.TypeGift.Uint8(), "%"+orderNo+"%"). - First(&row).Error; err != nil { - t.Fatalf("query gift log failed: %v", err) - } - if !strings.Contains(row.Content, want) { - t.Fatalf("expected gift log content to contain %q, got %s", want, row.Content) - } -} - -func assertNoSubscribeForUser(t *testing.T, db *gorm.DB, userID int64) { - t.Helper() - var count int64 - if err := db.Model(&user.Subscribe{}).Where("user_id = ?", userID).Count(&count).Error; err != nil { - t.Fatalf("count subscribes failed: %v", err) - } - if count != 0 { - t.Fatalf("expected user %d to have no direct subscriptions, got %d", userID, count) - } -} - -func boolPtr(v bool) *bool { - return &v -} - -func getenvDefault(key, fallback string) string { - v := os.Getenv(key) - if v == "" { - return fallback - } - return v -} diff --git a/queue/logic/order/activateOrderLogic_newUserEligibility_test.go b/queue/logic/order/activateOrderLogic_newUserEligibility_test.go deleted file mode 100644 index e8ff523..0000000 --- a/queue/logic/order/activateOrderLogic_newUserEligibility_test.go +++ /dev/null @@ -1,199 +0,0 @@ -package orderLogic - -import ( - "context" - "testing" - "time" - - modelOrder "github.com/perfect-panel/server/internal/model/order" - "github.com/perfect-panel/server/internal/model/subscribe" - "github.com/perfect-panel/server/internal/model/user" - "github.com/stretchr/testify/require" - "gorm.io/driver/sqlite" - "gorm.io/gorm" - "gorm.io/gorm/logger" -) - -func setupActivationEligibilityDB(t *testing.T) *gorm.DB { - t.Helper() - - db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{ - Logger: logger.Default.LogMode(logger.Silent), - }) - require.NoError(t, err) - - sqls := []string{ - `CREATE TABLE IF NOT EXISTS "user" ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - password VARCHAR(100) NOT NULL DEFAULT '', - created_at DATETIME, - updated_at DATETIME, - deleted_at DATETIME DEFAULT NULL - )`, - `CREATE TABLE IF NOT EXISTS "user_device" ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - user_id INTEGER NOT NULL DEFAULT 0, - identifier VARCHAR(255) NOT NULL DEFAULT '' UNIQUE, - created_at DATETIME, - updated_at DATETIME - )`, - `CREATE TABLE IF NOT EXISTS "user_family" ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - owner_user_id INTEGER NOT NULL DEFAULT 0, - status TINYINT NOT NULL DEFAULT 1, - deleted_at DATETIME DEFAULT NULL - )`, - `CREATE TABLE IF NOT EXISTS "user_family_member" ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - family_id INTEGER NOT NULL DEFAULT 0, - user_id INTEGER NOT NULL DEFAULT 0, - role TINYINT NOT NULL DEFAULT 0, - status TINYINT NOT NULL DEFAULT 0, - join_source VARCHAR(32) NOT NULL DEFAULT '', - deleted_at DATETIME DEFAULT NULL - )`, - `CREATE TABLE IF NOT EXISTS "order" ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - user_id INTEGER NOT NULL DEFAULT 0, - order_no VARCHAR(255) NOT NULL DEFAULT '' UNIQUE, - type TINYINT NOT NULL DEFAULT 1, - status TINYINT NOT NULL DEFAULT 1, - subscribe_id INTEGER NOT NULL DEFAULT 0, - quantity INTEGER NOT NULL DEFAULT 1, - created_at DATETIME, - updated_at DATETIME - )`, - } - for _, sql := range sqls { - require.NoError(t, db.Exec(sql).Error) - } - - return db -} - -func insertActivationUser(t *testing.T, db *gorm.DB, userID int64, createdAt time.Time) { - t.Helper() - require.NoError(t, db.Exec( - `INSERT INTO "user" (id, created_at, updated_at) VALUES (?, ?, datetime('now'))`, - userID, - createdAt.UTC().Format("2006-01-02 15:04:05"), - ).Error) -} - -func insertActivationDevice(t *testing.T, db *gorm.DB, userID int64, identifier string, createdAt time.Time) { - t.Helper() - require.NoError(t, db.Exec( - `INSERT INTO "user_device" (user_id, identifier, created_at, updated_at) VALUES (?, ?, ?, datetime('now'))`, - userID, - identifier, - createdAt.UTC().Format("2006-01-02 15:04:05"), - ).Error) -} - -func insertActivationFamily(t *testing.T, db *gorm.DB, familyID, ownerUserID int64) { - t.Helper() - require.NoError(t, db.Exec( - `INSERT INTO "user_family" (id, owner_user_id, status) VALUES (?, ?, 1)`, - familyID, - ownerUserID, - ).Error) -} - -func insertActivationFamilyMember(t *testing.T, db *gorm.DB, familyID, userID int64, role, status uint8, joinSource string) { - t.Helper() - require.NoError(t, db.Exec( - `INSERT INTO "user_family_member" (family_id, user_id, role, status, join_source) VALUES (?, ?, ?, ?, ?)`, - familyID, - userID, - role, - status, - joinSource, - ).Error) -} - -func insertActivationOrder(t *testing.T, db *gorm.DB, orderNo string, userID, subscribeID int64, status uint8) { - t.Helper() - require.NoError(t, db.Exec( - `INSERT INTO "order" (user_id, order_no, type, status, subscribe_id, quantity, created_at, updated_at) - VALUES (?, ?, 1, ?, ?, 1, datetime('now'), datetime('now'))`, - userID, - orderNo, - status, - subscribeID, - ).Error) -} - -func TestValidateNewUserOnlyEligibilityAtActivation_UsesEarliestBoundDeviceTime(t *testing.T) { - db := setupActivationEligibilityDB(t) - - const ( - ownerUserID = int64(1) - memberUserID = int64(2) - familyID = int64(10) - subscribeID = int64(100) - ) - - insertActivationUser(t, db, ownerUserID, time.Now().Add(-1*time.Hour)) - insertActivationUser(t, db, memberUserID, time.Now().Add(-72*time.Hour)) - insertActivationDevice(t, db, memberUserID, "activation-old-device", time.Now().Add(-72*time.Hour)) - insertActivationFamily(t, db, familyID, ownerUserID) - insertActivationFamilyMember(t, db, familyID, ownerUserID, user.FamilyRoleOwner, user.FamilyMemberActive, "owner_init") - insertActivationFamilyMember(t, db, familyID, memberUserID, user.FamilyRoleMember, user.FamilyMemberActive, "bind_email_with_verification") - - err := validateNewUserOnlyEligibilityAtActivation( - context.Background(), - db, - &modelOrder.Order{ - UserId: ownerUserID, - OrderNo: "activation-check-old-device", - Type: OrderTypeSubscribe, - Quantity: 1, - SubscribeId: subscribeID, - }, - &subscribe.Subscribe{ - Id: subscribeID, - Discount: `[{"quantity":1,"discount":90,"new_user_only":true}]`, - }, - ) - - require.Error(t, err) - require.Contains(t, err.Error(), "is not a new user") -} - -func TestValidateNewUserOnlyEligibilityAtActivation_SharesHistoryAcrossBoundScope(t *testing.T) { - db := setupActivationEligibilityDB(t) - - const ( - ownerUserID = int64(11) - memberUserID = int64(12) - familyID = int64(20) - subscribeID = int64(200) - ) - - insertActivationUser(t, db, ownerUserID, time.Now().Add(-1*time.Hour)) - insertActivationUser(t, db, memberUserID, time.Now().Add(-2*time.Hour)) - insertActivationDevice(t, db, memberUserID, "activation-shared-device", time.Now().Add(-2*time.Hour)) - insertActivationFamily(t, db, familyID, ownerUserID) - insertActivationFamilyMember(t, db, familyID, ownerUserID, user.FamilyRoleOwner, user.FamilyMemberActive, "owner_init") - insertActivationFamilyMember(t, db, familyID, memberUserID, user.FamilyRoleMember, user.FamilyMemberActive, "bind_email_with_verification") - insertActivationOrder(t, db, "previous-finished-order", memberUserID, subscribeID, OrderStatusFinished) - - err := validateNewUserOnlyEligibilityAtActivation( - context.Background(), - db, - &modelOrder.Order{ - UserId: ownerUserID, - OrderNo: "current-paid-order", - Type: OrderTypeSubscribe, - Quantity: 1, - SubscribeId: subscribeID, - }, - &subscribe.Subscribe{ - Id: subscribeID, - Discount: `[{"quantity":1,"discount":90,"new_user_only":true}]`, - }, - ) - - require.Error(t, err) - require.Contains(t, err.Error(), "already activated") -} diff --git a/result.txt b/result.txt deleted file mode 100644 index ab9bb7f..0000000 --- a/result.txt +++ /dev/null @@ -1,128 +0,0 @@ - -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - ไปฃ็† ID : 31618๏ผˆๆณจๅ†ŒไบŽ 2026-05-03 10:36:16๏ผ‰ - ็ปŸ่ฎก่ตท็‚น : 2026-05-03 15:37:18๏ผˆ้ฆ–ๆฌก้‚€่ฏทๆ—ถ้—ด๏ผ‰ - ็ปŸ่ฎกๆˆชๆญข : 2026-05-07 02:02:52๏ผˆๆœ€ๅŽ้‚€่ฏทๆ—ถ้—ด๏ผ‰ - ็ปŸ่ฎกๅคฉๆ•ฐ : 3.43 ๅคฉ - ๅކๅฒ้‚€่ฏทๆ€ปไบบๆ•ฐ : 49 ไบบ - ไธ‹็บฟๆ€ป่ฎขๅ•ๆ•ฐ : 11 ๅ•๏ผˆๆ‰€ๆœ‰ไธ‹็บฟ๏ผŒไธ้™ๆ—ถ้—ด๏ผ‰ - ๆ—ฅๅ‡่ฎขๅ• : 3.2029 ๅ•/ๅคฉ - ๆฏ็”จๆˆทๅนณๅ‡่ฎขๅ• : 1.0000 ๅ• - ๅކๅฒไฝฃ้‡‘ๆ€ป้ข : $46.30 - ๆ—ฅๅ‡ไฝฃ้‡‘ : $13.4812 - ๆฏ็”จๆˆทๅนณๅ‡ไฝฃ้‡‘ : $0.9449 - ไฝฃ้‡‘่ง„ๅˆ™ : 50% ไป…้ฆ–ๅ•=false -โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - ไธขๅคฑๆ—ถ้•ฟ : 22.42 ๅฐๆ—ถ๏ผˆ2026-05-07 02:02:52 โ†’ ็Žฐๅœจ๏ผ‰ - ้ข„ไผฐไธขๅคฑไฝฃ้‡‘ : $12.5914๏ผˆ$13.4812 ร— 22.42/24๏ผ‰ - ็›ฎๆ ‡่กฅๅฟ้‡‘้ข : $15.1097๏ผˆร— 120%๏ผ‰ - ้œ€่กฅๅ……ไบบๆ•ฐ : 16 ไบบ๏ผˆ$15.1097 รท $0.9449๏ผ‰ -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - -่‡ช็„ถๆต้‡็”จๆˆทๆฑ ๏ผˆ2025-05-04 00:00 ~ 2026-05-08 00:27๏ผŒreferer_id=0๏ผŒๆœ‰ๅทฒๆ”ฏไป˜่ฎขๅ•๏ผ‰๏ผšๅ…ฑ 2420 ไบบ - -้šๆœบๆŠฝๅ– 16 ไธช็”จๆˆท๏ผˆๅซๅพ…่ฟฝๆบฏไฝฃ้‡‘่ฎขๅ•๏ผ‰๏ผš -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• -[1] ็”จๆˆท 19282 ๆณจๅ†Œ: 2026-04-22 21:48:47 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 20260422214951826095981429 $ 0.99 $ 0.00 $ 0.49 ้ฆ–่ดญ - 202604302302367096852027224 $ 5.99 $ 0.00 $ 2.99 ็ปญ่ดน - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $3.48 - -[2] ็”จๆˆท 22675 ๆณจๅ†Œ: 2026-04-26 13:05:32 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 202604270056552342453283470 $ 0.99 $ 0.00 $ 0.49 ้ฆ–่ดญ - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $0.49 - -[3] ็”จๆˆท 676 ๆณจๅ†Œ: 2026-03-29 16:49:34 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 202603302144244505020334929 $ 0.99 $ 0.00 $ 0.49 ็ปญ่ดน - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $0.49 - -[4] ็”จๆˆท 23501 ๆณจๅ†Œ: 2026-04-27 22:17:59 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 202604272218253888000515243 $ 0.99 $ 0.00 $ 0.49 ้ฆ–่ดญ - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $0.49 - -[5] ็”จๆˆท 18921 ๆณจๅ†Œ: 2026-04-22 14:48:31 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 202604240030589405703117541 $ 2.79 $ 0.00 $ 1.39 ้ฆ–่ดญ - 202605020135558835271794030 $ 12.99 $ 0.00 $ 6.49 ็ปญ่ดน - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $7.88 - -[6] ็”จๆˆท 21300 ๆณจๅ†Œ: 2026-04-24 21:58:49 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 202604242201505521613971320 $ 0.99 $ 0.00 $ 0.49 ้ฆ–่ดญ - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $0.49 - -[7] ็”จๆˆท 18750 ๆณจๅ†Œ: 2026-04-22 10:05:38 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 20260422100625875802633569 $ 0.99 $ 0.00 $ 0.49 ้ฆ–่ดญ - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $0.49 - -[8] ็”จๆˆท 28305 ๆณจๅ†Œ: 2026-04-29 20:40:42 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 202604292044144381261998771 $ 5.99 $ 0.00 $ 2.99 ็ปญ่ดน - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $2.99 - -[9] ็”จๆˆท 18687 ๆณจๅ†Œ: 2026-04-22 07:22:38 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 202604220723053253069546184 $ 0.99 $ 0.00 $ 0.49 ้ฆ–่ดญ - 202604301218427084543381719 $ 12.99 $ 0.00 $ 6.49 ็ปญ่ดน - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $6.98 - -[10] ็”จๆˆท 27370 ๆณจๅ†Œ: 2026-04-29 13:07:04 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 202604291307299646401795678 $ 2.79 $ 0.00 $ 1.39 ้ฆ–่ดญ - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $1.39 - -[11] ็”จๆˆท 25141 ๆณจๅ†Œ: 2026-04-28 23:27:53 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 20260428232858118781522927 $ 2.79 $ 0.00 $ 1.39 ้ฆ–่ดญ - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $1.39 - -[12] ็”จๆˆท 21709 ๆณจๅ†Œ: 2026-04-25 09:07:11 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 202604250909319632867038991 $ 0.99 $ 0.00 $ 0.49 ็ปญ่ดน - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $0.49 - -[13] ็”จๆˆท 29584 ๆณจๅ†Œ: 2026-04-30 21:00:07 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 202604302100218949591805326 $ 12.99 $ 0.00 $ 6.49 ้ฆ–่ดญ - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $6.49 - -[14] ็”จๆˆท 18457 ๆณจๅ†Œ: 2026-04-22 00:56:01 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 202604282259482779907423944 $ 5.99 $ 0.00 $ 2.99 ็ปญ่ดน - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $2.99 - -[15] ็”จๆˆท 23746 ๆณจๅ†Œ: 2026-04-28 08:57:40 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 202605072036107130526727042 $ 2.79 $ 0.00 $ 1.39 ็ปญ่ดน - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $1.39 - -[16] ็”จๆˆท 23745 ๆณจๅ†Œ: 2026-04-28 08:56:25 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 202604280857579370192598355 $ 0.99 $ 0.00 $ 0.49 ้ฆ–่ดญ - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $0.49 - -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• -้ข„่ฎก่ฟฝๆบฏไฝฃ้‡‘ๆ€ป้ข: $38.41๏ผˆ็›ฎๆ ‡่กฅๅฟ้‡‘้ข: $15.11๏ผ‰ - -[dry-run] ้ข„่งˆๅฎŒๆˆ๏ผŒๆœชๆ‰ง่กŒไปปไฝ•ๅ†™ๅ…ฅใ€‚ diff --git a/retro_result.txt b/retro_result.txt deleted file mode 100644 index 4932fdc..0000000 --- a/retro_result.txt +++ /dev/null @@ -1,101 +0,0 @@ -โš ๏ธ ๅผบๅˆถ่ฆ†็›–ๆ‰€ๆœ‰ไปฃ็†ไฝฃ้‡‘ๆฏ”ไพ‹ไธบ 50% - -่‡ช็„ถๆต้‡็”จๆˆทๆฑ ๏ผˆ2025-05-04 00:00 ~ 2026-05-08 17:36๏ผŒreferer_id=0๏ผŒๆœ‰ๅทฒๆ”ฏไป˜่ฎขๅ•๏ผŒ่ฎขๅ• updated_at >= 2026-05-01๏ผ‰๏ผšๅ…ฑ 942 ไบบ - - -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - ไปฃ็† ID : 32690๏ผˆๆณจๅ†ŒไบŽ 2026-05-03 22:28:33๏ผ‰ - ็ปŸ่ฎก่ตท็‚น : 2026-05-03 23:05:16๏ผˆ้ฆ–ๆฌก้‚€่ฏทๆ—ถ้—ด๏ผ‰ - ็ปŸ่ฎกๆˆชๆญข : 2026-05-08 11:34:52๏ผˆๆœ€ๅŽ้‚€่ฏทๆ—ถ้—ด๏ผ‰ - ็ปŸ่ฎกๅคฉๆ•ฐ : 4.52 ๅคฉ - ๅކๅฒ้‚€่ฏทๆ€ปไบบๆ•ฐ : 56 ไบบ - ไธ‹็บฟๆ€ป่ฎขๅ•ๆ•ฐ : 23 ๅ•๏ผˆๆ‰€ๆœ‰ไธ‹็บฟ๏ผŒไธ้™ๆ—ถ้—ด๏ผ‰ - ๆ—ฅๅ‡่ฎขๅ• : 5.0879 ๅ•/ๅคฉ - ๆฏ็”จๆˆทๅนณๅ‡่ฎขๅ• : 1.0000 ๅ• - ๅކๅฒไฝฃ้‡‘ๆ€ป้ข : $67.37 - ๆ—ฅๅ‡ไฝฃ้‡‘ : $14.9031 - ๆฑ ๅ†…็”จๆˆทๅ‡ไฝฃ้‡‘ : $4.0394 - ไฝฃ้‡‘่ง„ๅˆ™ : 50% ไป…้ฆ–ๅ•=false -โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - ไธขๅคฑๆ—ถ้•ฟ : 89.62 ๅฐๆ—ถ๏ผˆ2026-05-05 00:00:00 โ†’ ็Žฐๅœจ๏ผ‰ - ้ข„ไผฐไธขๅคฑไฝฃ้‡‘ : $55.6494๏ผˆ$14.9031 ร— 89.62/24๏ผ‰ - ็›ฎๆ ‡่กฅๅฟ้‡‘้ข : $22.2597๏ผˆร— 40%๏ผ‰ - ้œ€่กฅๅ……ไบบๆ•ฐ : 6 ไบบ๏ผˆ$22.2597 รท $4.0394๏ผ‰ -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - -้šๆœบๆŠฝๅ– 7 ไธช็”จๆˆท๏ผˆๅซๅพ…่ฟฝๆบฏไฝฃ้‡‘่ฎขๅ•๏ผ‰๏ผš -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• -[1] ็”จๆˆท 20700 ๆณจๅ†Œ: 2026-04-24 10:23:54 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 202605021207336799836275999 $ 12.99 $ 0.00 $ 6.49 ็ปญ่ดน - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $6.49 - -[2] ็”จๆˆท 29646 ๆณจๅ†Œ: 2026-04-30 21:38:33 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 202605062120238700572523875 $ 5.99 $ 0.00 $ 2.99 ้ฆ–่ดญ - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $2.99 - -[3] ็”จๆˆท 30617 ๆณจๅ†Œ: 2026-05-02 00:05:31 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 202605021653207435530198247 $ 2.79 $ 0.00 $ 1.39 ้ฆ–่ดญ - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $1.39 - -[4] ็”จๆˆท 27884 ๆณจๅ†Œ: 2026-04-29 16:56:59 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 202605021434465448150056947 $ 2.79 $ 0.00 $ 1.39 ็ปญ่ดน - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $1.39 - -[5] ็”จๆˆท 30415 ๆณจๅ†Œ: 2026-05-01 20:16:56 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 202605031955444435684054876 $ 12.99 $ 0.00 $ 6.49 ็ปญ่ดน - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $6.49 - -[6] ็”จๆˆท 23970 ๆณจๅ†Œ: 2026-04-28 12:58:04 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 202605010755515633642395999 $ 5.99 $ 0.00 $ 2.99 ้ฆ–่ดญ - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $2.99 - -[7] ็”จๆˆท 29973 ๆณจๅ†Œ: 2026-05-01 02:43:14 - ่ฎขๅ•ๅท ้‡‘้ข ๆ‰‹็ปญ่ดน ไฝฃ้‡‘ ็ฑปๅž‹ - ------------------------------------------------------------------------ - 202605010243251111413018924 $ 2.79 $ 0.00 $ 1.39 ้ฆ–่ดญ - ๆœฌ็”จๆˆท่ฟฝๆบฏไฝฃ้‡‘ๅˆ่ฎก: $1.39 - -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• -้ข„่ฎก่ฟฝๆบฏไฝฃ้‡‘ๆ€ป้ข: $23.13๏ผˆ็›ฎๆ ‡่กฅๅฟ้‡‘้ข: $22.26๏ผ‰ - -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• -ๆฑ‡ๆ€ป๏ผšๅ…ฑ 1 ไธชไปฃ็†๏ผŒ่กฅๅ…… 7 ไธช็”จๆˆท - ้ข„่ฎก่ฟฝๆบฏไฝฃ้‡‘ๆ€ป้ข: $23.13๏ผˆ็›ฎๆ ‡่กฅๅฟ้‡‘้ข: $22.26๏ผ‰ -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - - -โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” -โ”‚ ๅณๅฐ†ๅ†™ๅ…ฅๆ•ฐๆฎๅบ“ โ”‚ -โ”‚ ไปฃ็†ๆ•ฐ้‡ : 1 ไธช โ”‚ -โ”‚ ่กฅๅ……็”จๆˆท : 7 ไบบ โ”‚ -โ”‚ ่ต ้€้‡‘้ข : $23.13 โ”‚ -โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ - - -โ”€โ”€ ๆ‰ง่กŒไปฃ็† 32690 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ -[OK] ็”จๆˆท 20700 โ†’ ไปฃ็† 32690๏ผŒๅ‘ไฝฃ 1 ๅ•๏ผŒ้‡‘้ข $6.49 -[OK] ็”จๆˆท 29646 โ†’ ไปฃ็† 32690๏ผŒๅ‘ไฝฃ 1 ๅ•๏ผŒ้‡‘้ข $2.99 -[OK] ็”จๆˆท 30617 โ†’ ไปฃ็† 32690๏ผŒๅ‘ไฝฃ 1 ๅ•๏ผŒ้‡‘้ข $1.39 -[OK] ็”จๆˆท 27884 โ†’ ไปฃ็† 32690๏ผŒๅ‘ไฝฃ 1 ๅ•๏ผŒ้‡‘้ข $1.39 -[OK] ็”จๆˆท 30415 โ†’ ไปฃ็† 32690๏ผŒๅ‘ไฝฃ 1 ๅ•๏ผŒ้‡‘้ข $6.49 -[OK] ็”จๆˆท 23970 โ†’ ไปฃ็† 32690๏ผŒๅ‘ไฝฃ 1 ๅ•๏ผŒ้‡‘้ข $2.99 -[OK] ็”จๆˆท 29973 โ†’ ไปฃ็† 32690๏ผŒๅ‘ไฝฃ 1 ๅ•๏ผŒ้‡‘้ข $1.39 - ไปฃ็† 32690 ๅฐ่ฎก๏ผšๆˆๅŠŸ 7 ไบบ๏ผŒๅคฑ่ดฅ 0 ไบบ๏ผŒไฝฃ้‡‘ $23.13 - -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• - ๆˆๅŠŸๆŒ‚่ฝฝ : 7 ไบบ - ๅคฑ่ดฅ/่ทณ่ฟ‡ : 0 ไบบ - ่ฟฝๆบฏไฝฃ้‡‘ : 7 ๅ•๏ผŒๆ€ป้ข $23.13 -โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• diff --git a/tempo/tempo-config.yaml b/tempo/tempo-config.yaml deleted file mode 100644 index 8a68571..0000000 --- a/tempo/tempo-config.yaml +++ /dev/null @@ -1,37 +0,0 @@ -server: - http_listen_port: 3200 - grpc_listen_port: 9095 - -distributor: - receivers: - otlp: - protocols: - grpc: - endpoint: 0.0.0.0:4317 - http: - endpoint: 0.0.0.0:4318 - -ingester: - max_block_duration: 5m - -compactor: - compaction: - block_retention: 168h - -storage: - trace: - backend: local - wal: - path: /var/tempo/wal - local: - path: /var/tempo/blocks - -metrics_generator: - registry: - external_labels: - source: tempo - cluster: ppanel - storage: - path: /var/tempo/generator/wal - remote_write: - - url: http://prometheus:9090/api/v1/write diff --git a/test_device_login b/test_device_login deleted file mode 100755 index d7d1a1a..0000000 Binary files a/test_device_login and /dev/null differ diff --git a/tests/config.go b/tests/config.go deleted file mode 100644 index 22dac06..0000000 --- a/tests/config.go +++ /dev/null @@ -1,136 +0,0 @@ -// Package tests provides HTTP client helpers for manually testing ppanel-server APIs. -// -// Usage: -// -// go test -v -run TestXxx ./tests/ -// -// Configure the constants below to match your local environment. -package tests - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - "net/http" - "testing" -) - -// โ”€โ”€โ”€ Environment Configuration โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -const ( - // BaseURL is the ppanel-server base URL (no trailing slash). - BaseURL = "http://localhost:8080" - - // AdminToken is the JWT token for an admin user. - // Obtain by calling CallAdminLogin first, then paste the token here. - AdminToken = "YOUR_ADMIN_TOKEN" - - // UserToken is the JWT token for a regular user. - // Obtain by calling CallUserLogin first, then paste the token here. - UserToken = "YOUR_USER_TOKEN" - - // TestEmail is the email address for user-related test calls. - TestEmail = "test@example.com" - - // TestPassword is the password for test user login. - TestPassword = "Test@123456" - - // AdminEmail is the email for admin login. - AdminEmail = "admin@example.com" - - // AdminPassword is the admin password. - AdminPassword = "Admin@123456" -) - -// โ”€โ”€โ”€ Request Options โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -type reqOption func(*http.Request) - -// withToken adds a Bearer token to the request. -func withToken(token string) reqOption { - return func(r *http.Request) { - r.Header.Set("Authorization", "Bearer "+token) - } -} - -// withAdminToken adds the AdminToken. -func withAdminToken() reqOption { return withToken(AdminToken) } - -// withUserToken adds the UserToken. -func withUserToken() reqOption { return withToken(UserToken) } - -// โ”€โ”€โ”€ Core HTTP Helper โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - -// doRequest sends an HTTP request and prints the response. -// body may be nil (for GET/DELETE without body), a map[string]any, or any JSON-serialisable value. -// Returns the raw response body as a string. -func doRequest(t *testing.T, method, path string, body any, opts ...reqOption) string { - t.Helper() - - var reqBody io.Reader - if body != nil { - b, err := json.Marshal(body) - if err != nil { - t.Fatalf("marshal body: %v", err) - } - reqBody = bytes.NewReader(b) - } - - req, err := http.NewRequest(method, BaseURL+path, reqBody) - if err != nil { - t.Fatalf("new request: %v", err) - } - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Accept", "application/json") - - for _, o := range opts { - o(req) - } - - resp, err := http.DefaultClient.Do(req) - if err != nil { - t.Fatalf("do request: %v", err) - } - defer resp.Body.Close() - - raw, _ := io.ReadAll(resp.Body) - result := prettyJSON(raw) - t.Logf("[%s %s] %d\n%s", method, path, resp.StatusCode, result) - return string(raw) -} - -// doRequestRaw is like doRequest but for non-testing contexts (prints to stdout). -func doRequestRaw(method, path string, body any, opts ...reqOption) string { - var reqBody io.Reader - if body != nil { - b, _ := json.Marshal(body) - reqBody = bytes.NewReader(b) - } - - req, _ := http.NewRequest(method, BaseURL+path, reqBody) - req.Header.Set("Content-Type", "application/json") - req.Header.Set("Accept", "application/json") - for _, o := range opts { - o(req) - } - - resp, err := http.DefaultClient.Do(req) - if err != nil { - fmt.Printf("request error: %v\n", err) - return "" - } - defer resp.Body.Close() - raw, _ := io.ReadAll(resp.Body) - result := prettyJSON(raw) - fmt.Printf("[%s %s] %d\n%s\n", method, path, resp.StatusCode, result) - return string(raw) -} - -func prettyJSON(raw []byte) string { - var buf bytes.Buffer - if err := json.Indent(&buf, raw, "", " "); err != nil { - return string(raw) - } - return buf.String() -}