mirror of
https://gitee.com/chuangxxt/share-copilot
synced 2025-06-09 18:33:26 +00:00
Compare commits
No commits in common. "fd1dea3ab31cb13b1b940bb674c763ddfb309009" and "934820d691daac67790163e077861b9b8f5b9a0b" have entirely different histories.
fd1dea3ab3
...
934820d691
35
README.md
35
README.md
@ -1,9 +1,9 @@
|
||||
[中文](README.md) | [English](README-EN.md)
|
||||
|
||||
[中文](README.md) |[English](README-EN.md)
|
||||
|
||||
***
|
||||
# share-copilot
|
||||
|
||||
- 作为代理服务器,中转copilot插件的API的请求(也可以代理无良商贩的,自行研究)
|
||||
- 作为代理服务器,中转copilot插件的API的请求
|
||||
- 支持vscode插件和jetbrains插件
|
||||
- 支持多用户共享一个token
|
||||
- 优化请求逻辑,降低suspended概率(别万人骑基本不会)
|
||||
@ -12,21 +12,22 @@
|
||||
简单说一下
|
||||
本地插件的请求逻辑:
|
||||
|
||||
1.本地插件携ghu_token 请求github的API
|
||||
1.本地插件携ghu_token请求github的API
|
||||
|
||||
2.返回带有时间戳的copilot的token(简称co_token),
|
||||
2.返回带有时间戳的copilot的token(下面简称co_token),
|
||||
代码提示都是用的co_token
|
||||
|
||||
3.co_token到期->ghu_token重新请求->获得新的co_token
|
||||
-------------------------------------------------------------
|
||||
|
||||
代理服务器的逻辑:
|
||||
|
||||
代理的是"ghu_token请求"这一环节
|
||||
|
||||
1.使用ghu_token请求github的API,暂存co_token
|
||||
1.携ghu_token请求github的API,暂存co_token
|
||||
|
||||
2.多用户请求时,判断co_token有没有过期,没过期直接返回co_token,
|
||||
减少对ghu_token的请求次数(大约10-20分钟过期)
|
||||
2.多用户请求时,判断co_token有没有过期,没过期直接返回,
|
||||
减少ghu_token的请求次数(大约10-20分钟过期)
|
||||
|
||||
3.至于本地co_token,也就是代码提示没有走代理(可以代理,但是要修改插件,jetbrains的插件还要重新build)
|
||||
猜测风控目前也只是停留在请求ghu_token这一层
|
||||
@ -35,21 +36,7 @@
|
||||
|
||||
```
|
||||
|
||||
------
|
||||
|
||||
```xml
|
||||
| 文件名 | 说明
|
||||
| -------------- | -------------------
|
||||
| config.json | 配置文件
|
||||
| copilot_api | guh_token和co_token相关逻辑
|
||||
| global | 全局变量、常量或配置
|
||||
| main | 主要入口文件
|
||||
| middleware | 中间件,验证域名,验证自定义请求头
|
||||
| routers | 路由信息,定义不同请求路径的处理逻辑。
|
||||
| server | 服务端的代码或相关配置,用于启动和运行服务器。
|
||||
| show_msg | 用于显示消息或信息的函数,展示内容。
|
||||
|
||||
```
|
||||

|
||||
|
||||
***
|
||||
# 一、自行编译:
|
||||
@ -192,7 +179,7 @@ GithubApi: --服务器请求gh_api次数
|
||||
```
|
||||
------
|
||||
|
||||
##### 4.3本地配置修改:可以使用zhile大佬的[cocopilot脚本](https://gitee.com/chuangxxt/share-copilot/releases/download/v1.0.3/cocopilot-master.zip) 改成自己的api一键配置
|
||||
##### 4.3本地配置修改:
|
||||
|
||||
**以windows为例**
|
||||
|
||||
|
@ -1,112 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-resty/resty/v2"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 初始化有效的github token列表
|
||||
func initValidGhuTokenMap() {
|
||||
for _, token := range configFile.CopilotConfig.Token {
|
||||
if getGithubApi(token) {
|
||||
// 有效的token
|
||||
validGhuTokenMap[token] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 代理服务器返回copilot token
|
||||
func proxyResp(c *gin.Context, respDataMap map[string]interface{}) {
|
||||
// 将map转换为JSON字符串
|
||||
responseJSON, _ := json.Marshal(respDataMap)
|
||||
// 请求成功统计
|
||||
successCount++
|
||||
// 将响应体作为JSON字符串返回
|
||||
c.Header("Content-Type", "application/json")
|
||||
c.String(http.StatusOK, string(responseJSON))
|
||||
}
|
||||
|
||||
// 获取有效的 copilot token
|
||||
func getCopilotToken() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
//用户请求代理服务器的计数
|
||||
requestCount++
|
||||
//随机从有效的github token列表中获取一个token
|
||||
token := getRandomToken(validGhuTokenMap)
|
||||
//通过token取对应的copilot token的map数据
|
||||
if respDataMap, exists := getTokenData(token); exists {
|
||||
//没过期直接返回
|
||||
if !isTokenExpired(respDataMap) {
|
||||
proxyResp(c, respDataMap)
|
||||
return
|
||||
}
|
||||
}
|
||||
//过期了或者没取到,重新获取
|
||||
if getGithubApi(token) {
|
||||
proxyResp(c, copilotTokenMap[token])
|
||||
} else {
|
||||
// 重新获取失败,返回自定义消息 400
|
||||
diyBadRequest(c, 400, "can't get copilot token")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 请求github api
|
||||
func getGithubApi(token string) bool {
|
||||
// githubApi请求计数
|
||||
githubApiCount++
|
||||
// 设置请求头
|
||||
headers := map[string]string{
|
||||
"Authorization": "token " + token,
|
||||
}
|
||||
// 发起GET请求
|
||||
response, _ := resty.New().R().
|
||||
SetHeaders(headers).
|
||||
Get(configFile.CopilotConfig.GithubApiUrl)
|
||||
// 判断响应状态码
|
||||
if response.StatusCode() == http.StatusOK {
|
||||
// 响应状态码为200 OK
|
||||
respDataMap := map[string]interface{}{}
|
||||
_ = json.Unmarshal(response.Body(), &respDataMap)
|
||||
copilotTokenMap[token] = respDataMap
|
||||
return true
|
||||
} else {
|
||||
// 响应状态码不为200 map删除无效token
|
||||
delete(validGhuTokenMap, token)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 从map中获取github token对应的copilot token
|
||||
func getTokenData(token string) (map[string]interface{}, bool) {
|
||||
respDataMap, exists := copilotTokenMap[token]
|
||||
return respDataMap, exists
|
||||
}
|
||||
|
||||
// 检测copilot token是否过期
|
||||
func isTokenExpired(respDataMap map[string]interface{}) bool {
|
||||
if expiresAt, ok := respDataMap["expires_at"].(float64); ok {
|
||||
currentTime := time.Now().Unix()
|
||||
expiresAtInt64 := int64(expiresAt)
|
||||
return expiresAtInt64 <= currentTime+60
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 从map中随机获取一个github token
|
||||
func getRandomToken(m map[string]bool) string {
|
||||
ghuTokenArray := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
ghuTokenArray = append(ghuTokenArray, k)
|
||||
}
|
||||
if len(ghuTokenArray) == 0 {
|
||||
return "" // 没有有效的token,返回空字符串
|
||||
}
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
randomIndex := r.Intn(len(ghuTokenArray))
|
||||
return ghuTokenArray[randomIndex]
|
||||
}
|
32
src/define.go
Normal file
32
src/define.go
Normal file
@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Server struct {
|
||||
Domain string `json:"domain"`
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
CertPath string `json:"certPath"`
|
||||
KeyPath string `json:"keyPath"`
|
||||
} `json:"server"`
|
||||
CopilotConfig struct {
|
||||
GithubApiUrl string `json:"github_api_url"`
|
||||
Token []string `json:"token"`
|
||||
} `json:"copilot_config"`
|
||||
Verification string `json:"verification"`
|
||||
}
|
||||
|
||||
var (
|
||||
//初始化需要返回给客户端的响应体
|
||||
tokenMap = make(map[string]map[string]interface{})
|
||||
//有效的token列表
|
||||
validTokenList = make(map[string]bool)
|
||||
requestCountMutex sync.Mutex
|
||||
githubApiCount = 0
|
||||
requestCount = 0
|
||||
successCount = 0
|
||||
configFile Config
|
||||
)
|
142
src/getCopilotToke.go
Normal file
142
src/getCopilotToke.go
Normal file
@ -0,0 +1,142 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-resty/resty/v2"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 初始化有效的github token列表
|
||||
func initValidTokenList() {
|
||||
//为了安全起见,应该等待请求完成并处理其响应。
|
||||
var wg sync.WaitGroup
|
||||
for _, token := range configFile.CopilotConfig.Token {
|
||||
wg.Add(1)
|
||||
go func(token string) {
|
||||
defer wg.Done()
|
||||
if getGithubApi(token) {
|
||||
validTokenList[token] = true
|
||||
}
|
||||
}(token)
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// 请求github api
|
||||
func getGithubApi(token string) bool {
|
||||
githubApiCount++
|
||||
// 设置请求头
|
||||
headers := map[string]string{
|
||||
"Authorization": "token " + token,
|
||||
/*"editor-version": c.GetHeader("editor-version"),
|
||||
"editor-plugin-version": c.GetHeader("editor-plugin-version"),
|
||||
"user-agent": c.GetHeader("user-agent"),
|
||||
"accept": c.GetHeader("accept"),
|
||||
"accept-encoding": c.GetHeader("accept-encoding"),*/
|
||||
}
|
||||
// 发起GET请求
|
||||
response, err := resty.New().R().
|
||||
SetHeaders(headers).
|
||||
Get(configFile.CopilotConfig.GithubApiUrl)
|
||||
if err != nil {
|
||||
// 处理请求错误
|
||||
return false
|
||||
}
|
||||
// 判断响应状态码
|
||||
if response.StatusCode() == http.StatusOK {
|
||||
// 响应状态码为200 OK
|
||||
respDataMap := map[string]interface{}{}
|
||||
err = json.Unmarshal(response.Body(), &respDataMap)
|
||||
if err != nil {
|
||||
// 处理JSON解析错误
|
||||
return false
|
||||
}
|
||||
//token map
|
||||
tokenMap[token] = respDataMap
|
||||
return true
|
||||
} else {
|
||||
// 处理其他状态码
|
||||
delete(validTokenList, token)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 获取copilot token
|
||||
func getGithubToken() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
requestCount++
|
||||
if err := verifyRequest(c); err != nil {
|
||||
badRequest(c)
|
||||
return
|
||||
}
|
||||
token := getRandomToken(validTokenList)
|
||||
if respDataMap, exists := getTokenData(token); exists {
|
||||
if !isTokenExpired(respDataMap) {
|
||||
proxyResp(c, respDataMap)
|
||||
return
|
||||
}
|
||||
}
|
||||
if getGithubApi(token) {
|
||||
proxyResp(c, tokenMap[token])
|
||||
} else {
|
||||
badRequest(c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 验证请求代理请求token
|
||||
func verifyRequest(c *gin.Context) error {
|
||||
if configFile.Verification != "" {
|
||||
token := c.GetHeader("Authorization")
|
||||
tokenStr := strings.ReplaceAll(token, " ", "")
|
||||
configCert := strings.ReplaceAll(configFile.Verification, " ", "")
|
||||
if tokenStr != "token"+configCert {
|
||||
return errors.New("verification failed")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 从map中获取github token对应的copilot token
|
||||
func getTokenData(token string) (map[string]interface{}, bool) {
|
||||
respDataMap, exists := tokenMap[token]
|
||||
return respDataMap, exists
|
||||
}
|
||||
|
||||
// 检测copilot token是否过期
|
||||
func isTokenExpired(respDataMap map[string]interface{}) bool {
|
||||
if expiresAt, ok := respDataMap["expires_at"].(float64); ok {
|
||||
currentTime := time.Now().Unix()
|
||||
expiresAtInt64 := int64(expiresAt)
|
||||
return expiresAtInt64 <= currentTime+60
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 重置请求计数
|
||||
func resetRequestCount() {
|
||||
requestCountMutex.Lock()
|
||||
defer requestCountMutex.Unlock()
|
||||
requestCount = 0
|
||||
successCount = 0
|
||||
}
|
||||
|
||||
// 从map中随机获取一个github token
|
||||
func getRandomToken(m map[string]bool) string {
|
||||
keys := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
if len(keys) == 0 {
|
||||
return "" // 返回空字符串或处理其他错误情况
|
||||
}
|
||||
r := rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||
randomIndex := r.Intn(len(keys))
|
||||
return keys[randomIndex]
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Config 配置文件结构体
|
||||
type Config struct {
|
||||
Server struct {
|
||||
Domain string `json:"domain"`
|
||||
Host string `json:"host"`
|
||||
Port int `json:"port"`
|
||||
CertPath string `json:"certPath"`
|
||||
KeyPath string `json:"keyPath"`
|
||||
} `json:"server"`
|
||||
CopilotConfig struct {
|
||||
GithubApiUrl string `json:"github_api_url"`
|
||||
Token []string `json:"token"`
|
||||
} `json:"copilot_config"`
|
||||
Verification string `json:"verification"`
|
||||
}
|
||||
|
||||
// 全局变量
|
||||
var (
|
||||
copilotGinEngine *gin.Engine
|
||||
//有效ghu_token的map
|
||||
validGhuTokenMap = make(map[string]bool)
|
||||
//与有效ghu_token对于的co_token的map
|
||||
copilotTokenMap = make(map[string]map[string]interface{})
|
||||
//服务器配置文件
|
||||
configFile Config
|
||||
//请求计数锁
|
||||
requestCountMutex sync.Mutex
|
||||
//githubApi请求计数
|
||||
githubApiCount = 0
|
||||
//总请求计数
|
||||
requestCount = 0
|
||||
//请求成功计数
|
||||
successCount = 0
|
||||
)
|
||||
|
||||
// 测试的玩意儿
|
||||
var (
|
||||
diyMsg = ";//授权已经过期,重新获取-> https://www.sharecopilot.top"
|
||||
completionUrl = "https://copilot-proxy.githubusercontent.com/v1/engines/copilot-codex/completions"
|
||||
telemetryUrl = "https://copilot-telemetry.githubusercontent.com/telemetry"
|
||||
isModMsg = true
|
||||
)
|
26
src/main.go
26
src/main.go
@ -1,13 +1,21 @@
|
||||
package main
|
||||
|
||||
func init() {
|
||||
loadConfig() // 1.加载服务器配置文件
|
||||
initGinEngine() // 2.初始化Gin引擎
|
||||
initValidGhuTokenMap() // 3.初始化有效Ghu_token
|
||||
}
|
||||
|
||||
func main() {
|
||||
Routes() // 1.url路由
|
||||
StartServer() // 2.启动服务器
|
||||
showMsg() // 3.控制台信息显示
|
||||
// 初始化配置文件
|
||||
configFile = initConfig()
|
||||
|
||||
// 创建Gin引擎
|
||||
engine := setupGinEngine()
|
||||
|
||||
// 初始化有效的token列表
|
||||
initValidTokenList()
|
||||
|
||||
// 定义路由
|
||||
setupRoutes(engine)
|
||||
|
||||
// 初始化并启动服务器
|
||||
initAndStartServer(engine)
|
||||
|
||||
// 显示信息
|
||||
showMsg()
|
||||
}
|
||||
|
@ -1,37 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//1.DomainMiddleware 域名中间件
|
||||
//2.VerifyRequestMiddleware 代理服务器自定义的token验证中间件
|
||||
|
||||
// DomainMiddleware 域名中间件
|
||||
func DomainMiddleware(domain string) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// 获取请求的域名(不包括端口)
|
||||
requestDomain := strings.Split(c.Request.Host, ":")[0]
|
||||
// 使用子域名的情况下,检查域名是否匹配或为本地地址
|
||||
if requestDomain == domain || requestDomain == "127.0.0.1" || requestDomain == "localhost" {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
c.AbortWithStatus(403)
|
||||
}
|
||||
}
|
||||
|
||||
// VerifyRequestMiddleware 代理服务器自定义的token验证中间件
|
||||
func VerifyRequestMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if configFile.Verification != "" {
|
||||
authHeader := c.GetHeader("Authorization")
|
||||
if authHeader != "token "+configFile.Verification {
|
||||
c.JSON(401, gin.H{"error": "Unauthorized"})
|
||||
return
|
||||
}
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
package main
|
||||
|
||||
// Routes 自定义代理服务器路由 附加中间件(域名验证和请求验证)
|
||||
func Routes() {
|
||||
// 定义根路由
|
||||
copilotApi := copilotGinEngine.Group("/copilot_internal", DomainMiddleware(configFile.Server.Domain), VerifyRequestMiddleware())
|
||||
|
||||
// 定义代理github token的路由
|
||||
copilotApi.GET("/v2/token", getCopilotToken())
|
||||
|
||||
// 定义 completions路由的反向代理
|
||||
registerProxyRoute(copilotGinEngine, "/v1/engines/copilot-codex/completions", completionUrl)
|
||||
|
||||
// 定义 telemetry路由的反向代理 ,
|
||||
registerProxyRoute(copilotGinEngine, "/telemetry", telemetryUrl)
|
||||
}
|
173
src/server.go
173
src/server.go
@ -1,71 +1,85 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// 加载服务器配置文件
|
||||
func loadConfig() {
|
||||
// 获取可执行文件所在目录 ./config.json
|
||||
exePath, _ := os.Executable()
|
||||
// 初始化配置文件
|
||||
func initConfig() Config {
|
||||
// 读取配置文件
|
||||
exePath, err := os.Executable()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
// 获取执行文件所在目录
|
||||
exeDir := filepath.Dir(exePath)
|
||||
configFileTemp, err := os.Open(exeDir + "/config.json")
|
||||
configFile, err := os.Open(exeDir + "/config.json")
|
||||
if err != nil {
|
||||
panic("file \"./config.json\" not found")
|
||||
}
|
||||
//函数退出时关闭文件流
|
||||
defer func(configFile *os.File) {
|
||||
_ = configFile.Close()
|
||||
}(configFileTemp)
|
||||
//解析json
|
||||
decoder := json.NewDecoder(configFileTemp)
|
||||
err = decoder.Decode(&configFile)
|
||||
err := configFile.Close()
|
||||
if err != nil {
|
||||
panic("close file \"./config.json\" err")
|
||||
}
|
||||
}(configFile)
|
||||
decoder := json.NewDecoder(configFile)
|
||||
config := Config{}
|
||||
err = decoder.Decode(&config)
|
||||
if err != nil {
|
||||
panic("config format err")
|
||||
}
|
||||
return config
|
||||
}
|
||||
|
||||
// 初始化Gin引擎
|
||||
func initGinEngine() {
|
||||
// 设置gin模式为发布模式
|
||||
// 创建和配置Gin引擎
|
||||
func setupGinEngine() *gin.Engine {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
//关闭gin日志输出 自认为小项目没什么用
|
||||
gin.DefaultWriter = io.Discard
|
||||
// 创建Gin引擎
|
||||
copilotGinEngine = gin.New()
|
||||
// 设置信任的前置代理 用nginx反代需要 不写这个编译会有个警告看着难受
|
||||
if err := copilotGinEngine.SetTrustedProxies([]string{"127.0.0.1"}); err != nil {
|
||||
engine := gin.New()
|
||||
// 设置信任的代理
|
||||
if err := engine.SetTrustedProxies([]string{"127.0.0.1"}); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return engine
|
||||
}
|
||||
|
||||
// StartServer 启动服务器并监听ip和端口
|
||||
func StartServer() {
|
||||
//监听地址是host+port
|
||||
listenAddress := configFile.Server.Host + ":" + strconv.Itoa(configFile.Server.Port)
|
||||
server := &http.Server{
|
||||
Addr: listenAddress,
|
||||
TLSConfig: &tls.Config{
|
||||
NextProtos: []string{"http/1.1", "http/1.2", "http/2"},
|
||||
},
|
||||
Handler: copilotGinEngine,
|
||||
// 定义路由和中间件
|
||||
func setupRoutes(engine *gin.Engine) {
|
||||
domainDefault := engine.Group("/", DomainMiddleware(configFile.Server.Domain))
|
||||
domainDefault.GET("/copilot_internal/v2/token", getGithubToken())
|
||||
}
|
||||
|
||||
// DomainMiddleware 域名中间件
|
||||
func DomainMiddleware(domain string) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
// 检查域名是否匹配
|
||||
requestDomain := strings.Split(c.Request.Host, ":")[0]
|
||||
if requestDomain == domain || requestDomain == "127.0.0.1" {
|
||||
c.Next()
|
||||
} else {
|
||||
c.String(403, "Forbidden")
|
||||
c.Abort()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化和启动服务器
|
||||
func initAndStartServer(engine *gin.Engine) {
|
||||
listenAddress := configFile.Server.Host + ":" + strconv.Itoa(configFile.Server.Port)
|
||||
server := createTLSServer(engine, listenAddress)
|
||||
go func() {
|
||||
if configFile.Server.Port != 443 {
|
||||
err := copilotGinEngine.Run(listenAddress)
|
||||
err := engine.Run(listenAddress)
|
||||
log.Fatal(err)
|
||||
} else {
|
||||
err := server.ListenAndServeTLS(configFile.Server.CertPath, configFile.Server.KeyPath)
|
||||
@ -74,75 +88,34 @@ func StartServer() {
|
||||
}()
|
||||
}
|
||||
|
||||
// 自定义请求失败返回的状态码和错误信息
|
||||
func diyBadRequest(c *gin.Context, code int, errorMessage string) {
|
||||
c.JSON(code, gin.H{
|
||||
"message": errorMessage,
|
||||
"documentation_url": "https://docs.github.com/rest",
|
||||
})
|
||||
// 创建TLS服务器配置
|
||||
func createTLSServer(engine *gin.Engine, address string) *http.Server {
|
||||
return &http.Server{
|
||||
Addr: address,
|
||||
TLSConfig: &tls.Config{
|
||||
NextProtos: []string{"http/1.1", "http/1.2", "http/2"},
|
||||
},
|
||||
Handler: engine,
|
||||
}
|
||||
}
|
||||
|
||||
// registerProxyRoute 反向代理路由
|
||||
func registerProxyRoute(r *gin.Engine, routePath, targetURL string) {
|
||||
target, err := url.Parse(targetURL)
|
||||
// 本服务器响应
|
||||
func proxyResp(c *gin.Context, respDataMap map[string]interface{}) {
|
||||
// 将map转换为JSON字符串
|
||||
responseJSON, err := json.Marshal(respDataMap)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "JSON marshaling error"})
|
||||
}
|
||||
proxy := &httputil.ReverseProxy{
|
||||
Director: func(req *http.Request) {
|
||||
req.URL.Host = target.Host
|
||||
req.URL.Scheme = "https"
|
||||
req.Host = target.Host
|
||||
},
|
||||
ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) {
|
||||
},
|
||||
}
|
||||
r.Any(routePath, func(c *gin.Context) {
|
||||
proxy.Director = func(req *http.Request) {
|
||||
req.URL.Host = target.Host
|
||||
req.URL.Scheme = "https"
|
||||
req.Host = target.Host
|
||||
}
|
||||
if isModMsg {
|
||||
modProxyResp(c, proxy)
|
||||
}
|
||||
proxy.ServeHTTP(c.Writer, c.Request)
|
||||
})
|
||||
// 请求成功统计
|
||||
successCount++
|
||||
// 将JSON字符串作为响应体返回
|
||||
c.Header("Content-Type", "application/json")
|
||||
c.String(http.StatusOK, string(responseJSON))
|
||||
}
|
||||
|
||||
// 修改代码提示内容
|
||||
func modProxyResp(c *gin.Context, proxy *httputil.ReverseProxy) {
|
||||
// 在代理响应之前修改响应
|
||||
proxy.ModifyResponse = func(response *http.Response) error {
|
||||
responseBuffer := new(bytes.Buffer)
|
||||
_, readErr := responseBuffer.ReadFrom(response.Body)
|
||||
if readErr != nil {
|
||||
return readErr
|
||||
}
|
||||
responseData := responseBuffer.Bytes()
|
||||
// 定义正则表达式模式
|
||||
pattern := `(.*?)data:`
|
||||
// 编译正则表达式
|
||||
regex := regexp.MustCompile(pattern)
|
||||
// 查找匹配项
|
||||
match := regex.FindStringSubmatch(string(responseData))
|
||||
var replacedData = ""
|
||||
if len(match) >= 2 {
|
||||
replacedData = match[1]
|
||||
} else {
|
||||
fmt.Println("No match found.")
|
||||
}
|
||||
// 将字符串转换为[]rune类型的字符数组
|
||||
runes := []rune(diyMsg)
|
||||
newStr := ""
|
||||
// 遍历字符数组,对每个字符进行处理
|
||||
for _, r := range runes {
|
||||
// 在字符前后添加内容,生成新的字符串
|
||||
newStr += fmt.Sprintf("data: {\"id\":\"cmpl-7xy1GLgssjHEubVrPyt534VRYVF0t\",\"model\":\"cushman-ml\",\"created\":1694526422,\"choices\":[{\"text\":\"%c\",\"index\":0,\"finish_reason\":null,\"logprobs\":null}]}\n", r)
|
||||
}
|
||||
newStr = replacedData + newStr + "data: [DONE]\n"
|
||||
fmt.Println(newStr)
|
||||
c.Data(response.StatusCode, response.Header.Get("Content-Type"), []byte(newStr))
|
||||
return nil
|
||||
}
|
||||
// 请求错误
|
||||
func badRequest(c *gin.Context) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"message": "Bad credentials",
|
||||
"documentation_url": "https://docs.github.com/rest"})
|
||||
}
|
||||
|
@ -7,15 +7,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// 重置计数
|
||||
func resetRequestCount() {
|
||||
requestCountMutex.Lock()
|
||||
defer requestCountMutex.Unlock()
|
||||
requestCount = 0
|
||||
successCount = 0
|
||||
}
|
||||
|
||||
// 控制台显示信息 无关紧要的内容
|
||||
// 控制台显示信息
|
||||
func showMsg() {
|
||||
fmt.Println(color.WhiteString("-----------------------------------------------------------------------"))
|
||||
fmt.Println(color.HiBlueString(" _ _ _ _ \n ___| |__ __ _ _ __ ___ ___ ___ _ __ (_) | ___ | |_ \n/ __| '_ \\ / _` | '__/ _ \\_____ / __/ _ \\| '_ \\| | |/ _ \\| __|\n\\__ \\ | | | (_| | | | __/_____| (_| (_) | |_) | | | (_) | |_ \n|___/_| |_|\\__,_|_| \\___| \\___\\___/| .__/|_|_|\\___/ \\__|\n |_| \n"))
|
||||
@ -29,10 +21,13 @@ func showMsg() {
|
||||
} else {
|
||||
url = "http://" + configFile.Server.Domain + ":" + strconv.Itoa(configFile.Server.Port)
|
||||
}
|
||||
jetStr, vsStr, valid := color.WhiteString("[Jetbrains]"), color.WhiteString("[Vscode]"), color.WhiteString("[Valid tokens]")
|
||||
fmt.Printf("%s: %s/copilot_internal/v2/token\n%s: %s\n%s: %d\n",
|
||||
jetStr, color.HiBlueString(url), vsStr, color.HiBlueString(url), valid, len(validGhuTokenMap))
|
||||
fmt.Println("-----------------------------------------------------------------------")
|
||||
var jetStr = color.WhiteString("[Jetbrains]")
|
||||
var vsStr = color.WhiteString("[Vscode]")
|
||||
var valid = color.WhiteString("[Valid tokens]")
|
||||
fmt.Println(jetStr + ": " + color.HiBlueString(url+"/copilot_internal/v2/token"))
|
||||
fmt.Println(vsStr + ": " + color.HiBlueString(url))
|
||||
fmt.Println(valid + ": " + color.HiBlueString(strconv.Itoa(len(validTokenList))))
|
||||
fmt.Println(color.WhiteString("-----------------------------------------------------------------------"))
|
||||
for {
|
||||
requestCountMutex.Lock()
|
||||
sCount := successCount
|
||||
@ -43,7 +38,9 @@ func showMsg() {
|
||||
if "00:00:00" == currentTime {
|
||||
resetRequestCount()
|
||||
}
|
||||
s2, s3, s4 := color.WhiteString("[Succeed]"), color.WhiteString("[Failed]"), color.WhiteString("[GithubApi]")
|
||||
var s2 = color.WhiteString("[Succeed]")
|
||||
var s3 = color.WhiteString("[Failed]")
|
||||
var s4 = color.WhiteString("[GithubApi]")
|
||||
// 打印文本
|
||||
fmt.Printf("\033[G%s - %s: %s %s: %s %s: %s ",
|
||||
color.HiYellowString(currentTime),
|
@ -82,5 +82,5 @@ func getGithubTest(c *gin.Context, token string) {
|
||||
}
|
||||
|
||||
//token map
|
||||
copilotTokenMap[token] = respDataMap
|
||||
tokenMap[token] = respDataMap
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user