From eb8f05cb61087035fa29b12f271dd9829c425ec2 Mon Sep 17 00:00:00 2001 From: cuiko Date: Fri, 19 Jun 2026 02:28:15 +0800 Subject: [PATCH] chore(deps): Bump gotd/td v0.107.0 -> v0.158.0 Catch the MTProto library up 51 releases (TL layer 185 -> 227) and migrate the breaking changes: - telegram.Options.Logger moved from *zap.Logger to gotd's own log.Logger interface; add a small zap adapter (session/gotdlog.go). - Forum-topic RPCs moved from channels.* to the messages.* namespace and now take Peer instead of Channel. messages.getForumTopics dropped the server-side search param, so `chat topic list --search` now filters by title client-side (single page, matching the existing no-pagination behavior). - channels.toggleSignatures: Enabled -> SignaturesEnabled. - Poll.Answers is now []PollAnswerClass; type-assert to *tg.PollAnswer. Verified: build / vet / golangci-lint / go test all green, plus a live smoke on the new library (connect, chat list, forum topic create/list/search/info/ delete, signatures toggle, poll send+read). --- go.mod | 44 +++++++---- go.sum | 106 ++++++++++++++++++++------- internal/telegram/chat_edit.go | 2 +- internal/telegram/forum.go | 79 ++++++++++---------- internal/telegram/poll.go | 12 ++- internal/telegram/session/dial.go | 2 +- internal/telegram/session/gotdlog.go | 52 +++++++++++++ 7 files changed, 214 insertions(+), 83 deletions(-) create mode 100644 internal/telegram/session/gotdlog.go diff --git a/go.mod b/go.mod index 37989e1..0fc7aae 100644 --- a/go.mod +++ b/go.mod @@ -6,43 +6,61 @@ require ( github.com/charmbracelet/x/ansi v0.11.6 github.com/go-faster/errors v0.7.1 github.com/gofrs/flock v0.13.0 - github.com/gotd/td v0.107.0 + github.com/gotd/log v0.1.0 + github.com/gotd/td v0.158.0 github.com/itchyny/gojq v0.12.19 github.com/mdp/qrterminal/v3 v3.2.1 github.com/pelletier/go-toml/v2 v2.3.0 github.com/spf13/cobra v1.10.2 github.com/stretchr/testify v1.11.1 - go.uber.org/zap v1.27.0 - golang.org/x/term v0.42.0 + go.uber.org/zap v1.28.0 + golang.org/x/term v0.44.0 ) require ( + github.com/andybalholm/brotli v1.2.0 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/clipperhouse/displaywidth v0.11.0 // indirect github.com/clipperhouse/uax29/v2 v2.7.0 // indirect + github.com/coder/websocket v1.8.15 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-faster/jx v1.1.0 // indirect + github.com/dlclark/regexp2 v1.11.5 // indirect + github.com/fatih/color v1.19.0 // indirect + github.com/ghodss/yaml v1.0.0 // indirect + github.com/go-faster/jx v1.2.0 // indirect github.com/go-faster/xor v1.0.0 // indirect + github.com/go-faster/yaml v0.4.6 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/gotd/ige v0.2.2 // indirect github.com/gotd/neo v0.1.5 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/itchyny/timefmt-go v0.1.8 // indirect - github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/compress v1.18.6 // indirect github.com/lucasb-eyer/go-colorful v1.3.0 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.20 // indirect + github.com/ogen-go/ogen v1.20.3 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/segmentio/asm v1.2.0 // indirect + github.com/refraction-networking/utls v1.8.2 // indirect + github.com/segmentio/asm v1.2.1 // indirect + github.com/shopspring/decimal v1.4.0 // indirect github.com/spf13/pflag v1.0.9 // indirect - go.opentelemetry.io/otel v1.28.0 // indirect - go.opentelemetry.io/otel/trace v1.28.0 // indirect + go.opentelemetry.io/otel v1.44.0 // indirect + go.opentelemetry.io/otel/metric v1.44.0 // indirect + go.opentelemetry.io/otel/trace v1.44.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.36.0 // indirect + golang.org/x/crypto v0.53.0 // indirect golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect - golang.org/x/net v0.38.0 // indirect - golang.org/x/sync v0.19.0 // indirect - golang.org/x/sys v0.43.0 // indirect + golang.org/x/mod v0.37.0 // indirect + golang.org/x/net v0.56.0 // indirect + golang.org/x/sync v0.21.0 // indirect + golang.org/x/sys v0.46.0 // indirect + golang.org/x/text v0.38.0 // indirect + golang.org/x/tools v0.46.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - nhooyr.io/websocket v1.8.11 // indirect rsc.io/qr v0.2.0 // indirect ) diff --git a/go.sum b/go.sum index f4298e3..5994e45 100644 --- a/go.sum +++ b/go.sum @@ -1,96 +1,146 @@ +github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= +github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8= github.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ= github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8= github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0= github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= +github.com/coder/websocket v1.8.15 h1:6B2JPeOGlpff2Uz6vOEH1Vzpi0iUz20A+lPVhPHtNUA= +github.com/coder/websocket v1.8.15/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= +github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w= +github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE= +github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg= github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo= -github.com/go-faster/jx v1.1.0 h1:ZsW3wD+snOdmTDy9eIVgQdjUpXRRV4rqW8NS3t+20bg= -github.com/go-faster/jx v1.1.0/go.mod h1:vKDNikrKoyUmpzaJ0OkIkRQClNHFX/nF3dnTJZb3skg= +github.com/go-faster/jx v1.2.0 h1:T2YHJPrFaYu21fJtUxC9GzmluKu8rVIFDwwGBKTDseI= +github.com/go-faster/jx v1.2.0/go.mod h1:UWLOVDmMG597a5tBFPLIWJdUxz5/2emOpfsj9Neg0PE= github.com/go-faster/xor v0.3.0/go.mod h1:x5CaDY9UKErKzqfRfFZdfu+OSTfoZny3w5Ak7UxcipQ= github.com/go-faster/xor v1.0.0 h1:2o8vTOgErSGHP3/7XwA5ib1FTtUsNtwCoLLBjl31X38= github.com/go-faster/xor v1.0.0/go.mod h1:x5CaDY9UKErKzqfRfFZdfu+OSTfoZny3w5Ak7UxcipQ= +github.com/go-faster/yaml v0.4.6 h1:lOK/EhI04gCpPgPhgt0bChS6bvw7G3WwI8xxVe0sw9I= +github.com/go-faster/yaml v0.4.6/go.mod h1:390dRIvV4zbnO7qC9FGo6YYutc+wyyUSHBgbXL52eXk= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw= github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gotd/ige v0.2.2 h1:XQ9dJZwBfDnOGSTxKXBGP4gMud3Qku2ekScRjDWWfEk= github.com/gotd/ige v0.2.2/go.mod h1:tuCRb+Y5Y3eNTo3ypIfNpQ4MFjrnONiL2jN2AKZXmb0= +github.com/gotd/log v0.1.0 h1:4LJUEvafD1xtBwx2QkrlzFnRgbYXTlWqJPDi8BvrLbU= +github.com/gotd/log v0.1.0/go.mod h1:5ilhdu1Ux0QvDY/FF3Ojfw24Ws3SlCtyLwOpXy8KYXs= +github.com/gotd/log/logzap v0.1.1 h1:O6l7d8HUbODe+UMcrM47eXYDwdJ6RNmpQejLjrlcEIQ= +github.com/gotd/log/logzap v0.1.1/go.mod h1:5ObZkITbfhbsBOLzBkzmMk9QxXc0eNQpimau7zRL+Y8= github.com/gotd/neo v0.1.5 h1:oj0iQfMbGClP8xI59x7fE/uHoTJD7NZH9oV1WNuPukQ= github.com/gotd/neo v0.1.5/go.mod h1:9A2a4bn9zL6FADufBdt7tZt+WMhvZoc5gWXihOPoiBQ= -github.com/gotd/td v0.107.0 h1:ahGo6Yez73mxIGm6AbUD+dJIQG+hMnSIOYI/JNaONqk= -github.com/gotd/td v0.107.0/go.mod h1:rHtaG0hd4EY0ice4f9CVH/JxsA7ZICqkcH3aFSVZplg= +github.com/gotd/td v0.158.0 h1:GzpQgUX9zVRd1HBRj+ingwR/X2eLeO08f77VK/Q7RJk= +github.com/gotd/td v0.158.0/go.mod h1:2aoh9Msau9BRVo+fZiQf/k5qvgBeAESnc9A6ErCxuJ4= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/itchyny/gojq v0.12.19 h1:ttXA0XCLEMoaLOz5lSeFOZ6u6Q3QxmG46vfgI4O0DEs= github.com/itchyny/gojq v0.12.19/go.mod h1:5galtVPDywX8SPSOrqjGxkBeDhSxEW1gSxoy7tn1iZY= github.com/itchyny/timefmt-go v0.1.8 h1:1YEo1JvfXeAHKdjelbYr/uCuhkybaHCeTkH8Bo791OI= github.com/itchyny/timefmt-go v0.1.8/go.mod h1:5E46Q+zj7vbTgWY8o5YkMeYb4I6GeWLFnetPy5oBrAI= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao= +github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.20 h1:WcT52H91ZUAwy8+HUkdM3THM6gXqXuLJi9O3rjcQQaQ= github.com/mattn/go-runewidth v0.0.20/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/mdp/qrterminal/v3 v3.2.1 h1:6+yQjiiOsSuXT5n9/m60E54vdgFsw0zhADHhHLrFet4= github.com/mdp/qrterminal/v3 v3.2.1/go.mod h1:jOTmXvnBsMy5xqLniO0R++Jmjs2sTm9dFSuQ5kpz/SU= +github.com/ogen-go/ogen v1.20.3 h1:1tvJuJE0BnQ7Nukd6ykiTOP0ucfL0yrAjHUg3S1DCQk= +github.com/ogen-go/ogen v1.20.3/go.mod h1:sJ1pJVp4S1RcSZlYIiMLo0QSMSt2pls4zfrc+hNKnzk= github.com/pelletier/go-toml/v2 v2.3.0 h1:k59bC/lIZREW0/iVaQR8nDHxVq8OVlIzYCOJf421CaM= github.com/pelletier/go-toml/v2 v2.3.0/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/refraction-networking/utls v1.8.2 h1:j4Q1gJj0xngdeH+Ox/qND11aEfhpgoEvV+S9iJ2IdQo= +github.com/refraction-networking/utls v1.8.2/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM= +github.com/rogpeppe/go-internal v1.15.0 h1:D0RCU5rMAp+SpgkiNdrjfJ+LX4J1M32V2NeCY7EJ6hc= +github.com/rogpeppe/go-internal v1.15.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= -github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= +github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= +github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU= +go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc= +go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc= +go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo= +go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk= +go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.uber.org/zap v1.28.0 h1:IZzaP1Fv73/T/pBMLk4VutPl36uNC+OSUh3JLG3FIjo= +go.uber.org/zap v1.28.0/go.mod h1:rDLpOi171uODNm/mxFcuYWxDsqWSAVkFdX4XojSKg/Q= +go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= +golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= +golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= +golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= +golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= -golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= -golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY= -golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= +golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= +golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= +golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= +golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= +golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= +golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= +golang.org/x/tools v0.46.0 h1:7jTurBkPZu4moS/Uy4OQT1M+QBlsj3wejyZwsT8Z7rk= +golang.org/x/tools v0.46.0/go.mod h1:FrD85F8l+NWL+9XWBSyVSHO6Ne4jutsfIFba7AWQ5Ys= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= -nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= +nhooyr.io/websocket v1.8.17 h1:KEVeLJkUywCKVsnLIDlD/5gtayKp8VoCkksHCGGfT9Y= +nhooyr.io/websocket v1.8.17/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY= rsc.io/qr v0.2.0/go.mod h1:IF+uZjkb9fqyeF/4tlBoynqmQxUoPfWEKh921coOuXs= diff --git a/internal/telegram/chat_edit.go b/internal/telegram/chat_edit.go index 74ed693..f09faae 100644 --- a/internal/telegram/chat_edit.go +++ b/internal/telegram/chat_edit.go @@ -83,7 +83,7 @@ func EditChat(ctx context.Context, api *tg.Client, resolver *peer.Resolver, q ac } } if q.Signatures != nil { - if _, err := api.ChannelsToggleSignatures(ctx, &tg.ChannelsToggleSignaturesRequest{Channel: inCh, Enabled: *q.Signatures}); err != nil { + if _, err := api.ChannelsToggleSignatures(ctx, &tg.ChannelsToggleSignaturesRequest{Channel: inCh, SignaturesEnabled: *q.Signatures}); err != nil { return output.ChatRow{}, err } } diff --git a/internal/telegram/forum.go b/internal/telegram/forum.go index b2660ee..b96105b 100644 --- a/internal/telegram/forum.go +++ b/internal/telegram/forum.go @@ -21,28 +21,33 @@ func ListForumTopics(ctx context.Context, api *tg.Client, resolver *peer.Resolve if err != nil { return nil, err } - inCh, ok := inputChannelFromPeer(resolved.InputPeer) - if !ok { + if _, ok := inputChannelFromPeer(resolved.InputPeer); !ok { return nil, fmt.Errorf("%w: topics are only available in forum supergroups", command.ErrUnsupported) } // Single page only: offset-based pagination over forum topics is not // implemented, so groups with more than one page (~100) of topics are - // truncated to what the server returns in one call. - req := &tg.ChannelsGetForumTopicsRequest{Channel: inCh, Limit: q.Limit} - if q.Q != "" { - req.SetQ(q.Q) - } - resp, err := api.ChannelsGetForumTopics(ctx, req) + // truncated to what the server returns in one call. messages.getForumTopics + // has no server-side search param, so --search filters by title client-side. + resp, err := api.MessagesGetForumTopics(ctx, &tg.MessagesGetForumTopicsRequest{ + Peer: resolved.InputPeer, + Limit: q.Limit, + }) if err != nil { return nil, mapForumErr(err) } + needle := strings.ToLower(q.Q) rows := make([]output.TopicRow, 0, len(resp.Topics)) for _, tc := range resp.Topics { // ForumTopicDeleted carries no fields worth surfacing; skip it. - if t, ok := tc.(*tg.ForumTopic); ok { - rows = append(rows, forumTopicToRow(t)) + t, ok := tc.(*tg.ForumTopic) + if !ok { + continue + } + if needle != "" && !strings.Contains(strings.ToLower(t.Title), needle) { + continue } + rows = append(rows, forumTopicToRow(t)) } return rows, nil } @@ -70,8 +75,7 @@ func CreateForumTopic(ctx context.Context, api *tg.Client, resolver *peer.Resolv if err != nil { return output.TopicRow{}, err } - inCh, ok := inputChannelFromPeer(resolved.InputPeer) - if !ok { + if _, ok := inputChannelFromPeer(resolved.InputPeer); !ok { return output.TopicRow{}, fmt.Errorf("%w: topics can only be created in forum supergroups", command.ErrUnsupported) } // createForumTopic requires a random_id. Honor --random-id when given so @@ -82,8 +86,8 @@ func CreateForumTopic(ctx context.Context, api *tg.Client, resolver *peer.Resolv return output.TopicRow{}, err } } - req := &tg.ChannelsCreateForumTopicRequest{ - Channel: inCh, + req := &tg.MessagesCreateForumTopicRequest{ + Peer: resolved.InputPeer, Title: q.Title, RandomID: randomID, } @@ -93,7 +97,7 @@ func CreateForumTopic(ctx context.Context, api *tg.Client, resolver *peer.Resolv if q.IconEmojiID != 0 { req.SetIconEmojiID(q.IconEmojiID) } - upd, err := api.ChannelsCreateForumTopic(ctx, req) + upd, err := api.MessagesCreateForumTopic(ctx, req) if err != nil { return output.TopicRow{}, mapForumErr(err) } @@ -109,11 +113,11 @@ func CreateForumTopic(ctx context.Context, api *tg.Client, resolver *peer.Resolv // the caller set (non-nil) are sent, so an edit changes title/closed/hidden // independently. func EditForumTopic(ctx context.Context, api *tg.Client, resolver *peer.Resolver, q actionchat.EditTopicQuery) (output.TopicRow, error) { - inCh, err := topicChannel(ctx, resolver, q.Ref) + inPeer, err := topicPeer(ctx, resolver, q.Ref) if err != nil { return output.TopicRow{}, err } - req := &tg.ChannelsEditForumTopicRequest{Channel: inCh, TopicID: q.TopicID} + req := &tg.MessagesEditForumTopicRequest{Peer: inPeer, TopicID: q.TopicID} row := output.TopicRow{ID: q.TopicID} if q.Title != nil { req.SetTitle(*q.Title) @@ -127,7 +131,7 @@ func EditForumTopic(ctx context.Context, api *tg.Client, resolver *peer.Resolver req.SetHidden(*q.Hidden) row.Hidden = *q.Hidden } - if _, err := api.ChannelsEditForumTopic(ctx, req); err != nil { + if _, err := api.MessagesEditForumTopic(ctx, req); err != nil { return output.TopicRow{}, mapForumErr(err) } return row, nil @@ -137,13 +141,13 @@ func EditForumTopic(ctx context.Context, api *tg.Client, resolver *peer.Resolver // the topic's message history; deleteTopicHistory returns the remaining // offset, so loop (bounded) until it's drained. func DeleteForumTopic(ctx context.Context, api *tg.Client, resolver *peer.Resolver, q actionchat.DeleteTopicQuery) error { - inCh, err := topicChannel(ctx, resolver, q.Ref) + inPeer, err := topicPeer(ctx, resolver, q.Ref) if err != nil { return err } for range 100 { - aff, err := api.ChannelsDeleteTopicHistory(ctx, &tg.ChannelsDeleteTopicHistoryRequest{ - Channel: inCh, + aff, err := api.MessagesDeleteTopicHistory(ctx, &tg.MessagesDeleteTopicHistoryRequest{ + Peer: inPeer, TopMsgID: q.TopicID, }) if err != nil { @@ -158,12 +162,12 @@ func DeleteForumTopic(ctx context.Context, api *tg.Client, resolver *peer.Resolv // PinForumTopic performs the RPC for `tg chat topic pin`. func PinForumTopic(ctx context.Context, api *tg.Client, resolver *peer.Resolver, q actionchat.PinTopicQuery) (output.TopicRow, error) { - inCh, err := topicChannel(ctx, resolver, q.Ref) + inPeer, err := topicPeer(ctx, resolver, q.Ref) if err != nil { return output.TopicRow{}, err } - if _, err := api.ChannelsUpdatePinnedForumTopic(ctx, &tg.ChannelsUpdatePinnedForumTopicRequest{ - Channel: inCh, + if _, err := api.MessagesUpdatePinnedForumTopic(ctx, &tg.MessagesUpdatePinnedForumTopicRequest{ + Peer: inPeer, TopicID: q.TopicID, Pinned: q.Pinned, }); err != nil { @@ -174,13 +178,13 @@ func PinForumTopic(ctx context.Context, api *tg.Client, resolver *peer.Resolver, // GetForumTopicByID fetches a single forum topic by its ID. func GetForumTopicByID(ctx context.Context, api *tg.Client, resolver *peer.Resolver, q actionchat.TopicInfoQuery) (output.TopicRow, error) { - inCh, err := topicChannel(ctx, resolver, q.Ref) + inPeer, err := topicPeer(ctx, resolver, q.Ref) if err != nil { return output.TopicRow{}, err } - resp, err := api.ChannelsGetForumTopicsByID(ctx, &tg.ChannelsGetForumTopicsByIDRequest{ - Channel: inCh, - Topics: []int{q.TopicID}, + resp, err := api.MessagesGetForumTopicsByID(ctx, &tg.MessagesGetForumTopicsByIDRequest{ + Peer: inPeer, + Topics: []int{q.TopicID}, }) if err != nil { return output.TopicRow{}, mapForumErr(err) @@ -220,13 +224,12 @@ func ReadForumTopic(ctx context.Context, api *tg.Client, resolver *peer.Resolver if err != nil { return output.TopicRow{}, err } - inCh, ok := inputChannelFromPeer(resolved.InputPeer) - if !ok { + if _, ok := inputChannelFromPeer(resolved.InputPeer); !ok { return output.TopicRow{}, fmt.Errorf("%w: topics are only available in forum supergroups", command.ErrUnsupported) } - resp, err := api.ChannelsGetForumTopicsByID(ctx, &tg.ChannelsGetForumTopicsByIDRequest{ - Channel: inCh, - Topics: []int{q.TopicID}, + resp, err := api.MessagesGetForumTopicsByID(ctx, &tg.MessagesGetForumTopicsByIDRequest{ + Peer: resolved.InputPeer, + Topics: []int{q.TopicID}, }) if err != nil { return output.TopicRow{}, mapForumErr(err) @@ -251,17 +254,17 @@ func ReadForumTopic(ctx context.Context, api *tg.Client, resolver *peer.Resolver return output.TopicRow{ID: q.TopicID}, nil } -// topicChannel resolves a ref to the InputChannel forum RPCs need. -func topicChannel(ctx context.Context, resolver *peer.Resolver, target ref.Ref) (tg.InputChannelClass, error) { +// topicPeer resolves a ref to the InputPeer the forum RPCs need, guarding that +// it's a channel/supergroup (forum topics only exist there). +func topicPeer(ctx context.Context, resolver *peer.Resolver, target ref.Ref) (tg.InputPeerClass, error) { resolved, err := resolver.Resolve(ctx, target) if err != nil { return nil, err } - inCh, ok := inputChannelFromPeer(resolved.InputPeer) - if !ok { + if _, ok := inputChannelFromPeer(resolved.InputPeer); !ok { return nil, fmt.Errorf("%w: topics are only available in forum supergroups", command.ErrUnsupported) } - return inCh, nil + return resolved.InputPeer, nil } // mapForumErr translates "this chat is not a forum" RPC errors into a clear diff --git a/internal/telegram/poll.go b/internal/telegram/poll.go index b64f8ca..b431e5e 100644 --- a/internal/telegram/poll.go +++ b/internal/telegram/poll.go @@ -66,7 +66,11 @@ func VotePoll(ctx context.Context, api *tg.Client, resolver *peer.Resolver, q ac if i < 0 || i >= len(media.Poll.Answers) { return output.VoteResult{}, fmt.Errorf("%w: option %d is out of range (poll has %d options)", command.ErrUsage, i+1, len(media.Poll.Answers)) } - options = append(options, media.Poll.Answers[i].Option) + ans, ok := media.Poll.Answers[i].(*tg.PollAnswer) + if !ok { + return output.VoteResult{}, fmt.Errorf("%w: unexpected poll answer type", command.ErrUnsupported) + } + options = append(options, ans.Option) } } if _, err := api.MessagesSendVote(ctx, &tg.MessagesSendVoteRequest{ @@ -129,7 +133,11 @@ func pollInfoFromMedia(m *tg.MessageMediaPoll) output.PollInfo { for _, r := range m.Results.Results { tally[string(r.Option)] = r } - for _, a := range m.Poll.Answers { + for _, ac := range m.Poll.Answers { + a, ok := ac.(*tg.PollAnswer) + if !ok { + continue + } opt := output.PollOption{Text: a.Text.Text} if r, ok := tally[string(a.Option)]; ok { opt.Voters = r.Voters diff --git a/internal/telegram/session/dial.go b/internal/telegram/session/dial.go index bd87daf..5965d39 100644 --- a/internal/telegram/session/dial.go +++ b/internal/telegram/session/dial.go @@ -28,7 +28,7 @@ func buildTelegramClientWithHandler(acct *account.Account, opts Options, handler sess := &account.FileSessionStorage{AccountName: acct.Meta.Name} b := &built{} tgOpts := telegram.Options{ - Logger: opts.Logger, + Logger: gotdLogger(opts.Logger), SessionStorage: sess, UpdateHandler: handler, Device: deviceConfig(opts.Device), diff --git a/internal/telegram/session/gotdlog.go b/internal/telegram/session/gotdlog.go new file mode 100644 index 0000000..610120e --- /dev/null +++ b/internal/telegram/session/gotdlog.go @@ -0,0 +1,52 @@ +package session + +import ( + "context" + + gotdlog "github.com/gotd/log" + "go.uber.org/zap" + "go.uber.org/zap/zapcore" +) + +// gotdLogger adapts our *zap.Logger to gotd's log.Logger interface. gotd +// migrated telegram.Options.Logger from *zap.Logger to its own minimal +// slog-style interface, so the zap logger no longer fits directly. +func gotdLogger(l *zap.Logger) gotdlog.Logger { + if l == nil { + return gotdlog.Nop + } + return zapGotdLogger{l: l} +} + +type zapGotdLogger struct{ l *zap.Logger } + +func (z zapGotdLogger) Enabled(_ context.Context, level gotdlog.Level) bool { + return z.l.Core().Enabled(zapLevel(level)) +} + +func (z zapGotdLogger) Log(_ context.Context, level gotdlog.Level, msg string, attrs ...gotdlog.Attr) { + ce := z.l.Check(zapLevel(level), msg) + if ce == nil { + return + } + fields := make([]zap.Field, len(attrs)) + for i, a := range attrs { + fields[i] = zap.Any(a.Key, a.Value.Any()) + } + ce.Write(fields...) +} + +// zapLevel maps gotd's slog-style levels (Debug=-4, Info=0, Warn=4, Error=8) +// onto zap levels. +func zapLevel(l gotdlog.Level) zapcore.Level { + switch { + case l >= gotdlog.LevelError: + return zapcore.ErrorLevel + case l >= gotdlog.LevelWarn: + return zapcore.WarnLevel + case l >= gotdlog.LevelInfo: + return zapcore.InfoLevel + default: + return zapcore.DebugLevel + } +}