FEEDER
using rc to add feed entries
tags
architectural
muffet
safe
slov
teal
utility
maybe i'll add sound to this later?
idk.
[src/feeder]
So I have this project idea.
I have been updating my feeds for my site by manually editing the ndtl file. Copy a previous entry's header, make modifications, look up date, write it in the proper formats. manually insert the tags I want. Only then can i actually start on the body of the feed entry.
It works. of course. but it is a bit fiddly. The date is especially annoying. especially because there is something that always bothers me about how I'm doing it. I don't want to have to manually do full time stamps, so i just manually do the date in essentially the correct format. then the rss / atom generation sets the time to midnight of that day. It's obviously not accurate, which isn't really a huge problem in realityince rss isn't really intended to be a realtime feed anyway. But it is always a little annoying any time I update it.
So here's the project idea.
a plan9 gui program that lets me put in the name of the post, click to select which tags (based on the tags available to {slov}) then add the body then click a button to add it to the file and slov.
maybe even run muffet as well? that really doesn't matter much, but I guess why not.
I want it to use the plan9 gui controls mostly as an excuse to learn how that stuff works.
additionally there are relatively few examples of programs using this library. in the default 9front only auth/factotum/fgui, bitsy/keyboard and bitsy/prompter use it.
cmd/auth/factotum/fgui.c:5: #include
cmd/bitsy/keyboard.c:7: #include
cmd/bitsy/prompter.c:7: #include
so looking through the man pages, I think I'll need a few libs. control(2) has ui elements, and requires draw thread keyboard and mouse.
Control(2) requires a thread(2) program.
according to the man for thread(2) we need to use threadmain() rather than main, as thread(2) provides a main() which sets up a proc with a thread and runs threadmain() as the entry for it.
we may need to set mainstacksize, as the default is 8kB. if we run into trouble this is something to keep in mind.
So threadmain has the same signature as default main, ie. void threadmain(int argc, char *argv[])
I'm going to want some arguments. -n for no slov connection, and -o for stdout output rather than /lib/slov/feed.ndtl
plan9 C has macros to make argurments quite nice in the code rather than manually decoding them. ARGBEGIN and ARGEND
they start a switch for each of the arguements we want to handle.
. . .
Actually fuck that.
The reason being, control doesn't have any element for a multi-line text field. The only text input control it has is single line, and I can't use that.
I don't want my first foray into control to be adding a new one to it. This was supposed to be a simple day project. like an easy one and done kind of thing.
But no.
an rc script is more than sufficient for my needs after all. This is that easy, so it should be that hard.
So as I was stepping into using rc to do it, i spent about 40 minutes trying to juggle all the calls to slov it takes to do a simple task.
That task being grab all the tags.
I want to have a nice list of tags to use for adding them to the feed entry. when i started with it, i thought that should be easy.
just grab the list of all the entries with a nice lookup command to slov, then read each name and do a lookup for its type (if it has one, which it should) then compare it to the value 'tag' well...
it might be that simple but i first started down the path of cating the slov.dat file. PROBLEM. cat hangs. slov.dat is registered as a log like file, so it never returns an eof. so cat never quits.
Well ok i thought. lets find some way of running a command with a timeout.
I thought i might have found something but it was a dead end. so after a while i was like "what's the right way to do this" and the answer was pretty obvious. read(1). see slov already has a way to tell the reader that it's done sending a datagram. a line with '!' and nothing else.
so i just need to read the file until i get one with that.
This turns out to be the right way. but still. it was read a line. echo it to a temp file. continue till !
then read that temp file and do another song and dance reading slov for the reply for each and every entry in slov. I dunno if you know this or not, but my website is not small. the database that makes it has a lot of entries. and really it's not like a big deal to have a 2 second run time on this process but I just felt this feeling of "god damn it would be nice if slov had a find function where i could just give it a key-value pair and it'd return the name of all the entries that have that key-value. "
Oh. wait.
I wrote slov.
i could totally just add that function.
so ya. Slov now has a "find" function.
so echo "find
type : tag
!" >> /srv/slov.cmd
now will return a list of all names in slov that have that as an entry.
This is also useful for finding children of a node, like
echo "find
host : parent
!" >> /srv/slov.cmd
will give all of parent's children.
This would have been useful when writing muffet.
OOPS.
the funny thing is that the find function is actually the simplest function that slov has. even not having seen the code in like... a year, it only took me 15 minutes to reunderstand how to write it and get it working without error. and it runs in O(1), as it should.
anyway. now that that works, i have an easy way to get a list of tags slov knows about.
Technically tho, any entry can be used as a tag name in muffet the tags themselves aren't special in anyway other than having type=tag. but having a easily usable list of "tags" without digging through the actual ndtl file is nice.
next on the list is everything else.
but it should all be easy.
well... i thought that getting the tag list would be easy so...
next thing I need to do is know what the next entry's number should be.
I use a numbering system to keep the feed entries sorted, because slov sorts the children of a host by alphabetical order, and numberic order is also alphebetical.
so i can easily grab the current first child of feed and that will be the one with the highest id. awk can parse that name to grab the number, then just use awk to add 1 to it.
But again it is not as straight forward as it might seem because I like to make things dificult.
I use a base 6 id. so for example 1 more than post 15 is post 20.
It wasn't difficult, but awk's syntax makes it a bit clunky. a ton of ifs for each place in the id to check if that one is 5, and do something different if I am adding to it.
well, i wrote that and it works now, so on to the next part
next was getting the time stamp in the proper format.
one annoying thing that I didn't know about before, and am glad to understand now, is that subcommands, ie `{date}, are broken up into an array based on the field seperator IFS. normally that's spaces comma and newlines i think. it can be set before, or you can specify it directly as in `~{date} where ~ would be field seperator.
i want to use something that won't be found because the whole return should be 1 field.
this took a bit more work than I'd like to admit. when an array is joined with non arrays, the non arrays essentially get duplicated across the array. so i was getting a result something like:
NAME
DATE : thisisdate
PUB : this
NAME
DATE : thisisdate
PUB : is
NAME
DATE : thisisdate
PUB : pub
rather than
NAME
DATE : thisisdate
PUB : this is pub
anyway. after all that song and dance, all that was left was to modify muffet to accept the new date format. did that with a check for the new date key values and use those if they exist, and if not use the old ones.
This way I don't have to change all the old entries.
not super ideal, and maybe in the future I'll fix it?
but really, if i ever have to manually add feed entries I want to keep the old way around because it's way easier for manual use.
well. this has been fun.
source is above if you want to take a look.
.
incoming references
INDEX