Files
hubproxy/ghproxy/proxysh.go
2025-05-20 15:40:57 +08:00

192 lines
5.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"bufio"
"compress/gzip"
"fmt"
"io"
"regexp"
"strings"
)
var (
// gitHubDomains 定义所有支持的GitHub相关域名
gitHubDomains = []string{
"github.com",
"raw.githubusercontent.com",
"raw.github.com",
"gist.githubusercontent.com",
"gist.github.com",
"api.github.com",
}
// urlPattern 使用gitHubDomains构建正则表达式
urlPattern = regexp.MustCompile(`https?://(?:` + strings.Join(gitHubDomains, "|") + `)[^\s'"]+`)
// 是否启用脚本嵌套代理的调试日志
DebugLog = true
)
// 打印调试日志的辅助函数
func debugPrintf(format string, args ...interface{}) {
if DebugLog {
fmt.Printf(format, args...)
}
}
// ProcessGitHubURLs 处理数据流中的GitHub URL将其替换为代理URL。
// 此处思路借鉴了 https://github.com/WJQSERVER-STUDIO/ghproxy/blob/main/proxy/nest.go
func ProcessGitHubURLs(input io.ReadCloser, isCompressed bool, host string, isShellFile bool) (io.Reader, int64, error) {
debugPrintf("开始处理文件: isCompressed=%v, host=%s, isShellFile=%v\n", isCompressed, host, isShellFile)
if !isShellFile {
debugPrintf("非shell文件跳过处理\n")
return input, 0, nil
}
// 使用更大的缓冲区以提高性能
pipeReader, pipeWriter := io.Pipe()
var written int64
go func() {
var err error
defer func() {
if err != nil {
debugPrintf("处理过程中发生错误: %v\n", err)
_ = pipeWriter.CloseWithError(err)
} else {
_ = pipeWriter.Close()
}
}()
defer input.Close()
var reader io.Reader = input
if isCompressed {
debugPrintf("检测到压缩文件,进行解压处理\n")
gzipReader, gzipErr := gzip.NewReader(input)
if gzipErr != nil {
err = gzipErr
return
}
defer gzipReader.Close()
reader = gzipReader
}
// 使用更大的缓冲区
bufReader := bufio.NewReaderSize(reader, 32*1024) // 32KB buffer
var writer io.Writer = pipeWriter
if isCompressed {
gzipWriter := gzip.NewWriter(writer)
defer gzipWriter.Close()
writer = gzipWriter
}
bufWriter := bufio.NewWriterSize(writer, 32*1024) // 32KB buffer
defer bufWriter.Flush()
written, err = processContent(bufReader, bufWriter, host)
if err != nil {
debugPrintf("处理内容时发生错误: %v\n", err)
return
}
debugPrintf("文件处理完成,共处理 %d 字节\n", written)
}()
return pipeReader, written, nil
}
// processContent 优化处理文件内容的函数
func processContent(reader *bufio.Reader, writer *bufio.Writer, host string) (int64, error) {
var written int64
lineNum := 0
for {
lineNum++
line, err := reader.ReadString('\n')
if err != nil && err != io.EOF {
return written, fmt.Errorf("读取行时发生错误: %w", err)
}
if line != "" {
// 在处理前先检查是否包含GitHub URL
if strings.Contains(line, "github.com") ||
strings.Contains(line, "raw.githubusercontent.com") {
matches := urlPattern.FindAllString(line, -1)
if len(matches) > 0 {
debugPrintf("\n在第 %d 行发现 %d 个GitHub URL:\n", lineNum, len(matches))
for _, match := range matches {
debugPrintf("原始URL: %s\n", match)
}
}
modifiedLine := processLine(line, host, lineNum)
n, writeErr := writer.WriteString(modifiedLine)
if writeErr != nil {
return written, fmt.Errorf("写入修改后的行时发生错误: %w", writeErr)
}
written += int64(n)
} else {
// 如果行中没有GitHub URL直接写入
n, writeErr := writer.WriteString(line)
if writeErr != nil {
return written, fmt.Errorf("写入原始行时发生错误: %w", writeErr)
}
written += int64(n)
}
}
if err == io.EOF {
break
}
}
// 确保所有数据都被写入
if err := writer.Flush(); err != nil {
return written, fmt.Errorf("刷新缓冲区时发生错误: %w", err)
}
return written, nil
}
// processLine 处理单行文本替换所有匹配的GitHub URL
func processLine(line string, host string, lineNum int) string {
return urlPattern.ReplaceAllStringFunc(line, func(url string) string {
newURL := modifyGitHubURL(url, host)
if newURL != url {
debugPrintf("第 %d 行URL替换:\n 原始: %s\n 替换后: %s\n", lineNum, url, newURL)
}
return newURL
})
}
// modifyGitHubURL 修改GitHub URL添加代理域名前缀
func modifyGitHubURL(url string, host string) string {
for _, domain := range gitHubDomains {
hasHttps := strings.HasPrefix(url, "https://"+domain)
hasHttp := strings.HasPrefix(url, "http://"+domain)
if hasHttps || hasHttp || strings.HasPrefix(url, domain) {
if !hasHttps && !hasHttp {
url = "https://" + url
}
if hasHttp {
url = "https://" + strings.TrimPrefix(url, "http://")
}
// 移除host开头的协议头如果有
host = strings.TrimPrefix(host, "https://")
host = strings.TrimPrefix(host, "http://")
// 返回组合后的URL
return host + "/" + url
}
}
return url
}
// IsShellFile 检查文件是否为shell文件基于文件名
func IsShellFile(filename string) bool {
return strings.HasSuffix(filename, ".sh")
}