Selaa lähdekoodia

增加mqtt鉴权相关基本可用代码ability.rs;创建批量载入设备的python脚本文件夹模版到devices-detail文件夹

zii 1 kuukausi sitten
vanhempi
sitoutus
49580698fc

+ 1 - 0
data_init.py

@@ -29,6 +29,7 @@ curs.execute('''
 create table if not exists device (
 id integer PRIMARY KEY,
 name text not null,
+sn text not null,
 typo text not null,
 area integer not null default 0, -- 0:未分配到区域 其他:所在区域编号
 belongto integer not null default 0,

+ 14 - 0
devices-detail/2026-2-8-测试.py

@@ -0,0 +1,14 @@
+import sqlite3;curs = (conn:=sqlite3.connect('db.sqlite')).cursor()
+
+conn.execute("""insert into device (name,sn,typo,area) values"""+str(tuple(
+(i,i,'4GPLC',0) for i in 
+'''460089721505170  460089721505175  460089721505180  460089721505185  460089721505190  460089721505195  460089721505200  460089721505205  460089721505210  460089721505215  460130085899960
+460089721505171  460089721505176  460089721505181  460089721505186  460089721505191  460089721505196  460089721505201  460089721505206  460089721505211  460089721505216  460130085899961   
+460089721505172  460089721505177  460089721505182  460089721505187  460089721505192  460089721505197  460089721505202  460089721505207  460089721505212  460089721505217  460130085899962   
+460089721505173  460089721505178  460089721505183  460089721505188  460089721505193  460089721505198  460089721505203  460089721505208  460089721505213  460089721505218  460130085899963   
+460089721505174  460089721505179  460089721505184  460089721505189  460089721505194  460089721505199  460089721505204  460089721505209  460089721505214  460089721505219  460130085899964
+'''.replace('\n','  ').split('  ') if i!=""
+
+))[1:-1].rstrip(','))
+
+conn.commit()

+ 11 - 0
docs/会议/2026-2-5.md

@@ -16,3 +16,14 @@ ssh证书地址为服务器上的
 /etc/letsencrypt/live/plcplatform.worldflying.cn/privkey.pem
 已经通过crontab添加了自动更新,直接调用即可。
+
+Parameter|Symbol|Gear 1|Gear 2
+-|-|-|-
+Module|m|2.0|-
+Pressure Angle (°)|α|20|-
+Number of Teeth|z|30|30
+Profile Shift|x|0|0
+Helix Angle (°)|β|20|-20
+Gear Width|W|12|-
+Extra Tip Vertex Position|v|0|-
+Twist angle (°)|φ|自动计算|自动计算

+ 15 - 3
job.md

@@ -4,13 +4,25 @@
 
 ssh root@183.56.252.244 -p 8022
 
+plcplatform.worldflying.cn
+
 scp -P 8022 target/x86_64-unknown-linux-gnu/release/iotplatform_lite root@183.56.252.244:iotplatform_lite/
 
 scp -P 8022 ../../../add_service.sh root@183.56.252.244:iotplatform_lite/
 
 [https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx664469117500d259&redirect_uri=https%3A%2F%2Fwww.worldflying.cn%2Ftools%2Fwxredirect%2Fplc.html&response_type=code&scope=snsapi_base&state=base#wechat_redirect]
 
+[https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx664469117500d259&redirect_uri=https%3A%2F%2Fwww.worldflying.cn%2Ftools%2Fwxredirect%2Fplc.html&response_type=code&scope=snsapi_base&state=base#wechat_redirect]
 
-https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx664469117500d259&redirect_uri=https%3A%2F%2Fwww.worldflying.cn%2Ftools%2Fwxredirect%2Fplc.html&response_type=code&scope=snsapi_base&state=base#wechat_redirect
-
-https://www.worldflying.cn/tools/wxredirect/iot.html?code=081C2G1w3lOms63CIf3w31t8n71C2G1j&state=base
+[https://www.worldflying.cn/tools/wxredirect/iot.html?code=081C2G1w3lOms63CIf3w31t8n71C2G1j&state=base]
+
+```TXT
+mosquitto插件开发完了,地址在这里https://code.worldflying.cn/jevian/mosquitto_plugin
+总代码不到100行,重要的逻辑代码不到50行,编译也简单,安装libmosquitto-dev mosquitto-dev后直接make即可。
+已经实现了一次性登录与登录有效期,acl也支持有效期功能
+我已经把这批设备需要添加的数据库内容添加进去了,你也把服务器的信息以及客户端的动态规则记得加进去,我的工作应该是结束了。
+用户表中有两个字段,一个是mode,另一个是deadline。
+如果mode为0就是长期有效账号密码,如果为1就是一次性账号密码,登录成功后,插件会把这条记录删除,下次就无法再用它登录了。
+deadline是允许使用的最后时间(linux时间戳),当超过这个时间后,这条记录也就无效了。
+至于你是想设最后时效,还是享设只使用一次,亦或是同时有效,这个随你。功能完成了,你怎么用随便你。反正就是要注意一下,不要让一个账号被破解后,他可以操作我们的所有设备,这是绝对不被允许的。
+```

+ 205 - 0
src/api/ability.rs

@@ -0,0 +1,205 @@
+use axum::{extract::{State},Json};
+use tokio::io::{AsyncWriteExt};
+use super::{Ident,check_token};
+use crate::{AppState, datasource::Datasource, log, LogLevel::*};
+
+#[derive(serde::Serialize)]
+pub struct MqttBack{
+    pub errcode: i16,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub errmsg: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub clientid: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub mqttu: Option<String>,
+    #[serde(skip_serializing_if = "Option::is_none")]
+    pub mqttp: Option<String>
+
+}
+
+pub async fn get_mqtt(
+    State(state): State<AppState>,
+    Json(u): axum::extract::Json<Ident>
+) -> Json<MqttBack> {
+    let uid=match check_token(&state, u.token).await {
+        Ok(id) => {id},
+        Err(_) => {
+            return Json(MqttBack{errcode: 2000, errmsg: Some("鉴权失败: token无效".to_string()),mqttp:None,clientid:None,mqttu:None})
+        }
+    };
+    let mut mqid:String;
+    match state.db_lite.query("select mqid from user where id=?", [uid], |r|{r.get::<usize,String>(0)}).await{
+        Ok(clientid)=>{
+            mqid=clientid;
+            // if clientid.is_empty(){
+            //     mqid = format!("webu{}",super::token(5));
+            // }else{
+            //     if let Err(e)=tokio::fs::remove_file(format!("/var/lib/mosquitto/{}",clientid)).await{
+            //         log(Warning, format!("fail to remove old mqtt user file {e}"))
+            //     };
+            //     mqid=clientid;
+            // }
+        }
+        Err(e) => {
+            if !e.is_empty(){
+                log(Error, format!("query mqid failed: {e}"));
+                return Json(MqttBack{errcode: 3000, errmsg: Some("数据库异常: 获取用户信息失败".to_string()),mqttp:None,clientid:None,mqttu:None});
+            }
+            mqid="".to_string();
+        }
+    }
+    if mqid.is_empty(){ 
+        
+    let mut mq: String;
+    let mut try_time=0;
+        loop{// 确保获取不重复的clientid,mqid设定为unique
+            if try_time>5{
+                return Json(MqttBack{errcode: 3000, errmsg: Some("数据库异常: 无法为用户绑定新clientid, 因为当前已经存在太多用户".to_string()),mqttp:None,clientid:None,mqttu:None});
+            }
+            match state.db_lite.execute("update user set mqid=? where id=?", ({mq=format!("webu{}",super::token(5));mq.clone()},uid)).await{
+                Ok(_) => {mqid=mq;break;},
+                Err(e) => {
+                    if e.is_empty(){
+                        try_time+=1;
+                        continue;
+                    }
+                    log(Error, format!("update mqid failed: {e}"));
+                    return Json(MqttBack{errcode: 3000, errmsg: Some("数据库异常: 未能绑定mqtt-clientid到用户".to_string()),mqttp:None,clientid:None,mqttu:None})
+                }
+            };
+        }
+    }
+    let (mqtp, mqtu): (String,String);
+    match tokio::fs::File::create(format!("/var/lib/mosquitto/user/{mqid}")).await{
+        Ok(mut f) => {
+            (mqtu,mqtp) = (super::token(12),super::token(12));
+            if let Err(e)=f.write(
+                format!("{}\n{}\n1\n{}",mqtu.clone(),mqtp.clone(),
+                    if let Ok(t)=(std::time::SystemTime::now()+std::time::Duration::from_mins(10)).duration_since(std::time::UNIX_EPOCH){
+                        t.as_secs()
+                    }else{0}
+                ).as_bytes()
+            ).await{
+                log(Warning, format!("mqtt user file write failed {e}"));
+            };
+        },
+        Err(e) => {
+            log(Warning, format!("mqtt user file create failed {e}"));
+            return  Json(MqttBack{errcode: 3000, errmsg: Some("数据库异常: 创建用户文件失败".to_string()),mqttp:None,clientid:None,mqttu:None});
+        }
+    };
+    match state.db_lite.query_rows("select d.sn from device d left join map_user_device m on d.id=m.did where m.uid=?", [uid], |r|{r.get::<usize,String>(0)}).await{
+        Ok(r)=>{
+            log(Debug, format!("get mqtt sub list{:?}",r));
+            let mut fsub = if let Ok(f)=tokio::fs::File::create(format!("/var/lib/mosquitto/sub/{}",mqid)).await{f}else{
+                log(Warning, format!("fail at mqtt sub create"));
+                return Json(MqttBack{errcode: 3000, errmsg: Some("mqtt鉴权失败: 创建用户文件失败".to_string()),mqttp:None,clientid:None,mqttu:None});
+            };
+            let mut fpub = if let Ok(f)=tokio::fs::File::create(format!("/var/lib/mosquitto/pub/{}",mqid)).await{f}else{
+                log(Warning, format!("fail at mqtt pub create"));
+                return Json(MqttBack{errcode: 3000, errmsg: Some("mqtt鉴权失败: 创建用户文件失败".to_string()),mqttp:None,clientid:None,mqttu:None});
+            };
+            if !r.is_empty(){
+                if let Err(e)=fpub.write(format!("/wf/Iot/device/{}", r.join("\n/wf/Iot/device/")).as_bytes()).await{
+                    log(Warning, format!("fail to write pub lit to file {e}"));
+                };
+                if let Err(e)=fsub.write(format!("/wf/Iot/client/{}", r.join("\n/wf/Iot/client/")).as_bytes()).await{
+                    log(Warning, format!("fail to write sub lit to file {e}"));
+                };
+            } else {
+                if let Err(e)=fpub.write(String::new().as_bytes()).await{
+                    log(Warning, format!("fail to write pub lit to file {e}"));
+                };
+                if let Err(e)=fsub.write(String::new().as_bytes()).await{
+                    log(Warning, format!("fail to write sub lit to file {e}"));
+                };
+            }
+        }
+        Err(e) => {
+            if !e.is_empty(){
+            return Json(MqttBack{errcode: 3000, errmsg: Some("mqtt鉴权失败: 获取用户下属清单失败".to_string()),mqttp:None,clientid:None,mqttu:None});
+            }
+        }
+    }
+    return Json(MqttBack{errcode: 0, errmsg: None,mqttp:Some(mqtp),clientid:Some(mqid),mqttu:Some(mqtu)})
+}
+
+
+// pub async fn get_mqtt(
+//     State(state): State<AppState>,
+//     Json(u): axum::extract::Json<Ident>
+// ) -> Json<MqttBack> {
+//     let uid=match check_token(&state, u.token).await {
+//         Ok(id) => {id},
+//         Err(_) => {
+//             return Json(MqttBack{errcode: 2000, errmsg: Some("鉴权失败: token无效".to_string()),mqttp:None,clientid:None,mqttu:None})
+//         }
+//     };
+
+//     match state.db_lite.query("select mqid from user where id=?", [uid], |r|{r.get::<usize,String>(0)}).await{
+//         Ok(mut mqid) => {
+//             if mqid.is_empty(){
+//                 loop{ // 确保获取不重复的clientid,mqid设定为unique
+//                     match state.db_lite.execute("update user set mqid=? where id=?", ({mqid=super::token(12);mqid.clone()},uid)).await{
+//                         Ok(_) => {break;},
+//                         Err(e) => {
+//                             if e.is_empty(){
+//                                 continue;
+//                             }
+//                             log(Error, format!("update mqid failed: {e}"));
+//                             break;
+//                         }
+//                     };
+//                 }
+//             }
+//             let (mqu,mqp) :(String,String);
+//             match state.db_mqtt.query("select user,pass from user where clientid=?", [mqid.clone()], |r|{Ok((r.get::<usize,String>(1)?,r.get::<usize,String>(2)?))}).await{
+//                 Ok((u,p)) => {mqu=u;mqp=p;},
+//                 Err(e) => {
+//                     log(Warning,format!("{e}"));
+//                     (mqu,mqp)=(super::token(12),super::token(12));
+//                     match state.db_mqtt.execute("insert into user(clientid,user,pass) values(?,?,?)", (mqid.clone(),mqu.clone(),mqp.clone())).await{
+//                         Ok(_) => {},
+//                         Err(e) => {log(Error, format!("insert mqtt user failed: {e}"));}
+//                     }
+//                 }
+//             };
+//             return Json(MqttBack{
+//                 errcode: 0,
+//                 errmsg: None,
+//                 mqttp:Some(mqp),clientid:Some(mqid),mqttu:Some(mqu)
+//             })
+//         }
+//         Err(e) => {
+//             return Json(MqttBack{errcode: 3000, errmsg: Some(format!("查询用户失败: {e}")),mqttp:None,clientid:None,mqttu:None})
+//         }
+//     }
+// }
+#[test]
+fn test_f(){
+use tokio::io::{AsyncReadExt};
+    tokio::runtime::Runtime::new().unwrap().block_on(async{
+        match tokio::fs::File::create("testf").await{
+            Ok(mut f) =>{
+            let buf: &mut [u8];
+            let mut b = [0;1024];
+            buf=b.as_mut_slice();
+            if let Ok(n)=f.read(buf).await{println!("file read {}",n)};
+            if let Ok(n)=f.write(format!("asdf").as_bytes()).await{println!("file write {}",n);
+                if let Err(e)=f.flush().await{ println!("file flush failed: {}",e)};};
+            }
+        Err(e) => {
+            // match tokio::fs::File::create("testf").await{
+            //     Ok(mut f) => {
+            //         println!("file create");
+            //         if let Err(e)=f.write(format!("creatt").as_bytes()).await{
+            //             println!("file write failed: {}",e);
+            //         };
+            //     }
+            //     Err(e) => {println!("file create failed: {}",e)}
+            // }
+            println!("file create failed: {}",e);
+        }
+    }
+    })
+}

+ 11 - 4
src/api/auth.rs

@@ -100,13 +100,22 @@ pub async fn auth(
     //     .and_then(|hv| hv.to_str().ok())
     //     .unwrap_or("localhost:3000");
     log(Debuging, format!("in authing"));
-    let token=super::token();
+    let token=super::token(32);
     let res = super::check_openid(&state, a.openid.clone()).await;
     if let Ok(id) = res{
         // 用户已经注册 函数末尾发生跳转到主页
         if let Err(e) = state.db_lite.execute("update user set token=? where id=?", (token.clone(), id)).await{
             println!("{e}");
         };
+        if let Some(did)= q.state.strip_prefix("did="){
+            if let Err(e) = state.db_lite.execute("update device set belongto=? where sn=? and belongto=0", (id,did)).await{
+                println!("{e}");
+            }else if let Some(did)=state.db_lite.last_insert_rowid().await.ok(){
+                if let Err(e) = state.db_lite.execute("insert into map_user_device (uid, did)values(?,?)", (id,did)).await{
+                    println!("{e}");
+                }
+            };  
+        }
     } else if a.scope !="snsapi_userinfo"{
         // 
         log(Debug, "send redirect for get uinfo".to_string());
@@ -152,10 +161,8 @@ pub async fn auth(
         // 注册成功 函数末尾发生跳转到主页
         // return Redirect::to(format!("http://124.222.106.170/plc_ctrl?token={}#{}",token.clone(),q.state).as_str());
     };
-
-
     // request::Request::get("body");
     // log(Info, format!("bad happend {:?}",res));
     log(Debug, format!("redirect back with token"));
-    return Redirect::to(format!("{}?token={}#{}",crate::WEBP,token.clone(),q.state).as_str());
+    return Redirect::to(format!("{}?token={}",crate::WEBP,token.clone()).as_str());
 }

+ 6 - 4
src/api/device.rs

@@ -152,6 +152,7 @@ pub async fn burn(
 pub struct Devices{
     pub id: u64,
     pub name: String,
+    pub sn: String,
     pub area: u64,
     pub belongto: bool,
     pub info: String
@@ -230,14 +231,15 @@ pub async fn d_all(
         errmsg: None,
         devices: Some(
             match state.db_lite.query_rows(
-                "select d.id,d.name,d.area,d.belongto,d.info from device d left join map_user_device m on d.id=m.did where d.isdelete=0 and m.uid=?", 
+                "select d.id,d.name,d.sn,d.area,d.belongto,d.info from device d left join map_user_device m on d.id=m.did where d.isdelete=0 and m.uid=?", 
                 [uid], 
                 |r|{Ok(Devices{
                 id: r.get::<usize,u64>(0)?,
                 name: r.get::<usize,String>(1)?,
-                area: r.get::<usize,u64>(2)?,
-                belongto: r.get::<usize,u64>(3)?==uid,
-                info:  r.get::<usize,String>(4)?
+                sn: r.get::<usize,String>(2)?,
+                area: r.get::<usize,u64>(3)?,
+                belongto: r.get::<usize,u64>(4)?==uid,
+                info:  r.get::<usize,String>(5)?
             })}).await{
                 Ok(ans) => ans,
                 Err(e) => {

+ 2 - 2
src/api/flow_task.rs

@@ -39,7 +39,7 @@ pub async fn new_flow_task_share_device(
         }
     }
     let mut tryno=0;
-    let linkrand = token();
+    let linkrand = token(32);
     while tryno<5 && match state.db_lite.execute(
         "insert into flow_task_share (did, typo, ticket,createby)values (?,?,?,?)", 
         (u.id,u.r#type,linkrand.clone(),uid)).await{
@@ -71,7 +71,7 @@ pub async fn new_flow_task_share_device(
 
 #[derive(Deserialize)]
 pub struct CheckoutShare {
-token: String,
+    token: String,
     linkrand: String,
 }
 

+ 4 - 3
src/api/mod.rs

@@ -3,6 +3,7 @@ pub mod area;
 pub mod auth;
 pub mod device;
 pub mod flow_task;
+pub mod ability;
 #[cfg(target_arch = "x86_64")]
 #[cfg(target_os = "windows")]
 mod code_helper;
@@ -69,8 +70,8 @@ pub async fn check_openid(state: &crate::AppState, openid: String) -> Result<u64
         |r|{r.get::<usize,u64>(0)}).await.map_err(|e| println!("{e}"))
 }
 
-pub fn token() -> String{
-    rand::rng().sample_iter(&rand::distr::Alphanumeric).take(32).map(char::from).collect()
+pub fn token(s: usize) -> String{
+    rand::rng().sample_iter(&rand::distr::Alphanumeric).take(s).map(char::from).collect()
 }
 
 
@@ -83,7 +84,7 @@ mod tests{
     #[test]
     fn test_token(){
         use super::token;
-        println!("{}",token());
+        println!("{}",token(32));
     }
      #[test]
     fn test_md5(){

+ 1 - 1
src/api/user.rs

@@ -72,7 +72,7 @@ pub async fn u_loggin(
                 })
             }
         };
-    let token = token();
+    let token = token(32);
     if let Err(e) = state.db_lite.execute("update user set lastlogin=current_timestamp,token=? where id=?", (token.clone(), uid)).await{
         println!("error when loggin {e}")
     }

+ 5 - 0
src/datasource/mod.rs

@@ -13,6 +13,11 @@ pub trait Datasource {
         P: rusqlite::Params,
         F: FnMut(&rusqlite::Row<'_>) -> rusqlite::Result<T>;
 
+    // async fn query_row<P, T, F>(&self, query: &str, params: P, f: F) ->Result<(rusqlite::Statement<'_>,rusqlite::Rows<'_>), String>
+    // where
+    //     P: rusqlite::Params,
+    //     F: FnMut(&rusqlite::Row<'_>) -> rusqlite::Result<T>;
+
     async fn execute<P>(&self, query: &str, params:P) -> Result<usize, String>
     where
         P: rusqlite::Params;

+ 2 - 2
src/datasource/sqlite.rs

@@ -54,6 +54,7 @@ pub async fn init_sqlite_pool(url: &str, max_size: u32) -> Result<SqlitePool, Bo
     Ok(pool)
 }
 impl crate::datasource::Datasource for SqlitePool{
+    /// 对于无结果会将err转为空字符串
     async fn query<P, T, F>(&self, sql: &str, params: P,f: F) -> Result<T, String> 
     where
         P: rusqlite::Params,
@@ -87,11 +88,10 @@ impl crate::datasource::Datasource for SqlitePool{
                     Err(e) => return Err(e.to_string()),
                 }
             }
-            
             Ok(results)
         })
     }
-    
+    /// 对于主键重复会将err转为空字符串
     async fn execute<P>(&self, sql: &str, params:P) -> Result<usize, String>
         where
             P: rusqlite::Params {

+ 44 - 30
src/main.rs

@@ -2,7 +2,7 @@ mod datasource;
 mod api;
 use std::{collections::HashMap, process::exit, str::FromStr};
 
-use axum::{extract::{Request, State}, middleware::Next, routing::any};
+use axum::{extract::State, routing::any};
 use datasource::sqlite;
 use tokio::sync::Mutex;
 use tower_http::cors::{Any, CorsLayer}; // 添加Any和CorsLayer的引用
@@ -42,7 +42,7 @@ pub fn log(level: LogLevel, msg: String) {
 
 #[derive(Clone)]
 struct AppState{
-    db_lite: sqlite::SqlitePool
+    db_lite: sqlite::SqlitePool,
 }
 
 #[derive(Clone)]
@@ -50,6 +50,7 @@ struct Counter {
     counts: std::sync::Arc<Mutex<HashMap<String, [u64;2]>>>,
 }
 
+#[allow(dead_code)]
 impl Counter {
     fn new() -> Self {
         Counter {
@@ -76,9 +77,11 @@ const CFGPATH: &'static str = "config.json";
 async fn main() -> Result<(), Box<dyn std::error::Error>> {
 #[derive(serde::Deserialize,serde::Serialize, Debug)]
     pub struct Conf{
-        host: String,
+        #[serde()]
+        host: Option<String>,
         ssl: Option<String>,
         db: String,
+        // mqtt: String,
         ssl_cert: Option<String>,
         ssl_key: Option<String>,
     }
@@ -87,15 +90,24 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
         Err(_) => {let f=std::fs::File::create_new(CFGPATH).unwrap();
             serde_json::to_writer(&f, &Conf{
                 ssl: None,
-                host: "0.0.0.0:3000".to_string(),
+                host: Some("0.0.0.0:3000".to_string()),
                 db: "db.sqlite".to_string(), 
+                // mqtt: "/vat/lib/mosquitto.db".to_string(), 
                 ssl_cert: None,
                 ssl_key: None,
         }).unwrap();
             f}
     }){
         Ok(conf) => conf,
-        Err(_) => {log(Warning, "config file phrase fail, overwriting ...\n\t\tdone, running with default configuration".to_string());Conf { host: "0.0.0.0:3000".to_string(), db: "db.sqlite".to_string(),ssl_cert:None, ssl_key:None,ssl:None }},
+        Err(_) => {log(Warning, "config file phrase fail, overwriting ...\n\t\tdone, running with default configuration".to_string());
+            Conf { 
+                host: Some("0.0.0.0:3000".to_string()), 
+                db: "db.sqlite".to_string(), 
+                // mqtt: " /var/lib/mosquitto/data.db".to_string(),
+                ssl_cert:None,
+                ssl_key:None,
+                ssl:None
+             }},
     };
 
     let appstat = AppState{db_lite: sqlite::init_sqlite_pool(&conf.db, 10).await?};
@@ -110,7 +122,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
         .nest("/apilite", axum::Router::new()
         // .nest("/api", axum::Router::new()
             // .route("/wx/auth", get(api::auth::auth))
-    
+        .route("/mq", post(api::ability::get_mqtt))
             .route("/loggin", post(api::user::u_loggin))
 
             .route("/device", post(api::device::d_all))
@@ -138,18 +150,18 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
             .route("/flow/share/new", post(api::flow_task::new_flow_task_share_device))
             .route("/flow/share/checkout", post(api::flow_task::checkout_flow_task_of_share_device))
             
-            .route_layer(
-                axum::middleware::from_fn_with_state(
-                    monitor.clone(), 
-                    |a:State<Counter>,req: Request,c:Next | async move{
-                        log(Debuging, format!("in url {} {:?}",req.uri().path(),req.uri().query()));
-                        let url = format!("{} {}",req.method().as_str(),req.uri().path());
-                        let resp = c.run(req).await;
-                        a.increment(url.as_str(),resp.status().is_success()).await;
-                        resp
-                    }
-                )
-            )
+            // .route_layer(
+            //     axum::middleware::from_fn_with_state(
+            //         monitor.clone(), 
+            //         |a:State<Counter>,req: Request,c:Next | async move{
+            //             log(Debuging, format!("in url {} {:?}",req.uri().path(),req.uri().query()));
+            //             let url = format!("{} {}",req.method().as_str(),req.uri().path());
+            //             let resp = c.run(req).await;
+            //             a.increment(url.as_str(),resp.status().is_success()).await;
+            //             resp
+            //         }
+            //     )
+            // )
             .with_state(appstat)
 
             // layer需要在最后添加,添加视为入栈,生效顺序为出栈顺序
@@ -169,15 +181,17 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
     if let (Some(cert),Some(key),Some(ssl)) = (conf.ssl_cert,conf.ssl_key,conf.ssl) {
         use axum_server::tls_rustls::RustlsConfig;
         use std::{path::PathBuf,net::SocketAddr};
-        log(Info, format!("rederect for http2https at {}==>{}",conf.host,ssl));
-        let (listener, app2) = (
-            tokio::net::TcpListener::bind(conf.host).await?, 
-            axum::Router::new()
-            .route("/", any(redirect_http_to_https)));
-        tokio::spawn(async move{
-            log(Info, format!("http2https start"));
-            axum::serve(listener,app2).await
-        });
+        if let Some(host)=conf.host{
+            log(Info, format!("rederect for http2https at {}==>{}",host,ssl));
+            let (listener, app2) = (
+                tokio::net::TcpListener::bind(host).await?, 
+                axum::Router::new()
+                .route("/", any(redirect_http_to_https)));
+            tokio::spawn(async move{
+                log(Info, format!("http2https start"));
+                axum::serve(listener,app2).await
+            });
+        };
 
         log(Info, format!("host https at {}",ssl));
         log(Info, "starting with ssl-https".to_string());
@@ -194,9 +208,9 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
                 Err(e) => {log(Error, format!("{e}"));exit(1)}
             }
         ).serve(app.into_make_service()).await?;
-    } else {
-        log(Info, format!("hosting at {}",conf.host));
-        let listener = tokio::net::TcpListener::bind(conf.host).await?;
+    } else if let Some(host)=conf.host{
+        log(Info, format!("hosting at {}",host));
+        let listener = tokio::net::TcpListener::bind(host).await?;
         axum::serve(listener, app).await?;    
     }
     log(Info, format!("bye!"));