Skip to content

Commit

Permalink
✨optimization fingerprint
Browse files Browse the repository at this point in the history
  • Loading branch information
aurorax-neo committed Apr 23, 2024
2 parents 914ddbb + 2e7705d commit 888746f
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 52 deletions.
86 changes: 65 additions & 21 deletions Pool/Gpt35Pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,40 +20,47 @@ func init() {
}

type Gpt35Pool struct {
Gpt35s []*chat.Gpt35
data []*chat.Gpt35
head int // 队头指针
tail int // 队尾指针
size int // 队列当前元素个数
capacity int // 队列容量
}

func newGpt35Pool(capacity int) *Gpt35Pool {
return &Gpt35Pool{
data: make([]*chat.Gpt35, capacity),
capacity: config.PoolMaxCount,
}
}

func GetGpt35PoolInstance() *Gpt35Pool {
once.Do(func() {
instance = newGpt35Pool(config.PoolMaxCount)
logger.Logger.Info(fmt.Sprint("PoolMaxCount: ", config.PoolMaxCount, ", AuthExpirationDate: ", config.AuthED, ", Init Pool..."))
// 定时刷新 Pool
go instance.updateGpt35Pool(200)
instance.updateGpt35Pool(time.Millisecond * 200)
})
return instance
}

func newGpt35Pool(capacity int) *Gpt35Pool {
return &Gpt35Pool{
Gpt35s: make([]*chat.Gpt35, capacity),
capacity: config.PoolMaxCount,
}
}

