mirror of
https://github.com/EasyTier/EasyTier.git
synced 2026-05-07 02:09:06 +00:00
feat/web (Patchset 2) (#444)
This patch implement a restful server without any auth.
usage:
```bash
# run easytier-web, which acts as an gateway and registry for all easytier-core
$> easytier-web
# run easytier-core and connect to easytier-web with a token
$> easytier-core --config-server udp://127.0.0.1:22020/fdsafdsa
# use restful api to list session
$> curl -H "Content-Type: application/json" -X GET 127.0.0.1:11211/api/v1/sessions
[{"token":"fdsafdsa","client_url":"udp://127.0.0.1:48915","machine_id":"de3f5b8f-0f2f-d9d0-fb30-a2ac8951d92f"}]%
# use restful api to run a network instance
$> curl -H "Content-Type: application/json" -X POST 127.0.0.1:11211/api/v1/network/de3f5b8f-0f2f-d9d0-fb30-a2ac8951d92f -d '{"config": "listeners = [\"udp://0.0.0.0:12344\"]"}'
# use restful api to get network instance info
$> curl -H "Content-Type: application/json" -X GET 127.0.0.1:11211/api/v1/network/de3f5b8f-0f2f-d9d0-fb30-a2ac8951d92f/65437e50-b286-4098-a624-74429f2cb839
```
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
use std::{fmt::Debug, sync::Arc};
|
||||
|
||||
use easytier::{
|
||||
proto::{
|
||||
rpc_impl::bidirect::BidirectRpcManager,
|
||||
rpc_types::{self, controller::BaseController},
|
||||
web::{
|
||||
HeartbeatRequest, HeartbeatResponse, WebClientService, WebClientServiceClientFactory,
|
||||
WebServerService, WebServerServiceServer,
|
||||
},
|
||||
},
|
||||
tunnel::Tunnel,
|
||||
};
|
||||
use tokio::sync::{broadcast, RwLock};
|
||||
|
||||
use super::storage::{Storage, StorageToken, WeakRefStorage};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SessionData {
|
||||
storage: WeakRefStorage,
|
||||
client_url: url::Url,
|
||||
|
||||
storage_token: Option<StorageToken>,
|
||||
notifier: broadcast::Sender<HeartbeatRequest>,
|
||||
req: Option<HeartbeatRequest>,
|
||||
}
|
||||
|
||||
impl SessionData {
|
||||
fn new(storage: WeakRefStorage, client_url: url::Url) -> Self {
|
||||
let (tx, _rx1) = broadcast::channel(2);
|
||||
|
||||
SessionData {
|
||||
storage,
|
||||
client_url,
|
||||
storage_token: None,
|
||||
notifier: tx,
|
||||
req: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn req(&self) -> Option<HeartbeatRequest> {
|
||||
self.req.clone()
|
||||
}
|
||||
|
||||
pub fn heartbeat_waiter(&self) -> broadcast::Receiver<HeartbeatRequest> {
|
||||
self.notifier.subscribe()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for SessionData {
|
||||
fn drop(&mut self) {
|
||||
if let Ok(storage) = Storage::try_from(self.storage.clone()) {
|
||||
if let Some(token) = self.storage_token.as_ref() {
|
||||
storage.remove_client(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type SharedSessionData = Arc<RwLock<SessionData>>;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct SessionRpcService {
|
||||
data: SharedSessionData,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl WebServerService for SessionRpcService {
|
||||
type Controller = BaseController;
|
||||
|
||||
async fn heartbeat(
|
||||
&self,
|
||||
_: BaseController,
|
||||
req: HeartbeatRequest,
|
||||
) -> rpc_types::error::Result<HeartbeatResponse> {
|
||||
let mut data = self.data.write().await;
|
||||
if data.req.replace(req.clone()).is_none() {
|
||||
assert!(data.storage_token.is_none());
|
||||
data.storage_token = Some(StorageToken {
|
||||
token: req.user_token.clone().into(),
|
||||
client_url: data.client_url.clone(),
|
||||
machine_id: req
|
||||
.machine_id
|
||||
.clone()
|
||||
.map(Into::into)
|
||||
.unwrap_or(uuid::Uuid::new_v4()),
|
||||
});
|
||||
if let Ok(storage) = Storage::try_from(data.storage.clone()) {
|
||||
storage.add_client(data.storage_token.as_ref().unwrap().clone());
|
||||
}
|
||||
}
|
||||
let _ = data.notifier.send(req);
|
||||
Ok(HeartbeatResponse {})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Session {
|
||||
rpc_mgr: BidirectRpcManager,
|
||||
|
||||
data: SharedSessionData,
|
||||
}
|
||||
|
||||
impl Debug for Session {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Session").field("data", &self.data).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Session {
|
||||
pub fn new(tunnel: Box<dyn Tunnel>, storage: WeakRefStorage, client_url: url::Url) -> Self {
|
||||
let rpc_mgr =
|
||||
BidirectRpcManager::new().set_rx_timeout(Some(std::time::Duration::from_secs(30)));
|
||||
rpc_mgr.run_with_tunnel(tunnel);
|
||||
|
||||
let data = Arc::new(RwLock::new(SessionData::new(storage, client_url)));
|
||||
|
||||
rpc_mgr.rpc_server().registry().register(
|
||||
WebServerServiceServer::new(SessionRpcService { data: data.clone() }),
|
||||
"",
|
||||
);
|
||||
|
||||
Session { rpc_mgr, data }
|
||||
}
|
||||
|
||||
pub fn is_running(&self) -> bool {
|
||||
self.rpc_mgr.is_running()
|
||||
}
|
||||
|
||||
pub fn data(&self) -> SharedSessionData {
|
||||
self.data.clone()
|
||||
}
|
||||
|
||||
pub fn scoped_rpc_client(
|
||||
&self,
|
||||
) -> Box<dyn WebClientService<Controller = BaseController> + Send> {
|
||||
self.rpc_mgr
|
||||
.rpc_client()
|
||||
.scoped_client::<WebClientServiceClientFactory<BaseController>>(1, 1, "".to_string())
|
||||
}
|
||||
|
||||
pub async fn get_token(&self) -> Option<StorageToken> {
|
||||
self.data.read().await.storage_token.clone()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user