master
veypi 1 year ago
parent f7ee8f7523
commit cc32bd481f

@ -31,3 +31,10 @@ buildweb:
@cd oaweb && yarn build @cd oaweb && yarn build
@rm -rf ./oab/dist/* @rm -rf ./oab/dist/*
@mv ./oaweb/dist/spa/* ./oab/dist/ @mv ./oaweb/dist/spa/* ./oab/dist/
nats:
@nats-server -c ./script/nats.cfg
.PHONY:oab
oab:
@cd oab && cargo run -- -c ./cfg-demo.yml

29
oab/Cargo.lock generated

@ -381,12 +381,6 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "anyhow"
version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
[[package]] [[package]]
name = "arrayvec" name = "arrayvec"
version = "0.7.4" version = "0.7.4"
@ -880,6 +874,16 @@ dependencies = [
"cfg-if", "cfg-if",
] ]
[[package]]
name = "crossbeam-channel"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]] [[package]]
name = "crossbeam-queue" name = "crossbeam-queue"
version = "0.3.8" version = "0.3.8"
@ -2060,7 +2064,6 @@ dependencies = [
"actix-multipart", "actix-multipart",
"actix-web", "actix-web",
"aes-gcm", "aes-gcm",
"anyhow",
"async-nats", "async-nats",
"base64 0.13.1", "base64 0.13.1",
"block-padding", "block-padding",
@ -2091,6 +2094,7 @@ dependencies = [
"thiserror", "thiserror",
"tokio", "tokio",
"tracing", "tracing",
"tracing-appender",
"tracing-subscriber", "tracing-subscriber",
"uuid", "uuid",
] ]
@ -3797,6 +3801,17 @@ dependencies = [
"tracing-core", "tracing-core",
] ]
[[package]]
name = "tracing-appender"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09d48f71a791638519505cefafe162606f706c25592e4bde4d97600c0195312e"
dependencies = [
"crossbeam-channel",
"time",
"tracing-subscriber",
]
[[package]] [[package]]
name = "tracing-attributes" name = "tracing-attributes"
version = "0.1.26" version = "0.1.26"

@ -57,7 +57,7 @@ rust-embed = "8.0.0"
mime_guess = "2.0.4" mime_guess = "2.0.4"
service-manager = "0.3.0" service-manager = "0.3.0"
async-nats = "0.32.1" async-nats = "0.32.1"
anyhow = "1.0.75"
bytes = "1.5.0" bytes = "1.5.0"
nkeys = "0.3.2" nkeys = "0.3.2"
tracing-appender = "0.2.2"

@ -6,7 +6,7 @@
# #
run: run:
@cargo run @cargo run -- -c ./cfg-demo.yml
init: init:
@cargo run -- init @cargo run -- init

@ -0,0 +1,29 @@
uuid: FR9P5t8debxc11aFF
key: AMpjwQHwVjGsb1WC4WG6
debug: true
server_url: 127.0.0.1:4001
media_path: /Users/veypi/test/media
db_url: localhost:3306
db_user: root
db_pass: '123456'
db_name: oneauth
log_dir: null
fs_root: /Users/veypi/test/media
log_level: info
nats_usr:
- UCXFAAVMCPTATZUZX6H24YF6FI3NKPQBPLM6BNN2EDFPNSUUEZPNFKEL
- SUACQNAAFKDKRBXS62J4JYZ7DWZS7UNUQI52BOFGGBUACHTDHRQP7I66GI
nats_node:
- UAU6HPAHVIQWODQ365HMSHGZPSXJHR35T6ACURR3STGXFZNWXFNG5EA6
- SUACZVC4UWLCKFA3DJFIYO5XYYGPJRQEKCBC773PKCD4TZS52GDU6JJ2JE
nats_sys:
- UCOKXBGDAXXQOR4XUPUJ4O22HZ2A3KQN3JLCCYM3ISSKHLBZJXXQ3NLF
- SUAEILQZDD2UT2ZNR6DCA44YCRKAZDYDOJRUPAUA7AOWFVGSSPFPCLXF24
info:
ws_url: http://127.0.0.1:4221
nats_url: http://127.0.0.1:4222
api_url: http://127.0.0.1:4001
user_init_space: 300

@ -49,9 +49,9 @@ pub async fn get(
let token = models::Token::from(&query.token, &key)?; let token = models::Token::from(&query.token, &key)?;
if aid.starts_with("nats") { if aid.starts_with("nats") {
let nonce = &query.nonce.clone().unwrap(); let nonce = &query.nonce.clone().unwrap();
let u = nkeys::KeyPair::from_seed(&stat.nats_secret).unwrap(); let u = nkeys::KeyPair::from_seed(&stat.nats_usr[1].clone()).unwrap();
let res = base64::encode(u.sign(nonce.as_bytes()).unwrap()); let res = base64::encode(u.sign(nonce.as_bytes()).unwrap());
return Ok(format!("{}@{}", res, &stat.nats_key)); return Ok(format!("{}@{}", res, &stat.nats_usr[0].clone()));
}; };
if !aid.is_empty() { if !aid.is_empty() {
// 从OA token 转向其他app token // 从OA token 转向其他app token

@ -15,16 +15,17 @@ use std::{
}; };
use clap::{Args, Parser, Subcommand}; use clap::{Args, Parser, Subcommand};
use lazy_static::lazy_static;
use sea_orm::{ConnectOptions, Database, DatabaseConnection}; use sea_orm::{ConnectOptions, Database, DatabaseConnection};
use serde::{Deserialize, Serialize};
use sqlx::{mysql::MySqlPoolOptions, Pool}; use sqlx::{mysql::MySqlPoolOptions, Pool};
use tracing::{info, Level}; use tracing::{info, Level};
use crate::Result; use crate::Result;
lazy_static! { // lazy_static! {
pub static ref CLI: AppCli = AppCli::new(); // pub static ref CLI: AppCli = AppCli::new();
} // }
// use lazy_static::lazy_static;
// lazy_static! { // lazy_static! {
// pub static ref CONFIG: ApplicationConfig = ApplicationConfig::new(); // pub static ref CONFIG: ApplicationConfig = ApplicationConfig::new();
@ -48,12 +49,13 @@ pub enum Clis {
Start, Start,
Stop, Stop,
Web, Web,
Stash(StashData), Dump,
Cfg(CfgOpt),
} }
#[derive(Debug, Args)] #[derive(Debug, Args)]
#[clap(args_conflicts_with_subcommands = true)] #[clap(args_conflicts_with_subcommands = true)]
pub struct StashData { pub struct CfgOpt {
command: Option<String>, command: Option<String>,
} }
@ -61,14 +63,14 @@ impl AppCli {
pub fn new() -> Self { pub fn new() -> Self {
AppCli::parse() AppCli::parse()
} }
pub fn handle_service(&self) -> Result<()> { pub fn handle_service(&self, data: AppState) -> Result<bool> {
let label: service_manager::ServiceLabel = "v.oa".parse().unwrap(); let label: service_manager::ServiceLabel = "v.oa".parse().unwrap();
// Get generic service by detecting what is available on the platform // Get generic service by detecting what is available on the platform
let manager = <dyn service_manager::ServiceManager>::native() let manager = <dyn service_manager::ServiceManager>::native()
.expect("Failed to detect management platform"); .expect("Failed to detect management platform");
if let Some(c) = &CLI.command { if let Some(c) = &self.command {
match c { match c {
Clis::Install => { Clis::Install => {
let p = std::env::current_exe()?; let p = std::env::current_exe()?;
@ -89,10 +91,15 @@ impl AppCli {
Clis::Stop => manager.stop(service_manager::ServiceStopCtx { Clis::Stop => manager.stop(service_manager::ServiceStopCtx {
label: label.clone(), label: label.clone(),
})?, })?,
_ => {} Clis::Dump => {
let res = serde_yaml::to_string(&data)?;
println!("{}", res);
} }
_ => return Ok(false),
}
return Ok(true);
}; };
Ok(()) Ok(false)
} }
} }
@ -102,6 +109,14 @@ pub struct ApplicationConfig {
pub db: DatabaseConnection, pub db: DatabaseConnection,
} }
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct InfoOpt {
nats_url: String,
ws_url: String,
api_url: String,
token: Option<String>,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct AppState { pub struct AppState {
pub uuid: String, pub uuid: String,
@ -115,12 +130,12 @@ pub struct AppState {
pub db_name: String, pub db_name: String,
pub log_dir: Option<String>, pub log_dir: Option<String>,
pub fs_root: String, pub fs_root: String,
pub nats_key: String, pub nats_usr: [String; 2],
pub nats_secret: String, pub nats_node: [String; 2],
pub nats_sys: [String; 2],
pub info: InfoOpt,
/// "100MB" 日志分割尺寸-单位KB,MB,GB
pub log_temp_size: Option<String>,
pub log_pack_compress: Option<String>,
pub log_level: Option<String>, pub log_level: Option<String>,
pub user_init_space: i64, pub user_init_space: i64,
@ -131,9 +146,9 @@ pub struct AppState {
} }
impl AppState { impl AppState {
pub fn new() -> Self { pub fn new(cli: &AppCli) -> Self {
let mut res = Self::defaut(); let mut res = Self::defaut();
let mut f = match File::open(CLI.cfg.clone()) { let mut f = match File::open(cli.cfg.clone()) {
Ok(f) => f, Ok(f) => f,
Err(ref e) if e.kind() == io::ErrorKind::NotFound => { Err(ref e) if e.kind() == io::ErrorKind::NotFound => {
// res.connect_sqlx().unwrap(); // res.connect_sqlx().unwrap();
@ -141,17 +156,11 @@ impl AppState {
} }
Err(e) => panic!("{}", e), Err(e) => panic!("{}", e),
}; };
File::open(CLI.cfg.clone()).unwrap(); File::open(cli.cfg.clone()).unwrap();
let mut yml_data = String::new(); let mut yml_data = String::new();
f.read_to_string(&mut yml_data).unwrap(); f.read_to_string(&mut yml_data).unwrap();
//读取配置 //读取配置
res = serde_yaml::from_str(&yml_data).expect("load config file fail"); res = serde_yaml::from_str(&yml_data).expect("load config file fail");
if res.debug {
println!("load config:{:?}", res);
println!("///////////////////// Start On Debug Mode ////////////////////////////");
} else {
println!("release_mode is enable!")
}
res res
} }
pub fn defaut() -> Self { pub fn defaut() -> Self {
@ -165,16 +174,30 @@ impl AppState {
db_pass: "123456".to_string(), db_pass: "123456".to_string(),
db_name: "oneauth".to_string(), db_name: "oneauth".to_string(),
log_dir: None, log_dir: None,
log_temp_size: None,
log_pack_compress: None,
media_path: "/Users/veypi/test/media".to_string(), media_path: "/Users/veypi/test/media".to_string(),
fs_root: "/Users/veypi/test/media".to_string(), fs_root: "/Users/veypi/test/media".to_string(),
log_level: None, log_level: None,
_sqlx: None, _sqlx: None,
_db: None, _db: None,
nats_key: "UCXFAAVMCPTATZUZX6H24YF6FI3NKPQBPLM6BNN2EDFPNSUUEZPNFKEL".to_string(), nats_usr: [
nats_secret: "SUACQNAAFKDKRBXS62J4JYZ7DWZS7UNUQI52BOFGGBUACHTDHRQP7I66GI".to_string(), String::from("UCXFAAVMCPTATZUZX6H24YF6FI3NKPQBPLM6BNN2EDFPNSUUEZPNFKEL"),
String::from("SUACQNAAFKDKRBXS62J4JYZ7DWZS7UNUQI52BOFGGBUACHTDHRQP7I66GI"),
],
nats_node: [
String::from("UAU6HPAHVIQWODQ365HMSHGZPSXJHR35T6ACURR3STGXFZNWXFNG5EA6"),
String::from("SUACZVC4UWLCKFA3DJFIYO5XYYGPJRQEKCBC773PKCD4TZS52GDU6JJ2JE"),
],
nats_sys: [
String::from("UCOKXBGDAXXQOR4XUPUJ4O22HZ2A3KQN3JLCCYM3ISSKHLBZJXXQ3NLF"),
String::from("SUAEILQZDD2UT2ZNR6DCA44YCRKAZDYDOJRUPAUA7AOWFVGSSPFPCLXF24"),
],
user_init_space: 300, user_init_space: 300,
info: InfoOpt {
ws_url: "http://127.0.0.1:4221".to_string(),
nats_url: "http://127.0.0.1:4222".to_string(),
api_url: "http://127.0.0.1:4001".to_string(),
token: None,
},
} }
} }
pub fn save(&self) {} pub fn save(&self) {}
@ -232,12 +255,34 @@ impl tracing_subscriber::fmt::time::FormatTime for FormatTime {
} }
} }
pub fn init_log() { pub fn init_log(stat: &AppState) -> Option<tracing_appender::non_blocking::WorkerGuard> {
let level = stat.log_level.clone().unwrap_or("info".to_string());
let level = match level.as_str() {
"trace" => Level::TRACE,
"debug" => Level::DEBUG,
"warn" => Level::WARN,
"error" => Level::ERROR,
"info" => Level::INFO,
_ => Level::INFO,
};
if let Some(log_dir) = stat.log_dir.clone() {
let file_appender = tracing_appender::rolling::hourly(log_dir, "oab.log");
let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender);
tracing_subscriber::fmt() tracing_subscriber::fmt()
.with_writer(non_blocking)
.with_line_number(true) .with_line_number(true)
.with_timer(FormatTime {}) .with_timer(FormatTime {})
.with_max_level(Level::INFO) .with_max_level(level)
// .with_target(false) .with_ansi(false)
// .with_file(true)
.init(); .init();
info!("asd");
Some(_guard)
} else {
tracing_subscriber::fmt()
.with_line_number(true)
.with_timer(FormatTime {})
.with_max_level(level)
.init();
None
}
} }

@ -10,5 +10,5 @@ mod cfg;
pub mod libs; pub mod libs;
pub mod models; pub mod models;
mod result; mod result;
pub use cfg::{init_log, AppState, ApplicationConfig, Clis, CLI}; pub use cfg::{init_log, AppCli, AppState, ApplicationConfig, Clis, InfoOpt};
pub use result::{Error, Result}; pub use result::{Error, Result};

@ -10,6 +10,7 @@ use bytes::Bytes;
use actix_files as fs; use actix_files as fs;
use actix_web::{ use actix_web::{
dev::{self, Service}, dev::{self, Service},
get,
http::StatusCode, http::StatusCode,
middleware::{self, ErrorHandlerResponse, ErrorHandlers}, middleware::{self, ErrorHandlerResponse, ErrorHandlers},
web::{self}, web::{self},
@ -20,37 +21,42 @@ use mime_guess::from_path;
use rust_embed::RustEmbed; use rust_embed::RustEmbed;
use http::{HeaderName, HeaderValue}; use http::{HeaderName, HeaderValue};
use oab::{api, init_log, libs, models, AppState, Clis, Result, CLI}; use oab::{api, init_log, libs, models, AppCli, AppState, Clis, Result};
use tracing::{error, info, warn}; use tracing::{error, info, warn};
#[tokio::main] #[tokio::main]
async fn main() -> Result<()> { async fn main() -> Result<()> {
let cli = AppCli::new();
let mut data = AppState::new(&cli);
if data.debug {
std::env::set_var("RUST_LOG", "debug"); std::env::set_var("RUST_LOG", "debug");
std::env::set_var("RUST_BACKTRACE", "1"); std::env::set_var("RUST_BACKTRACE", "1");
std::env::set_var("asd", "asd"); }
init_log(); let _log = init_log(&data);
let mut data = AppState::new(); if cli.handle_service(data.clone())? {
if let Some(c) = &CLI.command { info!("2");
return Ok(());
}
if let Some(c) = &cli.command {
match c { match c {
Clis::Init => { Clis::Init => {
data.connect_sqlx()?; data.connect_sqlx()?;
models::init(data).await; models::init(data).await;
return Ok(()); return Ok(());
} }
Clis::Install | Clis::Uninstall | Clis::Start | Clis::Stop => {
return CLI.handle_service();
}
_ => {} _ => {}
}; };
}; };
data.connect().await?; data.connect().await?;
data.connect_sqlx()?; data.connect_sqlx()?;
web(data).await?; web(data).await?;
info!("1");
info!("12");
Ok(()) Ok(())
} }
async fn web(data: AppState) -> Result<()> { async fn web(data: AppState) -> Result<()> {
let client = match async_nats::ConnectOptions::new() let client = match async_nats::ConnectOptions::new()
.nkey(data.nats_secret.clone()) .nkey(data.nats_sys[1].clone())
.connect("127.0.0.1:4222") .connect("127.0.0.1:4222")
.await .await
{ {
@ -88,6 +94,7 @@ async fn web(data: AppState) -> Result<()> {
app.wrap(logger) app.wrap(logger)
.wrap(middleware::Compress::default()) .wrap(middleware::Compress::default())
.app_data(web::Data::new(data.clone())) .app_data(web::Data::new(data.clone()))
.service(info)
.service(fs::Files::new("/media", data.media_path.clone()).show_files_listing()) .service(fs::Files::new("/media", data.media_path.clone()).show_files_listing())
.service( .service(
web::scope("api") web::scope("api")
@ -162,3 +169,8 @@ async fn index(p: web::Path<String>) -> impl Responder {
.body(Asset::get("index.html").unwrap().data.into_owned()), .body(Asset::get("index.html").unwrap().data.into_owned()),
} }
} }
#[get("/info")]
pub async fn info(stat: web::Data<AppState>) -> Result<impl Responder> {
Ok(web::Json(stat.info.clone()))
}

@ -126,11 +126,13 @@ pub enum Error {
#[error("invalid header (expected {expected:?}, found {found:?})")] #[error("invalid header (expected {expected:?}, found {found:?})")]
InvalidHeader { expected: String, found: String }, InvalidHeader { expected: String, found: String },
// #[error("serde yaml error")]
// SerdeYamlError{#[from] serde_yaml::Error}
#[error("serde yaml error")]
SerdeYamlError(#[from] serde_yaml::Error),
#[error("unknown error")] #[error("unknown error")]
Unknown, Unknown,
#[error(transparent)]
Other(#[from] anyhow::Error),
} }
impl From<std::io::Error> for Error { impl From<std::io::Error> for Error {

@ -0,0 +1,53 @@
# nats cfg
#
host: 0.0.0.0
port: 4222
# 监控端口
http: 127.0.0.1:8222
websocket: {
listen: '0.0.0.0:4221',
no_tls: true
}
jetstream: {
}
accounts: {
usrs: {
users: [
{ nkey: UCXFAAVMCPTATZUZX6H24YF6FI3NKPQBPLM6BNN2EDFPNSUUEZPNFKEL},
],
exports: [
{stream: pub.>},
{service: psrv.>},
],
imports: [
{stream: {account: SYS, subject: usr.>}, prefix: a},
],
},
nodes: {
users: [
{ nkey: UAU6HPAHVIQWODQ365HMSHGZPSXJHR35T6ACURR3STGXFZNWXFNG5EA6},
],
exports: [
{stream: pub.>},
{service: psrv.>},
],
},
SYS: {
users: [
{ nkey: UCOKXBGDAXXQOR4XUPUJ4O22HZ2A3KQN3JLCCYM3ISSKHLBZJXXQ3NLF},
{ user: cli, password: cli},
],
exports: [
{stream: usr.>},
{stream: node.>},
{service: usr.>},
{service: node.>},
],
},
}
system_account: SYS

@ -1,22 +0,0 @@
# nats cfg
#
host: 127.0.0.1
port: 4222
# 监控端口
http: 127.0.0.1:8222
jetstream: {
}
authorization: {
users: [
{ nkey: UCXFAAVMCPTATZUZX6H24YF6FI3NKPQBPLM6BNN2EDFPNSUUEZPNFKEL},
{ user: cli, password: cli},
]
}
websocket: {
listen: '0.0.0.0:4221',
no_tls: true
}
Loading…
Cancel
Save