@prologic@twtxt.net huh interesting! yeah i was stumped for a bit i was like WHAT config.json file are these logs talking about…. but then it worked after i moved the old meta.json file lol!
@kat@yarn.girlonthemoon.xyz it was like…. meta.json was corrupt or well it was empty actually whatever idk. ended up moving that elsewhere temporarily, rebuilding the binary, restarting server… and it worked?!?!? shit was confusing
If we don’t keep insisting on simplify and “The beauty of twtxt is, you put one file on your server, done. One.”, then people should just use ActivityPub-based software like Mastodon, PixelFed, etc. which are getting a lot of attention and uses migrating to the fediverse from meta/x here in Denmark over the last couple of months.
For point 1 and others using the metadata tags. we have implemented them in yarnd as [lang=en][meta=data]
What if i want to delete avatar? Im deleted avatar meta field but still see avatar on twtxt.net
I admit I’ve always compromised on this way too much myself, always to this day having Facebook Messenger just to communicate in my families group chats. Sure I run it in a Work profile on my GrapheneOS phone that I can switch off at any time, I can completely cut it off from network access any time as well, I can have a lot of rudimentary control over it, I use it as sparingly as possible, but it doesn’t change the fact everytime I use it we’re funneling private convos through bloody Meta’s servers and trackers etc.
@lyse@lyse.isobeef.org its a hierarchy key value format. I designed it for the network peering tools i use.. I can grant access to different parts of the tree to other users.. kinda like directory permissions. a basic example of the format is:
@namespace
# multi
# line
# comment
root :value
# example space comment
@namespace.name space-tag
# attribute comments
attribute attr-tag :value for attribute
# attribute with multiple
# lines of values
foo :bar
:bin
:baz
repeated :value1
repeated :value2
each @
starts the definition of a namespace kinda like [name]
in ini format. It can have comments that show up before. then each attribute is key :value
and can have their own #
comment lines.
Values can be multi line.. and also repeated..
the namespaces and values can also have little meta data tags added to them.
the service can define webhooks/mqtt topics to be notified when the configs are updated. That way it can deploy the changes out when they are updated.
I’ve added myself to the registries at registry.twtxt.org and twtxt.tilde.institute. I wonder if there’s a list of registries. #meta
@prologic@twtxt.net Perhaps we should add a meta flag to Twtxt to stop indexation by ChatGPT and consorts? I already use robots.txt for this.
(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
}
malign prior as an idealized case of meta-optimization
Thanks for the feedback! This site was designed to look perfect on good old 800x600 monitors (I even left a comment next to the meta tag). Maybe I’ll add a mobile-friendly version someday :-) P.S. Nice try with SQL injection, haha. Do you have any plans for XSS attacks? :D
the right level for solving the hard problem of consciousness is within existing science/within philosophy/within meta- or pre-philosophy/needs a fully new paradigm of thought
Upgraded my Twtxt feed to 2022 with the twtxt.net meta-data extensions.
I think it is long due dropping Facebook (now Meta) from the S&P 500 index funds. As an owner of some, I really have a problem with it—and yes, I know there is little I can do but voice it everywhere I make noise online.
@prologic@twtxt.net the meta info on the top I added manually. it’s following what I have seen from some other twtxt feeds. the new parser will read them.
@lucidiot@tilde.town “nuclear realtor” I like this twtxt. [meta: I guess I’ll often just reply with “I like this” or , although perhaps liking could be a primitive. I’ll do it rarely enough to not clutter my timeline tho]
added a !meta page. this proof of concept integrates with the weewiki !zettelkasten I am developing to produce something similar to this !feed.
meta-not-caring
James Tenney’s Meta Hodos and Meta Meta Hodos are an attempt to derive music theory from first principles: [[https://monoskop.org/images/1/13/Tenney_James_Meta-Hodos_and_Meta_Meta-Hodos.pdf]] #links #composition #musictheory
weewiki uses a custom org markup parser written in ANSI C to render the HTML. No emacs needed! my hope is to introduce a user-defined callback that can process these to allow for custom meta-commands.
/meta @ckipp@chronica.xyz About images, sure, I understand it’s useless for CLI-only use. But if we added our own format, maybe something like Markdown
would work?/meta @ckipp@chronica.xyz Also yes, a simple string search would be fine. I’m not JS-savvy enough to be sure, but I guess it would work a bit like tags?
/meta @ckipp@chronica.xyz Ok, I figured it out, sorry :) I entered my local time manually and forgot it’s supposed to be UTC, so my posts were in the future.
/meta @ckipp@chronica.xyz I’m trying to understand where my timestamp issue comes from, but I have no clue. My two latest posts were edited manually, yet the timestamp syntax seems right?
/meta @ckipp@chronica.xyz Regarding potential new features, maybe some kind of search box? And is there a way to embed images or other media?
/meta Great job on the pagination! Now I’m thinking about forking this and trying to see if I can use it as a personal nanoblog/wiki…
/meta I really like how this place looks. Is there any plan for some kind of pagination to browse older posts?
@mdom@domgoergen.com That’s interesting. So does txtnish read that metadata? or would an end user just look at the file to see it? Is the meta data going to be the standard?