Browse Source

Merge branch 'release/0.4.0'

liuyuqi-dellpc 2 months ago
parent
commit
dea61c0a5a
7 changed files with 116 additions and 13 deletions
  1. 68 7
      client.py
  2. 23 0
      docs/Develop.md
  3. 5 3
      fgh/api/home.py
  4. 1 1
      fgh/config.py
  5. 6 1
      fgh/utils/proxy.py
  6. 12 0
      fgh/utils/regex_util.py
  7. 1 1
      scripts/start_fgh.bat

+ 68 - 7
client.py

@@ -10,9 +10,17 @@
 import os,sys,re
 import argparse
 from fgh.utils.frozen_dir import get_app_path
+import requests, subprocess, platform
+import dotenv
 
 class Client:
+
     help_str ="""
+    fgh(fast github) quick clone github repo tools
+        contact: liuyuqi.gov@msn.cn
+
+Usage: fgh <command> [<args>]
+
 # clone repo
 fgh clone https://github.com/xx/yy.git
 fgh push https://github.com/xx/yy.git
@@ -23,18 +31,23 @@ fgh wget https://ghproxy.org/https://raw.githubusercontent.com/microsoft/vscode/
 
 fgh curl -O https://ghproxy.org/https://github.com/microsoft/vscode/archive/refs/tags/1.84.2.zip
 fgh curl -O https://ghproxy.org/https://raw.githubusercontent.com/microsoft/vscode/main/README.md
+
+
 """
 
     def __init__(self):
         self.fgit_host = ''
         self.token = ''
+        self.update_host()
         self.read_config()
         self.args = self.parse_args()
+        self.sess = requests.Session()
+        self.env_file_path = os.path.join(get_app_path(), '.env')
 
     def read_config(self):
-        import dotenv
+        """ read config """
         current_dir = get_app_path()
-        dotenv.load_dotenv(os.path.join(current_dir, '.env'))
+        dotenv.load_dotenv(self.env_file_path)
         fgit_host = os.getenv('FGH_HOST')
         try:
             if fgit_host[-1] == '/':
@@ -43,8 +56,32 @@ fgh curl -O https://ghproxy.org/https://raw.githubusercontent.com/microsoft/vsco
         except Exception as e:
             print(".env配置错误"+e)
 
+    @staticmethod
+    def ping(host: str) -> None|int:
+        """ ping host """
+        try:
+            if platform.system().lower() == 'windows':
+                command = ['ping', '-n', '1', '-w', '1000', host]
+            else:
+                command = ['ping', '-c', '1', '-W', '1', host]
+        
+            output = subprocess.run(command, capture_output=True, text=True)
+
+            # 从输出中提取延迟信息
+            if output.returncode == 0:
+                # 使用正则表达式从输出中匹配延迟时间
+                pattern = r"time=(\d+)ms"
+                match = re.search(pattern, output.stdout)
+                if match:
+                    return int(match.group(1))  # 返回延迟时间(毫秒)
+            return None  # 如果 ping 失败或延迟时间无法提取,则返回 None
+        except Exception as e:
+            print(e)
+        return None
+
     @staticmethod
     def parse_args():
+        """ parse args """
         parser = argparse.ArgumentParser(description='fgit client')
         parser.add_argument('command', type=str, help='fgit command', 
                             choices=['git','wget','curl','clone', 'push', 'pull', 'commit', 'add', 'status', 'log', 'diff', 'branch', 'checkout', 'merge', 'rebase', 'reset', 'tag', 'fetch', 'remote', 'init', 'config', 'help'])
@@ -52,11 +89,35 @@ fgh curl -O https://ghproxy.org/https://raw.githubusercontent.com/microsoft/vsco
         parser.add_argument('args', nargs=argparse.REMAINDER, help='git command args')
         return parser.parse_args()
 
-    def choose_host(self):
-        """choose host"""
-        pass
-
-    def run(self):   
+    def update_host(self):
+        """update host"""
+        res = []
+        try:
+            res = self.sess.get(self.fgit_host+'/update_host')
+            fgh_hosts= res.json()["hosts"]
+            fgh_host= self._get_best_host()
+            dotenv.set_key(self.env_file_path, 'FGH_HOST', fgh_host)
+        except Exception as e:
+            print(e)
+        
+    def _get_best_host(self, hosts: list) -> str:
+        """ 在所有 hosts 中,ping 延迟最短的返回 """
+        print("即将检测网络延迟...")
+        res =[]
+        for host in hosts:
+            res.append({'host': host, 'delay': self.ping(host) if self.ping(host) else 999999})
+            print("正在ping "+ host + " 延迟为:" + str(res[-1]['delay']) + "ms")
+        min_delay = 999999
+        min_host = ''
+        for item in res:
+            if item['delay'] and item['delay'] < min_delay:
+                min_delay = item['delay']
+                min_host = item['host']
+        print("选择最佳host: " + min_host + " 延迟为:" + str(min_delay) + "ms")
+        return min_host
+    
+    def run(self):
+        """ run """
         args = self.parse_args()
         command = args.command
         if len(args.args) == 0 and command != 'help':

