Skip to content

Commit

Permalink
eh
Browse files Browse the repository at this point in the history
  • Loading branch information
probable-basilisk committed Nov 2, 2019
1 parent 5670e3a commit 9bf076d
Show file tree
Hide file tree
Showing 5 changed files with 286 additions and 1 deletion.
14 changes: 14 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "pollws"
version = "0.1.0"
authors = ["Probable Basilisk"]

[dependencies]
url = "2.1.0"

[dependencies.ws]
version = "0.9.0"

[lib]
name = "pollws"
crate-type = ["dylib"]
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,22 @@
# pollws
Single DLL, C api, polling-based websocket client
Single DLL, C api, polling-based websocket client. Basically
a wrapper to the "ws" Rust library.

## Warning
This is probably the worst piece of Rust code ever written.

## Building
Assuming you're on a 64 bit machine,
building for 64 bit:
```
cargo build --release
```

However to use this from a 32 bit Windows binary (e.g., Noita),
you'll need to build for 32 bit:
```
rustup target add i686-pc-windows-msvc
cargo build --target=i686-pc-windows-msvc --release
```

The resulting .dll will end up in `target/i686-pc-windows-msvc/release/pollws.dll`.
47 changes: 47 additions & 0 deletions bindings/pollws.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
local ffi = ffi or _G.ffi or require("ffi")
ffi.cdef[[
struct pollsocket* pollws_open(const char* url);
void pollws_close(struct pollsocket* ctx);
int pollws_status(struct pollsocket* ctx);
void pollws_send(struct pollsocket* ctx, const char* msg);
int pollws_poll(struct pollsocket* ctx);
unsigned int pollws_get(struct pollsocket* ctx, char* dest, unsigned int dest_size);
unsigned int pollws_pop(struct pollsocket* ctx, char* dest, unsigned int dest_size);
]]

local pollws = ffi.load("pollws")

local socket_mt = {}
function socket_mt:open(url, scratch_size)
if self._socket then self:close() end
if not scratch_size then scratch_size = 64000 end
self._socket = pollws.pollws_open(url),
self._scratch = ffi.new("int8_t[?]", scratch_size),
self._scratch_size = scratch_size
end
function socket_mt:poll()
if not self._socket then return end
local msg_size = pollws.pollws_pop(self._socket, self._scratch, self._scratch_size)
if msg_size > 0 then
local smsg = ffi.string(self._scratch, msg_size)
return smsg
else
return nil
end
end
function socket_mt:send(msg)
if not self._socket then return end
pollws.pollws_send(self._socket, msg)
end
function socket_mt:close()
pollws.pollws_close(self._socket)
self._socket = nil
end

local function open(url, scratch_size)
local socket = setmetatable({}, {__index = socket_mt})
socket:open(url, scratch_size)
return socket
end

return {open = open, pollws = pollws}
19 changes: 19 additions & 0 deletions include/pollws.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#include <stddef.h>

typedef enum pollws_status_type
{
CLOSED,
OPENING,
OPEN,
ERROR,
} pollws_status_t;

typedef struct PollWSSocket PollWSSocket;

PollWSSocket* pollws_open(const char* url);
void pollws_close(PollWSSocket* ctx);
pollws_status_t pollws_status(PollWSSocket* ctx);
void pollws_send(PollWSSocket* ctx, const char* msg);
int pollws_poll(PollWSSocket* ctx);
unsigned int pollws_get(PollWSSocket* ctx, char* dest, unsigned int dest_size);
unsigned int pollws_pop(PollWSSocket* ctx, char* dest, unsigned int dest_size);
185 changes: 185 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
extern crate ws;
extern crate url;

use std::thread;
use std::sync::mpsc::channel;
//use libc::c_char;
use std::os::raw::c_char;
use std::ffi::CStr;

#[repr(C)]
#[derive(Copy, Clone)]
pub enum PollWSStatus {
CLOSED,
OPENING,
OPEN,
ERROR,
}

// working version?

enum SocketMessage {
Connect,
Disconnect,
Message(ws::Message),
}


pub struct PollWSSocket {
status: PollWSStatus,
sender: ws::Sender,
thread: Option<thread::JoinHandle<()>>,
rx: std::sync::mpsc::Receiver<SocketMessage>,
message: Option<ws::Message>,
}

