🧮 USERS:1 FEEDS:2 TWTS:347 ARCHIVED:36832 CACHE:1640 FOLLOWERS:13 FOLLOWING:14
**
🧮 USERS:3 FEEDS:6 TWTS:525 BLOGS:0 ARCHIVED:104495 CACHE:2567 FOLLOWERS:9 FOLLOWING:17
**
🧮 USERS:3 FEEDS:6 TWTS:525 BLOGS:0 ARCHIVED:104495 CACHE:2567 FOLLOWERS:9 FOLLOWING:17 ⌘ Read more
@prologic@twtxt.net I think those are fine because its just sharing someone elses post to people who follow you. Those people who follow you might not follow the orginal person and in return might never see that post unless its retoos/retweets. The thing that is harmful is likes.
🧮 USERS:1 FEEDS:2 TWTS:346 ARCHIVED:36780 CACHE:1627 FOLLOWERS:13 FOLLOWING:14
**
🧮 USERS:3 FEEDS:6 TWTS:524 BLOGS:0 ARCHIVED:103566 CACHE:2512 FOLLOWERS:9 FOLLOWING:17
**
🧮 USERS:3 FEEDS:6 TWTS:524 BLOGS:0 ARCHIVED:103566 CACHE:2512 FOLLOWERS:9 FOLLOWING:17 ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:345 ARCHIVED:36732 CACHE:1614 FOLLOWERS:13 FOLLOWING:14
**
🧮 USERS:3 FEEDS:6 TWTS:523 BLOGS:0 ARCHIVED:103459 CACHE:2487 FOLLOWERS:9 FOLLOWING:17
**
🧮 USERS:3 FEEDS:6 TWTS:523 BLOGS:0 ARCHIVED:103459 CACHE:2487 FOLLOWERS:9 FOLLOWING:17 ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:344 ARCHIVED:36689 CACHE:1603 FOLLOWERS:13 FOLLOWING:14
The thing is I don’t know how to search the web logs on Codeberg or even if they are public. That is the issue with just regular text files. The thing with having the follower list in the twtxt file is that then it knows to track friends of friends like with yarn.
If not having www is an issue when I will add it in. Good to know its something I have to change
@movq@uninformativ.de Do you know how I would find people that reply to my posts or replies or even mention my users? Prologic tried to contact me and unless I found him on the yarn pod then I would not know he exists and wants to talk to me. The user agents would work but I don’t know if I can view my web server logs from codeberg pages and I don’t know how to monitor my logs for mentions. What about the way yarn does it by added people you follow to your twtxt file and having friends of friends like yarn does it be a thing for jenny. Just an idea
**
🧮 USERS:3 FEEDS:6 TWTS:522 BLOGS:0 ARCHIVED:103343 CACHE:2434 FOLLOWERS:9 FOLLOWING:17
**
🧮 USERS:3 FEEDS:6 TWTS:522 BLOGS:0 ARCHIVED:103343 CACHE:2434 FOLLOWERS:9 FOLLOWING:17 ⌘ Read more
@prologic@twtxt.net I do think the post about how to setup jenny + mutt over on the uninformativ.de blog is still a great post. I used that post to see the steps to set it up and it works fine. Though I can write some blog post with some more documentation for things like auto publishing. The big issue with plain twtxt is that I would have not seen your post unless I looked on twtxt.net when I was looking at yarn a little bit more. Twtxt does overcome the issue by introducing the registry but I can’t figure out any way to use them for Jenny and almost no one uses them in the first place. So I can’t see anyones replies or mentions unless I am following them. Yarn does overcome the issue by friends of friends as you would know as the creator of yarn.
🧮 USERS:1 FEEDS:2 TWTS:343 ARCHIVED:36635 CACHE:1578 FOLLOWERS:13 FOLLOWING:14
**
🧮 USERS:3 FEEDS:6 TWTS:521 BLOGS:0 ARCHIVED:103270 CACHE:2431 FOLLOWERS:9 FOLLOWING:17
**
🧮 USERS:3 FEEDS:6 TWTS:521 BLOGS:0 ARCHIVED:103270 CACHE:2431 FOLLOWERS:9 FOLLOWING:17 ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:342 ARCHIVED:36624 CACHE:1594 FOLLOWERS:13 FOLLOWING:14
**
🧮 USERS:3 FEEDS:6 TWTS:520 BLOGS:0 ARCHIVED:103169 CACHE:2406 FOLLOWERS:9 FOLLOWING:17
**
🧮 USERS:3 FEEDS:6 TWTS:520 BLOGS:0 ARCHIVED:103169 CACHE:2406 FOLLOWERS:9 FOLLOWING:17 ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:341 ARCHIVED:36586 CACHE:1572 FOLLOWERS:13 FOLLOWING:14
**
🧮 USERS:3 FEEDS:6 TWTS:519 BLOGS:0 ARCHIVED:103091 CACHE:2429 FOLLOWERS:9 FOLLOWING:17
**
🧮 USERS:3 FEEDS:6 TWTS:519 BLOGS:0 ARCHIVED:103091 CACHE:2429 FOLLOWERS:9 FOLLOWING:17 ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:340 ARCHIVED:36553 CACHE:1551 FOLLOWERS:13 FOLLOWING:14
**
🧮 USERS:3 FEEDS:6 TWTS:518 BLOGS:0 ARCHIVED:103027 CACHE:2432 FOLLOWERS:9 FOLLOWING:17
**
🧮 USERS:3 FEEDS:6 TWTS:518 BLOGS:0 ARCHIVED:103027 CACHE:2432 FOLLOWERS:9 FOLLOWING:17 ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:339 ARCHIVED:36526 CACHE:1531 FOLLOWERS:13 FOLLOWING:14
**
🧮 USERS:3 FEEDS:6 TWTS:517 BLOGS:0 ARCHIVED:102942 CACHE:2421 FOLLOWERS:9 FOLLOWING:17
**
🧮 USERS:3 FEEDS:6 TWTS:517 BLOGS:0 ARCHIVED:102942 CACHE:2421 FOLLOWERS:9 FOLLOWING:17 ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:338 ARCHIVED:36495 CACHE:1521 FOLLOWERS:13 FOLLOWING:14
**
🧮 USERS:3 FEEDS:6 TWTS:516 BLOGS:0 ARCHIVED:102879 CACHE:2438 FOLLOWERS:9 FOLLOWING:17
**
🧮 USERS:3 FEEDS:6 TWTS:516 BLOGS:0 ARCHIVED:102879 CACHE:2438 FOLLOWERS:9 FOLLOWING:17 ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:337 ARCHIVED:36480 CACHE:1537 FOLLOWERS:13 FOLLOWING:14
**
🧮 USERS:3 FEEDS:6 TWTS:515 BLOGS:0 ARCHIVED:102785 CACHE:2423 FOLLOWERS:9 FOLLOWING:17
**
🧮 USERS:3 FEEDS:6 TWTS:515 BLOGS:0 ARCHIVED:102785 CACHE:2423 FOLLOWERS:9 FOLLOWING:17 ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:336 ARCHIVED:36468 CACHE:1545 FOLLOWERS:13 FOLLOWING:14
**
🧮 USERS:3 FEEDS:6 TWTS:514 BLOGS:0 ARCHIVED:102707 CACHE:2407 FOLLOWERS:9 FOLLOWING:17
**
🧮 USERS:3 FEEDS:6 TWTS:514 BLOGS:0 ARCHIVED:102707 CACHE:2407 FOLLOWERS:9 FOLLOWING:17 ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:335 ARCHIVED:36404 CACHE:1542 FOLLOWERS:13 FOLLOWING:14
**
🧮 USERS:3 FEEDS:6 TWTS:513 BLOGS:0 ARCHIVED:102607 CACHE:2441 FOLLOWERS:9 FOLLOWING:17
**
🧮 USERS:3 FEEDS:6 TWTS:513 BLOGS:0 ARCHIVED:102607 CACHE:2441 FOLLOWERS:9 FOLLOWING:17 ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:334 ARCHIVED:36379 CACHE:1589 FOLLOWERS:13 FOLLOWING:14
**
🧮 USERS:3 FEEDS:6 TWTS:512 BLOGS:0 ARCHIVED:102541 CACHE:2464 FOLLOWERS:9 FOLLOWING:17
**
🧮 USERS:3 FEEDS:6 TWTS:512 BLOGS:0 ARCHIVED:102541 CACHE:2464 FOLLOWERS:9 FOLLOWING:17 ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:333 ARCHIVED:36357 CACHE:1579 FOLLOWERS:13 FOLLOWING:14
**
🧮 USERS:3 FEEDS:6 TWTS:511 BLOGS:0 ARCHIVED:102473 CACHE:2457 FOLLOWERS:9 FOLLOWING:17
**
🧮 USERS:3 FEEDS:6 TWTS:511 BLOGS:0 ARCHIVED:102473 CACHE:2457 FOLLOWERS:9 FOLLOWING:17 ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:332 ARCHIVED:36316 CACHE:1563 FOLLOWERS:13 FOLLOWING:14
**
🧮 USERS:3 FEEDS:6 TWTS:510 BLOGS:0 ARCHIVED:102397 CACHE:2476 FOLLOWERS:9 FOLLOWING:17
**
🧮 USERS:3 FEEDS:6 TWTS:510 BLOGS:0 ARCHIVED:102397 CACHE:2476 FOLLOWERS:9 FOLLOWING:17 ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:331 ARCHIVED:36304 CACHE:1600 FOLLOWERS:13 FOLLOWING:14
**
🧮 USERS:3 FEEDS:6 TWTS:509 BLOGS:0 ARCHIVED:102326 CACHE:2474 FOLLOWERS:9 FOLLOWING:17
**
🧮 USERS:3 FEEDS:6 TWTS:509 BLOGS:0 ARCHIVED:102326 CACHE:2474 FOLLOWERS:9 FOLLOWING:17 ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:330 ARCHIVED:36287 CACHE:1596 FOLLOWERS:13 FOLLOWING:14
**
🧮 USERS:3 FEEDS:6 TWTS:508 BLOGS:0 ARCHIVED:102240 CACHE:2463 FOLLOWERS:9 FOLLOWING:17
**
🧮 USERS:3 FEEDS:6 TWTS:508 BLOGS:0 ARCHIVED:102240 CACHE:2463 FOLLOWERS:9 FOLLOWING:17 ⌘ Read more
🧮 Users: 2, Feeds: 6, Twts: 1026, Archived: 1116347, Cache: 89202, Followers: 29, and Following: 701.
🧮 USERS:1 FEEDS:2 TWTS:329 ARCHIVED:36277 CACHE:1614 FOLLOWERS:13 FOLLOWING:14
**
🧮 USERS:3 FEEDS:6 TWTS:507 BLOGS:0 ARCHIVED:102165 CACHE:2455 FOLLOWERS:9 FOLLOWING:17
**
🧮 USERS:3 FEEDS:6 TWTS:507 BLOGS:0 ARCHIVED:102165 CACHE:2455 FOLLOWERS:9 FOLLOWING:17 ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:328 ARCHIVED:36263 CACHE:1622 FOLLOWERS:13 FOLLOWING:14
👋 Hello @burglar@txt.sour.is, welcome to txt.sour.is, a Yarn.social Pod! To get started you may want to check out the pod’s Discover feed to find users to follow and interact with. To follow new users, use the ⨁ Follow button on their profile page or use the Follow form and enter a Twtxt URL. You may also find other feeds of interest via Feeds. Welcome! 🤗
**
🧮 USERS:3 FEEDS:6 TWTS:506 BLOGS:0 ARCHIVED:102071 CACHE:2446 FOLLOWERS:9 FOLLOWING:17
**
🧮 USERS:3 FEEDS:6 TWTS:506 BLOGS:0 ARCHIVED:102071 CACHE:2446 FOLLOWERS:9 FOLLOWING:17 ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:327 ARCHIVED:36241 CACHE:1665 FOLLOWERS:13 FOLLOWING:14
I’ve realized that trying to strictly follow what is on the IndieWeb wiki won’t work well for me. Thus, I have to invent and change some things to make it work better. ⌘ Read more
(cont.)
Just to give some context on some of the components around the code structure.. I wrote this up around an earlier version of aggregate code. This generic bit simplifies things by removing the need of the Crud functions for each aggregate.
Domain ObjectsA domain object can be used as an aggregate by adding the event.AggregateRoot struct and finish implementing event.Aggregate. The AggregateRoot implements logic for adding events after they are either Raised by a command or Appended by the eventstore Load or service ApplyFn methods. It also tracks the uncommitted events that are saved using the eventstore Save method.
type User struct {
Identity string ```json:"identity"`
CreatedAt time.Time
event.AggregateRoot
}
// StreamID for the aggregate when stored or loaded from ES.
func (a *User) StreamID() string {
return "user-" + a.Identity
}
// ApplyEvent to the aggregate state.
func (a *User) ApplyEvent(lis ...event.Event) {
for _, e := range lis {
switch e := e.(type) {
case *UserCreated:
a.Identity = e.Identity
a.CreatedAt = e.EventMeta().CreatedDate
/* ... */
}
}
}
Events
Events are applied to the aggregate. They are defined by adding the event.Meta and implementing the getter/setters for event.Event
type UserCreated struct {
eventMeta event.Meta
Identity string
}
func (c *UserCreated) EventMeta() (m event.Meta) {
if c != nil {
m = c.eventMeta
}
return m
}
func (c *UserCreated) SetEventMeta(m event.Meta) {
if c != nil {
c.eventMeta = m
}
}
Reading Events from EventStore
With a domain object that implements the event.Aggregate the event store client can load events and apply them using the Load(ctx, agg) method.
// GetUser populates an user from event store.
func (rw *User) GetUser(ctx context.Context, userID string) (*domain.User, error) {
user := &domain.User{Identity: userID}
err := rw.es.Load(ctx, user)
if err != nil {
if err != nil {
if errors.Is(err, eventstore.ErrStreamNotFound) {
return user, ErrNotFound
}
return user, err
}
return nil, err
}
return user, err
}
OnX Commands
An OnX command will validate the state of the domain object can have the command performed on it. If it can be applied it raises the event using event.Raise() Otherwise it returns an error.
// OnCreate raises an UserCreated event to create the user.
// Note: The handler will check that the user does not already exsist.
func (a *User) OnCreate(identity string) error {
event.Raise(a, &UserCreated{Identity: identity})
return nil
}
// OnScored will attempt to score a task.
// If the task is not in a Created state it will fail.
func (a *Task) OnScored(taskID string, score int64, attributes Attributes) error {
if a.State != TaskStateCreated {
return fmt.Errorf("task expected created, got %s", a.State)
}
event.Raise(a, &TaskScored{TaskID: taskID, Attributes: attributes, Score: score})
return nil
}
Crud Operations for OnX Commands
The following functions in the aggregate service can be used to perform creation and updating of aggregates. The Update function will ensure the aggregate exists, where the Create is intended for non-existent aggregates. These can probably be combined into one function.
// Create is used when the stream does not yet exist.
func (rw *User) Create(
ctx context.Context,
identity string,
fn func(*domain.User) error,
) (*domain.User, error) {
session, err := rw.GetUser(ctx, identity)
if err != nil && !errors.Is(err, ErrNotFound) {
return nil, err
}
if err = fn(session); err != nil {
return nil, err
}
_, err = rw.es.Save(ctx, session)
return session, err
}
// Update is used when the stream already exists.
func (rw *User) Update(
ctx context.Context,
identity string,
fn func(*domain.User) error,
) (*domain.User, error) {
session, err := rw.GetUser(ctx, identity)
if err != nil {
return nil, err
}
if err = fn(session); err != nil {
return nil, err
}
_, err = rw.es.Save(ctx, session)
return session, err
}
**
🧮 USERS:3 FEEDS:6 TWTS:505 BLOGS:0 ARCHIVED:102004 CACHE:2460 FOLLOWERS:9 FOLLOWING:17
**
🧮 USERS:3 FEEDS:6 TWTS:505 BLOGS:0 ARCHIVED:102004 CACHE:2460 FOLLOWERS:9 FOLLOWING:17 ⌘ Read more