ssbc / ssb-conn

SSB plugin for establishing and managing peer connections
MIT License
16 stars 5 forks source link

change deprecation warnings so they only happen once #20

Closed mixmix closed 3 years ago

mixmix commented 3 years ago

I'm running ssb-conn in Patchbay, but there are a lot of modules which need updating to avoid the deprecation warnings. Here's a slice of the startup experience:

 AHOY  main    starting Server
ssb-friends: stream legacy api used
 AHOY  main    starting UI
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
STARTING Patchbay UI
DEPRECATED gossip.changes() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.add() was called. Use ssb-conn instead
DEPRECATED gossip.changes() was called. Use ssb-conn instead
could not retrive msg: Error { notFound: true, status: 404 }
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead
DEPRECATED gossip.remove() was called. Use ssb-conn instead

It motivates me to fix the modules using the older api, but there are a lot of them. In the meantime it feels a little annoying because it means I can't see what other errors might be occurring, which could be dangerous.

This PR

I've modified the code to do something I've seen elsewhere in SSB - just warn once, then leave it.

NOTES:

staltz commented 3 years ago

Superb, thank you @mixmix

staltz commented 3 years ago

If you want to learn some TypeScript, here are some incremental suggestions:

-private deprecationWarning(method: any) {
+private deprecationWarning(method: string) {

makes is so that you cannot call this.deprecationWarning(null) or this.deprecationWarning(42), only strings are allowed.

But it's not optimal, because you could still call this.deprecationWarning('collect') (typo of "connect" as "collect"). Instead, we can inform that we only want "method names" of this class Gossip, like this:

-private deprecationWarning(method: string) {
+private deprecationWarning(method: keyof Gossip) {

Now if we call this.deprecationWarning('collect'), we get this compile error:

src/gossip.ts:204:29 - error TS2345: Argument of type '"collect"' is not assignable to 
parameter of type '"disconnect" | "connect" | "peers" | "ping" | "get" | "changes" | 
"add" | "remove" | "reconnect" | "enable" | "disable"'.

204     this.deprecationWarning('collect');
                                ~~~~~~~~~

Found 1 error.

That's good because we want to detect typos. Now one final thing:

- private deprecationWarned: any;
+ private deprecationWarned: Record<string, boolean>;

A Record<string, boolean> is an object that has string keys (e.g. {3: 'mother'} would be invalid because 3 is a number key), and boolean values (e.g. {'connect': null} would be invalid). But we can do better than strings! We just learned about keyof Gossip, right?

- private deprecationWarned: Record<string, boolean>;
+ private deprecationWarned: Record<keyof Gossip, boolean>;

That's better, but it actually errors on this line in the constructor:

    this.deprecationWarned = {};
src/gossip.ts:83:5 - error TS2740: Type '{}' is missing the following properties 
from type 'Record<"disconnect" | "connect" | "peers" | "ping" | "get" | "changes" | 
"add" | "remove" | "reconnect" | "enable" | "disable", boolean>': disconnect, 
connect, peers, ping, and 7 more.

83     this.deprecationWarned = {};
       ~~~~~~~~~~~~~~~~~~~~~~

Found 1 error.

Oh so TypeScript is telling you that since Record<keyof Gossip, boolean> is an object where keys are the same keys as Gossip class, this empty object {} is missing all those keys. What we need to do now is tell TypeScript that those keys could be missing. But if they are present, we are sure they are booleans:

- private deprecationWarned: Record<keyof Gossip, boolean>;
+ private deprecationWarned: Partial<Record<keyof Gossip, boolean>>;

And that's commit https://github.com/staltz/ssb-conn/commit/ba365e5aeec2d14b6a868ff9b576d62a4488f2a2

mixmix commented 3 years ago

Awesome, thank you so much for the breakdown about types. I tried type String and just left it when that errored ): keyof is super sweet. I guess Record and Partial are core typescript types. This looks quite similar to some of the Rust generics ... slowly reading the rust book (online one)