#Self and threading

10 messages · Page 1 of 1 (latest)

indigo mango
#
use std::io::{self, Read, Write};

use std::net::{TcpListener, TcpStream};
use std::sync::{mpsc, Arc, Mutex};
use std::thread;

use serde_derive::{Deserialize, Serialize};

use crate::devices;


pub struct IotServer {
    ip:String,
    port:u32,
    listener:TcpListener,
    handles:Vec<thread::JoinHandle<()>>
}

impl IotServer {
    pub fn open(ip:&str, port:u32) -> io::Result<Self> {
        let listener = TcpListener::bind(format!("{}:{}", &ip, &port))?;

        Ok(IotServer {
            ip:ip.to_string(),
            port,
            listener,
            handles:vec![],
        })
    }

    pub fn start(&mut self) {
        println!("Starting IOT Server On IP:{} PORT:{}...", self.ip, self.port);
        self.listen();
    }

    pub fn listen(&mut self) {
        for stream in self.listener.incoming() {
            match stream {
                Err(_) => {
                },
                Ok(mut ok_stream) => {
                    let handle = thread::spawn(move || {
                        self.handle_request(ok_stream);
                    });
                    self.handles.push(handle);
                }
            }
        }
    }

    pub fn handle_request(&self, mut stream:TcpStream) {
        let mut buffer = [0; 1024]; // Buffer size
        stream
            .read(&mut buffer)
            .expect("Failed To Read From Client"); // Reads stream data then puts it into the buffer

        // Turns buffer data into string but handles messy data
        let request = String::from_utf8_lossy(&buffer[..]);
        println!("Received Request {request}");

        let response = "Hello, Client".as_bytes();
        stream.write(response).expect("Failed To Respond");
    }

    pub fn shutdown(&mut self) {
        println!("Shutting Down Server...");
        for handle in self.handles.drain(..) {
            handle.join().unwrap();
        }
        println!("Server Shut Down");
    }
}

#

This is the Error Message

error[E0521]: borrowed data escapes outside of method
36 |       pub fn listen(&mut self) {
   |                     ---------
   |                     |
   |                     `self` is a reference that is only valid in the method body
   |                     let's call the lifetime of this reference `'1`
...
42 |                       let handle = thread::spawn(move || {
   |  ^
43 | |                         self.handle_request(ok_stream);
44 | |                     });
   | |                      ^
   | |                      |
   | |______________________`self` escapes the method body here
   |                        argument requires that `'1` must outlive `'static`
error[E0505]: cannot move out of `self` because it is borrowed
36 |     pub fn listen(&mut self) {
   |                   --------- binding `self` declared here
37 |         for stream in self.listener.incoming() {
   |                       ------------- borrow of `self.listener` occurs here
...
42 |                     let handle = thread::spawn(move || {
   |                                                ^^^^^^^ move out of `self` occurs here
43 |                         self.handle_request(ok_stream);
   |                         ---- move occurs due to use in closure
error[E0382]: borrow of moved value: `self`
  --> src\server.rs:45:21
   |
36 |     pub fn listen(&mut self) {
   |                   --------- move occurs because `self` has type `&mut IotServer`, which does not implement the `Copy` trait
42 |                     let handle = thread::spawn(move || {
   |                                                ------- value moved into closure here
43 |                         self.handle_request(ok_stream);
   |                         ---- variable moved due to use in closure
44 |                     });
45 |                     self.handles.push(handle);
   |                     ^^^^^^^^^^^^ value borrowed here after move
cobalt sapphire
#

are you familiar with closures and captures yet?

#

not like a deep level necessarily, but have you at least read the relevant chapter in the book

indigo mango
#

A closure is just a function that can use local variables from where its defined but im getting conflicts with ownership right now

#

This is my current progress

    pub fn start(&mut self) {
        println!("Starting IOT Server On IP:{} PORT:{}...", self.ip, self.port);
        self.listen();
    }

    pub fn listen(&mut self) {
        let copy = Arc::new(Mutex::new(&self));
        
        for stream in self.listener.incoming() {
            match stream {
                Err(_) => {
                },
                Ok(mut ok_stream) => {
                    let handle = thread::spawn(|| {
                        self.handle_request(ok_stream);
                    });
                    self.handles.push(handle);
                }
            }
        }
    }
cobalt sapphire
#

at risk of spoiling it, see if you can change something about handle_request

indigo mango
#

what make it not use self

cobalt sapphire
#

yeah, it can just be an associated function - it's related to IotServer so it makes sense to put it in the namespace, but it doesn't make sense to borrow the IotServer when the function doesn't need to use that borrow

#

borrowing from other lang terminology, it causes an ownership problem as an instance method, but as a static method you can call it from other threads no problem