-
Notifications
You must be signed in to change notification settings - Fork 5
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
Hash stored in map causes panick, type inconsistency between JS and Ruby #131
Comments
@eliias should I open this as an issue upstream with |
@wkirby I recall having a discussion w/ the other
There is technically no |
@wkirby I actually can't reproduce the panic, even using your example values. Could you provide me a value for https://github.com/y-crdt/yrb/blob/main/spec/y/map_spec.rb#L179-L192 |
@eliias Just got back from some time off myself. I'll send over the encoded document we have and work on setting up a more concise repro. There's always the chance that the error is on the encoding end with y-immer. |
@eliias attached is a file containing a Base64 string that presents the error. Here's how I reproduce with this data: ydata = File.read('ydoc.base64.txt')
ydata = Base64.decode64(ydata)
ydoc = Y::Doc.new
ydoc.transact { |tx| tx.apply(ydata.bytes.to_a) }
ymap = ydoc.get_map("data")
ymap[:testInt] # => 1.0
ymap[:testFloat] # => 3.1415
ymap[:testString] # => "foo"
ymap[:testBool] # => false
ymap[:testArray] # => Panick!
ymap[:testHash] # => Panick! Because this blob is pulled directly from our application, the Map at
In addition, the ydoc includes an XML fragment at Here are the relevant lines from my
And from
On the client side, the code (roughly) to serialize this data: const useSyncedData = (doc) => {
const ydoc = useMemo(() => new Y.Doc(), [doc.id]);
const [binder, setBinder] = useState(undefined);
useEffect(() => {
const localBinder = bindImmerYjs(ydoc.getMap("data"));
if (localBinder) {
setBinder(localBinder);
// optionally set initial data
localBinder.update((s) => {
return {
testString: "foo",
testInt: 1,
testFloat: 3.1415,
testBool: false,
testArray: [1, "two", true],
testHash: { a: 1, b: "2", c: false }
};
});
}
return () => {
localBinder.unbind();
};
}, [ydoc, doc]);
return ydoc;
}
const MyReactComponent = () => {
const { doc } = useDoc();
const ydoc = useSyncedData(doc);
console.log(ydoc);
return <p>Oh hey, a component</p>
} |
@eliias hope I'm not bugging you, but were the above resources enough to reproduce? If not I'm happy to schedule a call to work through this together. Just shoot me an email at [email protected] if you'd like. |
Yeah, I am able to reproduce this in a test case with your data. I also found the actual issue, but I do not have an immediate solution that is shippable. The logic that converts the internal CRDT representation for a Map/Array requests a new FWIW… I was able to access your test data after a somewhat hacky fix, so it is definitely doable. |
@eliias I'm not super versed in Rust, so I can't comment on the hackiness present here. I really appreciate your attention on this, and do let me know if there's any other way I can assist! |
@wkirby I am going to release |
@eliias sorry, we moved on in our project to other things, but are returning now. I will confirm within the next week or so whether your implementation fixes our issue. Thank you so much! |
@eliias sorry for re-using same issue for my problem, but I have feeling that it's same or very close
Then in the Rails log MyChannel#receive {"update"=>"AAFKAQK/lKqpBgAHAQVhcnJheQEoAL+UqqkGABZ0ZXN0MC42NjkwOTk1MzkyNDY1NjUyAXcWdGVzdDAuNjY5MDk5NTM5MjQ2NTY1MgA="} thread '' panicked at 'called and when I'm trying to reproduce it in the console
(Why [3..-1] - because of the 1st byte is yrb-actioncable's message type, the 2nd byte is y-protocol message type and the 3rd byte is the length of the update) If I put not an YMap into the array, but a primitive
then it works like a charm MyChannel#receive: {"update"=>"AAEpAQHs4JKHAgAIAQVhcnJheQF3FXRlc3QwLjU1NzkyODAyODMzNjEyMQA="} MyChannel#receive synced: ["test0.557928028336121"] and in the console
May be it's me doing something wrong? |
@Phaengris It is possible that Maps in an Array aren't handled properly (still). I am going to add your case as a test and try to fix. |
@Phaengris I identified the issue. Map/Array does not accept nested Y data-structures in |
@eliias thank you for investigating this :) No rush. If you can find time to fix it, it would make me happy, but if no - no worries. For now I switched to use xml fragments / elements which also supports data nesting, in it's own way. May be a possible drawback is some performance hit, but I didn't do any benchmarks yet to see if it is actually a problem for my project. |
@eliias came back to note that the most recent published version ( The structure of our {
title: "string",
order: 0,
data: {},
dataValues: []
} I can access all these values individually: ydoc = Y::Doc.new
ydata = get_file_from_s3()
ydoc.transact { |tx| tx.apply(ydata.bytes.to_a) }
ymap = ydoc.get_xml_map('data')
ymap['title'] # => 'string'
ymap['order'] # => 0.0
ymap['data'] # => {}
ymap['dataValues'] # => [] So far so good! The error arises from trying to get all the values: ymap.to_h # => Panic!
ymap.to_json # => Panic! Results in the same error as above:
The workaround, though:
Anyway, from my perspective this issue can be closed out. Appreciate all your hard work! |
So it looks like nested maps don't work as the only way to create a In javascript I can create and assign I can work around this by changing how I'm modelling data but I'd love to be told I'm wrong here! |
We are attempting to modify the same ydoc in the browser using yjs, and on our server using yrb. I have a pretty simple setup client side (this is simplified further for the sake of this report, but captures our use case fairly):
This ydoc is encoded as a
uint8array
, base64'd, then sent to the server where it's saved to a file store. In ruby, we load this content and try to access these values. This is mostly working. Roughly, this looks like:All that is working, but this is where we run into problems:
These Panicks are identical, producing:
There's an obvious workaround here where we can encode our hashes and arrays as a JSON string, but if we're going to do that, we might as well encode the whole map as a JSON string instead of as a map in the first place.
Note that this is not a problem when we decode these values on the client side.
The text was updated successfully, but these errors were encountered: