Skip to content

Commit

Permalink
Init commit
Browse files Browse the repository at this point in the history
  • Loading branch information
nickbabcock committed Aug 27, 2017
0 parents commit fa26553
Show file tree
Hide file tree
Showing 7 changed files with 267 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
@@ -0,0 +1,3 @@
/target/
**/*.rs.bk
Cargo.lock
13 changes: 13 additions & 0 deletions Cargo.toml
@@ -0,0 +1,13 @@
[package]
name = "collectd-rust-plugin"
version = "0.1.0"
authors = ["Nick Babcock <nbabcock19@hotmail.com>"]

[lib]
name = "myplugin"
crate-type = ["dylib"]

[dependencies]

[build-dependencies]
bindgen = "0.29"
38 changes: 38 additions & 0 deletions build.rs
@@ -0,0 +1,38 @@
extern crate bindgen;

use std::env;
use std::path::PathBuf;

fn main() {
// Tell cargo to tell rustc to link the system bzip2
// shared library.
// println!("cargo:rustc-link-lib=collectd");
// println!("cargo:rustc-link-search=native=/home/nick/projects/collectd");

// The bindgen::Builder is the main entry point
// to bindgen, and lets you build up options for
// the resulting bindings.
let bindings = bindgen::Builder::default()
// The input header we would like to generate
// bindings for.
.header("wrapper.h")
.clang_arg("-DHAVE_CONFIG_H")
.unstable_rust(true)
.hide_type("FP_NAN")
.hide_type("FP_INFINITE")
.hide_type("FP_ZERO")
.hide_type("FP_SUBNORMAL")
.hide_type("FP_NORMAL")
.hide_type("max_align_t")
.hide_type("module_register")
// Finish the builder and generate the bindings.
.generate()
// Unwrap the Result and panic on failure.
.expect("Unable to generate bindings");

// Write the bindings to the $OUT_DIR/bindings.rs file.
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}
164 changes: 164 additions & 0 deletions src/api.rs
@@ -0,0 +1,164 @@
#![allow(dead_code)]

use bindings::{value_t, value_list_t};
use std::os::raw::c_char;
use std::ffi::{CString, NulError};
use std::fmt;
use std::error::Error;
use ptr;

#[derive(Debug)]
pub enum CArrayError {
TooLong(usize),
NullPresent(NulError),
}

impl fmt::Display for CArrayError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
CArrayError::TooLong(l) => write!(f, "Length of {} is too long for collectd's max of 128", l),
CArrayError::NullPresent(ref err) => err.fmt(f),
}
}
}

impl Error for CArrayError {
fn description(&self) -> &str {
match *self {
CArrayError::TooLong(_) => "String must be less than 128 bytes long",
CArrayError::NullPresent(_) => "String must not contain a null character",
}
}
}

impl From<NulError> for CArrayError {
fn from(e: NulError) -> Self {
CArrayError::NullPresent(e)
}
}

pub enum Value {
Counter(u64),
Gauge(f64),
Derive(i64),
Absolute(u64),
}

impl Value {
pub fn to_value_t(&self) -> value_t {
match *self {
Value::Counter(x) => value_t { counter: x },
Value::Gauge(x) => value_t { gauge: x },
Value::Derive(x) => value_t { derive: x },
Value::Absolute(x) => value_t { absolute: x },
}
}
}

pub struct ValueListBuilder {
values: Vec<Value>,
plugin_instance: Option<String>,
plugin: String,
type_: String,
type_instance: Option<String>,
host: Option<String>,
time: Option<u64>,
interval: Option<u64>,
}

impl ValueListBuilder {
pub fn new(plugin: &str, type_: &str) -> ValueListBuilder {
ValueListBuilder {
values: Vec::new(),
plugin_instance: None,
plugin: plugin.to_owned(),
type_: type_.to_owned(),
type_instance: None,
host: None,
time: None,
interval: None,
}
}

pub fn values(mut self, values: Vec<Value>) -> ValueListBuilder {
self.values = values;
self
}

pub fn plugin_instance(mut self, plugin_instance: String) -> ValueListBuilder {
self.plugin_instance = Some(plugin_instance);
self
}

pub fn type_instance(mut self, type_instance: String) -> ValueListBuilder {
self.type_instance = Some(type_instance);
self
}

pub fn host(mut self, host: String) -> ValueListBuilder {
self.host = Some(host);
self
}

pub fn time(mut self, time: u64) -> ValueListBuilder {
self.time = Some(time);
self
}

pub fn interval(mut self, interval: u64) -> ValueListBuilder {
self.interval = Some(interval);
self
}

pub fn build(self) -> Result<value_list_t, CArrayError> {
let mut v: Vec<value_t> = self.values.iter().map(|x| x.to_value_t()).collect();
let plugin_instance = self.plugin_instance
.map(|x| to_array_res(&x))
.unwrap_or_else(|| Ok([0i8; 128]))?;

let type_instance = self.type_instance
.map(|x| to_array_res(&x))
.unwrap_or_else(|| Ok([0i8; 128]))?;

let host = self.host
.map(|x| to_array_res(&x))
.unwrap_or_else(|| Ok([0i8; 128]))?;

Ok(value_list_t {
values: v.as_mut_ptr(),
values_len: v.len(),
plugin_instance: plugin_instance,
plugin: to_array_res(&self.plugin)?,
type_: to_array_res(&self.type_)?,
type_instance: type_instance,
host: host,
time: self.time.unwrap_or(0),
interval: self.interval.unwrap_or(0),
meta: ptr::null_mut(),
})
}
}

fn to_array_res(s: &str) -> Result<[c_char; 128], CArrayError> {
let value = CString::new(s)?;
let data = value.as_bytes_with_nul();
if data.len() > 128 {
return Err(CArrayError::TooLong(s.len()));
}

let mut arr = [0; 128];
for (i, &c) in data.into_iter().enumerate() {
arr[i] = c as c_char;
}
Ok(arr)
}

#[cfg(test)]
mod tests {
use std::mem;
use super::*;
#[test]
fn it_works2() {
assert_eq!(8, mem::size_of::<value_t>());
}
}
6 changes: 6 additions & 0 deletions src/bindings.rs
@@ -0,0 +1,6 @@
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)]

include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
40 changes: 40 additions & 0 deletions src/lib.rs
@@ -0,0 +1,40 @@
mod bindings;
mod api;

use std::os::raw::{c_int};
use std::ffi::CString;
use std::ptr;
use bindings::{plugin_register_read,plugin_dispatch_values,LOG_WARNING,plugin_log};
use api::{ValueListBuilder, Value};

#[no_mangle]
pub extern "C" fn module_register() {
let s = CString::new("myplugin").unwrap();
unsafe {
plugin_register_read(s.as_ptr(), Some(my_read));
}
}

#[no_mangle]
pub extern "C" fn my_read() -> c_int {
let s = "Entering myplugin read function";
unsafe {
let cs = CString::new(s).unwrap();
plugin_log(LOG_WARNING as i32, cs.as_ptr());
}

let values: Vec<Value> = vec![
Value::Gauge(15.0),
Value::Gauge(10.0),
Value::Gauge(12.0),
];

let r = ValueListBuilder::new("myplugin", "load")
.values(values)
.plugin_instance(String::from("testing"))
.type_instance(String::from("CpuUsage"))
.build()
.expect("it to work");
unsafe { plugin_dispatch_values(&r) }
}

3 changes: 3 additions & 0 deletions wrapper.h
@@ -0,0 +1,3 @@
#include <dlfcn.h>
#include <stdlib.h>
#include <collectd/core/daemon/plugin.h>

0 comments on commit fa26553

Please sign in to comment.