backend for xcvr appview
3
fork

Configure Feed

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

at main 175 lines 5.3 kB view raw
1package recordmanager 2 3import ( 4 "context" 5 "errors" 6 "fmt" 7 atoauth "github.com/bluesky-social/indigo/atproto/auth/oauth" 8 "github.com/bluesky-social/indigo/atproto/syntax" 9 "rvcx/internal/atputils" 10 "rvcx/internal/lex" 11 "rvcx/internal/oauth" 12 "rvcx/internal/types" 13 "time" 14) 15 16func (rm *RecordManager) AcceptChannel(c *types.Channel, ctx context.Context) error { 17 wasNew, err := rm.storeChannel(c, ctx) 18 if err != nil { 19 return errors.New("failed to store channel: " + err.Error()) 20 } 21 if !wasNew { 22 return nil 23 } 24 err = rm.initChannel(c) 25 if err != nil { 26 return errors.New("failed to initialize channel: " + err.Error()) 27 } 28 return nil 29} 30 31func (rm *RecordManager) AcceptChannelUpdate(c *types.Channel, ctx context.Context) error { 32 err := rm.updateChanneldb(c, ctx) 33 if err != nil { 34 return errors.New("failed to update channel: " + err.Error()) 35 } 36 err = rm.updateChannelmodel(c) 37 if err != nil { 38 return errors.New("failed to update channel model: " + err.Error()) 39 } 40 return nil 41} 42 43func (rm *RecordManager) AcceptChannelDelete(uri string, ctx context.Context) error { 44 err := rm.db.DeleteChannel(uri, ctx) 45 if err != nil { 46 return errors.New("failed to delete channel: " + err.Error()) 47 } 48 return rm.broadcaster.DeleteChannel(uri) 49} 50 51func (rm *RecordManager) PostMyChannel(ctx context.Context, pcr *types.PostChannelRequest) (did string, uri string, err error) { 52 return rm.postchannelflow(rm.createMyChannel(), ctx, pcr) 53} 54 55func (rm *RecordManager) PostChannel(cs *atoauth.ClientSession, ctx context.Context, pcr *types.PostChannelRequest) (did string, uri string, err error) { 56 return rm.postchannelflow(rm.createChannel(cs), ctx, pcr) 57} 58 59func (rm *RecordManager) DeleteChannel(cs *atoauth.ClientSession, rkey string, ctx context.Context) error { 60 err := oauth.DeleteXCVRChannel(cs, rkey, ctx) 61 if err != nil { 62 return errors.New("failed to delete channel: " + err.Error()) 63 } 64 return rm.AcceptChannelDelete(fmt.Sprintf("at://%s/org.xcvr.feed.channel/%s", cs.Data.AccountDID.String(), rkey), ctx) 65} 66 67func (rm *RecordManager) postchannelflow(f func(*lex.ChannelRecord, *time.Time, context.Context) (*types.Channel, error), ctx context.Context, pcr *types.PostChannelRequest) (did string, uri string, err error) { 68 lcr, now, err := rm.validateChannel(pcr) 69 if err != nil { 70 err = errors.New("couldn't validate channel: " + err.Error()) 71 return 72 } 73 channel, err := f(lcr, now, ctx) 74 if err != nil { 75 err = errors.New("couldn't create channel: " + err.Error()) 76 return 77 } 78 wasNew, err := rm.storeChannel(channel, ctx) 79 if err != nil { 80 err = errors.New("couldn't store channel: " + err.Error()) 81 return 82 } 83 if !wasNew { 84 did = channel.DID 85 uri = channel.URI 86 return 87 } 88 err = rm.initChannel(channel) 89 if err != nil { 90 err = errors.New("couldn't init channel: " + err.Error()) 91 return 92 } 93 did = channel.DID 94 uri = channel.URI 95 return 96} 97 98func (rm *RecordManager) storeChannel(c *types.Channel, ctx context.Context) (wasNew bool, err error) { 99 return rm.db.StoreChannel(c, ctx) 100} 101 102func (rm *RecordManager) initChannel(c *types.Channel) error { 103 return rm.broadcaster.AddChannel(c) 104} 105 106func (rm *RecordManager) updateChanneldb(c *types.Channel, ctx context.Context) error { 107 return rm.db.UpdateChannel(c, ctx) 108} 109 110func (rm *RecordManager) updateChannelmodel(c *types.Channel) error { 111 return rm.broadcaster.UpdateChannel(c) 112} 113 114func (rm *RecordManager) createChannel(cs *atoauth.ClientSession) func(*lex.ChannelRecord, *time.Time, context.Context) (*types.Channel, error) { 115 return func(lcr *lex.ChannelRecord, now *time.Time, ctx context.Context) (*types.Channel, error) { 116 uri, cid, err := oauth.CreateXCVRChannel(cs, lcr, ctx) 117 if err != nil { 118 return nil, errors.New("something bad probs happened when posting a channel " + err.Error()) 119 } 120 channel := types.Channel{ 121 URI: uri, 122 CID: cid, 123 DID: cs.Data.AccountDID.String(), 124 Host: lcr.Host, 125 Title: lcr.Title, 126 Topic: lcr.Topic, 127 CreatedAt: *now, 128 IndexedAt: time.Now(), 129 } 130 return &channel, nil 131 } 132} 133 134func (rm *RecordManager) createMyChannel() func(*lex.ChannelRecord, *time.Time, context.Context) (*types.Channel, error) { 135 return func(lcr *lex.ChannelRecord, now *time.Time, ctx context.Context) (*types.Channel, error) { 136 cid, uri, err := rm.myClient.CreateXCVRChannel(lcr, ctx) 137 if err != nil { 138 return nil, errors.New("something bad probs happened when posting a channel " + err.Error()) 139 } 140 channel := types.Channel{ 141 URI: uri, 142 CID: cid, 143 DID: atputils.GetMyDid(), 144 Host: lcr.Host, 145 Title: lcr.Title, 146 Topic: lcr.Topic, 147 CreatedAt: *now, 148 IndexedAt: time.Now(), 149 } 150 return &channel, nil 151 } 152} 153 154func (rm *RecordManager) validateChannel(cr *types.PostChannelRequest) (*lex.ChannelRecord, *time.Time, error) { 155 var lcr lex.ChannelRecord 156 if cr.Title == "" || atputils.ValidateGraphemesAndLength(cr.Title, 64, 640) { 157 return nil, nil, errors.New("title empty or too long") 158 } 159 lcr.Title = cr.Title 160 if cr.Host == "" { 161 return nil, nil, errors.New("no host") 162 } 163 lcr.Host = cr.Host 164 if cr.Topic != nil { 165 if atputils.ValidateGraphemesAndLength(*cr.Topic, 256, 2560) { 166 return nil, nil, errors.New("topic too long") 167 } 168 lcr.Topic = cr.Topic 169 } 170 171 dtn := syntax.DatetimeNow() 172 lcr.CreatedAt = dtn.String() 173 time := dtn.Time() 174 return &lcr, &time, nil 175}