jerry пре 3 месеци
родитељ
комит
055085a7c6
8 измењених фајлова са 328 додато и 248 уклоњено
  1. 4 82
      config/accounts.json
  2. 39 33
      config/groups.json
  3. 0 47
      config/proxies.json
  4. 0 1
      core/app_manager.py
  5. 5 3
      gco.py
  6. 144 35
      toolkit/account_manager.py
  7. 135 46
      toolkit/proxy_manager.py
  8. 1 1
      vs_types.py

+ 4 - 82
config/accounts.json

@@ -2,37 +2,31 @@
     "au_fr": [
         {
             "id": 598,
-            "lock_until": 0,
             "password": "0cjO4ts6H@",
             "username": "au_fr_h74mby@gmail-app.com"
         },
         {
             "id": 599,
-            "lock_until": 0,
             "password": "gR1ORxYNA@",
             "username": "au_fr_p9iq5r@gmail-app.com"
         },
         {
             "id": 600,
-            "lock_until": 0,
             "password": "fAl7VmBc8@",
             "username": "au_fr_47p3jz@gmail-app.com"
         },
         {
             "id": 601,
-            "lock_until": 0,
             "password": "mey@D4ubD0",
             "username": "au_fr_k99ky1@gmail-app.com"
         },
         {
             "id": 602,
-            "lock_until": 0,
             "password": "Xui@Zj0HkN",
             "username": "au_fr_q87fl0@gmail-app.com"
         },
         {
             "id": 603,
-            "lock_until": 0,
             "password": "@kYfU9S5NI",
             "username": "au_fr_4cgp29@gmail-app.com"
         }
@@ -40,67 +34,56 @@
     "gb_it": [
         {
             "id": 556,
-            "lock_until": 0,
             "password": "2v@H2UXx74",
             "username": "gb_it_0msok0@gmail-app.com"
         },
         {
             "id": 557,
-            "lock_until": 0,
             "password": "@KMWaBf0w1",
             "username": "gb_it_0wxymp@gmail-app.com"
         },
         {
             "id": 559,
-            "lock_until": 0,
             "password": "Rc7@RFfzW3",
             "username": "gb_it_3j6nwd@gmail-app.com"
         },
         {
             "id": 560,
-            "lock_until": 0,
             "password": "LVUBntr4@5",
             "username": "gb_it_b2xhnr@gmail-app.com"
         },
         {
             "id": 561,
-            "lock_until": 0,
             "password": "B4@Q56dgu7",
             "username": "gb_it_0m93bm@gmail-app.com"
         },
         {
             "id": 562,
-            "lock_until": 0,
             "password": "5gQX7h3@VF",
             "username": "gb_it_ajcwvx@gmail-app.com"
         },
         {
             "id": 563,
-            "lock_until": 0,
             "password": "6Kc@3Eh@eL",
             "username": "gb_it_mfn0o4@gmail-app.com"
         },
         {
             "id": 564,
-            "lock_until": 0,
             "password": "Q9c2x@e6da",
             "username": "gb_it_tf2ync@gmail-app.com"
         },
         {
             "id": 565,
-            "lock_until": 0,
             "password": "miz@7FRuk3",
             "username": "gb_it_bn4j65@gmail-app.com"
         },
         {
             "id": 566,
-            "lock_until": 0,
             "password": "2s4@5VHYU5",
             "username": "gb_it_wtlffb@gmail-app.com"
         },
         {
             "id": 567,
-            "lock_until": 0,
             "password": "R@3s9jgNeO",
             "username": "gb_it_r5z9g5@gmail-app.com"
         }
@@ -108,37 +91,31 @@
     "gb_nl": [
         {
             "id": 620,
-            "lock_until": 0,
             "password": "INYl7Q@0x1",
             "username": "gb_nl_l6nv77@gmail-app.com"
         },
         {
             "id": 621,
-            "lock_until": 0,
             "password": "n1@iw3DfNO",
             "username": "gb_nl_ztsj28@gmail-app.com"
         },
         {
             "id": 622,
-            "lock_until": 0,
             "password": "w1RmZHL@7N",
             "username": "gb_nl_ifp27n@gmail-app.com"
         },
         {
             "id": 623,
-            "lock_until": 0,
             "password": "uZ@5vtkwJc",
             "username": "gb_nl_2sx13j@gmail-app.com"
         },
         {
             "id": 624,
-            "lock_until": 0,
             "password": "yZBEOqIZ@4",
             "username": "gb_nl_t4wi47@gmail-app.com"
         },
         {
             "id": 625,
-            "lock_until": 0,
             "password": "5i@GYmqh1x",
             "username": "gb_nl_rwzr3l@gmail-app.com"
         }
@@ -146,73 +123,61 @@
     "gb_no": [
         {
             "id": 632,
-            "lock_until": 0,
             "password": "qFYL4Kvi@7",
             "username": "gb_no_8kwb4k@gmail-app.com"
         },
         {
             "id": 633,
-            "lock_until": 0,
             "password": "LWh26@b1FO",
             "username": "gb_no_i5fmm5@gmail-app.com"
         },
         {
             "id": 634,
-            "lock_until": 0,
             "password": "Jn33M3j@Km",
             "username": "gb_no_31n1v9@gmail-app.com"
         },
         {
             "id": 635,
-            "lock_until": 0,
             "password": "kysEA@69en",
             "username": "gb_no_sktwxs@gmail-app.com"
         },
         {
             "id": 636,
-            "lock_until": 0,
             "password": "A@l8ZX7Vhp",
             "username": "gb_no_xvh47y@gmail-app.com"
         },
         {
             "id": 637,
-            "lock_until": 0,
             "password": "2CE76@fMTg",
             "username": "gb_no_a4xwpu@gmail-app.com"
         },
         {
             "id": 638,
-            "lock_until": 0,
             "password": "cb@M2j4Y6M",
             "username": "gb_no_nl9vdl@gmail-app.com"
         },
         {
             "id": 639,
-            "lock_until": 0,
             "password": "Db0cn2w@2M",
             "username": "gb_no_iaya2k@gmail-app.com"
         },
         {
             "id": 640,
-            "lock_until": 0,
             "password": "6iWb@C1vxo",
             "username": "gb_no_5yumya@gmail-app.com"
         },
         {
             "id": 641,
-            "lock_until": 0,
             "password": "R@b@43ngZ9",
             "username": "gb_no_io50uu@gmail-app.com"
         },
         {
             "id": 642,
-            "lock_until": 0,
             "password": "ePbSJ@x94U",
             "username": "gb_no_glpu8h@gmail-app.com"
         },
         {
             "id": 643,
-            "lock_until": 0,
             "password": "u6k6eUTky@",
             "username": "gb_no_np7oxv@gmail-app.com"
         }
@@ -220,37 +185,31 @@
     "ie_at": [
         {
             "id": 592,
-            "lock_until": 0,
             "password": "P1C7evb@LU",
             "username": "ie_at_oxjrdp@gmail-app.com"
         },
         {
             "id": 593,
-            "lock_until": 0,
             "password": "CHt@saBY2S",
             "username": "ie_at_cy6nst@gmail-app.com"
         },
         {
             "id": 594,
-            "lock_until": 0,
             "password": "12z8o@DmVc",
             "username": "ie_at_ivov3v@gmail-app.com"
         },
         {
             "id": 595,
-            "lock_until": 0,
             "password": "e@iC0fPpxP",
             "username": "ie_at_fatyy4@gmail-app.com"
         },
         {
             "id": 596,
-            "lock_until": 0,
             "password": "sLfpeK9@PV",
             "username": "ie_at_us8e66@gmail-app.com"
         },
         {
             "id": 597,
-            "lock_until": 0,
             "password": "h@@Qes5WdX",
             "username": "ie_at_2akgxq@gmail-app.com"
         }
@@ -258,37 +217,31 @@
     "ie_dk": [
         {
             "id": 626,
-            "lock_until": 0,
             "password": "7It@d0S038",
             "username": "ie_dk_c72y0m@gmail-app.com"
         },
         {
             "id": 627,
-            "lock_until": 0,
             "password": "TrIt0@eYdM",
             "username": "ie_dk_w5cr67@gmail-app.com"
         },
         {
             "id": 628,
-            "lock_until": 0,
             "password": "@7caSKB2l9",
             "username": "ie_dk_p9eqxz@gmail-app.com"
         },
         {
             "id": 629,
-            "lock_until": 0,
             "password": "ieS@tLsY24",
             "username": "ie_dk_4e8gmz@gmail-app.com"
         },
         {
             "id": 630,
-            "lock_until": 0,
             "password": "x@8ikj3AcL",
             "username": "ie_dk_2xywt2@gmail-app.com"
         },
         {
             "id": 631,
-            "lock_until": 0,
             "password": "TmA@SCxRg8",
             "username": "ie_dk_6c9gsf@gmail-app.com"
         }
@@ -296,37 +249,31 @@
     "ie_fi": [
         {
             "id": 586,
-            "lock_until": 0,
             "password": "FeuyJ@zl20",
             "username": "ie_fi_1txaxx@gmail-app.com"
         },
         {
             "id": 587,
-            "lock_until": 0,
             "password": "v22xGkFm@w",
             "username": "ie_fi_j2zeiw@gmail-app.com"
         },
         {
             "id": 588,
-            "lock_until": 0,
             "password": "Cw6J@sDpik",
             "username": "ie_fi_ez7inp@gmail-app.com"
         },
         {
             "id": 589,
-            "lock_until": 0,
             "password": "wbP@H@Ox2t",
             "username": "ie_fi_119ulr@gmail-app.com"
         },
         {
             "id": 590,
-            "lock_until": 0,
             "password": "PY71A7@Cds",
             "username": "ie_fi_bxc1n3@gmail-app.com"
         },
         {
             "id": 591,
-            "lock_until": 0,
             "password": "@5RC9t3L1w",
             "username": "ie_fi_subwbr@gmail-app.com"
         }
@@ -334,37 +281,31 @@
     "ie_hu": [
         {
             "id": 604,
-            "lock_until": 0,
             "password": "VKrh@0qVMN",
             "username": "ie_hu_ulyvgq@gmail-app.com"
         },
         {
             "id": 605,
-            "lock_until": 0,
             "password": "T03M@NQuhu",
             "username": "ie_hu_7gmp17@gmail-app.com"
         },
         {
             "id": 606,
-            "lock_until": 0,
             "password": "6fGJm281@C",
             "username": "ie_hu_rkscu3@gmail-app.com"
         },
         {
             "id": 607,
-            "lock_until": 0,
             "password": "A5j@rKBrcL",
             "username": "ie_hu_mxpot6@gmail-app.com"
         },
         {
             "id": 608,
-            "lock_until": 0,
             "password": "4KhzKA@Yxw",
             "username": "ie_hu_wexkp7@gmail-app.com"
         },
         {
             "id": 609,
-            "lock_until": 0,
             "password": "5eE@Vws3HZ",
             "username": "ie_hu_i3fcrs@gmail-app.com"
         }
@@ -372,37 +313,31 @@
     "ie_is": [
         {
             "id": 574,
-            "lock_until": 0,
             "password": "Keu5Rt@o9I",
             "username": "ie_is_p7ahqa@gmail-app.com"
         },
         {
             "id": 575,
-            "lock_until": 0,
             "password": "@3fw7HwcSZ",
             "username": "ie_is_h4yi4y@gmail-app.com"
         },
         {
             "id": 576,
-            "lock_until": 0,
             "password": "Or1duEJc5@",
             "username": "ie_is_cwwyxz@gmail-app.com"
         },
         {
             "id": 577,
-            "lock_until": 0,
             "password": "SMeG3hnD@u",
             "username": "ie_is_hxik14@gmail-app.com"
         },
         {
             "id": 578,
-            "lock_until": 0,
             "password": "@jE6IaiZFW",
             "username": "ie_is_28vm9n@gmail-app.com"
         },
         {
             "id": 579,
-            "lock_until": 0,
             "password": "fDTgp9ecH@",
             "username": "ie_is_nn9bjb@gmail-app.com"
         }
@@ -410,43 +345,36 @@
     "ie_nl": [
         {
             "id": 423,
-            "lock_until": 0,
             "password": "VS@OjoMs3f",
             "username": "ie_nl_quqc36@gmail-app.com"
         },
         {
             "id": 568,
-            "lock_until": 0,
             "password": "0z@VzYvt9i",
             "username": "ie_nl_vxzo9t@gmail-app.com"
         },
         {
             "id": 569,
-            "lock_until": 0,
             "password": "9@5J9UMxwK",
             "username": "ie_nl_cluyap@gmail-app.com"
         },
         {
             "id": 570,
-            "lock_until": 0,
             "password": "Ry5Ts7RA@R",
             "username": "ie_nl_yk3mah@gmail-app.com"
         },
         {
             "id": 571,
-            "lock_until": 0,
             "password": "Yw6La2Ig@C",
             "username": "ie_nl_cx2v7z@gmail-app.com"
         },
         {
             "id": 572,
-            "lock_until": 0,
             "password": "vDrmFxv@1V",
             "username": "ie_nl_y118ln@gmail-app.com"
         },
         {
             "id": 573,
-            "lock_until": 0,
             "password": "VaZ0@0I8vS",
             "username": "ie_nl_x0rh02@gmail-app.com"
         }
@@ -454,37 +382,31 @@
     "sg_fr": [
         {
             "id": 580,
-            "lock_until": 0,
             "password": "y1wm@hf0Bn",
             "username": "sg_fr_onoy9i@gmail-app.com"
         },
         {
             "id": 581,
-            "lock_until": 0,
             "password": "p7@@0NnOR8",
             "username": "sg_fr_k6vuhb@gmail-app.com"
         },
         {
             "id": 582,
-            "lock_until": 0,
             "password": "D@4OCh2j3I",
             "username": "sg_fr_cvq08b@gmail-app.com"
         },
         {
             "id": 583,
-            "lock_until": 0,
             "password": "xT01gsHw@j",
             "username": "sg_fr_4cn9xj@gmail-app.com"
         },
         {
             "id": 584,
-            "lock_until": 0,
             "password": "@aprZh7NbA",
             "username": "sg_fr_m32a2e@gmail-app.com"
         },
         {
             "id": 585,
-            "lock_until": 0,
             "password": "SR2hnX@ho5",
             "username": "sg_fr_p0nz5l@gmail-app.com"
         }
@@ -492,7 +414,7 @@
     "gb_fr": [
         {
             "id": 0,
-            "username":"romicloud@163.com",
+            "username": "romicloud@163.com",
             "password": "Visafly@111",
             "lock_until": 0
         }
@@ -500,7 +422,7 @@
     "ie_es": [
         {
             "id": 0,
-            "username":"arket_zz@163.com",
+            "username": "arket_zz@163.com",
             "password": "dx4ua@!.X.i8Xn8",
             "lock_until": 0
         }
@@ -508,9 +430,9 @@
     "ie_it": [
         {
             "id": 0,
-            "username":"Khandpur1@gmail-app.com",
+            "username": "Khandpur1@gmail-app.com",
             "password": "Visafly@111",
             "lock_until": 0
         }
     ]
-}
+}

+ 39 - 33
config/groups.json

@@ -2,13 +2,14 @@
     {
         "identifier": "VFS_IE_NL",
         "debug": false,
-        "enable": false,
+        "enable": true,
         "need_account": true,
         "local_account_pool": "ie_nl",
         "need_proxy": true,
         "proxy_pool": "isp_proxy",
+        "proxy_lock_interval": 5,
         "target_instances": 1,
-        "account_login_interval": 30,
+        "account_login_interval": 180,
         "order_account_routing": "",
         "order_account_online_limit": 0,
         "account_bind_applicant": false,
@@ -54,18 +55,18 @@
     {
         "identifier": "VFS_SG_FR",
         "debug": false,
-        "enable": false,
+        "enable": true,
         "need_account": true,
         "local_account_pool": "sg_fr",
         "need_proxy": true,
         "proxy_pool": "isp_proxy",
+        "proxy_lock_interval": 5,
         "target_instances": 1,
-        "account_login_interval": 30,
+        "account_login_interval": 180,
         "order_account_routing": "",
         "order_account_online_limit": 0,
         "account_bind_applicant": false,
         "session_max_life": 30,
-
         "query_wait": {
             "mode": "Random",
             "fixed_wait": 10,
@@ -112,13 +113,13 @@
         "local_account_pool": "au_fr",
         "need_proxy": true,
         "proxy_pool": "isp_proxy",
+        "proxy_lock_interval": 5,
         "target_instances": 1,
-        "account_login_interval": 30,
+        "account_login_interval": 180,
         "order_account_routing": "",
         "order_account_online_limit": 0,
         "account_bind_applicant": false,
         "session_max_life": 30,
-
         "query_wait": {
             "mode": "Random",
             "fixed_wait": 10,
@@ -174,18 +175,18 @@
     {
         "identifier": "VFS_GB_IT",
         "debug": false,
-        "enable": false,
+        "enable": true,
         "need_account": true,
         "local_account_pool": "gb_it",
         "need_proxy": true,
         "proxy_pool": "isp_proxy",
+        "proxy_lock_interval": 5,
         "target_instances": 1,
-        "account_login_interval": 30,
+        "account_login_interval": 180,
         "order_account_routing": "",
         "order_account_online_limit": 0,
         "account_bind_applicant": false,
         "session_max_life": 30,
-
         "query_wait": {
             "mode": "Random",
             "fixed_wait": 10,
@@ -241,18 +242,18 @@
     {
         "identifier": "VFS_GB_NL",
         "debug": false,
-        "enable": false,
+        "enable": true,
         "need_account": true,
         "local_account_pool": "gb_nl",
         "need_proxy": true,
         "proxy_pool": "isp_proxy",
+        "proxy_lock_interval": 5,
         "target_instances": 1,
-        "account_login_interval": 30,
+        "account_login_interval": 180,
         "order_account_routing": "",
         "order_account_online_limit": 0,
         "account_bind_applicant": false,
         "session_max_life": 30,
-
         "query_wait": {
             "mode": "Random",
             "fixed_wait": 10,
@@ -308,18 +309,18 @@
     {
         "identifier": "VFS_GB_NO",
         "debug": false,
-        "enable": false,
+        "enable": true,
         "need_account": true,
         "local_account_pool": "gb_no",
         "need_proxy": true,
         "proxy_pool": "isp_proxy",
+        "proxy_lock_interval": 5,
         "target_instances": 1,
-        "account_login_interval": 30,
+        "account_login_interval": 180,
         "order_account_routing": "",
         "order_account_online_limit": 0,
         "account_bind_applicant": false,
         "session_max_life": 30,
-
         "query_wait": {
             "mode": "Random",
             "fixed_wait": 10,
@@ -361,18 +362,18 @@
     {
         "identifier": "VFS_IE_AT",
         "debug": false,
-        "enable": false,
+        "enable": true,
         "need_account": true,
         "local_account_pool": "ie_at",
         "need_proxy": true,
         "proxy_pool": "isp_proxy",
+        "proxy_lock_interval": 5,
         "target_instances": 1,
-        "account_login_interval": 30,
+        "account_login_interval": 180,
         "order_account_routing": "",
         "order_account_online_limit": 0,
         "account_bind_applicant": false,
         "session_max_life": 30,
-
         "query_wait": {
             "mode": "Random",
             "fixed_wait": 10,
@@ -414,18 +415,18 @@
     {
         "identifier": "VFS_IE_DK",
         "debug": false,
-        "enable": false,
+        "enable": true,
         "need_account": true,
         "local_account_pool": "ie_dk",
         "need_proxy": true,
         "proxy_pool": "isp_proxy",
+        "proxy_lock_interval": 5,
         "target_instances": 1,
-        "account_login_interval": 30,
+        "account_login_interval": 180,
         "order_account_routing": "",
         "order_account_online_limit": 0,
         "account_bind_applicant": false,
         "session_max_life": 30,
-
         "query_wait": {
             "mode": "Random",
             "fixed_wait": 10,
@@ -467,18 +468,18 @@
     {
         "identifier": "VFS_IE_FI",
         "debug": false,
-        "enable": false,
+        "enable": true,
         "need_account": true,
         "local_account_pool": "ie_fi",
         "need_proxy": true,
         "proxy_pool": "isp_proxy",
+        "proxy_lock_interval": 5,
         "target_instances": 1,
-        "account_login_interval": 30,
+        "account_login_interval": 180,
         "order_account_routing": "",
         "order_account_online_limit": 0,
         "account_bind_applicant": false,
         "session_max_life": 30,
-
         "query_wait": {
             "mode": "Random",
             "fixed_wait": 10,
@@ -520,18 +521,18 @@
     {
         "identifier": "VFS_IE_HU",
         "debug": false,
-        "enable": false,
+        "enable": true,
         "need_account": true,
         "local_account_pool": "ie_hu",
         "need_proxy": true,
         "proxy_pool": "isp_proxy",
+        "proxy_lock_interval": 5,
         "target_instances": 1,
-        "account_login_interval": 30,
+        "account_login_interval": 180,
         "order_account_routing": "",
         "order_account_online_limit": 0,
         "account_bind_applicant": false,
         "session_max_life": 30,
-
         "query_wait": {
             "mode": "Random",
             "fixed_wait": 10,
@@ -573,18 +574,18 @@
     {
         "identifier": "VFS_IE_IS",
         "debug": false,
-        "enable": false,
+        "enable": true,
         "need_account": true,
         "local_account_pool": "ie_is",
         "need_proxy": true,
         "proxy_pool": "isp_proxy",
+        "proxy_lock_interval": 5,
         "target_instances": 1,
-        "account_login_interval": 30,
+        "account_login_interval": 180,
         "order_account_routing": "",
         "order_account_online_limit": 0,
         "account_bind_applicant": false,
         "session_max_life": 30,
-
         "query_wait": {
             "mode": "Random",
             "fixed_wait": 10,
@@ -626,11 +627,12 @@
     {
         "identifier": "BLS_IE_ES",
         "debug": false,
-        "enable": false,
+        "enable": true,
         "need_account": true,
         "local_account_pool": "ie_es",
         "need_proxy": true,
         "proxy_pool": "iproyal",
+        "proxy_lock_interval": 5,
         "target_instances": 1,
         "account_login_interval": 30,
         "order_account_routing": "",
@@ -676,6 +678,7 @@
         "local_account_pool": "gb_es",
         "need_proxy": true,
         "proxy_pool": "iproyal",
+        "proxy_lock_interval": 5,
         "target_instances": 1,
         "account_login_interval": 30,
         "order_account_routing": "",
@@ -716,11 +719,12 @@
     {
         "identifier": "TLS_GB_FR",
         "debug": false,
-        "enable": false,
+        "enable": true,
         "need_account": true,
         "local_account_pool": "gb_fr",
         "need_proxy": true,
         "proxy_pool": "isp_proxy",
+        "proxy_lock_interval": 5,
         "target_instances": 1,
         "account_login_interval": 30,
         "order_account_routing": "auto.slot.lon.fr.tourist",
@@ -767,6 +771,7 @@
         "local_account_pool": "",
         "need_proxy": true,
         "proxy_pool": "iproyal",
+        "proxy_lock_interval": 5,
         "target_instances": 1,
         "account_login_interval": 30,
         "order_account_routing": "",
@@ -803,6 +808,7 @@
         "local_account_pool": "ie_it",
         "need_proxy": true,
         "proxy_pool": "iproyal",
+        "proxy_lock_interval": 5,
         "target_instances": 1,
         "account_login_interval": 30,
         "order_account_routing": "",

+ 0 - 47
config/proxies.json

@@ -3,7 +3,6 @@
         {
             "id": 100003,
             "ip": "disp.oxylabs.io",
-            "lock_until": 0,
             "password": "jYubEsw6~g3z1Uh",
             "port": 8001,
             "scheme": "http",
@@ -12,7 +11,6 @@
         {
             "id": 100004,
             "ip": "disp.oxylabs.io",
-            "lock_until": 0,
             "password": "jYubEsw6~g3z1Uh",
             "port": 8002,
             "scheme": "http",
@@ -23,7 +21,6 @@
         {
             "id": 100001,
             "ip": "95.135.130.175",
-            "lock_until": 0,
             "password": "hmuROCk1FDebCnL",
             "port": 46247,
             "scheme": "http",
@@ -32,7 +29,6 @@
         {
             "id": 100002,
             "ip": "95.135.130.29",
-            "lock_until": 0,
             "password": "WmqFTSvRvtxChIT",
             "port": 43740,
             "scheme": "http",
@@ -41,7 +37,6 @@
         {
             "id": 100003,
             "ip": "95.135.130.105",
-            "lock_until": 0,
             "password": "a9udkCOGYZKGkLS",
             "port": 47342,
             "scheme": "http",
@@ -50,7 +45,6 @@
         {
             "id": 100004,
             "ip": "95.135.130.157",
-            "lock_until": 0,
             "password": "q1UNK1gmiQdxJ1g",
             "port": 42290,
             "scheme": "http",
@@ -59,7 +53,6 @@
         {
             "id": 100005,
             "ip": "95.135.130.167",
-            "lock_until": 0,
             "password": "bmKmauMV5CuOCrh",
             "port": 48333,
             "scheme": "http",
@@ -68,7 +61,6 @@
         {
             "id": 100006,
             "ip": "95.135.130.181",
-            "lock_until": 0,
             "password": "0HU9RGLRTNNwecf",
             "port": 46253,
             "scheme": "http",
@@ -77,7 +69,6 @@
         {
             "id": 100007,
             "ip": "95.135.130.192",
-            "lock_until": 0,
             "password": "anYmNO4luxcm22m",
             "port": 41255,
             "scheme": "http",
@@ -86,7 +77,6 @@
         {
             "id": 100008,
             "ip": "95.135.130.203",
-            "lock_until": 0,
             "password": "qXEZWLa74q8Awdx",
             "port": 49012,
             "scheme": "http",
@@ -95,7 +85,6 @@
         {
             "id": 100009,
             "ip": "95.135.130.206",
-            "lock_until": 0,
             "password": "MnL8pmNAdpLo0h7",
             "port": 47504,
             "scheme": "http",
@@ -104,7 +93,6 @@
         {
             "id": 100010,
             "ip": "95.135.130.33",
-            "lock_until": 0,
             "password": "slxIVWHqzZpkSPY",
             "port": 44720,
             "scheme": "http",
@@ -113,7 +101,6 @@
         {
             "id": 100011,
             "ip": "95.135.130.53",
-            "lock_until": 0,
             "password": "5fS8EMqdto9JnO9",
             "port": 44764,
             "scheme": "http",
@@ -122,7 +109,6 @@
         {
             "id": 100012,
             "ip": "95.135.130.66",
-            "lock_until": 0,
             "password": "4HzLag9JYiPTZ5J",
             "port": 46470,
             "scheme": "http",
@@ -131,7 +117,6 @@
         {
             "id": 100021,
             "ip": "89.33.195.129",
-            "lock_until": 0,
             "password": "d160bc0854",
             "port": 12323,
             "scheme": "http",
@@ -140,7 +125,6 @@
         {
             "id": 100022,
             "ip": "89.33.195.64",
-            "lock_until": 0,
             "password": "d160bc0854",
             "port": 12323,
             "scheme": "http",
@@ -149,7 +133,6 @@
         {
             "id": 100023,
             "ip": "89.33.195.93",
-            "lock_until": 0,
             "password": "d160bc0854",
             "port": 12323,
             "scheme": "http",
@@ -158,7 +141,6 @@
         {
             "id": 100024,
             "ip": "89.33.195.42",
-            "lock_until": 0,
             "password": "d160bc0854",
             "port": 12323,
             "scheme": "http",
@@ -167,7 +149,6 @@
         {
             "id": 100025,
             "ip": "95.170.29.126",
-            "lock_until": 0,
             "password": "d160bc0854",
             "port": 12323,
             "scheme": "http",
@@ -176,7 +157,6 @@
         {
             "id": 100026,
             "ip": "91.193.255.166",
-            "lock_until": 0,
             "password": "d160bc0854",
             "port": 12323,
             "scheme": "http",
@@ -185,7 +165,6 @@
         {
             "id": 100027,
             "ip": "91.193.255.60",
-            "lock_until": 0,
             "password": "d160bc0854",
             "port": 12323,
             "scheme": "http",
@@ -194,7 +173,6 @@
         {
             "id": 100028,
             "ip": "91.193.255.210",
-            "lock_until": 0,
             "password": "d160bc0854",
             "port": 12323,
             "scheme": "http",
@@ -203,7 +181,6 @@
         {
             "id": 100029,
             "ip": "91.193.255.149",
-            "lock_until": 0,
             "password": "d160bc0854",
             "port": 12323,
             "scheme": "http",
@@ -212,7 +189,6 @@
         {
             "id": 100030,
             "ip": "91.193.255.245",
-            "lock_until": 0,
             "password": "d160bc0854",
             "port": 12323,
             "scheme": "http",
@@ -223,7 +199,6 @@
         {
             "id": 100021,
             "ip": "89.33.195.129",
-            "lock_until": 0,
             "password": "d160bc0854",
             "port": 12323,
             "scheme": "http",
@@ -232,7 +207,6 @@
         {
             "id": 100022,
             "ip": "89.33.195.64",
-            "lock_until": 0,
             "password": "d160bc0854",
             "port": 12323,
             "scheme": "http",
@@ -241,7 +215,6 @@
         {
             "id": 100023,
             "ip": "89.33.195.93",
-            "lock_until": 0,
             "password": "d160bc0854",
             "port": 12323,
             "scheme": "http",
@@ -250,7 +223,6 @@
         {
             "id": 100024,
             "ip": "89.33.195.42",
-            "lock_until": 0,
             "password": "d160bc0854",
             "port": 12323,
             "scheme": "http",
@@ -259,7 +231,6 @@
         {
             "id": 100025,
             "ip": "95.170.29.126",
-            "lock_until": 0,
             "password": "d160bc0854",
             "port": 12323,
             "scheme": "http",
@@ -268,7 +239,6 @@
         {
             "id": 100026,
             "ip": "91.193.255.166",
-            "lock_until": 0,
             "password": "d160bc0854",
             "port": 12323,
             "scheme": "http",
@@ -277,7 +247,6 @@
         {
             "id": 100027,
             "ip": "91.193.255.60",
-            "lock_until": 0,
             "password": "d160bc0854",
             "port": 12323,
             "scheme": "http",
@@ -286,7 +255,6 @@
         {
             "id": 100028,
             "ip": "91.193.255.210",
-            "lock_until": 0,
             "password": "d160bc0854",
             "port": 12323,
             "scheme": "http",
@@ -295,7 +263,6 @@
         {
             "id": 100029,
             "ip": "91.193.255.149",
-            "lock_until": 0,
             "password": "d160bc0854",
             "port": 12323,
             "scheme": "http",
@@ -304,7 +271,6 @@
         {
             "id": 100030,
             "ip": "91.193.255.245",
-            "lock_until": 0,
             "password": "d160bc0854",
             "port": 12323,
             "scheme": "http",
@@ -315,7 +281,6 @@
         {
             "id": 100001,
             "ip": "95.135.130.175",
-            "lock_until": 0,
             "password": "hmuROCk1FDebCnL",
             "port": 46247,
             "scheme": "http",
@@ -324,7 +289,6 @@
         {
             "id": 100002,
             "ip": "95.135.130.29",
-            "lock_until": 0,
             "password": "WmqFTSvRvtxChIT",
             "port": 43740,
             "scheme": "http",
@@ -333,7 +297,6 @@
         {
             "id": 100003,
             "ip": "95.135.130.105",
-            "lock_until": 0,
             "password": "a9udkCOGYZKGkLS",
             "port": 47342,
             "scheme": "http",
@@ -342,7 +305,6 @@
         {
             "id": 100004,
             "ip": "95.135.130.157",
-            "lock_until": 0,
             "password": "q1UNK1gmiQdxJ1g",
             "port": 42290,
             "scheme": "http",
@@ -351,7 +313,6 @@
         {
             "id": 100005,
             "ip": "95.135.130.167",
-            "lock_until": 0,
             "password": "bmKmauMV5CuOCrh",
             "port": 48333,
             "scheme": "http",
@@ -360,7 +321,6 @@
         {
             "id": 100006,
             "ip": "95.135.130.181",
-            "lock_until": 0,
             "password": "0HU9RGLRTNNwecf",
             "port": 46253,
             "scheme": "http",
@@ -369,7 +329,6 @@
         {
             "id": 100007,
             "ip": "95.135.130.192",
-            "lock_until": 0,
             "password": "anYmNO4luxcm22m",
             "port": 41255,
             "scheme": "http",
@@ -378,7 +337,6 @@
         {
             "id": 100008,
             "ip": "95.135.130.203",
-            "lock_until": 0,
             "password": "qXEZWLa74q8Awdx",
             "port": 49012,
             "scheme": "http",
@@ -387,7 +345,6 @@
         {
             "id": 100009,
             "ip": "95.135.130.206",
-            "lock_until": 0,
             "password": "MnL8pmNAdpLo0h7",
             "port": 47504,
             "scheme": "http",
@@ -396,7 +353,6 @@
         {
             "id": 100010,
             "ip": "95.135.130.33",
-            "lock_until": 0,
             "password": "slxIVWHqzZpkSPY",
             "port": 44720,
             "scheme": "http",
@@ -405,7 +361,6 @@
         {
             "id": 100011,
             "ip": "95.135.130.53",
-            "lock_until": 0,
             "password": "5fS8EMqdto9JnO9",
             "port": 44764,
             "scheme": "http",
@@ -414,7 +369,6 @@
         {
             "id": 100012,
             "ip": "95.135.130.66",
-            "lock_until": 0,
             "password": "4HzLag9JYiPTZ5J",
             "port": 46470,
             "scheme": "http",
@@ -425,7 +379,6 @@
         {
             "id": 100029,
             "ip": "127.0.0.1",
-            "lock_until": 0,
             "port": 7890,
             "scheme": "http"
         }

+ 0 - 1
core/app_manager.py

@@ -41,7 +41,6 @@ class AppManager:
         for item in data:
             # JSON -> GroupConfig 转换
             grp_cfg = GroupConfig.from_json(item)
-            print(grp_cfg.free_config)
             self.configs[grp_cfg.identifier] = grp_cfg
             
         VSC_INFO("app_mgr", f"Loaded {len(self.configs)} group configurations.")

+ 5 - 3
gco.py

@@ -285,7 +285,7 @@ class GCO:
             )
 
             if not config_data:
-                time.sleep(2.0)
+                time.sleep(10.0)
                 continue
 
             plg_cfg, task_ref = config_data
@@ -395,10 +395,12 @@ class GCO:
         # =================================================================
         if self.m_cfg.need_proxy:
             # 轮询代理
-            proxy = ProxyManager.Instance().next(self.m_cfg.proxy_pool)
+            proxy_lock_time = self.m_cfg.proxy_lock_interval
+            proxy = ProxyManager.Instance().next(self.m_cfg.proxy_pool, lock_duration=proxy_lock_time)
             if not proxy:
                 try:
-                    if task_ref: VSCloudApi.Instance().return_vas_task_to_queue(task_ref['id'])
+                    if task_ref:
+                        VSCloudApi.Instance().return_vas_task_to_queue(task_ref['id'])
                     return None
                 except Exception as e:
                     self._log(f"Return Order task to queue exception, e={e}")

+ 144 - 35
toolkit/account_manager.py

@@ -4,12 +4,16 @@ import json
 import os
 import random
 from typing import Optional, Dict, Any, List
+# 假设这些日志宏在你的项目中可用,如果不可用请替换为 print 或 logging
 from vs_log_macros import VSC_DEBUG, VSC_WARN, VSC_INFO, VSC_ERROR
 
 class AccountManager:
     """
-    账户管理器 (仅本地配置文件模式)
-    读取 config/accounts.json
+    账户管理器 (支持数据落盘持久化 + 账号池隔离)
+    - 静态配置: config/accounts.json
+    - 动态状态: data/account_states.json
+    
+    关键特性:同一个邮箱如果存在于不同的 pool 中,其冷却时间是隔离的。
     """
     _instance = None
     _lock = threading.RLock()
@@ -26,20 +30,44 @@ class AccountManager:
         return AccountManager()
 
     def _init_data(self):
-        self._accounts: Dict[str, List[Dict]] = {} # pool_name -> [account_dict]
+        # 静态账号数据: pool_name -> List[Dict]
+        self._accounts: Dict[str, List[Dict]] = {} 
+        
+        # 动态锁定状态: "pool_name::username" -> lock_until_timestamp
+        # 使用组合键来保证不同池子的同名账号隔离
+        self._lock_states: Dict[str, float] = {}
+        
         self._account_lock = threading.RLock()
+        
+        # 路径配置
         self._config_path = "config/accounts.json"
+        self._state_path = "data/account_states.json"
+        
+        # 确保 data 目录存在
+        os.makedirs(os.path.dirname(self._state_path), exist_ok=True)
         
         # 初始化时加载
         self.reload_config()
 
+    def _get_state_key(self, pool_name: str, username: str) -> str:
+        """
+        生成唯一的锁定状态 Key。
+        格式: pool_name::username
+        这保证了不同池子里的同名账号互不干扰。
+        """
+        return f"{pool_name}::{username}"
+
     def reload_config(self):
-        """(重新)加载本地配置文件"""
+        """(重新)加载本地配置文件,并恢复锁定状态"""
         if not os.path.exists(self._config_path):
             VSC_WARN("acc_mgr", f"Config file not found: {self._config_path}. Account pools are empty.")
             return
 
         try:
+            # 1. 先加载磁盘上的锁定状态
+            self._load_state_from_disk()
+
+            # 2. 加载静态配置
             with open(self._config_path, 'r', encoding='utf-8') as f:
                 data = json.load(f)
             
@@ -49,80 +77,161 @@ class AccountManager:
                 for pool_name, acc_list in data.items():
                     processed_list = []
                     for acc in acc_list:
-                        # 确保必要字段存在,并初始化状态
                         if "id" not in acc or "username" not in acc:
                             continue
-                            
-                        acc.setdefault('lock_until', 0)
-                        # bound_data 用于存储绑定的预约人信息,配置文件里可以是 null
-                        acc.setdefault('bound_data', None) 
+                        
+                        # 初始化 bound_data
+                        acc.setdefault('bound_data', None)
+                        
+                        # 生成组合键,去查找之前的锁定记录
+                        username = acc["username"]
+                        state_key = self._get_state_key(pool_name, username)
+                        
+                        # 恢复锁定时间 (如果文件中没有记录,默认为0)
+                        saved_lock = self._lock_states.get(state_key, 0)
+                        acc['lock_until'] = saved_lock
                         
                         processed_list.append(acc)
                         count += 1
                     
                     self._accounts[pool_name] = processed_list
                     
-            VSC_INFO("acc_mgr", f"Loaded {count} accounts from {self._config_path}")
+            VSC_INFO("acc_mgr", f"Loaded {count} accounts. Lock states restored from {self._state_path}")
             
         except json.JSONDecodeError:
             VSC_ERROR("acc_mgr", f"Invalid JSON format in {self._config_path}")
         except Exception as e:
             VSC_ERROR("acc_mgr", f"Failed to load config: {e}")
 
+    def _load_state_from_disk(self):
+        """从磁盘读取状态文件"""
+        with self._account_lock:
+            self._lock_states.clear()
+            if not os.path.exists(self._state_path):
+                return
+            try:
+                with open(self._state_path, 'r', encoding='utf-8') as f:
+                    data = json.load(f)
+                    # 加载数据到内存
+                    for k, v in data.items():
+                        self._lock_states[str(k)] = float(v)
+            except Exception as e:
+                VSC_WARN("acc_mgr", f"Failed to load state file: {e}. Starting fresh.")
+
+    def _save_state_to_disk(self):
+        """
+        将当前内存中的锁定状态写入磁盘
+        注意:此方法必须在 self._account_lock 保护下调用
+        """
+        try:
+            now = time.time()
+            # 过滤:只保存未来还会被锁定的账号
+            # Key 是 "pool_name::username"
+            active_states = {
+                k: v for k, v in self._lock_states.items() 
+                if v > now
+            }
+            
+            # 更新内存缓存(剔除已过期的)
+            self._lock_states = active_states
+
+            with open(self._state_path, 'w', encoding='utf-8') as f:
+                json.dump(active_states, f, indent=4)
+                
+        except Exception as e:
+            VSC_ERROR("acc_mgr", f"Failed to save state to disk: {e}")
+
     def next(self, pool_name: str, lock_duration: float = 60.0) -> Optional[Dict[str, Any]]:
         """
-        获取下一个可用账号 (随机策略),并自动锁定指定时长。
+        获取下一个可用账号,并自动锁定指定时长。
         
         @param pool_name: 账号池名称
-        @param lock_duration: 锁定时间(秒),默认60秒
+        @param lock_duration: 锁定时间(秒)
         @return: 账号信息字典 或 None
         """
-        with self._account_lock:
+        with self._account_lock:  # 全局锁
             accounts = self._accounts.get(pool_name, [])
             if not accounts:
-                VSC_WARN("acc_mgr", "No accounts found for pool '%s'", pool_name)
+                # VSC_WARN("acc_mgr", "No accounts found for pool '%s'", pool_name)
                 return None
 
             now = time.time()
-            # 筛选未锁定的账号 (lock_until 必须小于等于当前时间)
-            available = [acc for acc in accounts if acc.get("lock_until", 0) <= now]
+            available = []
+            
+            # 筛选逻辑
+            for acc in accounts:
+                username = acc.get("username")
+                # 生成组合键
+                state_key = self._get_state_key(pool_name, username)
+                
+                # 检查隔离的锁定状态
+                current_lock = self._lock_states.get(state_key, 0)
+                
+                if current_lock <= now:
+                    available.append(acc)
             
             if not available:
-                VSC_DEBUG("acc_mgr", "Pool '%s' has %d accounts but all are locked.", pool_name, len(accounts))
+                # 当前池子所有账号都在冷却中
                 return None
 
             # 随机选择
             selected = random.choice(available)
+            username = selected.get("username")
+            
+            # === 更新状态 ===
+            new_lock_until = now + lock_duration
+            state_key = self._get_state_key(pool_name, username)
+            
+            # 1. 更新全局隔离状态字典
+            self._lock_states[state_key] = new_lock_until
             
-            # === 关键修改:立即更新锁定时间 ===
-            # 直接修改引用的对象,确保其他线程或其他逻辑能感知到该账号已被占用
-            selected["lock_until"] = now + lock_duration
+            # 2. 更新内存对象 (供 remove 等其他逻辑参考)
+            selected["lock_until"] = new_lock_until
             
-            VSC_DEBUG("acc_mgr", "Selected account %s (id=%s) from pool %s, locked for %.1fs", 
-                      selected.get("username"), selected.get("id"), pool_name, lock_duration)
+            # 3. 立即落盘
+            self._save_state_to_disk()
             
-            # 返回账号数据的浅拷贝,防止调用者无意修改 Manager 内部的其他字段
-            # (虽然 Python dict 是引用传递,但 copy 一下是个好习惯,除非你需要引用修改)
+            VSC_INFO("acc_mgr", "Selected %s (Pool: %s), locked for %.0fs (Until: %s)", 
+                      username, pool_name, lock_duration, 
+                      time.strftime("%H:%M:%S", time.localtime(new_lock_until)))
+            
+            # 返回深拷贝或浅拷贝,防止外部污染
             return selected.copy()
 
     def lock(self, pool_name: str, account_id: int, duration_seconds: int):
         """
-        锁定账号一段时间
+        手动锁定账号 (支持隔离)
         """
         with self._account_lock:
             accounts = self._accounts.get(pool_name, [])
+            target_acc = None
+            
+            # 找到账号对象
             for acc in accounts:
                 if acc["id"] == account_id:
-                    acc["lock_until"] = time.time() + duration_seconds
-                    VSC_INFO("acc_mgr", "Locked account %s (id=%d) for %ds", 
-                             acc.get("username"), account_id, duration_seconds)
-                    return
-            VSC_WARN("acc_mgr", "Account %d not found in pool %s to lock", account_id, pool_name)
+                    target_acc = acc
+                    break
+            
+            if target_acc:
+                username = target_acc.get("username")
+                new_lock_until = time.time() + duration_seconds
+                state_key = self._get_state_key(pool_name, username)
+                
+                # 更新状态
+                self._lock_states[state_key] = new_lock_until
+                target_acc["lock_until"] = new_lock_until
+                
+                # 落盘
+                self._save_state_to_disk()
+                
+                VSC_INFO("acc_mgr", "Manually locked %s (Pool: %s) for %ds", 
+                         username, pool_name, duration_seconds)
+            else:
+                VSC_WARN("acc_mgr", "Account ID %d not found in pool %s to lock", account_id, pool_name)
 
     def remove(self, pool_name: str, account_id: int, reason: str = "success", extra_data: dict = None):
         """
-        从内存中移除账号 (预订成功后不再使用)
-        注意:这不会修改磁盘上的 accounts.json 文件,重启程序后账号会恢复
+        从内存池中移除账号 (仅影响本次运行内存,不影响文件配置)
         """
         with self._account_lock:
             accounts = self._accounts.get(pool_name, [])
@@ -134,7 +243,7 @@ class AccountManager:
             
             if target_acc:
                 accounts.remove(target_acc)
-                VSC_INFO("acc_mgr", "Removed account %s (id=%d) from memory pool %s. Reason: %s", 
-                         target_acc.get("username"), account_id, pool_name, reason)
+                VSC_INFO("acc_mgr", "Removed %s from memory pool %s. Reason: %s", 
+                         target_acc.get("username"), pool_name, reason)
             else:
-                VSC_WARN("acc_mgr", "Attempt to remove non-existent account %d from pool %s", account_id, pool_name)
+                pass

+ 135 - 46
toolkit/proxy_manager.py

@@ -8,8 +8,9 @@ from vs_log_macros import VSC_DEBUG, VSC_WARN, VSC_INFO, VSC_ERROR
 
 class ProxyManager:
     """
-    代理管理器 (仅本地配置文件模式)
-    读取 config/proxies.json
+    代理管理器 (支持数据落盘持久化 + 代理池隔离)
+    - 静态配置: config/proxies.json
+    - 动态状态: data/proxy_states.json
     """
     _instance = None
     _lock = threading.RLock()
@@ -26,19 +27,41 @@ class ProxyManager:
         return ProxyManager()
 
     def _init_data(self):
-        self._proxies: Dict[str, List[Dict]] = {} # pool_name -> [proxy_dict]
+        # 静态数据: pool_name -> List[Dict]
+        self._proxies: Dict[str, List[Dict]] = {}
+        
+        # 动态锁定状态: "pool_name::proxy_id" -> lock_until_timestamp
+        self._lock_states: Dict[str, float] = {}
+        
         self._proxy_lock = threading.RLock()
+        
+        # 路径配置
         self._config_path = "config/proxies.json"
+        self._state_path = "data/proxy_states.json"
+        
+        # 确保 data 目录存在
+        os.makedirs(os.path.dirname(self._state_path), exist_ok=True)
         
         self.reload_config()
 
+    def _get_state_key(self, pool_name: str, proxy_id: Any) -> str:
+        """
+        生成唯一的锁定状态 Key (组合键)
+        格式: pool_name::proxy_id
+        """
+        return f"{pool_name}::{proxy_id}"
+
     def reload_config(self):
-        """(重新)加载本地配置文件"""
+        """(重新)加载本地配置文件,并恢复锁定状态"""
         if not os.path.exists(self._config_path):
             VSC_WARN("proxy_mgr", f"Config file not found: {self._config_path}. Proxy pools are empty.")
             return
 
         try:
+            # 1. 先加载磁盘上的锁定状态
+            self._load_state_from_disk()
+
+            # 2. 加载静态配置
             with open(self._config_path, 'r', encoding='utf-8') as f:
                 data = json.load(f)
             
@@ -52,83 +75,149 @@ class ProxyManager:
                         if "id" not in p or "ip" not in p or "port" not in p:
                             continue
                         
-                        # 初始化状态
-                        p.setdefault('lock_until', 0)
+                        # 初始化默认字段
                         p.setdefault('scheme', 'http')
                         p.setdefault('username', '')
                         p.setdefault('password', '')
                         
+                        # 恢复锁定状态
+                        proxy_id = p["id"]
+                        state_key = self._get_state_key(pool_name, proxy_id)
+                        
+                        # 从全局状态中获取该池子下该代理的锁定时间
+                        saved_lock = self._lock_states.get(state_key, 0)
+                        p['lock_until'] = saved_lock
+                        
                         processed_list.append(p)
                         count += 1
                     
                     self._proxies[pool_name] = processed_list
                     
-            VSC_INFO("proxy_mgr", f"Loaded {count} proxies from {self._config_path}")
+            VSC_INFO("proxy_mgr", f"Loaded {count} proxies. Lock states restored from {self._state_path}")
             
         except json.JSONDecodeError:
             VSC_ERROR("proxy_mgr", f"Invalid JSON format in {self._config_path}")
         except Exception as e:
             VSC_ERROR("proxy_mgr", f"Failed to load proxy config: {e}")
 
-    def next(self, pool_name: str) -> Optional[Dict[str, Any]]:
+    def _load_state_from_disk(self):
+        """从磁盘读取状态文件"""
+        with self._proxy_lock:
+            self._lock_states.clear()
+            if not os.path.exists(self._state_path):
+                return
+            try:
+                with open(self._state_path, 'r', encoding='utf-8') as f:
+                    data = json.load(f)
+                    for k, v in data.items():
+                        self._lock_states[str(k)] = float(v)
+            except Exception as e:
+                VSC_WARN("proxy_mgr", f"Failed to load state file: {e}. Starting fresh.")
+
+    def _save_state_to_disk(self):
         """
-        从指定池中获取下一个可用代理 (随机)
+        将当前内存中的锁定状态写入磁盘
+        只保存未来还会被锁定的记录,减少文件大小
         """
-        with self._proxy_lock:
-            proxies = self._proxies.get(pool_name, [])
-            if not proxies:
-                VSC_WARN("proxy_mgr", "No proxies found in pool '%s'", pool_name)
-                return None
-            
+        try:
             now = time.time()
-            available_proxies = [p for p in proxies if p["lock_until"] <= now]
-            
-            if not available_proxies:
-                VSC_WARN("proxy_mgr", "Pool '%s' has proxies but all are locked/busy.", pool_name)
-                return None
+            active_states = {
+                k: v for k, v in self._lock_states.items() 
+                if v > now
+            }
             
-            proxy = random.choice(available_proxies)
-            VSC_DEBUG("proxy_mgr", "Selected proxy ID %d (%s) from pool '%s'", 
-                      proxy["id"], proxy["ip"], pool_name)
-            return proxy
+            # 更新内存缓存
+            self._lock_states = active_states
 
-    def get_unbind(self, pool_name: str, bounded_ids: List[int]) -> Optional[Dict[str, Any]]:
+            with open(self._state_path, 'w', encoding='utf-8') as f:
+                json.dump(active_states, f, indent=4)
+                
+        except Exception as e:
+            VSC_ERROR("proxy_mgr", f"Failed to save state to disk: {e}")
+
+    def next(self, pool_name: str, lock_duration: float = 0.0) -> Optional[Dict[str, Any]]:
         """
-        获取一个未绑定(且未锁定)的代理。
-        用于 GCO 的 IP 绑定逻辑。
+        从指定池中获取下一个可用代理,并锁定指定时长。
+        
+        @param pool_name: 代理池名称
+        @param lock_duration: 锁定时间(秒)。
+                              注意:如果不传或传0,则不锁定(仅获取),适合无状态请求。
+                              如果为了限制频率,请传入大于0的值。
         """
         with self._proxy_lock:
             proxies = self._proxies.get(pool_name, [])
             if not proxies:
-                VSC_WARN("proxy_mgr", "No proxies found in pool '%s'", pool_name)
+                # VSC_WARN("proxy_mgr", "No proxies found in pool '%s'", pool_name)
                 return None
-
-            now = time.time()
             
-            # 筛选条件:1. 未锁定  2. ID 不在已绑定列表中
-            unbound_and_available = [
-                p for p in proxies 
-                if p["id"] not in bounded_ids and p["lock_until"] <= now
-            ]
+            now = time.time()
+            available = []
+
+            # 筛选可用代理
+            for p in proxies:
+                proxy_id = p["id"]
+                state_key = self._get_state_key(pool_name, proxy_id)
+                
+                # 检查隔离的锁定状态
+                current_lock = self._lock_states.get(state_key, 0)
+                
+                if current_lock <= now:
+                    available.append(p)
             
-            if not unbound_and_available:
-                VSC_WARN("proxy_mgr", "No unbound and available proxies in pool '%s'", pool_name)
+            if not available:
+                # VSC_WARN("proxy_mgr", "Pool '%s' has proxies but all are locked/busy.", pool_name)
                 return None
             
-            proxy = random.choice(unbound_and_available)
-            VSC_DEBUG("proxy_mgr", "Selected unbound proxy ID %d from pool '%s'", proxy["id"], pool_name)
-            return proxy
+            # 随机选择
+            selected = random.choice(available)
+            proxy_id = selected["id"]
+            
+            # === 如果需要锁定,更新全局状态并落盘 ===
+            if lock_duration > 0:
+                new_lock_until = now + lock_duration
+                state_key = self._get_state_key(pool_name, proxy_id)
+                
+                # 1. 更新状态
+                self._lock_states[state_key] = new_lock_until
+                selected["lock_until"] = new_lock_until
+                
+                # 2. 立即落盘
+                self._save_state_to_disk()
+                
+                VSC_DEBUG("proxy_mgr", "Selected proxy ID %s (Pool: %s), locked for %.0fs", 
+                          proxy_id, pool_name, lock_duration)
+            else:
+                VSC_DEBUG("proxy_mgr", "Selected proxy ID %s (Pool: %s) without lock", 
+                          proxy_id, pool_name)
+
+            return selected.copy()
 
     def lock(self, pool_name: str, proxy_id: int, duration_seconds: int):
         """
-        锁定指定代理一段时间 (例如请求过于频繁被 429)
+        手动锁定指定代理 (支持数据落盘)
+        通常用于在请求失败(如429)时紧急调用
         """
         with self._proxy_lock:
             proxies = self._proxies.get(pool_name, [])
+            target_proxy = None
+            
             for p in proxies:
                 if p["id"] == proxy_id:
-                    p["lock_until"] = time.time() + duration_seconds
-                    VSC_INFO("proxy_mgr", "Locked proxy ID %d in pool '%s' for %ds",
-                             proxy_id, pool_name, duration_seconds)
-                    return
-            VSC_WARN("proxy_mgr", "Proxy ID %d not found in pool '%s' for locking", proxy_id, pool_name)
+                    target_proxy = p
+                    break
+            
+            if target_proxy:
+                state_key = self._get_state_key(pool_name, proxy_id)
+                new_lock_until = time.time() + duration_seconds
+                
+                # 更新状态
+                self._lock_states[state_key] = new_lock_until
+                target_proxy["lock_until"] = new_lock_until
+                
+                # 立即落盘
+                self._save_state_to_disk()
+                
+                VSC_INFO("proxy_mgr", "Manually locked proxy ID %d in pool '%s' for %ds",
+                         proxy_id, pool_name, duration_seconds)
+            else:
+                VSC_WARN("proxy_mgr", "Proxy ID %d not found in pool '%s' for locking", proxy_id, pool_name)

+ 1 - 1
vs_types.py

@@ -108,7 +108,7 @@ class GroupConfig(BaseModel):
 
     need_proxy: bool = False
     proxy_pool: str = ""
-    need_ip_bind: bool = False
+    proxy_lock_interval: int = 5
 
     account_login_interval: int = 0
     target_instances: int = 1