

Fair enough, although that actually has worse optics IMO. It goes from “this costs us money, so pay us” to “we need money, so we’re creating an artificial reason for you to pay us”
Fair enough, although that actually has worse optics IMO. It goes from “this costs us money, so pay us” to “we need money, so we’re creating an artificial reason for you to pay us”
The self-hosted servers use UPnP and NAT-PMP to automatically forward the port used for media streaming.
Very, apparently.
They use UPnP and NAT-PMP1 to have clients directly stream the media from users’ own self-hosted servers. It costs them almost nothing in bandwidth to do that.
Software costs money how would they continue to developed it if not getting paid?
Apparently a hot take as evidenced the downvotes on my other comments here, but by adding things people want instead of taking away things people already have and charging more for it.
They don’t even have the excuse that they need to pay for the bandwidth costs of relaying video from servers to clients. Video is streamed directly from the user’s self-hosted server, using UPnP or NAT-PMP to make the server accessible from outside the local network.
And this isn’t a new feature they’re adding. Remote streaming was already implemented and generally available to users.
I don’t discount there being a cost in maintaining code over time, but it’s not as though they have to spend any significant employee time on improving it. They already support UPnP and NAT-PMP to have the clients connect directly to the self-hosted servers.
It would be nice if they added NAT hole punching on top of that, but it’s evidently good enough to work as-is in its current form. If they’re not even running relays to support more tricky networks (which the linked support article has no mention of), keeping this feature free costs them literally nothing extra.
No, it’s still wrong.
We have ways to do NAT traversal and hole punching on consumer routers. Failing that, UPnP and port forwarding exist. Or, god forbid, IPv6.
In the rare case that literally none of those are an option, they would have to use TURN to relay between an intermediary. That is a reasonable case to ask the user to pay for their bandwidth usage, but they don’t have to be greedy fuckers by making everyone pay for it.
This is enshittification and corporate greed. Nothing more, nothing less.
Hellwig was a bit crusty about being overruled by Torvalds, it seems.
There is always some sort of fucking child throwing a tantrum about some shit. Has it always been the case?
Petty much. The big difference this time is that there’s a common enemy (Rust) instead of relatively isolated petty crap.
yq can do both JSON and YAML :)
It’s not as useful, sadly. Nohup disconnects standard input, output, and error. With screen or tmux, you can reattach them later.
Wireguard uses UDP, by the way.
That’s not the point, though. The point is to use a nominal type that asserts an invariant and make it impossible to create an instance of said type which violates the invariant.
Both validation functions and refinement types put the onus on the caller to ensure they’re not passing invalid data around, but only refinement types can guarantee it. Humans are fallible, and it’s easy to accidentally forget to put a check_if_valid()
function somewhere or assume that some function earlier in the call stack did it for you.
With smart constructors and refinement types, the developer literally can’t pass an unvalidated type downstream by accident.
You’re going to need to cite that.
I’m not familiar with C23 or many of the compiler-specific extensions, but in all the previous versions I worked with, there is no type visibility other than “fully exposed” or opaque and dangerous (void*
).
You could try wrapping your Foo
in
typedef struct {
Foo validated
} ValidFoo;
But nothing stops someone from being an idiot about it and constructing it by hand:
ValidFoo trustMeBro;
trustMeBro.validated = someFoo;
otherFunction(trustMeBro);
Or even just casting it.
Foo* someFoo;
otherFunction((ValidFoo*) someFoo);
If it were poorly designed and used exceptions, yes. The correct way to design smart constructors is to not actually use a constructor directly but instead use a static method that forces the caller to handle both cases (or explicitly ignore the failure case). The static method would have a return type that either indicates “success and here’s the refined type” or “error and this is why.”
In Rust terminology, that would be a Result
.
For Go, it would be (*RefinedType, error)
(where dereferencing the first value without checking it would be at your own peril).
C++ would look similar to Rust, but it doesn’t come as part of the standard library last I checked.
C doesn’t have the language-level features to be able to do this. You can’t make a refined type that’s accessible as a type while also making it impossible to construct arbitrarily.
Unless you’re a functional programming purist or coming from a systems programming background, it takes a lot longer than a few days to get used to the borrow checker. If you’re coming as someone who most often uses garbage-collected languages, it’s even worse.
The problem isn’t so much understanding what the compiler is bitching about, as it is understanding why the paradigm you used isn’t safe and learning how to structure your code differently. That part takes the longest and only really starts to become easier when you learn to stop fighting the language.
Of course. Rust isn’t immune to logic errors, off-by-one mistakes, and other such issues. Nor is it memory safe in unsafe
blocks.
Just by virtue of how memory safety issues account for 50%+ of vulnerabilities, it’s worth genuinely considering as long as the bindings don’t cause maintainability issues.
Let me know when you find one?
The first directory block is a hole. But type == DIRENT, so no error is reported. After that, we get a directory block without ‘.’ and ‘…’ but with a valid dentry. This may cause some code that relies on dot or dotdot (such as make_indexed_dir()) to crash
The problem isn’t that the block is a hole. It’s that the downstream function expects the directory block to contain .
and ..
, and it gets given one without because of incorrect error handling.
You can encode the invariant of “has dot and dot dot” using a refinement type and smart constructor. The refined type would be a directory block with a guarantee it meets that invariant, and an instance of it could only be created through a function that validates the invariant. If the invariant is met, you get the refined type. If it isn’t, you only get an error.
This doesn’t work in C, but in languages with stricter type systems, refinement types are a huge advantage.
Arrogant hypocrites are a pet peeve of mine. If someone is going to act like progressive technology changes are beneath them and unnecessary, they should be able to put their money where their mouth is.
I actually jumped ship a while back. I agree that Plex is a business and they do deserve to get paid for development and infrastructure costs, but it’s the blatant enshitification that I have a big issue with.
They chose to lock a previously-free feature behind a paywall for everybody and asked for even more money to get it back. The less shitty alternative would have been to ask only the users who needed to use the relays to purchase a Plex Pass. Or, if they wanted to make it seem like a positive thing, they could have made the new subscription into an “enhanced quality” remote streaming experience that enabled higher bitrates over relays.
They gave their users the middle finger by picking the most transparently greedy option that they could get away with justifying.