Cannot borrow `socket` as mutable, as it is not declared as mutable

if let Ok(socket) = accept_hdr(stream, callback) {
let client_id = Uuid::new_v4().to_string();
let mut mgr_clients = mgr_clients.lock().unwrap();
mgr_clients.insert(client_id.to_owned(), socket);
match socket.read_message() {
Ok(msg) => {
...
},
Err(e) => {
...
}
}
spawn(move || {
...
});
}

Use if let Ok(mut socket) = ....

socket.read_message() error:

cannot move out of a shared reference\nmove occurs because value has type WebSocket<TcpStream>

#tungstenite

after borrow of moved value: socket\nvalue borrowed here after move

Mate, this ain't Twitter. You can write replies longer than 140 characters or whatever the limit there is.
Please paste the full error and format your code properly.

3 Likes
use std::{net::{TcpListener, TcpStream}, borrow::{Borrow, BorrowMut}};
use tungstenite::{Error, Result, accept_hdr, handshake::server::{Request, Response}, Message, WebSocket, client};
use uuid::Uuid;
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use std::thread::{spawn};
use std::sync::{Arc, Mutex};
use http;

#[derive(Serialize, Deserialize)]
struct Inf {
    hostname: String,
    ip: String,
    mac: String,
    update_time: i64
}

#[derive(Clone)]
struct App {
    fc: Arc<Mutex<AppFc>>
}

type MgrClientItem = Arc<Mutex<HashMap<String, WebSocket<TcpStream>>>>;

#[derive(Clone)]
struct AppFc {
    clients: Arc<Mutex<HashMap<String, Inf>>>,
    mgr_clients: MgrClientItem
}

const SEC: &'static str = "key";

fn check_access(v: String) -> Result<()> {
    if v == SEC {
        return Ok(())
    }
    Err(Error::ConnectionClosed)
}

impl AppFc {
    fn handle_client(&self, stream: TcpStream) -> Result<()> {
        let mgr_clients = Arc::clone(&self.mgr_clients);
        let callback = |req: &Request, response: Response| {
            if let Some(token) = req.headers().get(http::header::AUTHORIZATION) {
                let access_token = token.to_str().unwrap().to_string();
                check_access(access_token).unwrap();
            }else {
                check_access("".to_owned()).unwrap();
            }
            Ok(response)
        };
        if let Ok(mut socket) = accept_hdr(stream, callback) {
            let client_id = Uuid::new_v4().to_string();
            let mut mgr_clients = mgr_clients.lock().unwrap();
            mgr_clients.insert(client_id.to_owned(), socket);
            match socket.read_message() {
                Ok(msg) => {
                    
                },
                Err(e) => {
                    
                }
            }
            spawn(move || {
                
            });
        }
        Ok(())
    }

    fn send_mgr_clients(&self, clients: &HashMap<String, Inf>, mgr_clients: &HashMap<String, WebSocket<TcpStream>>) {
        
    }

}

impl App {
    pub fn new() -> Self {
        App {
            fc: Arc::new(Mutex::new(AppFc { 
                clients: Arc::new(Mutex::new(HashMap::new())),
                mgr_clients: Arc::new(Mutex::new(HashMap::new())),
            })),
        }
    }

    pub fn create_server(&self) {
        let server = TcpListener::bind("127.0.0.1:6500").unwrap();
        for stream in server.incoming() {
            let fc = self.fc.clone();
            spawn(move || match stream {
                Ok(stream) => {
                    if let Err(err) = fc.lock().unwrap().handle_client(stream) {
                        match err {
                            Error::ConnectionClosed | Error::Protocol(_) | Error::Utf8 => (),
                            _ => {}
                        }
                    }
                },
                Err(_) => {}
            });
        }
    }
}

fn main() {
    let app = App::new();
    app.create_server();
}

Thanks for the reminder, I added the full code

And the full error? Formatted the way that cargo build prints it, please.

error[E0382]: borrow of moved value: socket
--> src\main.rs:56:19
|
52 | if let Ok(mut socket) = accept_hdr(stream, callback) {
| ---------- move occurs because socket has type WebSocket<TcpStream>, which does not implement the Copy trait
...
55 | mgr_clients.insert(client_id.to_owned(), socket);
| ------ value moved here
56 | match socket.read_message() {
| ^^^^^^^^^^^^^^^^^^^^^ value borrowed here after move

Rust enforces the single owner principle. The mgr_clients.insert(client_id.to_owned(), socket) call moves socket into mgr_clients. After the move, the socket variable no longer owns the socket, so you cannot access the socket via the socket variable.

One thing you could do is to do mgr_clients.get(&client_id) to get a reference to the socket that is now inside mgr_clients, but as a general design comment, you should not put an IO resource inside a hash map in the first place — that's almost always a design mistake. One possible alternate design is the actor pattern, where you put a handle to the websocket inside the map, instead of the socket itself. (The linked article uses async/await, but you can use the same pattern in non-async code too.)

1 Like