RT by @mind_booster: 🎂 COMPETITION 🎂 To celebrate our 75th anniversary, we’re launching the most exciting competition in Folio’s history… One lucky Folio fan will win their choice of 75 different Folio editions! To enter: RT this post and follow @foliosociety.
🎂 COMPETITION 🎂 To celebrate our 75th anniversary, we’re launching the most exciting competition in Folio’s history… One lucky Folio fan will win their choice of 75 different Folio editions! To enter: RT this post and follow [@foliosociety](https … ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:377 ARCHIVED:37967 CACHE:1697 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:376 ARCHIVED:37926 CACHE:1720 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:375 ARCHIVED:37903 CACHE:1733 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:374 ARCHIVED:37857 CACHE:1719 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:373 ARCHIVED:37841 CACHE:1723 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:372 ARCHIVED:37806 CACHE:1733 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:371 ARCHIVED:37736 CACHE:1726 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:370 ARCHIVED:37679 CACHE:1740 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:369 ARCHIVED:37654 CACHE:1743 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:368 ARCHIVED:37599 CACHE:1716 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:367 ARCHIVED:37546 CACHE:1707 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:366 ARCHIVED:37509 CACHE:1695 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:365 ARCHIVED:37466 CACHE:1694 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:364 ARCHIVED:37415 CACHE:1687 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:363 ARCHIVED:37386 CACHE:1696 FOLLOWERS:13 FOLLOWING:14
Kubernetes in Production Environments
Follow along as we chat about this week’s Dear Moby question! What’s the best way to develop if your production environment runs Kubernetes? ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:362 ARCHIVED:37354 CACHE:1675 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:361 ARCHIVED:37299 CACHE:1657 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:360 ARCHIVED:37250 CACHE:1624 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:359 ARCHIVED:37213 CACHE:1645 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:358 ARCHIVED:37195 CACHE:1652 FOLLOWERS:13 FOLLOWING:14
@prologic@twtxt.net what Content-Security-Policy should I have on my web server for salty? the frontend ain’t reacting well to my global config lol
evalerror: refused to create a webassembly object because ‘unsafe-eval’ is not an allowed source of script in the following content security policy directive: “default-src ‘self’”.
<<
🧮 USERS:1 FEEDS:2 TWTS:357 ARCHIVED:37170 CACHE:1654 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:356 ARCHIVED:37129 CACHE:1664 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:355 ARCHIVED:37106 CACHE:1654 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:354 ARCHIVED:37081 CACHE:1652 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:353 ARCHIVED:37050 CACHE:1651 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:352 ARCHIVED:37016 CACHE:1642 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:351 ARCHIVED:36986 CACHE:1651 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:350 ARCHIVED:36961 CACHE:1650 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:349 ARCHIVED:36908 CACHE:1644 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:348 ARCHIVED:36871 CACHE:1644 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:347 ARCHIVED:36832 CACHE:1640 FOLLOWERS:13 FOLLOWING:14
@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:1 FEEDS:2 TWTS:345 ARCHIVED:36732 CACHE:1614 FOLLOWERS:13 FOLLOWING:14
🧮 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
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.
@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
@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:1 FEEDS:2 TWTS:342 ARCHIVED:36624 CACHE:1594 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:341 ARCHIVED:36586 CACHE:1572 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:340 ARCHIVED:36553 CACHE:1551 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:339 ARCHIVED:36526 CACHE:1531 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:338 ARCHIVED:36495 CACHE:1521 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:337 ARCHIVED:36480 CACHE:1537 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:336 ARCHIVED:36468 CACHE:1545 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:335 ARCHIVED:36404 CACHE:1542 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:334 ARCHIVED:36379 CACHE:1589 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:333 ARCHIVED:36357 CACHE:1579 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:332 ARCHIVED:36316 CACHE:1563 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:331 ARCHIVED:36304 CACHE:1600 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:330 ARCHIVED:36287 CACHE:1596 FOLLOWERS:13 FOLLOWING:14
🧮 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: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! 🤗
👋 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: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
}
(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:1 FEEDS:2 TWTS:326 ARCHIVED:36217 CACHE:1658 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:325 ARCHIVED:36174 CACHE:1662 FOLLOWERS:13 FOLLOWING:14
The XMPP Standards Foundation: Mid Term Evaluation Updates
It’s been a month since I wrote my last blog. For those of you who have been following my blogs, thanks a lot for taking the time to read them. In this blog, I will give the updates post mid-term evaluation and the challenges that I have been facing and how I overcame some of them.
For those of you who don’t know much about GSoC, a mid-term evaluat … ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:324 ARCHIVED:36126 CACHE:1630 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:323 ARCHIVED:36095 CACHE:1620 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:322 ARCHIVED:36071 CACHE:1610 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:321 ARCHIVED:36041 CACHE:1614 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:320 ARCHIVED:36015 CACHE:1629 FOLLOWERS:13 FOLLOWING:14
To all my feed subscribers: If you are annoyed by the TTS audio or the “Interactions” link, add a “.min” in front of the feed type in the URL. For example https://jlelse.blog/.min.rss. Thanks for following! 😄 ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:319 ARCHIVED:35977 CACHE:1621 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:318 ARCHIVED:35951 CACHE:1608 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:317 ARCHIVED:35790 CACHE:1611 FOLLOWERS:13 FOLLOWING:14
Ignite Realtime Blog: REST API Openfire plugin 1.9.1 released!
Woopsie doodle! It turns out that a rather annoying bug was introduced in version 1.9.0 of the REST API plugin for Openfire, that we released earlier today!
To avoid unnecessary issues, we’ve decided to follow up with an immediate new release that addresses this issue. … ⌘ Read more
🧮 USERS:1 FEEDS:2 TWTS:316 ARCHIVED:35745 CACHE:1618 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:315 ARCHIVED:35714 CACHE:1620 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:314 ARCHIVED:35694 CACHE:1628 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:313 ARCHIVED:35653 CACHE:1609 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:312 ARCHIVED:35548 CACHE:1535 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:311 ARCHIVED:35521 CACHE:1525 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:310 ARCHIVED:35401 CACHE:1496 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:309 ARCHIVED:35369 CACHE:1481 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:308 ARCHIVED:35338 CACHE:1485 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:307 ARCHIVED:35290 CACHE:1458 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:306 ARCHIVED:35250 CACHE:1455 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:305 ARCHIVED:35225 CACHE:1459 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:304 ARCHIVED:35175 CACHE:1452 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:303 ARCHIVED:35163 CACHE:1475 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:302 ARCHIVED:35148 CACHE:1473 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:301 ARCHIVED:35133 CACHE:1463 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:300 ARCHIVED:35117 CACHE:1470 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:299 ARCHIVED:35064 CACHE:1473 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:298 ARCHIVED:35034 CACHE:1450 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:297 ARCHIVED:35006 CACHE:1434 FOLLOWERS:13 FOLLOWING:14
🧮 USERS:1 FEEDS:2 TWTS:296 ARCHIVED:34976 CACHE:1413 FOLLOWERS:13 FOLLOWING:14
Minkowski Space
⌘ Read more