mediaconn.go 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // Copyright (c) 2021 Tulir Asokan
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. package whatsmeow
  7. import (
  8. "context"
  9. "fmt"
  10. "time"
  11. waBinary "git.bobomao.top/joey/testwh/binary"
  12. "git.bobomao.top/joey/testwh/types"
  13. )
  14. //type MediaConnIP struct {
  15. // IP4 net.IP
  16. // IP6 net.IP
  17. //}
  18. // MediaConnHost represents a single host to download media from.
  19. type MediaConnHost struct {
  20. Hostname string
  21. //IPs []MediaConnIP
  22. }
  23. // MediaConn contains a list of WhatsApp servers from which attachments can be downloaded from.
  24. type MediaConn struct {
  25. Auth string
  26. AuthTTL int
  27. TTL int
  28. MaxBuckets int
  29. FetchedAt time.Time
  30. Hosts []MediaConnHost
  31. }
  32. // Expiry returns the time when the MediaConn expires.
  33. func (mc *MediaConn) Expiry() time.Time {
  34. return mc.FetchedAt.Add(time.Duration(mc.TTL) * time.Second)
  35. }
  36. func (cli *Client) refreshMediaConn(ctx context.Context, force bool) (*MediaConn, error) {
  37. if cli == nil {
  38. return nil, ErrClientIsNil
  39. }
  40. cli.mediaConnLock.Lock()
  41. defer cli.mediaConnLock.Unlock()
  42. if cli.mediaConnCache == nil || force || time.Now().After(cli.mediaConnCache.Expiry()) {
  43. var err error
  44. cli.mediaConnCache, err = cli.queryMediaConn(ctx)
  45. if err != nil {
  46. return nil, err
  47. }
  48. }
  49. return cli.mediaConnCache, nil
  50. }
  51. func (cli *Client) queryMediaConn(ctx context.Context) (*MediaConn, error) {
  52. resp, err := cli.sendIQ(ctx, infoQuery{
  53. Namespace: "w:m",
  54. Type: "set",
  55. To: types.ServerJID,
  56. Content: []waBinary.Node{{Tag: "media_conn"}},
  57. })
  58. if err != nil {
  59. return nil, fmt.Errorf("failed to query media connections: %w", err)
  60. } else if len(resp.GetChildren()) == 0 || resp.GetChildren()[0].Tag != "media_conn" {
  61. return nil, fmt.Errorf("failed to query media connections: unexpected child tag")
  62. }
  63. respMC := resp.GetChildren()[0]
  64. var mc MediaConn
  65. ag := respMC.AttrGetter()
  66. mc.FetchedAt = time.Now()
  67. mc.Auth = ag.String("auth")
  68. mc.TTL = ag.Int("ttl")
  69. mc.AuthTTL = ag.Int("auth_ttl")
  70. mc.MaxBuckets = ag.Int("max_buckets")
  71. if !ag.OK() {
  72. return nil, fmt.Errorf("failed to parse media connections: %+v", ag.Errors)
  73. }
  74. for _, child := range respMC.GetChildren() {
  75. if child.Tag != "host" {
  76. cli.Log.Warnf("Unexpected child in media_conn element: %s", child.XMLString())
  77. continue
  78. }
  79. cag := child.AttrGetter()
  80. mc.Hosts = append(mc.Hosts, MediaConnHost{
  81. Hostname: cag.String("hostname"),
  82. })
  83. if !cag.OK() {
  84. return nil, fmt.Errorf("failed to parse media connection host: %+v", ag.Errors)
  85. }
  86. }
  87. return &mc, nil
  88. }