1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//! Netidx is like DNS for values. With netidx you can name individual
//! values in your program, and other programs can find and subscribe
//! to those values securely over the network.
//!
//! Like DNS netidx maintains a hierarchical namespace in a resolver
//! server. Publishers tell the resolver about values they
//! have. Subscribers ask the resolver for values they want. Once a
//! subscriber knows where to find a value it is looking for, it
//! connects directly to the publisher, and the resolver is no longer
//! involved.
//!
//! # Publisher
//! ```no_run
//! # fn get_cpu_temp() -> f32 { 42. }
//! use netidx::{
//!     publisher::{Publisher, Value, BindCfg},
//!     config::Config,
//!     resolver::Auth,
//!     path::Path,
//! };
//! use tokio::time;
//! use std::time::Duration;
//!
//! # use anyhow::Result;
//! # async fn run() -> Result<()> {
//! // load the site cluster config. You can also just use a file.
//! let cfg = Config::load_default()?;
//!
//! // no authentication (kerberos v5 is the other option)
//! // listen on any unique address matching 192.168.0.0/16
//! let publisher = Publisher::new(cfg, Auth::Anonymous, "192.168.0.0/16".parse()?).await?;
//!
//! let temp = publisher.publish(
//!     Path::from("/hw/washu-chan/cpu-temp"),
//!     Value::F32(get_cpu_temp())
//! )?;
//! publisher.flush(None).await;
//!
//! loop {
//!     time::sleep(Duration::from_millis(500)).await;
//!     temp.update(Value::F32(get_cpu_temp()));
//!     publisher.flush(None).await;
//! }
//! # Ok(())
//! # };
//! ```
//!
//! # Subscriber
//! ```no_run
//! use netidx::{
//!     subscriber::Subscriber,
//!     config::Config,
//!     resolver::Auth,
//!     path::Path,
//! };
//! use futures::{prelude::*, channel::mpsc};
//! # use anyhow::Result;
//!
//! # async fn run() -> Result<()> {
//! let cfg = Config::load_default()?;
//! let subscriber = Subscriber::new(cfg, Auth::Anonymous)?;
//! let path = Path::from("/hw/washu-chan/cpu-temp");
//! let temp = subscriber.subscribe_one(path, None).await?;
//! println!("washu-chan cpu temp is: {:?}", temp.last());
//!
//! let (tx, mut rx) = mpsc::channel(10);
//! temp.updates(false, tx);
//! while let Some(mut batch) = rx.next().await {
//!     for (_, v) in batch.drain(..) {
//!         println!("washu-chan cpu temp is: {:?}", v);
//!     }
//! }
//! # Ok(())
//! # };
//! ```
//!
//! Published values always have a value, and new subscribers receive
//! the most recent published value initially. Thereafter a
//! subscription is a lossless ordered stream, just like a tcp
//! connection, except that instead of bytes `publisher::Value` is the
//! unit of transmission. Since the subscriber can write values back
//! to the publisher, the connection is bidirectional, also like a Tcp
//! stream.
//!
//! Values include many useful primitives, including zero copy bytes
//! buffers (using the awesome bytes crate), so you can easily use
//! netidx to efficiently send any kind of message you like. However
//! it's advised to stick to primitives and express structure with
//! muliple published values in a hierarchy, since this makes your
//! system more discoverable, and is also quite efficient.
//!
//! In many environments security is a requirement, whereas in others
//! it's not necessary. To handle both of these cases netidx includes
//! optional support for kerberos v5 (including Active Directory). If
//! enabled, all components will do mutual authentication between the
//! resolver, subscriber, and publisher as well as encryption of all
//! data on the wire. In addition to authentication, the resolver
//! server in krb5 mode maintains and enforces authorization
//! permissions for the entire namespace, so the resolvers can
//! centrally enforce who can publish where, and who can subscribe to
//! what.
//!
//! * Publish with a [`Publisher`](publisher/struct.Publisher.html)
//! * Subscribe with a [`Subscriber`](subscriber/struct.Subscriber.html)
#![recursion_limit = "1024"]
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate pin_utils;
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate anyhow;

pub mod pool;
mod pack;
mod batch_channel;
#[macro_use]
pub mod utils;
mod auth;
mod channel;
pub mod chars;
pub mod config;
mod os;
pub mod path;
mod protocol;
pub mod publisher;
pub mod resolver;
pub mod resolver_server;
mod resolver_single;
mod shard_resolver_store;
mod resolver_store;
mod secstore;
pub mod subscriber;
#[cfg(test)]
mod test;