func (G *Gpt35Pool) updateGpt35Pool(duration time.Duration) {
for {
func (G *Gpt35Pool) updateGpt35Pool(nanosecond time.Duration) {
common.TimingTask(nanosecond, func() {
// 遍历队列中的所有元素
G.Traverse(func(index int, gpt35 *chat.Gpt35) {
// 判断是否为无效 Gpt35 实例
if !G.isLiveGpt35(gpt35) {
// 移除无效 Gpt35 实例
G.RemoveAt(index)
}
})
if !G.IsFull() {
G.Enqueue(chat.NewGpt35())
G.Enqueue(chat.NewGpt35(1))
}
time.Sleep(time.Millisecond * duration)
}
})
}

func (G *Gpt35Pool) IsLiveGpt35(gpt35 *chat.Gpt35) bool {
func (G *Gpt35Pool) isLiveGpt35(gpt35 *chat.Gpt35) bool {
//判断是否为空
if gpt35 == nil ||
gpt35.MaxUseCount <= 0 || //无可用次数
Expand Down Expand Up @@ -85,7 +92,7 @@ func (G *Gpt35Pool) GetGpt35(retry int) *chat.Gpt35 {
return G.GetGpt35(retry - 1)
}
// 缓存内无可用 Gpt35 实例,返回新 Gpt35 实例
return chat.NewGpt35()
return chat.NewGpt35(0)
}

// GetSize 获取队列当前元素个数
Expand All @@ -104,11 +111,11 @@ func (G *Gpt35Pool) IsFull() bool {
}

// Enqueue 入队
func (G *Gpt35Pool) Enqueue(gpt35 *chat.Gpt35) bool {
if G.IsFull() || gpt35 == nil {
func (G *Gpt35Pool) Enqueue(v *chat.Gpt35) bool {
if G.IsFull() || v == nil {
return false
}
G.Gpt35s[G.tail] = gpt35
G.data[G.tail] = v
G.tail = (G.tail + 1) % G.capacity
G.size++
return true
Expand All @@ -126,12 +133,49 @@ func (G *Gpt35Pool) Dequeue() *chat.Gpt35 {
return nil
}
// 获取 Gpt35 实例
gpt35 := G.Gpt35s[G.head]
gpt35 := G.data[G.head]
// 判断是否为无效 Gpt35 实例
if !G.IsLiveGpt35(gpt35) {
if !G.isLiveGpt35(gpt35) {
G.head = (G.head + 1) % G.capacity
G.size--
return nil
}
return gpt35
}

// RemoveAt 移除指定位置的元素
func (G *Gpt35Pool) RemoveAt(index int) (*chat.Gpt35, bool) {
if index < 0 || index >= G.size {
return nil, false
}
// 计算要移除的元素在数组中的索引
removeIndex := (G.head + index) % G.capacity
removedValue := G.data[removeIndex]

// 移动队列中被移除元素后面的元素
for i := index; i < G.size-1; i++ {
currentIndex := (G.head + i) % G.capacity
nextIndex := (currentIndex + 1) % G.capacity
G.data[currentIndex] = G.data[nextIndex]
}
// 将最后一个元素置为空
emptyIndex := (G.head + G.size - 1) % G.capacity
G.data[emptyIndex] = nil

// 更新队尾指针和元素个数
G.tail = (G.tail - 1 + G.capacity) % G.capacity
G.size--
return removedValue, true
}

// Traverse 遍历队列中的所有元素,并对每个元素执行指定操作
func (G *Gpt35Pool) Traverse(callback func(int, *chat.Gpt35)) {
if G.IsEmpty() {
return
}
// 从队头开始遍历到队尾
for i := 0; i < G.size; i++ {
index := (G.head + i) % G.capacity
callback(index, G.data[index])
}
}
43 changes: 31 additions & 12 deletions ProxyPool/ProxyPool.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
browser "github.com/EDDYCJY/fake-useragent"
"net/url"
"sync"
"time"
)

func init() {
Expand All @@ -24,47 +25,65 @@ type ProxyPool struct {

type Proxy struct {
Link *url.URL
CanUseAt int64
Ua string
Language string
}

func GetProxyPoolInstance() *ProxyPool {
Once.Do(func() {
Instance = NewProxyPool()
Instance = NewProxyPool(nil)
for _, px := range config.Proxy {
proxy := &Proxy{
Instance.AddProxy(&Proxy{
Link: common.ParseUrl(px),
CanUseAt: common.GetTimestampSecond(0),
Ua: browser.Random(),
Language: common.RandomLanguage(),
}
Instance.AddProxy(proxy)
})
}
// 定时刷新代理
Instance.timingUpdateProxy(time.Duration(config.AuthED) * time.Minute)
})
return Instance
}

func NewProxyPool() *ProxyPool {
func NewProxyPool(proxies []*Proxy) *ProxyPool {
return &ProxyPool{
Proxies: []*Proxy{},
Index: 0,
Proxies: append([]*Proxy{
{
Link: &url.URL{},
CanUseAt: common.GetTimestampSecond(0),
Ua: browser.Random(),
Language: common.RandomLanguage(),
},
}, proxies...),
Index: 0,
}
}

func (PP *ProxyPool) GetProxy() *Proxy {
// 如果没有代理则返回空代理
if len(PP.Proxies) == 0 {
return &Proxy{
Link: &url.URL{},
Ua: browser.Safari(),
Language: common.RandomLanguage(),
}
return PP.Proxies[0]
}
// 获取代理
proxy := PP.Proxies[PP.Index]
PP.Index = (PP.Index + 1) % len(PP.Proxies)
if PP.Index == 0 {
PP.Index = 1
}
return proxy
}

func (PP *ProxyPool) AddProxy(proxy *Proxy) {
PP.Proxies = append(PP.Proxies, proxy)
}

func (PP *ProxyPool) timingUpdateProxy(nanosecond time.Duration) {
common.TimingTask(nanosecond, func() {
for _, px := range PP.Proxies {
px.Ua = browser.Random()
px.Language = common.RandomLanguage()
}
})
}
19 changes: 19 additions & 0 deletions RequestClient/TlsClient.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
tlsClient "github.com/bogdanfinn/tls-client"
"github.com/bogdanfinn/tls-client/profiles"
"io"
"math/rand"
"time"
)

type TlsClient struct {
Expand All @@ -30,6 +32,23 @@ func NewTlsClient(timeoutSeconds int, clientProfile profiles.ClientProfile) *Tls
}
}

func RandomClientProfile() profiles.ClientProfile {
// 初始化随机数生成器
seed := time.Now().UnixNano()
rng := rand.New(rand.NewSource(seed))
clientProfiles := []profiles.ClientProfile{
profiles.Firefox_102,
profiles.Safari_15_6_1,
profiles.Safari_16_0,
profiles.Chrome_110,
profiles.Okhttp4Android13,
profiles.CloudflareCustom,
profiles.Firefox_117,
}
// 随机选择一个
randomIndex := rng.Intn(len(clientProfiles))
return clientProfiles[randomIndex]
}
func (T *TlsClient) NewRequest(method, url string, body io.Reader) (*fhttp.Request, error) {
request, err := fhttp.NewRequest(method, url, body)
if err != nil {
Expand Down
39 changes: 27 additions & 12 deletions chat/Gpt35.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"free-gpt3.5-2api/config"
"github.com/aurorax-neo/go-logger"
fhttp "github.com/bogdanfinn/fhttp"
"github.com/bogdanfinn/tls-client/profiles"
"github.com/google/uuid"
"io"
)
Expand All @@ -20,6 +19,7 @@ const SessionUrl = BaseUrl + "/backend-anon/sentinel/chat-requirements"

type Gpt35 struct {
RequestClient RequestClient.RequestClient
Proxy *ProxyPool.Proxy
MaxUseCount int
ExpiresIn int64
Session *session
Expand All @@ -45,15 +45,16 @@ type turnstile struct {
Required bool `json:"required"`
}

func NewGpt35() *Gpt35 {
// NewGpt35 创建 Gpt35 实例 0 获取 1 刷新获取
func NewGpt35(newType int) *Gpt35 {
// 创建 Gpt35 实例
gpt35 := &Gpt35{
MaxUseCount: -1,
ExpiresIn: -1,
Session: &session{},
}
// 获取请求客户端
err := gpt35.getNewRequestClient()
err := gpt35.getNewRequestClient(newType)
if err != nil {
return nil
}
Expand All @@ -65,26 +66,36 @@ func NewGpt35() *Gpt35 {
return gpt35
}

func (G *Gpt35) getNewRequestClient() error {
func (G *Gpt35) getNewRequestClient(newType int) error {
// 获取代理池
ProxyPoolInstance := ProxyPool.GetProxyPoolInstance()
// 获取代理
proxy := ProxyPoolInstance.GetProxy()
G.Proxy = ProxyPoolInstance.GetProxy()
// 判断代理是否可用
if G.Proxy.CanUseAt > common.GetTimestampSecond(0) && newType == 1 {
errStr := fmt.Sprint(G.Proxy.Link, ": Proxy restricted, Reuse at ", G.Proxy.CanUseAt)
logger.Logger.Debug(errStr)
return fmt.Errorf(errStr)
}
// 请求客户端
G.RequestClient = RequestClient.NewTlsClient(300, profiles.Okhttp4Android13)
G.RequestClient = RequestClient.NewTlsClient(300, RequestClient.RandomClientProfile())
if G.RequestClient == nil {
logger.Logger.Error("RequestClient is nil")
return fmt.Errorf("RequestClient is nil")
errStr := fmt.Sprint("RequestClient is nil")
logger.Logger.Debug(errStr)
return fmt.Errorf(errStr)
}
// 设置代理
err := G.RequestClient.SetProxy(proxy.Link.String())
err := G.RequestClient.SetProxy(G.Proxy.Link.String())
if err != nil {
logger.Logger.Error(fmt.Sprint("SetProxy Error: ", err))
errStr := fmt.Sprint("SetProxy Error: ", err)
logger.Logger.Debug(errStr)
}
// 设置 User-Agent
G.Ua = proxy.Ua
G.Ua = G.Proxy.Ua
// 设置语言
G.Language = proxy.Language
G.Language = G.Proxy.Language
// 成功后更新代理的可用时间
G.Proxy.CanUseAt = common.GetTimestampSecond(0)
return nil
}

Expand All @@ -104,6 +115,10 @@ func (G *Gpt35) getNewSession() error {
return err
}
if response.StatusCode != 200 {
if response.StatusCode == 429 {
G.Proxy.CanUseAt = common.GetTimestampSecond(600)
}
logger.Logger.Debug(fmt.Sprint("StatusCode: ", response.StatusCode))
return fmt.Errorf("StatusCode: %d", response.StatusCode)
}
defer func(Body io.ReadCloser) {
Expand Down
17 changes: 17 additions & 0 deletions common/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,20 @@ func fileIsExistAndCreat(filePath string, content string) bool {
}
return true
}

// TimingTask 定时任务 参数含函数
func TimingTask(nanosecond time.Duration, f func()) {
go func() {
timerChan := time.After(nanosecond)
// 使用for循环阻塞等待定时器的信号
for {
// 通过select语句监听定时器通道和其他事件
select {
case <-timerChan:
f()
// 重新设置定时器,以便下一次执行
timerChan = time.After(nanosecond)
}
}
}()
}
8 changes: 1 addition & 7 deletions service/v1/tokens.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,7 @@ type TokensResp struct {

func Tokens(c *gin.Context) {
resp := &TokensResp{
Count: 0,
}
instance := Pool.GetGpt35PoolInstance()
for i := 0; i < instance.GetCapacity(); i++ {
if instance.IsLiveGpt35(instance.Gpt35s[i]) {
resp.Count++
}
Count: Pool.GetGpt35PoolInstance().GetSize(),
}
logger.Logger.Info(fmt.Sprint("Pool Tokens: ", resp.Count))
c.JSON(200, resp)
Expand Down

0 comments on commit 888746f

Please sign in to comment.