Live video on the AT Protocol
79
fork

Configure Feed

Select the types of activity you want to include in your feed.

at eli/fix-postgres-locking 121 lines 4.0 kB view raw
1package spxrpc 2 3import ( 4 "context" 5 "fmt" 6 "net/http" 7 "time" 8 9 comatprototypes "github.com/bluesky-social/indigo/api/atproto" 10 "github.com/bluesky-social/indigo/atproto/syntax" 11 "github.com/bluesky-social/indigo/xrpc" 12 "github.com/google/uuid" 13 "github.com/labstack/echo/v4" 14 "github.com/streamplace/oatproxy/pkg/oatproxy" 15 "stream.place/streamplace/pkg/config" 16 "stream.place/streamplace/pkg/log" 17 "stream.place/streamplace/pkg/media" 18 "stream.place/streamplace/pkg/model" 19) 20 21func (s *Server) handleComAtprotoModerationCreateReport(ctx context.Context, body *comatprototypes.ModerationCreateReport_Input) (*comatprototypes.ModerationCreateReport_Output, error) { 22 c, ok := ctx.Value(echoContextKey).(echo.Context) 23 if !ok { 24 return nil, echo.NewHTTPError(http.StatusInternalServerError, "echo context not found") 25 } 26 27 atprotoProxy := c.Request().Header.Get("Atproto-Proxy") 28 if atprotoProxy == "" { 29 if len(s.cli.Labelers) > 0 { 30 atprotoProxy = fmt.Sprintf("%s#atproto_labeler", s.cli.Labelers[0]) 31 } else { 32 return nil, echo.NewHTTPError(http.StatusBadRequest, "Atproto-Proxy header is required (where are you sending this report?)") 33 } 34 } 35 36 log.Log(ctx, "handleComAtprotoModerationCreateReport", "body", body) 37 38 session, client := oatproxy.GetOAuthSession(ctx) 39 if session == nil { 40 return nil, echo.NewHTTPError(http.StatusUnauthorized, "oauth session not found") 41 } 42 43 if body.Reason == nil { 44 empty := "" 45 body.Reason = &empty 46 } 47 48 if body.Subject == nil { 49 return nil, echo.NewHTTPError(http.StatusBadRequest, "subject is required") 50 } 51 52 var did string 53 54 if body.Subject.AdminDefs_RepoRef != nil { 55 d, err := syntax.ParseDID(body.Subject.AdminDefs_RepoRef.Did) 56 if err != nil { 57 return nil, echo.NewHTTPError(http.StatusBadRequest, "invalid subject did") 58 } 59 did = d.String() 60 } else if body.Subject.RepoStrongRef != nil { 61 aturi, err := syntax.ParseATURI(body.Subject.RepoStrongRef.Uri) 62 if err != nil { 63 return nil, echo.NewHTTPError(http.StatusBadRequest, "invalid subject uri") 64 } 65 did = aturi.Authority().String() 66 // if it's chat, we want the clip from the streamer, not from the chatter 67 if aturi.Collection() == "place.stream.chat.message" { 68 msg, err := s.model.GetChatMessage(body.Subject.RepoStrongRef.Uri) 69 if err != nil { 70 log.Error(ctx, "failed to get chat message for chat report", "error", err) 71 } else { 72 did = msg.StreamerRepoDID 73 } 74 } 75 } else { 76 return nil, echo.NewHTTPError(http.StatusBadRequest, "invalid subject") 77 } 78 79 clipID, err := makeClip(ctx, s.cli, s.model, did) 80 if err != nil { 81 // we still want the report to go through! 82 log.Error(ctx, "failed to make clip for report", "error", err) 83 } else { 84 clipURL := fmt.Sprintf("https://%s/api/clip/%s/%s.mp4", s.cli.PublicHost, did, clipID) 85 newReason := fmt.Sprintf("%s\n\nClip: %s", *body.Reason, clipURL) 86 body.Reason = &newReason 87 } 88 89 client.SetHeaders(map[string]string{ 90 "Atproto-Proxy": atprotoProxy, 91 }) 92 93 var output comatprototypes.ModerationCreateReport_Output 94 err = client.Do(ctx, xrpc.Procedure, "application/json", "com.atproto.moderation.createReport", nil, body, &output) 95 if err != nil { 96 return nil, echo.NewHTTPError(http.StatusInternalServerError, err.Error()) 97 } 98 99 return &output, nil 100} 101 102func makeClip(ctx context.Context, cli *config.CLI, mod model.Model, did string) (string, error) { 103 after := time.Now().Add(-time.Duration(60) * time.Second) 104 105 uu, err := uuid.NewV7() 106 if err != nil { 107 return "", echo.NewHTTPError(http.StatusInternalServerError, "failed to generate uuid") 108 } 109 110 fd, err := cli.DataFileCreate([]string{did, "clips", fmt.Sprintf("%s.mp4", uu.String())}, false) 111 if err != nil { 112 return "", echo.NewHTTPError(http.StatusInternalServerError, "failed to create data file") 113 } 114 defer fd.Close() 115 116 err = media.ClipUser(ctx, mod, cli, did, fd, nil, &after) 117 if err != nil { 118 return "", echo.NewHTTPError(http.StatusInternalServerError, "failed to clip user") 119 } 120 return uu.String(), nil 121}