| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106 |
- package telegram
- import (
- "context"
- "log"
- "time"
- )
- // PrepareAccountResult reports the outcome of one account's prepare attempt.
- type PrepareAccountResult struct {
- Phone string `json:"phone"`
- Joined bool `json:"joined"` // true if newly joined OR USER_ALREADY_PARTICIPANT
- Message string `json:"message"` // error message or "已加入" / "首次加入成功"
- }
- // PrepareGroup has every currently-enabled account attempt to join the given
- // group/channel. No scraping is performed — this is a batch "warm up" so that
- // subsequent clone passes have accounts that TG treats as real group members.
- // Best practice is to run this, then wait hours/days, then scrape.
- //
- // Accounts that hit FloodWait are cooled via HandleFloodWait just like in
- // other flows.
- func PrepareGroup(ctx context.Context, mgr *AccountManager, username string) ([]PrepareAccountResult, error) {
- // Acquire every available account in sequence (Acquire blocks only on mu).
- // If an account is cooling, it's skipped with a "cooling" result.
- statuses := mgr.GetStatuses()
- results := make([]PrepareAccountResult, 0, len(statuses))
- for phone, status := range statuses {
- if status == "cooling" {
- results = append(results, PrepareAccountResult{Phone: phone, Joined: false, Message: "冷却中,跳过"})
- continue
- }
- acc, err := mgr.Acquire(ctx)
- if err != nil {
- results = append(results, PrepareAccountResult{Phone: phone, Joined: false, Message: err.Error()})
- // ErrAllCooling → no more accounts to try
- break
- }
- // Acquire returns SOME available account — might not be the one we were
- // iterating on. Use acc.Account.Phone for reporting. The phone variable
- // from the outer loop is only used to skip cooling ones.
- pr := PrepareAccountResult{Phone: acc.Account.Phone}
- connectCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
- if err := acc.Client.Connect(connectCtx); err != nil {
- cancel()
- pr.Message = "connect: " + err.Error()
- mgr.Release(acc, 0)
- results = append(results, pr)
- continue
- }
- inputCh, ch, _, err := acc.Client.ResolveGroupPeer(connectCtx, username)
- if err != nil {
- cancel()
- pr.Message = "resolve: " + err.Error()
- acc.Client.Disconnect()
- mgr.Release(acc, 0)
- results = append(results, pr)
- continue
- }
- if inputCh == nil {
- cancel()
- pr.Message = "非超级群组,基础聊天无需加群"
- pr.Joined = true
- acc.Client.Disconnect()
- mgr.Release(acc, 0)
- results = append(results, pr)
- continue
- }
- // JoinChannel returns nil for both success and USER_ALREADY_PARTICIPANT.
- joinErr := acc.Client.JoinChannel(connectCtx, inputCh)
- cancel()
- if joinErr != nil {
- if fwe, ok := joinErr.(*FloodWaitError); ok {
- pr.Message = "FloodWait: " + joinErr.Error()
- mgr.HandleFloodWait(acc, fwe.Seconds)
- } else {
- pr.Message = joinErr.Error()
- mgr.Release(acc, 0)
- }
- acc.Client.Disconnect()
- results = append(results, pr)
- continue
- }
- pr.Joined = true
- title := ""
- if ch != nil {
- title = ch.Title
- }
- pr.Message = "加入成功 " + title
- log.Printf("[prepare_group] %s joined %s via %s", username, title, acc.Account.Phone)
- acc.Client.Disconnect()
- mgr.Release(acc, 0)
- results = append(results, pr)
- }
- return results, nil
- }
|