make all frontend functions works (#466)

This commit is contained in:
Sijie.Sun
2024-11-10 11:06:58 +08:00
committed by GitHub
parent e948dbfcc1
commit 88e6de9d7e
36 changed files with 1039 additions and 483 deletions
+17 -4
View File
@@ -6,8 +6,9 @@ use easytier::{
rpc_impl::bidirect::BidirectRpcManager,
rpc_types::{self, controller::BaseController},
web::{
HeartbeatRequest, HeartbeatResponse, RunNetworkInstanceRequest, WebClientService,
WebClientServiceClientFactory, WebServerService, WebServerServiceServer,
HeartbeatRequest, HeartbeatResponse, NetworkConfig, RunNetworkInstanceRequest,
WebClientService, WebClientServiceClientFactory, WebServerService,
WebServerServiceServer,
},
},
tunnel::Tunnel,
@@ -160,7 +161,13 @@ impl Session {
);
return;
}
let req = req.unwrap();
if req.machine_id.is_none() {
tracing::warn!(?req, "Machine id is not set, ignore");
continue;
}
let running_inst_ids = req
.running_network_instances
.iter()
@@ -187,7 +194,11 @@ impl Session {
}
};
let local_configs = match storage.db.list_network_configs(user_id, true).await {
let local_configs = match storage
.db
.list_network_configs(user_id, Some(req.machine_id.unwrap().into()), true)
.await
{
Ok(configs) => configs,
Err(e) => {
tracing::error!("Failed to list network configs, error: {:?}", e);
@@ -206,7 +217,9 @@ impl Session {
BaseController::default(),
RunNetworkInstanceRequest {
inst_id: Some(c.network_instance_id.clone().into()),
config: c.network_config,
config: Some(
serde_json::from_str::<NetworkConfig>(&c.network_config).unwrap(),
),
},
)
.await;
+12 -4
View File
@@ -16,7 +16,7 @@ pub struct StorageToken {
pub struct StorageInner {
// some map for indexing
pub token_clients_map: DashMap<String, DashSet<url::Url>>,
pub machine_client_url_map: DashMap<uuid::Uuid, url::Url>,
pub machine_client_url_map: DashMap<uuid::Uuid, DashSet<url::Url>>,
pub db: Db,
}
@@ -51,7 +51,9 @@ impl Storage {
self.0
.machine_client_url_map
.insert(stoken.machine_id, stoken.client_url.clone());
.entry(stoken.machine_id)
.or_insert_with(DashSet::new)
.insert(stoken.client_url.clone());
}
pub fn remove_client(&self, stoken: &StorageToken) {
@@ -60,7 +62,12 @@ impl Storage {
set.is_empty()
});
self.0.machine_client_url_map.remove(&stoken.machine_id);
self.0
.machine_client_url_map
.remove_if(&stoken.machine_id, |_, set| {
set.remove(&stoken.client_url);
set.is_empty()
});
}
pub fn weak_ref(&self) -> WeakRefStorage {
@@ -71,7 +78,8 @@ impl Storage {
self.0
.machine_client_url_map
.get(&machine_id)
.map(|url| url.clone())
.map(|url| url.iter().next().map(|url| url.clone()))
.flatten()
}
pub fn list_token_clients(&self, token: &str) -> Vec<url::Url> {
@@ -9,6 +9,8 @@ pub struct Model {
#[sea_orm(primary_key)]
pub id: i32,
pub user_id: i32,
#[sea_orm(column_type = "Text")]
pub device_id: String,
#[sea_orm(column_type = "Text", unique)]
pub network_instance_id: String,
#[sea_orm(column_type = "Text")]
+16 -4
View File
@@ -65,6 +65,7 @@ impl Db {
pub async fn insert_or_update_user_network_config<T: ToString>(
&self,
user_id: UserIdInDb,
device_id: uuid::Uuid,
network_inst_id: uuid::Uuid,
network_config: T,
) -> Result<(), DbErr> {
@@ -81,6 +82,7 @@ impl Db {
.to_owned();
let insert_m = urnc::ActiveModel {
user_id: sea_orm::Set(user_id),
device_id: sea_orm::Set(device_id.to_string()),
network_instance_id: sea_orm::Set(network_inst_id.to_string()),
network_config: sea_orm::Set(network_config.to_string()),
disabled: sea_orm::Set(false),
@@ -116,6 +118,7 @@ impl Db {
pub async fn list_network_configs(
&self,
user_id: UserIdInDb,
device_id: Option<uuid::Uuid>,
only_enabled: bool,
) -> Result<Vec<user_running_network_configs::Model>, DbErr> {
use entity::user_running_network_configs as urnc;
@@ -126,6 +129,11 @@ impl Db {
} else {
configs
};
let configs = if let Some(device_id) = device_id {
configs.filter(urnc::Column::DeviceId.eq(device_id.to_string()))
} else {
configs
};
let configs = configs.all(self.orm_db()).await?;
@@ -167,8 +175,9 @@ mod tests {
let user_id = 1;
let network_config = "test_config";
let inst_id = uuid::Uuid::new_v4();
let device_id = uuid::Uuid::new_v4();
db.insert_or_update_user_network_config(user_id, inst_id, network_config)
db.insert_or_update_user_network_config(user_id, device_id, inst_id, network_config)
.await
.unwrap();
@@ -183,7 +192,7 @@ mod tests {
// overwrite the config
let network_config = "test_config2";
db.insert_or_update_user_network_config(user_id, inst_id, network_config)
db.insert_or_update_user_network_config(user_id, device_id, inst_id, network_config)
.await
.unwrap();
@@ -193,14 +202,17 @@ mod tests {
.await
.unwrap()
.unwrap();
println!("{:?}", result2);
println!("device: {}, {:?}", device_id, result2);
assert_eq!(result2.network_config, network_config);
assert_eq!(result.create_time, result2.create_time);
assert_ne!(result.update_time, result2.update_time);
assert_eq!(
db.list_network_configs(user_id, true).await.unwrap().len(),
db.list_network_configs(user_id, Some(device_id), true)
.await
.unwrap()
.len(),
1
);
@@ -4,94 +4,6 @@ use sea_orm_migration::{prelude::*, schema::*};
pub struct Migration;
/*
-- # Entity schema.
-- Create `users` table.
create table if not exists users (
id integer primary key autoincrement,
username text not null unique,
password text not null
);
-- Create `groups` table.
create table if not exists groups (
id integer primary key autoincrement,
name text not null unique
);
-- Create `permissions` table.
create table if not exists permissions (
id integer primary key autoincrement,
name text not null unique
);
-- # Join tables.
-- Create `users_groups` table for many-to-many relationships between users and groups.
create table if not exists users_groups (
user_id integer references users(id),
group_id integer references groups(id),
primary key (user_id, group_id)
);
-- Create `groups_permissions` table for many-to-many relationships between groups and permissions.
create table if not exists groups_permissions (
group_id integer references groups(id),
permission_id integer references permissions(id),
primary key (group_id, permission_id)
);
-- # Fixture hydration.
-- Insert "user" user. password: "user"
insert into users (username, password)
values (
'user',
'$argon2i$v=19$m=16,t=2,p=1$dHJ5dXZkYmZkYXM$UkrNqWz0BbSVBq4ykLSuJw'
);
-- Insert "admin" user. password: "admin"
insert into users (username, password)
values (
'admin',
'$argon2i$v=19$m=16,t=2,p=1$Ymd1Y2FlcnQ$x0q4oZinW9S1ZB9BcaHEpQ'
);
-- Insert "users" and "superusers" groups.
insert into groups (name) values ('users');
insert into groups (name) values ('superusers');
-- Insert individual permissions.
insert into permissions (name) values ('sessions');
insert into permissions (name) values ('devices');
-- Insert group permissions.
insert into groups_permissions (group_id, permission_id)
values (
(select id from groups where name = 'users'),
(select id from permissions where name = 'devices')
), (
(select id from groups where name = 'superusers'),
(select id from permissions where name = 'sessions')
);
-- Insert users into groups.
insert into users_groups (user_id, group_id)
values (
(select id from users where username = 'user'),
(select id from groups where name = 'users')
), (
(select id from users where username = 'admin'),
(select id from groups where name = 'users')
), (
(select id from users where username = 'admin'),
(select id from groups where name = 'superusers')
);
*/
impl MigrationName for Migration {
fn name(&self) -> &str {
"m20241029_000001_init"
@@ -141,6 +53,7 @@ enum UserRunningNetworkConfigs {
Table,
Id,
UserId,
DeviceId,
NetworkInstanceId,
NetworkConfig,
Disabled,
@@ -273,6 +186,7 @@ impl MigrationTrait for Migration {
.table(UserRunningNetworkConfigs::Table)
.col(pk_auto(UserRunningNetworkConfigs::Id).not_null())
.col(integer(UserRunningNetworkConfigs::UserId).not_null())
.col(text(UserRunningNetworkConfigs::DeviceId).not_null())
.col(
text(UserRunningNetworkConfigs::NetworkInstanceId)
.unique_key()
+17
View File
@@ -22,6 +22,10 @@ pub struct LoginResult {
pub fn router() -> Router<AppStateInner> {
let r = Router::new()
.route("/api/v1/auth/password", put(self::put::change_password))
.route(
"/api/v1/auth/check_login_status",
get(self::get::check_login_status),
)
.route_layer(login_required!(Backend));
Router::new()
.merge(r)
@@ -168,4 +172,17 @@ mod get {
)),
}
}
pub async fn check_login_status(
auth_session: AuthSession,
) -> Result<Json<Void>, HttpHandleError> {
if auth_session.user.is_some() {
Ok(Json(Void::default()))
} else {
Err((
StatusCode::UNAUTHORIZED,
Json::from(other_error("Not logged in")),
))
}
}
}
+25 -3
View File
@@ -11,7 +11,7 @@ use axum_login::tower_sessions::{ExpiredDeletion, SessionManagerLayer};
use axum_login::{login_required, AuthManagerLayerBuilder, AuthzBackend};
use axum_messages::MessagesManagerLayer;
use easytier::common::scoped_task::ScopedTask;
use easytier::proto::{rpc_types};
use easytier::proto::rpc_types;
use network::NetworkApi;
use sea_orm::DbErr;
use tokio::net::TcpListener;
@@ -43,6 +43,11 @@ type AppState = State<AppStateInner>;
#[derive(Debug, serde::Deserialize, serde::Serialize)]
struct ListSessionJsonResp(Vec<StorageToken>);
#[derive(Debug, serde::Deserialize, serde::Serialize)]
struct GetSummaryJsonResp {
device_count: u32,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
pub struct Error {
message: String,
@@ -98,16 +103,32 @@ impl RestfulServer {
auth_session: AuthSession,
State(client_mgr): AppState,
) -> Result<Json<ListSessionJsonResp>, HttpHandleError> {
let pers = auth_session
let perms = auth_session
.backend
.get_group_permissions(auth_session.user.as_ref().unwrap())
.await
.unwrap();
println!("{:?}", pers);
println!("{:?}", perms);
let ret = client_mgr.list_sessions().await;
Ok(ListSessionJsonResp(ret).into())
}
async fn handle_get_summary(
auth_session: AuthSession,
State(client_mgr): AppState,
) -> Result<Json<GetSummaryJsonResp>, HttpHandleError> {
let Some(user) = auth_session.user else {
return Err((StatusCode::UNAUTHORIZED, other_error("No such user").into()));
};
let machines = client_mgr.list_machine_by_token(user.tokens[0].clone());
Ok(GetSummaryJsonResp {
device_count: machines.len() as u32,
}
.into())
}
pub async fn start(&mut self) -> Result<(), anyhow::Error> {
let listener = TcpListener::bind(self.bind_addr).await?;
@@ -143,6 +164,7 @@ impl RestfulServer {
let auth_layer = AuthManagerLayerBuilder::new(backend, session_layer).build();
let app = Router::new()
.route("/api/v1/summary", get(Self::handle_get_summary))
.route("/api/v1/sessions", get(Self::handle_list_all_sessions))
.merge(self.network_api.build_route())
.route_layer(login_required!(Backend))
+39 -4
View File
@@ -9,7 +9,7 @@ use dashmap::DashSet;
use easytier::launcher::NetworkConfig;
use easytier::proto::common::Void;
use easytier::proto::rpc_types::controller::BaseController;
use easytier::proto::{web::*};
use easytier::proto::web::*;
use crate::client_manager::session::Session;
use crate::client_manager::ClientManager;
@@ -38,7 +38,7 @@ struct ValidateConfigJsonReq {
#[derive(Debug, serde::Deserialize, serde::Serialize)]
struct RunNetworkJsonReq {
config: String,
config: NetworkConfig,
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
@@ -145,7 +145,7 @@ impl NetworkApi {
BaseController::default(),
RunNetworkInstanceRequest {
inst_id: None,
config: config.clone(),
config: Some(config.clone()),
},
)
.await
@@ -155,8 +155,9 @@ impl NetworkApi {
.db()
.insert_or_update_user_network_config(
auth_session.user.as_ref().unwrap().id(),
machine_id,
resp.inst_id.clone().unwrap_or_default().into(),
config,
serde_json::to_string(&config).unwrap(),
)
.await
.map_err(convert_db_error)?;
@@ -288,6 +289,36 @@ impl NetworkApi {
Ok(Json(ListMachineJsonResp { machines }))
}
async fn handle_get_network_config(
auth_session: AuthSession,
State(client_mgr): AppState,
Path((machine_id, inst_id)): Path<(uuid::Uuid, uuid::Uuid)>,
) -> Result<Json<NetworkConfig>, HttpHandleError> {
let inst_id = inst_id.to_string();
let db_row = client_mgr
.db()
.list_network_configs(auth_session.user.unwrap().id(), Some(machine_id), false)
.await
.map_err(convert_db_error)?
.iter()
.find(|x| x.network_instance_id == inst_id)
.map(|x| x.network_config.clone())
.ok_or((
StatusCode::NOT_FOUND,
other_error(format!("No such network instance: {}", inst_id)).into(),
))?;
Ok(serde_json::from_str::<NetworkConfig>(&db_row)
.map_err(|e| {
(
StatusCode::INTERNAL_SERVER_ERROR,
other_error(format!("Failed to parse network config: {:?}", e)).into(),
)
})?
.into())
}
pub fn build_route(&mut self) -> Router<AppStateInner> {
Router::new()
.route("/api/v1/machines", get(Self::handle_list_machines))
@@ -311,5 +342,9 @@ impl NetworkApi {
"/api/v1/machines/:machine-id/networks/info/:inst-id",
get(Self::handle_collect_one_network_info),
)
.route(
"/api/v1/machines/:machine-id/networks/config/:inst-id",
get(Self::handle_get_network_config),
)
}
}