github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/chat/attachments/sender.go (about) 1 package attachments 2 3 import ( 4 "errors" 5 6 "github.com/keybase/client/go/chat/globals" 7 "github.com/keybase/client/go/chat/storage" 8 "github.com/keybase/client/go/chat/types" 9 "github.com/keybase/client/go/chat/utils" 10 "github.com/keybase/client/go/protocol/chat1" 11 "github.com/keybase/client/go/protocol/gregor1" 12 "github.com/keybase/client/go/protocol/keybase1" 13 "golang.org/x/net/context" 14 ) 15 16 type Sender struct { 17 globals.Contextified 18 utils.DebugLabeler 19 } 20 21 func NewSender(g *globals.Context) *Sender { 22 return &Sender{ 23 Contextified: globals.NewContextified(g), 24 DebugLabeler: utils.NewDebugLabeler(g.ExternalG(), "Attachments.Sender", false), 25 } 26 } 27 28 func (s *Sender) MakePreview(ctx context.Context, filename string, outboxID chat1.OutboxID) (res chat1.MakePreviewRes, err error) { 29 defer s.Trace(ctx, &err, "MakePreview")() 30 src, err := NewReadCloseResetter(ctx, s.G().GlobalContext, filename) 31 if err != nil { 32 return res, err 33 } 34 defer src.Close() 35 pre, err := PreprocessAsset(ctx, s.G(), s.DebugLabeler, src, filename, s.G().NativeVideoHelper, nil) 36 if err != nil { 37 return chat1.MakePreviewRes{}, err 38 } 39 if pre.Preview != nil { 40 if err := NewPendingPreviews(s.G()).Put(ctx, outboxID, pre); err != nil { 41 return res, err 42 } 43 return pre.Export(func() *chat1.PreviewLocation { 44 loc := chat1.NewPreviewLocationWithUrl(s.G().AttachmentURLSrv.GetPendingPreviewURL(ctx, outboxID)) 45 return &loc 46 }) 47 } 48 return pre.Export(func() *chat1.PreviewLocation { return nil }) 49 } 50 51 func (s *Sender) preprocess(ctx context.Context, filename string, callerPreview *chat1.MakePreviewRes) (res Preprocess, err error) { 52 src, err := NewReadCloseResetter(ctx, s.G().GlobalContext, filename) 53 if err != nil { 54 return res, err 55 } 56 defer src.Close() 57 return PreprocessAsset(ctx, s.G(), s.DebugLabeler, src, filename, s.G().NativeVideoHelper, callerPreview) 58 } 59 60 func (s *Sender) makeBaseAttachmentMessage(ctx context.Context, tlfName string, vis keybase1.TLFVisibility, 61 inOutboxID *chat1.OutboxID, filename, title string, md []byte, ephemeralLifetime *gregor1.DurationSec, 62 callerPreview *chat1.MakePreviewRes) (msg chat1.MessagePlaintext, outboxID chat1.OutboxID, err error) { 63 if inOutboxID == nil { 64 if outboxID, err = storage.NewOutboxID(); err != nil { 65 return msg, outboxID, err 66 } 67 } else { 68 outboxID = *inOutboxID 69 } 70 71 var assetMetadata chat1.AssetMetadata 72 if pre, err := s.preprocess(ctx, filename, callerPreview); err != nil { 73 // If we can't generate a preview here, let's not blow the whole thing up, we can try 74 // again when we are actually uploading the attachment 75 s.Debug(ctx, "makeBaseAttachmentMessage: failed to process caller preview, skipping: %s", err) 76 } else { 77 if err := NewPendingPreviews(s.G()).Put(ctx, outboxID, pre); err != nil { 78 s.Debug(ctx, "makeBaseAttachmentMessage: failed to save pending preview: %s", err) 79 } 80 assetMetadata = pre.BaseMetadata() 81 } 82 83 msg = chat1.MessagePlaintext{ 84 ClientHeader: chat1.MessageClientHeader{ 85 MessageType: chat1.MessageType_ATTACHMENT, 86 TlfName: tlfName, 87 TlfPublic: vis == keybase1.TLFVisibility_PUBLIC, 88 OutboxID: &outboxID, 89 }, 90 MessageBody: chat1.NewMessageBodyWithAttachment(chat1.MessageAttachment{ 91 Object: chat1.Asset{ 92 Title: title, 93 Filename: filename, 94 Metadata: assetMetadata, 95 }, 96 Metadata: md, 97 }), 98 } 99 if ephemeralLifetime != nil { 100 msg.ClientHeader.EphemeralMetadata = &chat1.MsgEphemeralMetadata{ 101 Lifetime: *ephemeralLifetime, 102 } 103 } 104 105 return msg, outboxID, nil 106 } 107 108 func (s *Sender) PostFileAttachmentMessage(ctx context.Context, sender types.Sender, 109 convID chat1.ConversationID, tlfName string, vis keybase1.TLFVisibility, inOutboxID *chat1.OutboxID, 110 filename, title string, md []byte, clientPrev chat1.MessageID, ephemeralLifetime *gregor1.DurationSec, 111 callerPreview *chat1.MakePreviewRes) (outboxID chat1.OutboxID, msgID *chat1.MessageID, err error) { 112 defer s.Trace(ctx, &err, "PostFileAttachmentMessage")() 113 var msg chat1.MessagePlaintext 114 if msg, outboxID, err = s.makeBaseAttachmentMessage(ctx, tlfName, vis, inOutboxID, filename, title, md, 115 ephemeralLifetime, callerPreview); err != nil { 116 return outboxID, msgID, err 117 } 118 s.Debug(ctx, "PostFileAttachmentMessage: generated message with outbox ID: %s", outboxID) 119 _, boxed, err := sender.Send(ctx, convID, msg, clientPrev, &outboxID, nil, nil) 120 if err != nil { 121 return outboxID, msgID, err 122 } 123 if boxed != nil && boxed.ServerHeader != nil { 124 msgID = new(chat1.MessageID) 125 *msgID = boxed.GetMessageID() 126 } 127 return outboxID, msgID, nil 128 } 129 130 func (s *Sender) PostFileAttachment(ctx context.Context, sender types.Sender, uid gregor1.UID, 131 convID chat1.ConversationID, tlfName string, vis keybase1.TLFVisibility, inOutboxID *chat1.OutboxID, 132 filename, title string, md []byte, clientPrev chat1.MessageID, ephemeralLifetime *gregor1.DurationSec, 133 callerPreview *chat1.MakePreviewRes) (outboxID chat1.OutboxID, msgID *chat1.MessageID, err error) { 134 defer s.Trace(ctx, &err, "PostFileAttachment")() 135 var msg chat1.MessagePlaintext 136 if msg, outboxID, err = s.makeBaseAttachmentMessage(ctx, tlfName, vis, inOutboxID, filename, title, md, 137 ephemeralLifetime, callerPreview); err != nil { 138 return outboxID, msgID, err 139 } 140 // Start upload 141 uresCb, err := s.G().AttachmentUploader.Register(ctx, uid, convID, outboxID, title, filename, md, 142 callerPreview) 143 if err != nil { 144 return outboxID, msgID, err 145 } 146 // Wait for upload 147 ures := <-uresCb.Wait() 148 if ures.Error != nil { 149 s.Debug(ctx, "PostFileAttachment: upload failed, bailing out: %s", *ures.Error) 150 return outboxID, msgID, errors.New(*ures.Error) 151 } 152 // Fill in the rest of the message 153 attachment := chat1.MessageAttachment{ 154 Object: ures.Object, 155 Metadata: md, 156 Uploaded: true, 157 } 158 if ures.Preview != nil { 159 s.Debug(ctx, "PostFileAttachment: attachment preview asset added") 160 attachment.Previews = []chat1.Asset{*ures.Preview} 161 attachment.Preview = ures.Preview 162 } 163 msg.MessageBody = chat1.NewMessageBodyWithAttachment(attachment) 164 165 s.Debug(ctx, "PostFileAttachment: attachment assets uploaded, posting attachment message") 166 _, boxed, err := sender.Send(ctx, convID, msg, clientPrev, &outboxID, nil, nil) 167 if err != nil { 168 return outboxID, msgID, err 169 } 170 if boxed != nil && boxed.ServerHeader != nil { 171 msgID = new(chat1.MessageID) 172 *msgID = boxed.GetMessageID() 173 } 174 return outboxID, msgID, nil 175 }