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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
//! # Webwire command-line Interface
//!
//! [![Crates.io](https://img.shields.io/crates/v/webwire-cli)](https://crates.io/crates/webwire-cli)
//! [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/webwire/webwire-cli/Rust)](https://github.com/webwire/webwire-cli/actions)
//!
//! [![Discord Chat](https://img.shields.io/discord/726922033039933472?label=Discord+Chat&color=%23677bc4&logo=discord&logoColor=white&style=for-the-badge)](https://discord.gg/jjD6aWG)
//!
//! ![webwire logo](https://webwire.dev/logo.svg)
//!
//! Webwire is a **contract-first API system** which features an
//! interface description language a network protocol and
//! code generator for both servers and clients.
//!
//! This repository contains the the **command-line interface** used
//! to validate Webwire IDL files and generate code and documentation.
//!
//! To learn more about webwire in general please visit the documentation
//! repository [webwire/webwire-docs](https://github.com/webwire/webwire-docs).
//!
//! # Example
//!
//! The following example assumes a Rust server and a TypeScript client. Webwire
//! is by no means limited to those two but those languages show the potential of
//! webwire best.
//!
//! Given the following IDL file:
//!
//! ```webwire
//! struct HelloRequest {
//!     name: String,
//! }
//!
//! struct HelloResponse {
//!     message: String,
//! }
//!
//! service Hello {
//!     hello: HelloRequest -> HelloResponse
//! }
//! ```
//!
//! The server and client files can be generated using the code generator:
//!
//! ```bash
//! $ webwire gen rust < api/chat.ww > server/src/api.rs
//! $ webwire gen ts < api/chat.ww > client/src/api.ts
//! ```
//!
//! A Rust server implementation for the given code would look like this:
//!
//! ```rust,ignore
//! use std::net::SocketAddr;
//! use std::sync::{Arc};
//!
//! use async_trait::async_trait;
//!
//! use ::api::chat;
//!
//! use ::webwire::server::hyper::MakeHyperService;
//! use ::webwire::server::session::{Auth, AuthError};
//! use ::webwire::{Response, Router, Server, ConsumerError};
//!
//! struct ChatService {
//!     #[allow(dead_code)]
//!     session: Arc<Session>,
//!     server: Arc<Server<Session>>,
//! }
//!
//! #[async_trait]
//! impl chat::Server<Session> for ChatService {
//!     async fn send(&self, message: &chat::Message) -> Response<Result<(), chat::SendError>> {
//!         let client = chat::ClientConsumer(&*self.server);
//!         assert!(matches!(client.on_message(message).await, Err(ConsumerError::Broadcast)));
//!         Ok(Ok(()))
//!     }
//! }
//!
//! #[derive(Default)]
//! struct Session {}
//!
//! struct Sessions {}
//!
//! impl Sessions {
//!     pub fn new() -> Self {
//!         Self {}
//!     }
//! }
//!
//! #[async_trait]
//! impl webwire::SessionHandler<Session> for Sessions {
//!     async fn auth(&self, _auth: Option<Auth>) -> Result<Session, AuthError> {
//!         Ok(Session::default())
//!     }
//!     async fn connect(&self, _session: &Session) {}
//!     async fn disconnect(&self, _session: &Session) {}
//! }
//!
//! #[tokio::main]
//! async fn main() {
//!     // Create session handler
//!     let session_handler = Sessions::new();
//!
//!     // Create service router
//!     let router = Arc::new(Router::<Session>::new());
//!
//!     // Create webwire server
//!     let server = Arc::new(webwire::server::Server::new(
//!         session_handler,
//!         router.clone(),
//!     ));
//!
//!     // Register services
//!     router.service(chat::ServerProvider({
//!         let server = server.clone();
//!         move |session| ChatService {
//!             session,
//!             server: server.clone(),
//!         }
//!     }));
//!
//!     // Start hyper service
//!     let addr = SocketAddr::from(([0, 0, 0, 0], 2323));
//!     let make_service = MakeHyperService { server };
//!     let server = hyper::Server::bind(&addr).serve(make_service);
//!
//!     if let Err(e) = server.await {
//!         eprintln!("server error: {}", e);
//!     }
//! }
//! ```
//!
//! A TypeScript client using the generated code would look like that:
//!
//! ```typescript
//! import { Client } from 'webwire'
//! import api from 'api' // this is the generated code
//!
//! let client = new Client('http://localhost:8000/', [
//!     api.chat.ClientProvider({
//!         async on_message(message) {
//!             console.log("Message received:", message)
//!         }
//!     })
//! ])
//!
//! assert(await client.connect())
//!
//! let chat = api.chat.ServerConsumer(client)
//! let response = await chat.message({ text: "Hello world!" })
//!
//! assert(response.Ok === null)
//! ```
//!
//! ## License
//!
//! Licensed under either of
//!
//! - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0)>
//! - MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT)>
//!
//! at your option.
pub mod codegen;
pub mod common;
pub mod idl;
pub mod schema;