-
Notifications
You must be signed in to change notification settings - Fork 169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Generalize client storage from the filesystem #2194
Conversation
6905cc6
to
e074913
Compare
0bb2f91
to
ce83b06
Compare
af493f9
to
28df385
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | ||
} | ||
|
||
pub struct File<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: The name File
is a bit counter-intuitive: afaict this is a value persisted on file. Maybe OnFile<T>
is a step in the right direction?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another approach (which was highly debated before but perhaps ok here) is to use the module name for the distinction between different implementations. Something like persistence::file_system::Value
implementing the trait persistence::(Persistent)Value
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a wrapper over the type (as indicated by the Deref
impl), so I read the name persistent::File<Wallet>
as ‘a persistent file containing a wallet’. The grammar of this name is hurt a bit with the rename to persistence
, as well as file_system
(a persistence::file_system::Value<Wallet>
is not a persistence file system value containing a wallet). I agree that File
should never be used unqualified!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if you swap the storage medium, it will be called persistent::Web<Wallet>
or persistent::Network<Wallet>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something like persistent::LocalStorageEntry<Wallet>
or persistent::S3Bucket<Wallet>
, yes (the name refers to the entry that stores the value, not the medium the entry lives on).
linera-service/src/persistent/mod.rs
Outdated
|
||
pub use file::File; | ||
|
||
pub trait Persistent: Deref { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could use some short (oneline) comment on public APIs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: perhaps PersistentValue
or Value
(I don't mean to open a big debate though :))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree on the docs, good catch :) Though technically nothing in linera-service
is ‘public’ as it can't be imported as a library, that will change in a little bit when this goes into linera-client
:)
On the name — there's no clear consensus on this in Rust, but I prefer adjectives for trait names rather than nouns (as it avoids name clash with implementers, especially generic implementers). The competing convention is verbs, so this could be named Persist
; happy to switch to that if we think it's better. If we want a noun then it should be agentive/patientive, i.e. Persistable
, but suffixes like -able
are specifically recommended against by the guidelines. I think Value
is an essentially meaningless type name — anything nameable by a type is a value, so including the word ‘value’ in a type or trait name never adds information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact I think I'm convinced that Persist
is more in line with Rust (std::io::{Read,Write}
, et cetera) — I'll rewrite to that unless you have objections.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added the docs and renamed Persistent
to Persist
.
This is more in line both with Rust standard library traits, which tend to be transitive verbs, and also with the Rust trait naming conventions RFC rust-lang/rfcs#344, which states: > Prefer (transitive) verbs, nouns, and then adjectives; avoid > grammatical suffixes (like able).
… handling, do not hide the outer error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I love it! Not just more general, but also cleaner! 👍
linera-service/src/proxy.rs
Outdated
let genesis_config = GenesisConfig::read(&self.genesis_config_path) | ||
.expect("Fail to read initial chain config"); | ||
let genesis_config: GenesisConfig = | ||
util::read_json(&self.genesis_config_path).expect("Fail to read initial chain config"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The recommended style would be:
util::read_json(&self.genesis_config_path).expect("Fail to read initial chain config"); | |
util::read_json(&self.genesis_config_path).expect("should read initial chain config"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Also, I think @ma2bd prefers explicit generic arguments over type annotations, i.e. read_json::<GenesisConfig>
over genesis_config: GenesisConfig
?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I think that's the letter of the recommendation but not the spirit of it 😅 The message in expect
is supposed to convey the invariant that we expect to lead to the Result
being Ok
. Probably this shouldn't be expect
at all, but return the error up for anyhow
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the turbofish — I don't see any official advice, but most Rustaceans (including the book) seem to prefer annotating the variable. It's less noisy and provides better (i.e. more localized) feedback when the type and value don't match. The turbofish is variously described as ‘a hack’ or ‘a wart’ that is unfortunately needed to keep the ability to provide generic arguments in some corner cases, but acceptable only because of how rarely it's encountered.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have a lot of stuff to do so I think we can agree on some tolerance on this particular point for now. In my view, the problem with type annotations in the let
is that they tend to stick around even after the reason for adding them has disappeared.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yes, I was blocked on the tests flaking out, not this discussion :) It was clearly marked as a nit. IMO if it's not obvious whether a type annotation is needed or not, then it's nice to have it there for clarity anyway. But the same can be said of the turbofish — quite remote changes in the function, or even the signatures of other items that the function depends on, can obviate a turbofish without anybody noticing.
Co-authored-by: Andreas Fackler <[email protected]> Signed-off-by: James Kay <[email protected]>
Motivation
The browser doesn't have access to a filesystem. In order to store and load wallet configuration, we must use a different backend, such as localStorage. Currently, though, the
linera-service
crate assumes filesystem access, and stores configuration as JSON on the filesystem.Proposal
Generalize the
WalletState
struct with a new trait that represents any data that can be persisted. Move the previous behaviour into an implementation of that trait specialized to filesystem storage.Test Plan
CI.
Release Plan
None required.
Links