1

I have a problme serializing/desserializing an struct with serde_json in rust, i had used the impl's (dont used derive) that are on serde_json:ser and serde_json:de, but something is happening when i try to write it in a file, i hava thread (this is the unique thread that open that file) that is in a loop saving some data to a file named "config.json", but some times it saves an extra '}' at the end of the file and i don't know why.

{"Alive":true,...,"Threads":20}}
pub fn write_config(data: &Struct_object) -> () {
    let file = OpenOptions::new().read(true).write(true).create(true).open("config.json");
    let mut refval: Struct_object = data.clone();

    match to_string::<Struct_object>(&mut refval) {
        Ok(u) => {
            match file {
                Ok(mut s) => match s.write(u.as_bytes()) {
                    Ok(_) => (),
                    Err(u) => warn!("Config.json couldn't be writen, data: {{ {} }}, Error: {{ {} }}", data, u),
                },
                Err(t) => {
                    warn!("Config.json couldn't be writen, data: {{ {} }}, Error: {{ {} }}", data, t);
                },
            }
        },
        Err(v) => warn!("Config.json couldn't be writen, data: {{ {} }}, Error: {{ {} }}", data, v),
    }


}
pub fn read_config() -> Struct_object{
    if file_exist() {
        let file = OpenOptions::new().read(true).open("config.json");
        let mut buf = String::new();

        match file {
            Ok(mut s) => {
                let _ = s.read_to_string(&mut buf);
                match from_str::<Struct_object>(&buf) {
                Ok(t) => t,
                Err(u) => {
                    warn!("config.json couldn't be loaded, loading default configuration, Error: {}", u);
                    Struct_object::default()
                }
            }
        },
            Err(v) => {warn!("config.json couldn't be readed, loading default configuration, Error: {}", v);
            Struct_object::default()},
        }
    } else {
        //write_config(&Struct_object::default());
        Struct_object::default()
    }

}

there is the code to read and write the data, and the loop is something like this:

pub fn daemon_variable_set(val: Struct_object) {
    loop {
        let data = read_config();
        val.write_rpc_url(data.read_rpc_url());
        thread::sleep(Duration::from_secs(1));
        write_config(&val);
        thread::sleep(Duration::from_secs(1));
        if !val.read_alive() {
            break;
        }
    }
    info!("Thread variable_set stop");
}

the information in the Struct_object are Arc<RwLock>, but in the serde is saving just the information of the primitive, and at read, i create the Arc to encapsulate the Primitives, so, i dont understand why is adding this extra '}' at the end of the line

Also i tried with the next, but was worst

use serde_json::de::from_reader;
use serde_json::ser::to_writer;
Dykeiichi
  • 21
  • 1

2 Answers2

3

You're overwriting the config.txt file but you aren't truncating it before writing to it, so data from previous writes can be seen if the data being written is shorter.

Before:

{"foo":12}

After writing {"foo":5} without truncating the file (since its 1 character shorter):

{"foo":5}}

You should simply use File::create:

Opens a file in write-only mode.

This function will create a file if it does not exist, and will truncate it if it does.

It will internally use .write(true).create(true).truncate(true) which is usually what you want when writing to a file like this.

kmdreko
  • 42,554
  • 6
  • 57
  • 106
1

You are missing a call to std::fs::OpenOptions::truncate(true) in your write_config() function.

Without that, the file will be written to, overwriting the previous content, but leaving the previous content in place. If the file's conent from the previous iteration of write_config happens to be longer by exactly one character (for instance: some value changes from 123 to 99), that will show up as an "extra" } during the next read.

user2722968
  • 13,636
  • 2
  • 46
  • 67