impl PollWSSocket {
fn poll(&mut self) -> bool {
let mut got_message = false;
while let Ok(msg) = self.rx.try_recv() {
println!("We got a message!");
match msg {
SocketMessage::Connect => {
self.status = PollWSStatus::OPEN;
},
SocketMessage::Disconnect => {
self.status = PollWSStatus::CLOSED;
break
},
SocketMessage::Message(msg) => {
self.message = Some(msg);
got_message = true;
break
},
};
};
got_message
}

fn send(&mut self, msg: ws::Message) {
match self.status {
PollWSStatus::OPEN => self.sender.send(msg).unwrap_or_default(),
_ => (),
};
}

fn close(&mut self) {
match self.status {
PollWSStatus::OPEN | PollWSStatus::OPENING => {
self.sender.shutdown().unwrap_or_default();
self.status = PollWSStatus::CLOSED;
},
_ => (),
}
if let Some(handle) = self.thread.take() {
handle.join().unwrap_or_default();
};
}

fn new(url: String) -> PollWSSocket {
println!("Trying to make a socket!");
let (tx, rx) = channel();
let mut socket = ws::Builder::new().build(move |_| {
tx.send(SocketMessage::Connect).unwrap_or_default();
println!("Sending the message that we connecte!");
let tx2 = tx.clone();
move |msg| {
tx2.send(SocketMessage::Message(msg)).unwrap_or_default();
Ok(())
}
}).unwrap();
let handle = socket.broadcaster();
let t = thread::spawn(move || {
let actual_url = url::Url::parse(&url).unwrap();
match socket.connect(actual_url) {
Ok(_) => {
println!("So far so good!");
socket.run();
true
},
Err(err) => {
println!("Failed to create WebSocket due to: {:?}", err);
false
},
};
});

PollWSSocket {
status: PollWSStatus::OPENING,
sender: handle,
thread: Some(t),
rx: rx,
message: None,
}
}
}

#[no_mangle]
pub extern fn pollws_open(url: *const c_char) -> *mut PollWSSocket {
let url = unsafe { CStr::from_ptr(url).to_string_lossy().into_owned() };
Box::into_raw(Box::new(PollWSSocket::new(url)))
}

#[no_mangle]
pub extern fn pollws_close(ctx: *mut PollWSSocket) {
let ctx = unsafe{&mut *ctx};
ctx.close();

// take ownership and drop
let b = unsafe{ Box::from_raw(ctx) };
drop(b);
}

#[no_mangle]
pub extern fn pollws_status(ctx: *mut PollWSSocket) -> PollWSStatus {
let ctx = unsafe{&*ctx};
ctx.status
}

// #[no_mangle]
// pub extern fn pollws_send(ctx: *mut PollWSSocket, msg: *const u8, msg_len: u32) {
// let ctx = unsafe{&mut *ctx};
// let bytes = unsafe { std::slice::from_raw_parts(msg, msg_len) };
// ctx.send(ws_msg);
// }

#[no_mangle]
pub extern fn pollws_send(ctx: *mut PollWSSocket, msg: *const c_char) {
let ctx = unsafe{&mut *ctx};
let msg = unsafe { CStr::from_ptr(msg).to_string_lossy().into_owned() };
ctx.send(ws::Message::text(msg));
}

#[no_mangle]
pub extern fn pollws_poll(ctx: *mut PollWSSocket) -> bool {
let ctx = unsafe{&mut *ctx};
ctx.poll()
}

#[no_mangle]
pub extern fn pollws_get(ctx: *mut PollWSSocket, dest: *mut u8, dest_size: u32) -> u32 {
let ctx = unsafe{&mut *ctx};
match ctx.message.take() {
Some(msg) => {
let ncopy = msg.len();
if ncopy < (dest_size as usize) {
unsafe {
std::ptr::copy_nonoverlapping(msg.into_data().as_ptr(), dest, ncopy);
}
ncopy as u32
} else {
0
}
},
None => 0,
}
}

#[no_mangle]
pub extern fn pollws_pop(ctx: *mut PollWSSocket, dest: *mut u8, dest_size: u32) -> u32 {
if pollws_poll(ctx) {
pollws_get(ctx, dest, dest_size)
} else {
0
}
}

0 comments on commit 9bf076d

Please sign in to comment.