+ 23 - 0
docs/Develop.md

@@ -0,0 +1,23 @@
+# Develop
+
+## Introduction
+
+基于flask,提供如下接口:
+
+```
+@home.route('/<path:u>', methods=['GET', 'POST'])
+def handler(u):
+```
+对于任意的url,都会调用handler函数,参数u为url的path部分。如访问: https://localhost:8080/https://github.com/xx/yy.git 时,u为 https://github.com/xx/yy.git
+
+### 三种模式:
+
+白名单:只有在白名单中的url才会被处理,其他的url会返回404
+黑名单:只有不在黑名单中的url才会被处理
+pass_py: 替换为 cdn 链接,不处理
+
+
+
+
+
+

+ 5 - 3
fgh/api/home.py

@@ -40,10 +40,12 @@ def index():
 
 @home.route('/<path:u>', methods=['GET', 'POST'])
 def handler(u):
-    # 确保它是以 'http://' 或 'https://' 开头
+    # 自动加上https://
     u = u if u.startswith('http') else 'https://' + u
     if u.rfind('://', 3, 9) == -1:
-        u = u.replace('s:/', 's://', 1)  # uwsgi会将//传递为/
+        u = u.replace('s:/', 's://', 1)  # uwsgi 会将//传递为/
+    # save the original url to db
+    
     pass_by = False
     m = check_url(u)
     if m:
@@ -52,7 +54,7 @@ def handler(u):
             for i in white_list:
                 if m[:len(i)] == i or i[0] == '*' and len(m) == 2 and m[1] == i[1]:
                     break
-            else:
+            else:  # 如果 for 循环完成而没有break被执行,那么会执行else
                 return Response('Forbidden by white list.', status=403)
         for i in black_list:
             if m[:len(i)] == i or i[0] == '*' and len(m) == 2 and m[1] == i[1]:

+ 1 - 1
fgh/config.py

@@ -7,7 +7,7 @@
 @Desc    :   config
 """
 
-import os, sys
+import os
 from dotenv import load_dotenv
 from fgh.utils.frozen_dir import get_app_path
 

+ 6 - 1
fgh/utils/proxy.py

@@ -26,6 +26,10 @@ CHUNK_SIZE = 1024 * 10
 
 
 def check_url(u):
+    """ 检测URL是否GitHub链接
+    :param u: URL
+    :return: 匹配到返回 match object,否则返回 False
+    """
     for exp in (exp1, exp2, exp3, exp4, exp5):
         m = exp.match(u)
         if m:
@@ -92,7 +96,8 @@ def proxy(u, allow_redirects=False):
         url = u + request.url.replace(request.base_url, '', 1)
         if url.startswith('https:/') and not url.startswith('https://'):
             url = 'https://' + url[7:]
-        r = requests.request(method=request.method, url=url, data=request.data, headers=r_headers, stream=True, allow_redirects=allow_redirects)
+        r = requests.request(method=request.method, url=url, data=request.data, 
+                             headers=r_headers, stream=True, allow_redirects=allow_redirects)
         headers = dict(r.headers)
         
         # 是否超过设定的 size_limit,如果超过则重定向到原始URL

+ 12 - 0
fgh/utils/regex_util.py

@@ -20,3 +20,15 @@ exp4 = re.compile(r'^(?:https?://)?raw\.(?:githubusercontent|github)\.com/(?P<au
 exp5 = re.compile(r'^(?:https?://)?gist\.(?:githubusercontent|github)\.com/(?P<author>.+?)/.+?/.+$')
 
 
+if __name__=='__main__':
+    github_str = {
+        "str0": r'http://github.com/jianboy/test1/releases/tag/v1.0',
+        "str1": r'https://github.com/jianboy/test1/releases/a.zip',
+        "str2": r'https://github.com/author/repo/blob'
+    }
+
+    for k, v in github_str.items():
+        i=1
+        for exp in [exp1, exp2, exp3, exp4, exp5]:
+            print(k + ", exp"+ str(i), exp.match(v))
+            i+=1

+ 1 - 1
scripts/start_fgh.bat

@@ -12,4 +12,4 @@ REM ***************************************************************************
 
 rem start cmd on current path, and add the path to the system path
 set PATH=%PATH%;%~dp0
-cmd
+cmd /K fgh help