Search code examples
rustfile-ioserde-json

Cannot write file without appending to it


I am trying to write to a json file but it kepts appending to the files instead of overwriting it, even when I set append to false

What did i do wrong? thx

use serde::{Deserialize, Serialize};
use serde_json::{json, Map, Value};
use sha2::{Digest, Sha256};
use std::{error::Error, fs::{OpenOptions}, io::prelude::*};

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Session {
    username: String,
    hashed_ip: String,
    session_id: String,
    expires_at: u64,
}

impl Session {
    pub fn add(&self) -> Result<(), Box<dyn Error>> {
        let session_path = "./storage/sessions/current_sessions.json";
        let mut file = OpenOptions::new()
            .write(true)
            .read(true)
            .append(false)
            .open(session_path)?;
        let mut file_content = String::new();
        file.read_to_string(&mut file_content)?;
        let sessions_value = serde_json::from_str(&file_content)?;
        let mut sessions;
        if let Value::Object(map) = sessions_value {
            sessions = map;
        } else {
            sessions = Map::new();
        }
        let clean = SessionClean::from_session(self);
        sessions.insert(self.session_id.clone(), serde_json::to_value(clean)?);
        println!("{}", Value::Object(sessions.clone()).to_string());
        file.write_all(Value::Object(sessions.clone()).to_string().as_str().as_bytes())?;
        file.flush()?;
        Ok(())
    }
}

Expected result be:

{"some_session_id":{"expires_at":1646583038,"hashed_ip":"1ea442a134b2a184bd5d40104401f2a37fbc09ccf3f4bc9da161c6099be3691d","username":"Someone"}}

Instead this happened:

{}{"some_session_id":{"expires_at":1646583038,"hashed_ip":"1ea442a134b2a184bd5d40104401f2a37fbc09ccf3f4bc9da161c6099be3691d","username":"Someone"}}

heres the whole code: https://github.com/Siriusmart/siribot-registry


Solution

  • You are reading the file before writing it. That makes the cursor to be located at the end of the file. You would have to set it to the initial position before writing. For example using Seek::rewind

    Example from the documentation:

    use std::io::{Read, Seek, Write};
    use std::fs::OpenOptions;
    
    let mut f = OpenOptions::new()
        .write(true)
        .read(true)
        .create(true)
        .open("foo.txt").unwrap();
    
    let hello = "Hello!\n";
    write!(f, "{}", hello).unwrap();
    f.rewind().unwrap();
    
    let mut buf = String::new();
    f.read_to_string(&mut buf).unwrap();
    assert_eq!(&buf, hello);