refactor(store): drop the Telethon session import

The Go session is already stored, so the one-time conversion from the
Python version's Telethon session is no longer needed. Remove it along
with its tests and the README upgrade section.
This commit is contained in:
tiennm99 committed 2026-10-15 14:38:28 +07:00
1 parent d041503a47
commit 56d71a0e79
5 files changed
+9 -95

No files matched your search

-8
View File
@@ -147,14 +147,6 @@ All groups in one crawl share one timestamp. The login session grants full
account access, so restrict Redis access accordingly; deleting
`telegram-export:session-gotd` forces a clean re-login.
### Upgrading from the Python version
The config and export keys keep the same format, so existing crawls stay
readable by `compare` and `export`. The Python version kept a Telethon session
under `telegram-export:session`. On first run, the Go version converts it into
`telegram-export:session-gotd`, so you do not need a new login code. The old key
is only read, never changed, and can be deleted afterwards.
## Development
```bash
+1 -1
View File
@@ -24,7 +24,7 @@ func TestConfigRoundTrip(t *testing.T) {
}
}
func TestLoadConfigReadsPythonWrittenJSON(t *testing.T) {
func TestLoadConfigReadsStoredJSON(t *testing.T) {
st, mr := newTestStore(t)
mr.Set("telegram-export:config",
`{"api_id": 123, "api_hash": "hash", "phone": "+1555", "group_ids": [-1001234567890]}`)
+6 -40
View File
@@ -11,12 +11,7 @@ import (
// The login session grants full account access; it lives only in Redis
// (behind TLS/auth), never on local disk. Deleting it forces a clean re-login.
//
// The Python version stored a Telethon StringSession under "session". This
// version keeps its own format under a separate key and only reads the old
// one once, so an existing login carries over without a new code.
func sessionKey() string { return key("session-gotd") }
func telethonSessionKey() string { return key("session") }
func sessionKey() string { return key("session-gotd") }
// SessionStorage implements gotd's session.Storage on Redis.
type SessionStorage struct {
@@ -28,33 +23,16 @@ func (s *Store) SessionStorage() *SessionStorage {
return &SessionStorage{store: s}
}
// LoadSession returns the stored session, importing a Telethon session when
// no gotd session exists yet.
// LoadSession returns the stored session, or session.ErrNotFound before the
// first login.
func (ss *SessionStorage) LoadSession(ctx context.Context) ([]byte, error) {
raw, err := ss.store.rdb.Get(ctx, sessionKey()).Bytes()
if err == nil {
return raw, nil
if errors.Is(err, redis.Nil) {
return nil, session.ErrNotFound
}
if !errors.Is(err, redis.Nil) {
if err != nil {
return nil, fmt.Errorf("read session: %w", err)
}
telethon, err := ss.store.rdb.Get(ctx, telethonSessionKey()).Result()
if errors.Is(err, redis.Nil) || telethon == "" {
return nil, session.ErrNotFound
}
if err != nil {
return nil, fmt.Errorf("read Telethon session: %w", err)
}
raw, err = convertTelethonSession(ctx, telethon)
if err != nil {
// An unreadable old session should mean a fresh login, not a dead end.
return nil, session.ErrNotFound
}
if err := ss.StoreSession(ctx, raw); err != nil {
return nil, err
}
return raw, nil
}
@@ -65,15 +43,3 @@ func (ss *SessionStorage) StoreSession(ctx context.Context, data []byte) error {
}
return nil
}
func convertTelethonSession(ctx context.Context, telethon string) ([]byte, error) {
data, err := session.TelethonSession(telethon)
if err != nil {
return nil, err
}
var mem session.StorageMemory
if err := (&session.Loader{Storage: &mem}).Save(ctx, data); err != nil {
return nil, err
}
return mem.LoadSession(ctx)
}
-44
View File
@@ -1,23 +1,13 @@
package store
import (
"bytes"
"context"
"encoding/base64"
"errors"
"testing"
"github.com/gotd/td/session"
)
// telethonString builds a Telethon StringSession: version "1" plus base64
// of DC ID, IPv4, port, and a 256-byte auth key.
func telethonString(dc byte) string {
raw := []byte{dc, 149, 154, 167, 51, 0x01, 0xbb}
raw = append(raw, bytes.Repeat([]byte{7}, 256)...)
return "1" + base64.URLEncoding.EncodeToString(raw)
}
func TestLoadSessionNotFound(t *testing.T) {
st, _ := newTestStore(t)
@@ -39,37 +29,3 @@ func TestSessionRoundTrip(t *testing.T) {
t.Fatalf("LoadSession = %q, %v", got, err)
}
}
func TestLoadSessionImportsTelethonSession(t *testing.T) {
st, mr := newTestStore(t)
ctx := context.Background()
mr.Set("telegram-export:session", telethonString(2))
raw, err := st.SessionStorage().LoadSession(ctx)
if err != nil {
t.Fatalf("LoadSession: %v", err)
}
data, err := (&session.Loader{Storage: st.SessionStorage()}).Load(ctx)
if err != nil {
t.Fatalf("Loader.Load: %v", err)
}
if data.DC != 2 || data.Addr != "149.154.167.51:443" {
t.Fatalf("imported session DC=%d Addr=%q", data.DC, data.Addr)
}
if stored, _ := mr.Get("telegram-export:session-gotd"); stored != string(raw) {
t.Fatal("imported session was not saved under the gotd key")
}
if old, _ := mr.Get("telegram-export:session"); old != telethonString(2) {
t.Fatal("Telethon session key was modified")
}
}
func TestLoadSessionIgnoresBrokenTelethonSession(t *testing.T) {
st, mr := newTestStore(t)
mr.Set("telegram-export:session", "not-a-session")
_, err := st.SessionStorage().LoadSession(context.Background())
if !errors.Is(err, session.ErrNotFound) {
t.Fatalf("LoadSession error = %v, want session.ErrNotFound", err)
}
}
+2 -2
View File
@@ -22,8 +22,8 @@ type groupRef struct {
id int64
}
// parseGroupID splits a marked ID (as Telethon and the Python version store
// it) into a basic group or a channel/supergroup and its raw Telegram ID.
// parseGroupID splits a marked ID (as configured and stored) into a basic
// group or a channel/supergroup and its raw Telegram ID.
func parseGroupID(markedID int64) (groupRef, error) {
switch {
case markedID <= -channelIDOffset: