This video demonstrates building a Rust event server that persists events to a JSON file using a ring buffer, reads events from disk on startup, and supports configurable execution of external programs when new events are received. The presenter shows how to implement file-based persistence with serde_json, use TOML configuration files for server settings, and spawn external processes using std::process::Command with environment variable passing for event data.
Deep Dive
Prerequisite Knowledge
- No data available.
Where to go next
- No data available.
Deep Dive
writing some rust (custom event-handler syslog-inspired service) day5Added:
Heat. Heat.
Heat. Heat.
Yo, what's going on everyone? What's up, Random Logic? Nice job getting the first redeem. Loving that new input device.
Yeah, exactly.
What's up? I love English kids. What a wild username. Good day. Good day to you too.
Live coding about live stream about coding in a language I know nothing about. Strapping young strapping strapping young lad. That's where my brain ran. Strapping in energy drink.
Stand by, dude. Love to hear it.
Awesome. We'll have a ton of fun today.
What's up, Jeff Row 97?
Don't worry, Random Logic. I have timed that user out.
Hope you are all having a fantastic week. What a nice comment. I'm having a pretty good week. I can't complain.
What's up? Signal segmentation violation 200. How you doing?
You're good. That's awesome. You know how to play piano? Oh, yeah. Absolutely I do.
This note just sticks. The E sometimes hits.
All right, probably should get started here, huh?
There we go.
Oh, yeah. All right, let's write some code.
I just really you guys really just want me to do a stream where I teach piano.
I feel like you guys would watch me teach anything. Now, if you're in my stream, then you clearly enjoy my content. That's not I'm not even like trying to say that with like a bunch of hubris. Just like if you're the kind of person who watch my stream, you probably like my stuff more than most of the other people that consume this content.
What do we got in the main layout? So, we got the terminals open from last time. I haven't actually even touched the stuff since last time, which is nice.
I haven't touched a computer since since the last stream. Evening. What's up, Daniel Away? How you doing? Welcome.
Welcome.
XS.AP.sh.
pipe that to bash.
There we go. Merry Christmas.
Were you going to get Rust Analyzer set up? No, I was going to check it out eventually, but I don't know when that will be. So, that was definitely not something I was going to do between the stream and the and next or or last stream, I mean.
So, I'll do that eventually, but right now it's not it's not on my top of the top of the list of things to do. I think we've checked everything in, right?
Yeah, we have day four checked in. Let's start with some cargo clippy because I think we have a variable named foo.
There we go.
There we go. So now we have a cargo clippy clean program and it runs.
I think let's look at the read me and figure out what we should do next.
We should probably the CLI should support posting. I think that might be H. What should we do next?
Let's do this. Let's cache the events to disk and read the events to disk from or at startup. So, we have to figure out, do we want to cache the events to disk when the program exits or do we want to cache them to disk when a new event is received? Because I feel like that makes more sense like when a new event is received, we should write the cache out to disk because the only way we can get a new event is if someone posts it here.
And we modify the ring buffer before we send out the broadcast event, which is nice.
I do have to figure out if we really want to just use a database instead.
I really feel like eventually using the database just makes sense.
But that's fine. We can just rewrite code if we ever get there. Serialize the events to disk.
So like get the first one then when a new one comes in push the original to disk. Uh not sure exactly what you mean right there. Basically what I'm envisioning is like let's make a events.json.
This will have events in it. It'll be empty by default. So let's just make it an empty array, right? We'll have events.json. This will be an empty array. When the server starts up, it'll read this array into memory. So that will prefill the data. That will initialize the data. And then when we update that file, we'll update that file whenever a new event is received. So a user comes, they post a new event in this little Tokyo task that we have running. We will get the new event and then we will serialize all of the events to the JSON thing. And this will handle the ring bufferization. So the JSON file will only ever have, you know, five elements or whatever we decide to make that number. That way if the program were to like crash or whatever, when we go to start it again, we'll just read those files back in.
Delicious.json. You got it. Absolutely.
I like text files. I find them just easy. JSON's like one little step above that. I know some people will want full history here and they'll want database, but I'm going to write the software for myself and then we may add features in the future. I feel like in the future when we start making a config file for this, we can do all sorts of things like create a backing store what you want. So let's serialize the events disc first.
Let's initialize the events.
So we have this. This is a vec deck new.
So let's do this where we have a vec deck new. We should read that from the file system. So, the way to do this, I think is to make I think we want to make a ve and then turn it into a ve deck. That's what I think we want to do here.
So, this will be a ve of event. Oh my god, we might just be able to do this actually.
And then this will be a we'll have to read in a file and then serday JSON it.
Does Sarah JSON support reading in from a file or do I have to use fs read to string or whatever from reader. Okay. from slice from stir from value from reader you have to make a reader file open put a buff reader and then read it I think fs2 string is just going to be easier for us so let's just do this fs read to string events json we'll make this customizable unwrap and that will be the file as a string so now we You just want to parse it. Saturday JSON from stir this. And this can also fail, right? So unwrap here.
Let's see if that works.
Oh, we just have to pull in FS now. Use standard FS.
There we go. Okay, that works. Perfect.
Awesome. So that will read the new events.json file here. So we can preload an event here if we wanted to. So I could put like um this component equals foole level debug message hello. Then we'd also need a time stamp and stuff. So let's just not even bother putting that stuff in there. Let's just make it an empty array for now.
Instead of using ring buffers, why not KV store? I mean, you could, but the the key doesn't really make much sense. It's just a UYU ID.
All right. What do we got here?
So events is here.
We actually need to get the shared state out of it here, which is fine. If we use shared state, can we clone it?
Can we do this?
shared state.events clone.
I think we can do this.
We wrap it here.
Uh oh, we're pulling in shared state.
That's not what we want. We just want events now.
Okay, we can do it that way. That's fine cuz it just moves in there.
We put it its own function. might be easier to work with.
There we go. So now we should have access to all the events. We will just need to acquire the lock and write them out. So we'd have to do something like this. Like let items equals events.lock.wait.
Oh, wait.
Does that work?
Oh, read, not lock.
It's not a future. What kind of arc is it? See? Okay. Why do we sometimes use the standard sync ones and sometimes we use the Tokyo ones? I feel like we shouldn't be using these when we're inside an async contact. So, we may have to mess with that. That might not be the right way to do it. But for now, I think it might be.
Yeah, let's just do it this way and then we'll maybe clean up and let me put that into concerns concerns mixture of standard sync and Tokyo sync value borrowed here after move value moved here. Yeah. Did we just get rid of this?
Okay, cool. So now we should have the items. We've read them. We have the lock on that. So now we just need to write them out into a disk or write them out to the disk. So s equals Saturday JSON 2 string on items.
Now we should have a string. So we can do fs write file. FS write. What is it?
Unwrap. Unwrap. Unwrap. Dude, it really is. We'll be cleaning all this up later, but for now it's literally just unwrap.
Unwrap. Unwrap until we can come up with a better plan. Events.json uh sunwrap cargo build.
Readwrite lock card. Okay.
Can I do that or do I have to do it where I Yeah, I think I have to do it here.
There we go.
So, if this works, we should have no events.
Nice. We should be able to post a single event there. And that failed because we wanted a component.
There we go. Now we have a single event there. We can verify it with this. That looks good. And then if we look at events.json, it should already be serialized there.
Nice. Nice. Okay, it is. Perfect. So now if we close the server and we reopen it and then we get the events, they are persistent. Okay, cool. That's huge.
That's awesome. Nice. Great. That's fantastic. Uh first time chatter. Hi.
You could drop the lock before you write. That is true.
That is true.
Yeah, there's no reason to hold the whole lock open while that's happening.
So, we could actually just drop items.
Trying to think of a cleaner way to do it because it'd be nice to like do something like this. Well, we could do this.
Good call.
There we go.
So, we made a new string here called S.
And the way we get S is by acquiring the lock, serializing the data while we have the lock, and then once S is set, then we've dropped the lock. So that's really cool. Good, good, good addition there.
That's awesome.
Okay.
And then if we run it again, we should still have that data. It should still be there. Beautiful. Awesome. Fantastic.
Let's go ahead and put some debugging in here.
Some logging would be nice. Maybe a logging crate would be the way to go.
But for now, let's just log things um manually.
Okay.
We'll definitely clean up the uh logging and stuff.
All right. We'll need a derived debug on config.
Makes sense.
Beautiful cargo run. Look at that. We have the config right here. We have red one cache events from disk. So we can go over here and we could put like a whole bunch of stuff. I think we have a whole for loop to do it. Yeah, this this for loop has 10 items that will push to the event thing. Now if that works, we shouldn't have 10 written out to the disk. Wow, look at this. Broadcast a new event.
gota event this. Serialize it to events.json. Perfect. I wrote events, but that's okay. So now if we do this, we should only have five. Cool. We only ever write out five because that's the length of our ring buffer. Beautiful.
Awesome. This file never actually gets too big. So that's great.
Now we do everything in the same task.
So like for instance we have this task here that's responsible for getting an event writing it to the disk and then doing the fork and exactly which you haven't implemented yet. It might make sense to do this as two separate tasks and I'll write that down. Potentially break this into two separate tasks. Beautiful.
Okay. Awesome.
fork and exec when new event is seen optionally.
Let's go to our readme cache events to disk. Reading events from disk on startup. Bam. We've solved that problem.
Now we don't have the actual file name configurable. But hey, we're getting there. Maybe we should make a config file for this like a toml config file that we could read in. Um we are serializing to JSON. I like toml though.
Well, what do you guys want to work on next? Should we give this program a config file?
Program should take a config file.
Should we work on giving this program a config file? um creating support for the CLI to do the um posting events. Like should we make the CLI actually nice so I can write like event create and event list and event stream or should we work on executing a program whenever a new event is received? So like when a new event comes in, I could fork off an arbitrary script. Uh I'll let you guys vote and if no one says anything, I'll just come up with something on my own.
I'm going to go grab another drink. I'll be right back.
All right, we are back. Uh, let's get the config going. All right, we got one vote. That's good enough for me. Let's do the config next. Is this also on Twitch? Yes, I am dual streaming on Twitch and YouTube. So, we got 28 viewers concurrently on Twitch and we have 46 concurrent viewers on YouTube.
You wouldn't know it because the chat is very very slow on both uh platforms.
However, I know that I have a lot of lurkers. A lot of people that put me on in the background, they put me in a second monitor and they work on their own code. So, that's awesome. Sometimes I call in the lurkers. I say, "Go ahead, let me know you're here." But that's fine. I'm totally cool if you guys want to lurk. So, I don't mind it.
I think it's awesome, actually. you guys just like lurk and you just feel like watching this in the background. That's super cool. But yeah, let's do the config and then we will do a nice CLI after that. Let's do it in that order.
So, let's do the config first.
We're going to use TOML, which is the same config as like, you know, cargo uses cargo.toml. There we go. This style. It's like a very simple ini style thing. So, I know there's a toml crate. Um, pull it up for you guys.
We got the Toml crate here. use toml table and there's a whole bunch of stuff here. Basically, we'll just define our strrus and then we can just do tumml from stir the same way you can do sirday json from stir and then we'll just pull it in that way. So that's what we'll do.
Let's go ahead and make a config first and then write the parser for it I think. So of course cargo add toml uh there are some other features here but I don't think any of that stuff matters.
Cargo build just to make sure we have it. Yes, I sleep to your bash course in the background often. Dude, that's awesome, man. That's so great to hear. I think that's sweet.
Apologies on behalf of me and my lurker friends. Dude, I don't mind at all. I love the lurkers. I think it's great. I don't care, man. I'm I'm happy that you guys want to lurk. I think it's cool.
All right, so let's do this. Let's make a config.
Config.l.
There we go. So, this is what the config will look like. And we can make up our own format here. It doesn't have to be like anything specifically. I imagine it'll be something like this. Like http server listen equals http slash. I don't know if you need the http. Hold on.
Uh we don't need that. We should have 127. Okay. Max events.
Okay.
mind if I ask how many YouTube subscribers did you have before your I quit my tech job video? I don't know. I truly don't know. I don't keep track of those metrics. If you go watch the video, there's a good chance that at the end I say something like, "At the time of this recording, we have this many subscribers." I do that often, but I don't do that in every video. So, I don't actually keep track of the information. You could go to SocialBlade, like socialblade.com, and look up my channel. You'd probably be able to get that information answered.
Um, I just don't know it.
Love to hear how you work through the process. Not a strong coder, but can apply the logic to other tasks. Yes, I am a big proponent. Thank you. First of all, first awesome comment. I'm a big proponent of there is no such thing as a complex problem. Um, a complex problem is just a series of connected simple problems. So, if you can you can break all complex things down to simple problems. That's the hardest part is being able to go from complex to simple.
Once you can break it down to simple, then it's like, oh, suddenly a lot of this stuff makes sense.
So, I think we can just put global config stuff up here. Like I could just say like um max events ring buff equals five.
So, So we have the maximum events to allow uh HTTP configure stuff down there. We can do this. We could do um broadcast channel size equals. I think we have it set to 16. Like you probably don't actually need to change that, but I'll still make it configurable cuz why not?
Yo, what's up fallen learns? How you doing? Hello. Hello, welcome, welcome.
I'm new to this build. Have you used the clap library for CLI features? Oh, yes, I have used clap. I use clap all the way back in version two when we were using like YAML files to define it. I think last time I used it was version four. Is it still on version four? It might be version five. So, I've gotten pretty used to like the derive style macros that it uses. You probably don't need to change these. Tokyo broadcast channel size max events ringbuff. Okay, so let's vim source config.rs. We'll make a whole new file for this and we can read in config.ttoml just so we can like get an idea of what we're kind of what am I doing? Get an idea of what we're going to make the config look like. So it'll be like this. Pubstruct config max events bring buff u size pub http server is the http server config and the pub internal is the internal config. Nice. Then we'll go ahead and define those strruct http server config has a listen field which is a string and then the pubstruct uh internal config has a Tokyo broadcast channel size which is a U size I believe.
There we go. Let's go ahead and derive.
We might need clone on this probably. Let's just derive debug and clone.
Do we have to put in the lib or do you put in mod? We can just mod it, right?
Because I think we can just do this, right? I can just say mod config.
There we go. Okay. Yeah, because I don't need to make it accessible to the library. I just need to be able to access it from the main function. We might have to clean this up later, but I going to say that about everything. You need to get a nice mechanical keyboard.
I hate them, dude. They're so loud.
mod config use config config. There we go. So now let's go down here.
There we go.
Config will be Again, we'll stop hard coding these paths. But for now, this works.
Um, what does Tom will have? read stir from stir from stir from stir sunwrap.
There we go. And this will give us the config file. That might be all we need.
Uh we call it max events. That's not what we called it. Also, if we are going to pull the config in, we have to be able to des serialize to it. So use sdeerialize internal.
We have max events.
Uh don't even call it ring buff. Just call it max events I think.
Quiet mechanical switches exist now, too. And there's quiet ones.
Interesting. That might be a reason to look at them, but I don't know. I'm I don't mind my keyboard. I like my keyboard, but I'm kind of boring config.
Tokyo broadcast channel size I think is what we called it, right?
Okay. No.
Oh, is it because we're giving the config away?
That is exactly what's happening. Okay.
cargo format. Let's see what that actually ends up looking like because some of these stuff is some of this stuff is just long like ridiculous names. config.inter internal.tok broadcast channel size like yeah that's a little bit wildly named but who cares.
All right, cool. Look at this. Red config max events five HTTP servers configure here. Internal stuff here. Red five events from this. We go over here.
We curl the events.
And we get them. Beautiful.
That's awesome. Uh oh. JQ fails because of dash I. Yeah, that makes sense. Do you remap any VIN motions? Nope. I'll leave them all the same.
Can you explain what you are doing to someone that doesn't understand coding?
Sure. I'm making a program that it's technically a server. I don't know how much you understand. So, I'll try to make this like I would talk to someone who doesn't know anything about computers. I'm making a thing that I I'm keeping a journal of things that happen at my house. So, I'm programming the journal effectively. Now, this journal is going to sit there and anyone who walks in my house can write in this journal. My own computers can write in this journal. Any other thing that I have in mind can write to this journal.
This journal is a little bit special because I can say, "Hey, journal, show me your last five entries. I want to see their date when they actually happened.
I want to see what wrote in the journal.
If it was Dave, if it was Bob, if it was Alice, I want to see the severity level.
Is it just like a hello message or is it like your toilet's running message?"
Some of that's a little bit more important than the other. They can write whatever they want in there. So, anyone can write in this journal. I can go look at the last X entries in the journal.
It's five right now, but I could change that to 100 if I wanted to. And I can get a live stream event of all the journal entries. So, my magic mirror right there, I'm going to have it live stream all the events, all the lines that people write down in this journal as they come in. So, I'll be able to see things like, "Oh, this computer rebooted. Oh, the garage door opened.
Oh, there was motion detected in the backyard." Things like that.
I much prefer long names to like super short function names like I've seen in code bases. Yeah, I've done some Objective C so I am not afraid of the longer names. I've seen some wildly long names.
That's dope. Sweet. Yo. Yeah. Thank you.
And hopefully that uh that description made sense like what I'm doing here. So, we are working on a server that will coalesce events. So, you know, it's not technically a journal. It's an event server. Events can happen from anything.
And then I can say, "Hey, what events happened?" So, that's what we'll be doing.
This way of coding, you'll never hit your KPIs and be fired. Use cloud code.
Well, good thing I already quit, huh?
We could probably add more stuff to the config like max events five Okay. So, we can have a new persist thing in the config which will have a file thing and it will be optional which will be kind of cool. So, you can just comment this out. So, let's do this.
So now we need to add persist which will be persist config.
We can just copy this which will be an option of a string.
That means it is an optional field. It does not have to be there.
So if we cargo build this it all still should work. We'll get some errors because we're not using it. But now instead of hard- coding events.json, we can have it's set in the config. And if it's not set, we won't write or read from this file.
How are you going to store the events?
Well, that's what we're using. We're using a JSON file for now. Maybe eventually in the future, we'll add a database. And wouldn't it be nice if the persist part of the config had something like, okay, we have file there. What if we had like, you know, SQLite equal food.sql and then suddenly we support reading and writing from SQLite. Maybe something like that or like you know DB driver and then suddenly it's like oh we want to store it in Postgress that's later that's not for right now for now we just support writing to a simple JSON file because that's easy. Yo Black A72 thank you for the $4.99 super chat on YouTube dude that's awesome. Hope you're having a good day Dave. I am having a good day dude and now that I got a $5 super chat from you I'm rounding up. Now that I got a $5 super chat I'm having an even better day. So yo thank you. I appreciate that man. Dude, donations are never expected, but they are always appreciated. So, thank you so much. I appreciate that. I really appreciate your content. I've used a lot of bash tips you showed me already at work. Keep it up, dude. That's awesome. So glad to hear that. That's dope.
All right, what do we got here?
I would struggle horribly to break my concept down to something digestible.
Um, let me tell you right now, I get a lot of comments from people that when I, so I'll make videos where I take a complex topic and break it down to something digestible. And I'll get a lot of comments from people that are like, "Wow, it's amazing you're able to do that." And I'm like, "Thank you. That's so awesome." I'll get people like that say this. They're like, "Oh, I wish I could do that. Like, I wish I had that gift." And I'm like, "Bro, it's not a gift. It is a skill. You can learn it."
Um, I'm not saying you're saying this directly. I'm just saying for anyone listening who wants to be able to do that, that's a skill, dude. breaking complex topics down into simple topics.
Like there's a reason we pay teachers.
Uh like it's a tough skill to be able to do that. Like it's something you have to learn. It's something I practice. It's something I actually like think about actively. So that's awesome, dude. I appreciate you saying that. And yeah, at work, one class whose name is eight words, 59 characters, but it's descriptive enough we always know exactly what it does. Yeah, dude. I've seen some like gnarly names where it's like, you know, um do not run in prod ever and it's like all uppercase and underscores between it and stuff.
having in time series would be awesome.
Yeah, like there are so many good ways to be able to store this data. Um, right now we're just doing JSON file, but like this is this is for a V1.
Mirror, mirror on the wall. Who did not flush it all? What a what a wild thing to write, but it I can't even be mad at you because it shows you're listening to what I'm saying. So, like that's actually that's pretty on the nose, man.
That's awesome. You took what I said and synthesized it into something horrible.
All right. So, let's do this. Let's go ahead and implement that. Now, we have our file thing in the config. That's awesome.
We have this. So, let's go and look where we use events.json everywhere.
So, how do we want to do this?
Check if the config has it. Uh, if let some file equals config.persist file. There we go. JSON file specified in the config.
Read it. There we go. Otherwise, just default to an empty vec, which I think or we could just do vec deck. Um, new.
Wow.
A lot of cloning going on here.
Can I just do this?
Yeah, there we go. And then right here, fs registry. Let's just do this. Let s equals fs read to string.
Uh, file's already a I think this will work. I think file is already a reference.
Expected stir found string.
Wait, hold on. Where did that get the damage from?
Yeah, there we go. Okay.
Red cached events from disk.
Here is where we write them to disk. So we should write them to config.persist.file.
That's not going to work. We have to figure out if we actually want to serialize them.
Ah we maybe we do want two ser we may want two channels here. But for now let's do this.
If set let file equals let um if let if let file config dot persistfile.
If that file is set, then we need to do this work.
There we go. Beautiful. Awesome. Uh, let's see. Hey again, Dave. Yo, what's up? How you doing, man? Paladine, what's up? What's up? Kind of late to the party today, dude. It's all good, man. We're just hanging out. And if you're watching on Twitch or you're watching on YouTube, uh well, if you're watching on Twitch, I'm also dual streaming on YouTube. And if you're watching on YouTube, you already know this. But if you miss the stream or you come in late or blah blah blah blah, it's all on YouTube, so it's stored there. The VODs are already there. You can go check them out. All the previous episodes will be up. I should probably come up with links to them and put them in like a pinned comment or something. But yeah, don't worry. All these videos, because they're on YouTube, they'll just be persisted there forever. So all these videos will be up there, which is nice. I'll probably go through and maybe turn this into a video if it's entertaining enough. I don't know. It might just be a lot of yapping. Maybe this is only useful for people who like the streaming content. But yeah, if you're watching on Twitch, go ahead and hit the follow button if you aren't already. If you're watching on YouTube, make sure to subscribe and make sure to like the stream. According to my analytics, only 20 people have liked the stream. So, I don't know if that's good or bad. No, seriously. But yeah, like the stream if you want to hit that little button and then go back to lurking. I don't mind. I won't ask that much out of you guys.
All right. Do we have any more events.json anywhere? I don't think we hardcode anymore. Okay.
So, watching both on Twitch and YouTube.
That's wild.
Twitch is probably way more ahead than the YouTube stream. I think Twitch has less latency.
Oh, we got 28 likes now. Thank you everyone. Appreciate it.
Couldn't tell you what the likes on the stream do, but you know, why not hit that little thumbs up button? It's got to do something good, right?
Oh, read zero cache events from disk.
Yeah, because that's confusing.
Here we go. Red blank cached events from disk.
We should put the print line here.
Um, what I want to do is I want to have a log line that makes sense like Um, there we go. And then print line. Um, persistence persist file not set not reading cached data. There we go.
There we go. Might be a little bit confusing, but I want that to show up when we do a cargo run here. So we can see like persist file not set not reading cache data. That's why we have zero cached events first.
Whereas if we go to our config.toml, we put that here, we can see that reading cached events and events.json have five cached events.
That's great. So now if I were to put let's say 10 more in there now we can see that we serialized events serialized events serialized events. That's all well and good. If we don't have that option set then we shouldn't be serializing the events to it. So if we run this we go over here we write 10 events to it.
Yeah, there's no serialization notification. So that's really cool.
Awesome. Nice. That's great. Now we have a customizable events.json file to cach this stuff.
the YouTube stream is ahead for you.
That's wild. In my experience, the Twitch stream is always like very very low latency and YouTube seems to have a crazy delay. But I think that depends if you're watching on mobile, if you're watching on your phone or or watching on your TV, watching on your computer.
Hot reloading for the config file. No.
No.
Maybe in the future maybe I would add that option if you update the config file and you want to hit us with like a SIG user one and we can reload the config. But for right now, that seems that seems out of scope right now.
That's a little bit too advanced for what we need. We need to get this thing off the ground first before we start hot reloading the config. I like the idea. I just don't think we're there yet. Let me add it to um to a possible to-do.
Reload config. Yeah, probably a reload config and uh optional data stores, things like that.
Something like that. Yo, Black Ace 72, thank you for the $10 super chat on YouTube. More accurately, $9.99. Uh, thank you for the super chat on YouTube, dude. That's awesome. How do you keep track of the logical flow of a program so that you cover all possible if else cases conditionals? I've heard about unit test but I haven't tried them before. I do my best to keep an entire program in my head until I can't anymore. I do my best to keep it in my head but every time I create like a little if else conditional branch in my head that's it. I just keep it in my head once it's grown beyond the scope of what I give my brain. That's where you want unit tests. Sure. But for this I think you actually want what are called like integration tests. So like unit test let me test like a specific function but integration test will let me test like a specific workflow and I think that's more what you're talking about. So I would make tests for this later down the road that would actually spin up this binary with a configuration file. So I would like make a like a config file like and make it use like dev null and ensure that we are trying to write to it or I would configure it with a config file with a events.json file that like exists. So like I would make an integration test that would start the server with a config that uses a known file and then when I close the server down I would check that file to make sure it has all the data in it that I want. So that's kind of how I do it. So unit tests are good for testing like specific functions and pieces of um code. But integration test I think is really what you want here.
Hey Dave, love the content. Any plans to make a course similar to your bash one for Rust or C? Uh, no real like actual plans, but like I would like to, but no real promise on like when. But that's definitely something that's on my radar.
Yes, I want a R course by Dave the unemployed. That would be excellent.
Listen, it's on my radar, but yeah, no problem. Black Ace. Yeah, unit test are great and Rust compiler will do it for you. I can maybe show how to do some of that testing stuff, but we'll definitely want some like integration test, which Russ Rust can do all this stuff with Cargo Test. Super nice.
What OS are you using? This is on Mac OS.
I don't have Neo Fetch on here.
Interesting.
Yeah, good question, Black Ace. Thank you for that.
All right, what do we got here? We have program should take a config file. I think we successfully take a config file now. We could probably get rid of that, but let's go and check if there's anything else we would like to add the configuration. Absolutely goated Metroid shirt. Yo, dude. One of the best like just series of video games ever, dude. I love Metroid so much. Oh my god, incredible.
Came back to the stream and fast patching. Hey, you happened to catch me right at the worst moment. Then did you get Rust Analyzer going for Vin? Nope. I haven't even touched this. I haven't touched a computer since the last time I streamed. Literally, I was I was busy today. I had to go get an adapter, went to the mall, got a massage, just did a whole bunch of stuff. Um yeah, just just a busy day. Um what was I going to say? I was going to say something else. Oh, I was out in the woods recording a YouTube video that'll probably go up in a couple days, maybe tomorrow. I don't know. So, yeah, just some fun stuff, dude. A massage is awesome. I had a gift card to a place that I went to today.
It's not the normal guy I go to. Uh, I go to a normal person every a normal person. I go to the same person every two weeks roughly. So, I was there last week and I'm going to go there again this week, but I had a gift card for a different place. So, I'm Dude, I'm massage maxing, which is absolutely wild. But I just I love them, dude.
They're they're so great. They're so useful. Oh, man. Wonderful. I am new here and enjoying the ambiance. I stumbled upon the bash course. I think that's why I'm here. Dude, welcome.
Welcome. You know what? Actually, now that you say the ambiance, let's go ahead and take a little break. Let's get some uh let's get some other ambience ambiance. Let's get some other ambiance going.
I'll show you what else we do on the stream. You ready for this? We got the big camera. It's what I call the scene in OBS.
I click this button.
Where's it? There it is.
That's right. I play the piano. It's amazing how many people don't know that.
I do it on most streams. Usually at the beginning, though.
Yo, Paladine, you got it. It's one of my favorite things.
It's uh Shopan's Fantasy Impromptu is what really made me like lock in and learn that because it's like a six over eight thing which is basically you know three and three over four. But it's crazy because it starts the left hand is doing three while the right hand's doing four but the right hand starts on a rest. Do you know how hard that was to learn?
Like most people just know the song I can't do it. This is That was bad. I'm very out of practice and this is not the keyboard for it. But if I slow it down, it's the right hand starts in a rest, but it's like so I had to learn that like that's that's it's crazy.
So this by contrast is easy. I could do this all day long.
Just got to practice that, you know. You got to you got to get the feel for it and then switch it up.
Ton of fun.
Paladine, what do you play? What rhythm games?
Oh, so of course, okay, I can instantly gauge how old I think you are.
I don't mean that in a bad way.
It's low-key my birthday tomorrow, so like, you could play my song request and I wouldn't have a complaint. Listen, request what you want. There's no guarantee I know how to play it. I'll try, but we'll see. Yeah, I figured you were younger. I don't mean that in a bad way. I I truly don't. It's just that's a young man's game. See, when I was growing up, that was when Dance Dance Revolution was coming on the scene and Pump It Up. So, I played the hell out of some DDR and some Pump It Up. Some might even say I bought arcade pump it up cabinets in 2018 and refurbished them and I have them downstairs in my house and then I'm actually pretty good at it and I used to play a little bit competitively.
But that's some real deep you suck at programming lore you guys aren't ready for yet.
Yeah, the syncupation is just h I love it. It just makes it such a good I don't know. I just love the way it sounds.
Yeah, like Paladon, you aren't ready for me to go. I' I'd have to go grab it from the other room, but I have a laminated print out of like max 300 on heavy so I could memorize it. And when I say like memorize it, I mean like like I know you can't see that, but if you know the rhythm, that's it. I have it.
It's in my brain. So, I might have to do a DDR stream or a pump it up stream sometime.
Can you play the Nan Cat thing? I can't.
that one. I don't know. I I No, I there.
I'm sorry. I would not be able to play it.
Yeah. Yeah, dude. Song of Storms. It's so good.
My favorite song.
something like that. If you like syncopation, do you play any Mario tunes? Well, hey, there's one.
something like that as an introvert profile. I don't think Well, I don't know if you're talking about yourself, but I am definitely not an introvert. Anytime I've ever taken any one of those tests, I score extrovert like off the charts.
Ben drown, dude. Oh my god. Classic.
Yeah, there we go.
We should probably be coating, shouldn't we? Oh my god, we're getting distracted here.
Don't know if you watch videos on stream. I do not typically watch videos on streams, but maybe I'll make an exception for you. That's cool that you uh that you uh have videos of you playing. That's one thing that like I wish I had, but like you know, playing DDR like 15 years ago, 20 years ago, people weren't putting videos on the internet like that.
Make any programs that integrate with the keyboard? Uh, no. I have not done that yet. It's definitely on my radar, but I have not done that.
Oh, you you OSU players are insane.
You guys are wild.
Hopefully this won't like give me weird copyright for the music. Probably not.
I'll throw you a like.
This game is wild, man.
Oh yeah.
This is disgusting, bro.
All right, let me I'm going to pull up something else for you guys. We'll do a fun little surprise. Let me make sure I can find it real quick.
Let me leave you a comment real quick.
Dude, this music is crazy.
All right, hold on. I got something for you guys. Let me queue it up real quick.
All right, you guys ready for a deep cut here? Oh man, here we go.
This is six years ago.
This is pre pre- pandemic. I got my short hair.
Here we go.
This is a deep dive into what I was doing before I was making programming content on my 10,000 subscriber music channel.
So, here we go. Here's a deep dive that I don't think I've showed off on stream before.
Oh yeah, I still got it.
Yeah, I was shorter hair and I wasn't lifting back then. So So it was weird.
Skinny arms, fat stomach, way different proportions than I have now.
I cannot do the steps with my feet. They just It's just automatic.
Yeah, if you're used to like DDR like this, the BPM is by how far spaced everything is.
Best part.
Crossovers.
Yeah. Let's go.
>> Nice, dude. Goatated >> one grade.
>> Oh, well.
Ah, there you go. There's some There's some fun Dave Lore for you guys.
Oh, that's fun. Oh, man.
be careful with the pump it up accuracy.
Now the game is way stricter than it used to be, but before its timing window was like a joke. Like pump it ups compared to DDR was like a joke. So I came from the DDR world, so I was really good at pump it up accuracy, but my friends who knew pump it up and then went over to DDR were like getting destroyed by the accuracy meters. I had some people that played a lot of osu and they just crush pump it up. Their accuracy was perfect. And then you have the people over in Guitar Hero and I don't even know what they're playing, dude. You just I don't know what the accuracy window is over there. Nothing.
Oh man, dude. So yeah, thank you everyone for indulging me there. Ton of fun. Maybe I'll do a pump it up stream in the future because I still play. It's fun. I haven't played as much as I want to, but I'm getting like hyped up. My feet are like moving. I love it.
Oh, such a good exercise. It really is.
All right, you guys have distracted me enough. Well, I distracted myself. What were we doing? We were looking through the config to see if there was more stuff we could add to the config, right?
What a good sentence.
I don't want this drink. I got this drink, but I want a different drink.
I'm going to go grab one more drink and then we'll get back to coating.
DDR maxing DDR max DDR max 2.
All right, you push yourself. gives you a plus or minus 23.5 ms hit window. That's like two to three frames per object. Yeah, it's funny. Like when accuracy becoming became such a huge thing, suddenly like refresh rate and like frame window started to matter like way more and more. It's just amazing how good humans have gotten at some of this stuff.
All right, let's figure out what we want to do next. We have a config. Let's go ahead and maybe add more stuff to the config if it makes sense.
Um, that might be all we need for the config, though. What else are we What else are we hard coding?
Wrap this data type and have it encapsulate the max size. We could do that. Make our own ring buffer type.
Maybe eventually we'll do that. Fork and exact when a new event is seen. I think that's what we want to do next. Let's fork an exec when a new event is seen.
refresh on what this program does. Uh, not right now. We're getting No, I'm too far into it. Uh, I've I've gone over it a couple times earlier in the stream. If you re rewind, I'll go over like a couple different description of it, but getting too sidetracked by just keep constantly reiterating it. Let me figure out what we want to do here. So, let's do config. We have persist HTTP server internal and maybe I don't know what we should call this.
Not everything needs a key. could just be like file to execute when a new event is seen.
File to execute if set. There we go.
Oh, thank you. Thank you, Paladine.
Actually, that's good. I'll just read your message out loud. So, Lemon, uh, Paladine in Twitch chat, I'm going to cross homogeneate these messages. It's a server for his home lab, which can be pinged and sent events by other appliances, sort of like a central toast notification system for his home. That's a great description.
All right.
So we have exec program here which will be new event. So let's go ahead and add that to our config should be an option of a string.
So it'll be optional.
Beautiful.
If let some progue equal config.exec program.
There we go. Now we should fork an exact it. So print line. Um now we got to figure out how to actually do that. Uh, this is just regular Vim.
Is it spawn?
Probably want spawn, I think.
Rust spawn command. Oh, it's giving me for the rust game. That's so annoying.
So, we can do command new, give it the args, and get the output.
probably want like a timeout on this or something. This is why we're going to want separate tasks because there's so many things that can fail here.
Wrong rust. It makes sense. That's like that common.
That's really funny.
Does it let me do like a timeout and stuff?
spawn.
Greetings from Texas. Yo, what up? What up? Welcome.
Okay, we might have to modify the N.
doing like an end clear type of thing.
Maybe it makes sense just to get something working here and then we can modify it later.
This example panics Yeah, maybe we just want status.
Yeah, I think that's what we want. Let's go ahead and do that.
So we'll put Prague here and then we'll give it there's no argument so we can just call status and then that returns something because uh status returns a result and inside it will be the exit status and that will have things that we care about.
So, let's just see what we have here because I think this will be a result.
Nice. So, it'll run dot / new event that doesn't exist. So, we're going to break it. So, let's break it.
Cool. It broke. It returned a result.
And in this was an error. Awesome.
Beautiful. So now we can do this.
H would be nicer if this was in a function because then we could just early return from it.
Yeah, let's just do this.
Oh, we don't really want to early return, but we want to be able to break out of the loop. So, we basically want Oh, I'm thinking in C. I want to go to but I think we just want a break here or a continue.
We can also do errint line. That is true. I'll figure out logging later, I think, because I do want these all going to uh like a log file type of thing.
Failed to run new event. And then we get the error message here. Nice. Good.
I'll do a print line here. Yeah. Until we actually get a real logging facility.
What does the fully debug output of that error look like?
Oh, that looks pretty good actually.
All right. So now we have this status object which returns an exit status. Don't we have uh maybe we don't want status, we want output, right?
Yeah, I don't think we want status. We want output which returns an output object which I think has a status call on it. Yeah, that's what we wanted.
There we go. So now if we were to vim new event make it a bash script.
Now, if we rerun this, look at this. We have an exit status of zero. We have a standard out and we have a standard error. That's beautiful.
That's really nice. It might make sense.
We'll figure out the logging facility stuff. It literally might make sense to just let it inherit the terminal, but it probably doesn't.
I don't see any previous message with the link in it, so it sounds like it was blocked.
My friend, I'm unsubscribing because of Rust. I like the C/Bash stuff more. I don't understand. So, can't read this at all. Okay.
Yeah, we should definitely wrap this a little bit.
We could definitely clean this up and make it look nicer, but this is kind of cool. We can see the exit code and we can see the standard out and the standard air from it. So, that is pretty cool.
I like Rust. I think Rust is cool. I think C is cool. I don't know. I like like both languages are great.
All right. Now, if we run environment, right? Like, I don't think we clear any of the environment. Yeah. Okay. So, we get everything in there. Okay. That's a mess. We should definitely we should definitely clear the environment and then do some work with it.
Like I just want all the environment except for like three things to be there. So let's do this. Let's go back.
We have N which lets you set it insert or updates.
Oh, you can filter out the NARS. Okay, interesting.
Yeah. End clear ends filtered ends.
That's interesting. I see what they're doing. That's clever.
This like actually this might be the play right here.
Yeah, I think we'll do this.
I get analysis paralysis usually until I either end up not writing anything or doing C or JS depending on if it's for work or not. Yeah, analysis paralysis is super dumb. I'm not saying you're dumb.
I'm just saying it's a dumb thing that happens. I hate analysis paralysis.
Sometimes I find that even making a decision, even if it's the wrong decision, is still better than being paralyzed.
That's my advice there.
I don't understand as much, but I really enjoy watching programming and live coding videos. I will consider myself like less than junior, but vibe coding with some technical knowledge. Listen, man, I'm not a big vibe coding fan. I'm worried that you might be doing your brain a service, but if you enjoy programming, hey, that's awesome. You're welcome. Anyone's welcome here, really.
So, also, hi. Yeah, welcome.
All right, let's use this code because I actually like this code.
The environment will never actually change. So, we can just do this once.
Yeah, we'll just put these in. I these tasks will go into separate functions, but for now, let's not even worry about that.
There we go.
You're awesome though. Yo, appreciate it. Thank you, man. What's your take on she on C sharp? I've never I've just never used it. Like that's really all it is. Like literally I've just never used it. So like I don't have a meaningful take on that.
I don't know why coding languages always devolved into religious wars. Each has their place. One isn't necessarily better than the other. Just different.
It's how I feel about like Vim, VI, Neo Vim, Emacs. Like I don't care, dude. Use what you're comfortable with, man. Like we're writing Rust right now because it's fun. Like I agree with you. Like we're writing Rust because it's fun. In my previous video that I just put out like a couple days ago, we did C. In the video before that, we did Bash. Like, yeah, I just just I don't know. Coding's fun. I just like it, guys.
Okay, nice.
Exact program seems kind of like an awesome attack vector for hackers. Yeah, definitely. Make sure your script is safe. Make sure it's running with limited permissions. Make sure it doesn't do anything important.
Absolutely.
Luckily, you don't have to use it if you don't want it. If you don't have it set in the config, then it won't actually exec anything.
So, we can do this. So we can do envcle clear. Ens. I'm pulling this right from the uh source code that I or the documentation I had up before.
There we go. So it should clear the entire environment. And then if I go over here and I run it, nice. We can see the standard out is very simple. We just have the pwd. We just have the term variable. We just have the path variable. And we have an underscore variable. Well, that makes sense. That's cuz we're inside bash.
Cool. So, we just have very, very simple terminals. That's nice.
What's your thoughts on Versel0ero?
I don't know what that is. I have no idea what that is. I don't know what versal zero is. Versel versal. I'm not sure.
Holy C versus Holy Sea, dude. Holy C.
Legit.
Yeah, we'll have to format the output better. I don't really like the way that it's coming out.
It'd be nice if we could just capture all the output into one pipe. I mean, we definitely can, but what do we have?
I'll put that status.
Let's just do this just for now.
Uh oh, it's a vea view, isn't it?
What can we do this? Like standard out equals string from UTF8 lossy. Is that right? I think that's right. And then we can just give it output.st standard out, which is a veab bytes. And then we just change this to this.
There we go. That works. So now if we run this, we should just see the standard out. Hey, look at that. That's way easier. We got a PWD, a TZ, a lang, a term, a shell level, a path, and an underbar variable. That looks very simple. So nice.
They created a language zero lang. I have no idea what that is.
When you say not a fan of vibe coding, just realize you're not even using old school autocomplete suggestions. I love it. I'm one step away from removing syntax highlighting.
Like this syntax highlighting is already so much. just lessen the amount of colors here and I think I would like it better. Yeah, I'm literally one step away from that. Like I I don't need autocomplete. I like to think of what I need and then I like to go look it up directly. That keeps my brain sharp.
The more things are handed to me like in coding and stuff, the dumber my brain gets and I just hate the way it feels.
All right, what are we doing? We have our new event here. What we need to do is pass data to this script so we can make decisions based on the event. And the way we can do that is by using environmental variables. Is there a cleaner way to write this? Like can I just match K?
Like can I just like is there a simpler way to do that? I don't know.
Let's make this mut. And then we can add things like foo um equals bar. There's no way this works, right?
That's not right. There's no way that works. Yeah. What am I doing? Yeah. I just started making up syntax and the compiler even like knew enough idiots have done that. So there we go. So now when we run this script, we should get foo equals bar. So we can pass arbitrary data through the environment variables. We'll have to watch out for how much data is actually in there.
There's a macro that doesn't matches.
Yeah, I'm just wondering if that like looks nice. I'm wondering what the Rust idiomatic way is. The fact that this is in like the documentation leads me to believe that this is right, but it just seems like lame. You could also do like a put all these in an array and do like a contains or a dot includes or something, I guess. I don't know what the best way is. I mean, honestly, this is fine. This this is fine.
Do you think that iodes fds and contract exhaustion problems common in companies now? What do you think about container that monitors all the others? I don't even know how to approach that question.
I'm not even sure specifically what you're asking. If you could break that down a little bit more for me or make it a simpler question, I could probably handle it. Or like when I say simpler, I mean break down a portion of the question for me. Otherwise, I'm not really sure what you're asking there. Do you make any mental model like a full mental map before working on a project?
I have a rough idea I wanted in this one. In this case, I figured we would just start discovering things along the way, but I had a rough idea of what I was doing. If I'm programming on my own, I probably would have like documented the CLI and stuff that I wanted, but yeah.
Did you rust update stable today? Nope.
Yeah, Paladine. So, yeah, it seems like the matches macro just kind of does it.
That makes sense.
Uh, what we doing? Okay, we have foo equals bar here. That's great. So, that works. So, we can enter in insert things in the environment variable. Well, I guess we'll have to be careful about size.
We could pass it over standard in.
That might be an easier way to do it.
No, because then we have to come up with a format for it. Let's just do environment variable for now. We can clean this up. So for here we can insert uh event id is equal to uh where is the event? What is the event called?
I think it's just called event. Yeah.
Yeah.
There we go.
So look at this event ID and we have this. That is beautiful. It's being passed as an environment variable to our program. Let's go here and let's do this.
So we'll just grab for ones that start with event underbar.
Look at this. Here we go. Event ID is this. That's beautiful. So we can just add a couple more to that.
Uh what does the event have? Component level.2 string and then level and then message. We could also give it the data. I think that's there.
Let's see if this works. There's got to be some type mismatches. Here we go.
Event level due to unconstrained does not satisfy two string. Oh, it doesn't have display.
That's interesting. But we can serialize it.
I'm confused.
We have Sarah being able to do this, but it doesn't. So that doesn't make it. It doesn't have display. I would have assumed that was a display there.
H how do we convert that to a string? Is there an easy way to make it implement display? I thought Saturday would have done that. Can we serialize it?
You could definitely serialize it.
But for now, we're going to cheat. You ready?
I'm going to do a format.
Going to debug format it. It'll work.
It's ugly, but it'll work.
Cool. Event is this. Event data is this.
Event message is this. event component is this event level is this. So again this is wrong. It shouldn't be like this but that is a huge thing. So we are able to fork an exact a program if it is set.
That is huge. So program should take a config. It does support running an arbitrary program when new event is fired. That's correct. We do need to do these three things. We have some optional things down here. We have some concerns.
timeout um command that gets executed on event.
There should probably be some sort of timeout there. And yeah, I think that's what we got. So, I think that's good progress for today. I think I'm going to call the stream here. Seems like this is good. Oh, wow. The example from the uh book doesn't even need that.
That's so funny.
Let's go ahead and clean up some of the clippy nets.
There we go. No more clippy nets.
Beautiful. All right. Yeah, I think this is good. We made a lot of good progress today. Uh what's is today? We committed day four. So, this will be day five.
Uh new event config events.json and toml.l.l.l.l.l.l.l.l.l.l Yeah, it's all fine.
Wait, what day did I say it was? I already forgot. Day five. Okay.
There we go. It has been pushed. And yeah, I think I'm going to call the stream here. Uh, thank you for watching everyone. Thank you for jumping in. I appreciate it. Super cool. If you're watching on Twitch, make sure you're followed. And uh, oh wow, I have over a thousand followers. 147 on Twitch.
That's wild. And if you're watching on YouTube, make sure you subscribe. Make sure you like the stream. We got 44 likes on the stream. Not bad. Can't complain. Um, so yeah, thank you everyone. I appreciate you guys tuning in. And uh, this project's actually coming together. We're making something cool. I've never really built a full project like this on stream, so it's kind of weird. Normally, I would just be on my own and I would probably bang this out in, you know, couple hours, but I'm doing things nice and slow and working with you guys and getting distracted.
So, yeah. Thank you everyone for tuning in. I appreciate it. Uh, nice stream.
Thank you, Random Logic. Nice to see you. Nice to see you, Palenime Fallen Learns. Yeah, have a good one. Have a good one. Thank you, Dave. Thank you, Rand.dev.
That was a nice first stream. Thanks for the music, too. Hey, I'm glad you could catch the stream. That's awesome. I got a whole bunch of VODs on YouTube if you want to watch anymore. New YouTube video probably going up tomorrow.
Depending on how I edit it, it's just a yapping session, so I give my thoughts on some AI stuff and some other stuff.
But yeah, so yeah, that's all I got. Uh, thank you all for tuning in. I appreciate it. And uh, yeah, that's it.
Have a good night.
Related Videos
Agentforce NOW AMA: Build with React and Salesforce Multi-Framework
SalesforceDevs
490 views•2026-05-28
How agent o11y differs from traditional o11y — Phil Hetzel, Braintrust
aiDotEngineer
450 views•2026-05-28
WEB TECHNOLOGIES UNIT-2 | Degree 4th sem BCOM Computers web technologies unit-2 full explanation💯✅
LearnwithSahera
1K views•2026-05-29
More tests are always better? How to use AI to identify tests that bring little value
Alliance4Qualification
335 views•2026-05-29
Search Algorithms Explained in 60 Seconds! 🤖💨
samarthtuliofficial
218 views•2026-06-01
People of Game of Thrones using JavaScript DOM
AltCampus
296 views•2026-05-30
Introduction to Problem Solving Part - 1 | Lecture 1 | Intermediate DSA
ascensionix
107 views•2026-05-29
So What's Odin Lang Even Good For
TechOverTea
131 views•2026-06-01











