@sorenpeter@darch.dk I like this idea. Just for fun, I’m using a variant in this twt. (Also because I’m curious how it non-hash subjects appear in jenny and yarn.)
URLs can contain commas so I suggest a different character to separate the url from the date. Is this twt I’ve used space (also after “replyto”, for symmetry).
I think this solves:
- Changing feed identities: although @mckinley@twtxt.net points out URLs can change, I think this syntax should be okay as long as the feed at that URL can be fetched, and as long as the current canonical URL for the feed lists this one as an alternate.
- editing, if you don’t care about message integrity
- finding the root of a thread, if you’re not following the author
An optional hash could be added if message integrity is desired. (E.g. if you don’t trust the feed author not to make a misleading edit.) Other recent suggestions about how to deal with edits and hashes might be applicable then.
People publishing multiple twts per second should include sub-second precision in their timestamps. As you suggested, the timestamp could just be copied verbatim.
@mckinley@twtxt.net Thanks for the feedback.
- Yeah I agrees that nick sound not be part of syntax. Any valid URL to a twtxt.txt-file should be enough and is more clear, so it is not confused with a email (one of the the issues with webfinger and fedivese handles)
- I think any valid URL would work, since we are not bound to look for exact matches. Accepting both http and https as well as a gemni and gophe could all work as long as the path to the twtxt.txt is the same.
- My idea is that you quote the timestamp as it is in the original twtxt.txt that you are referring to, so you can do it by simply copy/pasting. Also what are the change that the same human will make two different posts within the same second?!
Regarding the whole cryptographic keys for identity, to me it seems like an unnecessary layer of complexity. If you move to a new house or city you tell people that you moved - you can do the same in a twtxt.txt. Just post something like “I move to this new URL, please follow me there!” I did that with my feeds at least twice, and you guys still seem to read my posts:)
HTTPS is supposed to do [verification] anyway.
TLS provides verification that nobody is tampering with or snooping on your connection to a server. It doesn’t, for example, verify that a file downloaded from server A is from the same entity as the one from server B.
I was confused by this response for a while, but now I think I understand what you’re getting at. You are pointing out that with signed feeds, I can verify the authenticity of a feed without accessing the original server, whereas with HTTPS I can’t verify a feed unless I download it myself from the origin server. Is that right?
I.e. if the HTTPS origin server is online and I don’t mind taking the time and bandwidth to contact it, then perhaps signed feeds offer no advantage, but if the origin server might not be online, or I want to download a big archive of lots of feeds at once without contacting each server individually, then I need signed feeds.
feed locations [being] URLs gives some flexibility
It does give flexibility, but perhaps we should have made them URIs instead for even more flexibility. Then, you could use a tag URI,
urn:uuid:*
, or a regular old URL if you wanted to. The spec seems to indicate that theurl
tag should be a working URL that clients can use to find a copy of the feed, optionally at multiple locations. I’m not very familiar with IP{F,N}S but if it ensures you own an identifier forever and that identifier points to a current copy of your feed, it could be a great way to fix it on an individual basis without breaking any specs :)
I’m also not very familiar with IPFS or IPNS.
I haven’t been following the other twts about signatures carefully. I just hope whatever you smart people come up with will be backwards-compatible so it still works if I’m too lazy to change how I publish my feed :-)
@bender@twtxt.net So far I’ve been following feeds fairly liberally. I’ll check to see if we have anything in common and lean toward following, just because this is new to me and it feels like a small community. But I’m still figuring out what I want. Later I’ll probably either trim my follower list or come up with some way to prioritize the feeds I’m more interested in.
@movq@www.uninformativ.de ha! Here are my top 10:
24056 "prologic"
5103 "lyse"
3932 "movq"
1984 "abucci"
1876 "adi"
1633 "fastidious"
1551 "jlj"
1455 "mckinley"
1413 "offgridliving
1280 "eaplmx"
Some of those I no longer follow, or do not exist, but their wisdom remains. LOL.
I just manually followed the steps at https://dev.twtxt.net/doc/twthashextension.html and got 6mdqxrq. I wonder what happened. Did @cuaxolo@sunshinegardens.org edit the twt in some subtle way after twtxt.net downloaded it? I couldn’t spot a diff, other than ‘ appearing as ’ on yarn.social, which I assume is a transformation done by twtxt.net.
@prologic@twtxt.net How does yarn.social’s API fix the problem of centralization? I still need to know whose API to use.
Say I see a twt beginning (#hash) and I want to look up the start of the thread. Is the idea that if that twt is hosted by a a yarn.social pod, it is likely to know the thread start, so I should query that particular pod for the hash? But what if no yarn.social pods are involved?
The community seems small enough that a registry server should be able to keep up, and I can have a couple of others as backups. Or I could crawl the list of feeds followed by whoever emitted the twt that prompted my query.
I have successfully used registry servers a little bit, e.g. to find a feed that mentioned a tag I was interested in. Was even thinking of making my own, if I get bored of my too many other projects :-)
For following notifications I would say use webmetion refering to the the line in your twtxt.txt as per: https://darch.dk/mentions-twtxt
Or send them an email, so it would be an idea to add a # contact = mailto:me@domain.net
to ones twtxt.txt
@movq@www.uninformativ.de I think you are worrying about a non-issue. I see nothing to do on your example twt, because there is no context. Furthermore, if I wanted to follow the feed, everything I need is already on that twt example. :-)
@movq@www.uninformativ.de is there a way to purge twtxts from a feed I no longer follow?
@movq@www.uninformativ.de I don’t know if I’d want to discard the twts. I think what I’m looking for is a command “jenny -g https://host.org/twtxt.txt” to fetch just that one feed, even if it’s not in my follow list. I could wrap that in a shell script so that when I see a twt in reply to a feed I don’t follow, I can just tap a key and the feed will get added to my maildir. I guess the script would look for a mention at the start of a selected twt and call jenny -g on the feed.
@movq@www.uninformativ.de Is there a good way to get jenny to do a one-off fetch of a feed, for when you want to fill in missing parts of a thread? I just added @slashdot@feeds.twtxt.net to my private follow file just because @prologic@twtxt.net keeps responding to the feed :-P and I want to know what he’s commenting on even though I don’t want to see every new slashdot twt.
@bender@twtxt.net Based on my experience so far, as a user, I would be upset if my client dropped someone from my follower list, i.e. stopped fetching their feed, without me asking for that to happen.
@bender@twtxt.net I’m not a yarnd user, but automatically unfollowing on 404 doesn’t seem right. Besides @lyse@lyse.isobeef.org’s example, I could imagine just accidentally renaming my own twtxt file, or forgetting to push it when I point my DNS to a new web server. I’d rather not lose all my yarnd followers in a situation like that (and hopefully they feel the same).
@Prologic@twtxt.net can you pleas fix this line in your twtxt.txt:
# follow = dbucklin@www.davebucklin.com https://www.davebucklin.com/twtxt.txt?nick=dbucklin
It is cause this weird effect on my timeline, where you are now called dbucklin
http://darch.dk/timeline/?profile=https://twtxt.net/user/prologic/twtxt.txt
The wording can be more subtle like “This feed have not seen much activity within the last year” and maybe adding a UI like I did in timeline showing time ago for all feeds
I agree that it good to clean up the Mastodon re-feeds, but it should also be okay for anyone to spin up a twtxt.txt just for syndicating they stuff from blog or what ever.
The “not receiving replies” could partly be fixed by implementing a working webmentions for twtxt.txt
anthony.buc.ci
account. I am assuming these kind of bugs were never addressed by @prologic. :-(
@quark@ferengi.one @mckinley@twtxt.net
i think you have to be following the person so it does it correctly.
We could ask them? But on the counter would bukket or jan6 follow the pure twtxt feeds? Probably not either way… We could use content negotiation as well. text/plain for basic and text/yarn for enhanced.
@prologic@twtxt.net I have updated to kinda follow this. It now redirects to other webfingers if the resource has a different hostname. I’m still not sure what I should put multiple services with the same domain name. Like if they were to have conflicting properties.
it seems they are following the URN format of a URI where you just prefix things with colons.
urn:example:apple:pear:plum:cherry
@prologic@twtxt.net That was exactly my thought at first too. but what do we put as the rel
for salty account? since it is decentralized we dont have a set URL for machines to key off. so for example take the standard response from okta:
# http GET https://example.okta.com/.well-known/webfinger resource==acct:bob
{
"links": [
{
"href": "https://example.okta.com/sso/idps/OKTA?login_hint=bob#",
"properties": {
"okta:idp:type": "OKTA"
},
"rel": "http://openid.net/specs/connect/1.0/issuer",
"titles": {
"und": "example"
}
}
],
"subject": "acct:bob"
}
It gives one link that follows the OpenID login. So the details are specific to the subject acct:bob
.
Mastodons response:
{
"subject": "acct:xuu@chaos.social",
"aliases": [
"https://chaos.social/@xuu",
"https://chaos.social/users/xuu"
],
"links": [
{
"rel": "http://webfinger.net/rel/profile-page",
"type": "text/html",
"href": "https://chaos.social/@xuu"
},
{
"rel": "self",
"type": "application/activity+json",
"href": "https://chaos.social/users/xuu"
},
{
"rel": "http://ostatus.org/schema/1.0/subscribe"
}
]
}
it supplies a profile page and a self
which are both specific to that account.
philosophytube followers be pondering the impossibility of white bears in novaya semlya
I learned how to make gopls syntax highlight go templates in VSCodium.
By adding the following to my config
i could go from into
$name$
and then dispatch the hashing or checking to its specific format.
Hold up now, that example hash doesn’t have a
$
prefix!
Well for this there is the option for a hash type to set itself as a fall through if a matching hash doesn’t exist. This is good for legacy password types that don’t follow the convention.
func (p *plainPasswd) ApplyPasswd(passwd *passwd.Passwd) {
passwd.Register("plain", p)
passwd.SetFallthrough(p)
}
https://github.com/sour-is/go-passwd/blob/main/passwd_test.go#L28-L31
@movq@www.uninformativ.de, well, yes, that has always been the case. Not just on jenny, but on Yarn. I can’t follow everything, and everyone. To see whether is a reply, a simple h
on mutt shows the headers, and there you have it. That is not too convoluted, is it? I mean, if you really want to know–but why?–it is a simple key press. If I don’t see a context on something as obvious as the example you used, it is simply a reply to someone I don’t follow, and pretty much ignore. End of story. 😂
🧮 Users: 2, Feeds: 6, Twts: 1026, Archived: 1116347, Cache: 89202, Followers: 29, and Following: 701.
👋 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! 🤗
(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
}
following legislation from the ELSC (european long site commission), I now have to adopt an ocelot
🧮 Users: 2, Feeds: 6, Twts: 1007, Archived: 886396, Cache: 121354, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 1006, Archived: 883595, Cache: 122433, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 1005, Archived: 880048, Cache: 122224, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 1004, Archived: 876133, Cache: 122028, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 1003, Archived: 872231, Cache: 119530, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 1002, Archived: 868478, Cache: 123331, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 1001, Archived: 865325, Cache: 121064, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 1000, Archived: 862613, Cache: 120799, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 999, Archived: 859778, Cache: 119420, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 998, Archived: 856190, Cache: 122169, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 997, Archived: 852458, Cache: 123917, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 996, Archived: 848477, Cache: 122453, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 995, Archived: 844715, Cache: 122535, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 994, Archived: 841291, Cache: 120212, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 993, Archived: 838479, Cache: 118860, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 992, Archived: 835550, Cache: 125558, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 991, Archived: 831799, Cache: 123240, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 990, Archived: 828153, Cache: 121993, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 989, Archived: 824437, Cache: 122821, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 988, Archived: 820674, Cache: 123788, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 987, Archived: 817080, Cache: 124441, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 986, Archived: 814212, Cache: 122468, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 985, Archived: 810696, Cache: 123506, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 984, Archived: 806843, Cache: 125539, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 982, Archived: 803105, Cache: 124855, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 981, Archived: 799294, Cache: 121986, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 980, Archived: 795473, Cache: 123297, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 979, Archived: 791859, Cache: 121598, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 978, Archived: 788990, Cache: 124482, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 977, Archived: 786073, Cache: 122661, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 976, Archived: 782301, Cache: 120617, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 975, Archived: 778448, Cache: 125420, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 974, Archived: 774716, Cache: 122045, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 973, Archived: 770722, Cache: 122036, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 972, Archived: 767269, Cache: 125584, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 971, Archived: 764435, Cache: 124199, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 970, Archived: 761376, Cache: 123750, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 969, Archived: 757702, Cache: 122819, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 968, Archived: 753599, Cache: 122343, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 967, Archived: 748356, Cache: 119723, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 966, Archived: 739385, Cache: 122734, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 965, Archived: 739385, Cache: 120382, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 964, Archived: 739385, Cache: 122622, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 963, Archived: 739385, Cache: 122480, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 962, Archived: 739385, Cache: 124491, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 961, Archived: 739385, Cache: 122801, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 960, Archived: 739385, Cache: 123606, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 959, Archived: 739322, Cache: 124010, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 958, Archived: 739322, Cache: 124066, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 957, Archived: 739322, Cache: 122784, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 956, Archived: 739322, Cache: 121074, Followers: 29, and Following: 699.
one then checks that the following diagrams commute [devil god diagram]
🧮 Users: 2, Feeds: 6, Twts: 955, Archived: 739322, Cache: 122158, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 954, Archived: 739322, Cache: 122654, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 953, Archived: 739322, Cache: 120545, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 952, Archived: 736616, Cache: 122049, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 951, Archived: 733356, Cache: 121332, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 950, Archived: 730630, Cache: 122399, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 949, Archived: 727772, Cache: 121613, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 948, Archived: 724486, Cache: 121389, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 946, Archived: 720995, Cache: 120391, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 945, Archived: 717189, Cache: 119340, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 944, Archived: 713444, Cache: 117872, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 943, Archived: 710078, Cache: 116742, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 942, Archived: 707257, Cache: 117002, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 941, Archived: 697332, Cache: 118595, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 940, Archived: 693841, Cache: 117323, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 939, Archived: 689964, Cache: 116257, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 936, Archived: 686278, Cache: 119023, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 933, Archived: 682703, Cache: 118115, Followers: 29, and Following: 699.
🧮 Users: 2, Feeds: 6, Twts: 932, Archived: 679348, Cache: 119465, Followers: 29, and Following: 699.