aboutsummaryrefslogtreecommitdiff
path: root/jsonrpc/README.md
blob: 83107d4bdc5b8cc948dda47f056c9742999ca9ed (plain)
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
# karyon jsonrpc

A fast and lightweight async implementation of [JSON-RPC
2.0](https://www.jsonrpc.org/specification).

features: 
- Supports TCP, TLS, WebSocket, and Unix protocols.
- Uses `smol`(async-std) as the async runtime, but also supports `tokio` via the 
  `tokio` feature.
- Allows registration of multiple services (structs) of different types on a
  single server.
- Supports pub/sub  
- Allows passing an `async_executors::Executor` or tokio's `Runtime` when building
  the server.


## Install 

```bash
    
$ cargo add karyon_jsonrpc 

```

## Example

```rust
use std::{sync::Arc, time::Duration};

use serde_json::Value;
use smol::stream::StreamExt;

use karyon_jsonrpc::{
    RPCError, Server, Client, rpc_impl, rpc_pubsub_impl, SubscriptionID, Channel
};

struct HelloWorld {}

#[rpc_impl]
impl HelloWorld {
    async fn say_hello(&self, params: Value) -> Result<Value, RPCError> {
        let msg: String = serde_json::from_value(params)?;
        Ok(serde_json::json!(format!("Hello {msg}!")))
    }

    async fn foo(&self, params: Value) -> Result<Value, RPCError> {
        Ok(serde_json::json!("foo!"))
    }

    async fn bar(&self, params: Value) -> Result<Value, RPCError> {
        Ok(serde_json::json!("bar!"))
    }
}

#[rpc_pubsub_impl]
impl HelloWorld {
    async fn log_subscribe(&self, chan: Arc<Channel>, method: String, _params: Value) -> Result<Value, RPCError> {
        let sub = chan.new_subscription(&method).await;
        let sub_id = sub.id.clone();
        smol::spawn(async move {
            loop {
                smol::Timer::after(std::time::Duration::from_secs(1)).await;
                if let Err(err) = sub.notify(serde_json::json!("Hello")).await {
                    println!("Failed to send notification: {err}");
                    break;
                }
            }
        })
        .detach();

        Ok(serde_json::json!(sub_id))
    }

    async fn log_unsubscribe(&self, chan: Arc<Channel>, method: String, params: Value) -> Result<Value, RPCError> {
        let sub_id: SubscriptionID = serde_json::from_value(params)?;
        chan.remove_subscription(&sub_id).await;
        Ok(serde_json::json!(true))
    }
}


// Server
async {
    let service = Arc::new(HelloWorld {});
    // Creates a new server

    let server = Server::builder("tcp://127.0.0.1:60000")
        .expect("create new server builder")
        .service(service.clone())
        .pubsub_service(service)
        .build()
        .await
        .expect("build the server");

    // Starts the server
    server.start();

    smol::Timer::after(Duration::MAX).await;
};

// Client
async {
    // Creates a new client
    let client = Client::builder("tcp://127.0.0.1:60000")
        .expect("create new client builder")
        .build()
        .await
        .expect("build the client");

    let result: String = client.call("HelloWorld.say_hello", "world".to_string())
        .await
        .expect("send a request");

    let sub = client
            .subscribe("HelloWorld.log_subscribe", ())
            .await
            .expect("Subscribe to log_subscribe method");

    let sub_id = sub.id();
    smol::spawn(async move {
        loop {
            let m = sub.recv().await.expect("Receive new log msg");
            println!("Receive new log {m}");
        }
    })
    .detach();

    // Unsubscribe after 5 seconds
    smol::Timer::after(std::time::Duration::from_secs(5)).await;

    client
        .unsubscribe("HelloWorld.log_unsubscribe", sub_id)
        .await
        .expect("Unsubscribe from log_unsubscirbe method");
};

```

## Supported Client Implementations 

- [X] [Golang](https://github.com/karyontech/karyon-go)
- [ ] Python 
- [ ] JavaScript/TypeScript