RUST语言的初印象-从一个模拟登陆谈起-slint+reqwest+aes

news2024/12/25 1:35:56

本文就一个做了三四天的小程序讲第一次学用RUST的感受,内附代码。

了角语言

从一些渠道听说了R,这个字母挺魔性,那个文章说C++和R的团体已经上升到了宗教崇拜的高度,然后,我觉得必 有过人之处,大约10年没碰C++,只知皮毛。于是想要去学一下R,这样简写是为了方便凑合看。粗粗一打听,这语言是系统的,平台通吃,android,arm,x86.苹果,安装起来也十分方便,curl一段代码就行。除了win下要用VStuty。正好我上次python,exe化的进候安装上了。所以大约10分就安好了,拿出helloworld,cargo build,cargo run,也能通过了。后来发现R在文档和库管理这一块是不是要比C++这几十年的老 将好很多呢,虽然很久没用C++,不知道发展了没有,感叹时代真是进步太大了。R的学习资料,网上有太多电子版,网页搜索查询方便,库,文档,规范也自动, 这种方便性真是让人爽快,不说别的了,还是挺推荐一学的。

任务

以前有一个模拟访问网页的python,全套代码就在里面,就剩下要了解R的语法和库就能完成任务了。于是了解reqwest是模仿request来的就用它了。结果它总是aynsc方法,看着头大,怕是掌握不住,于是就找到了reqwest::blocking这就顺利多了。还是习惯老方法。不过完成了任务就可以尝试新的了。剩下的是cookies。好在,目前的版本一步启用,

use reqwest::blocking::Client;
let client = Client::builder()
   .cookie_store(true)
    .build()?;

这就具备第一个轮子了。在登陆密码的以后,来了一个成功地址,做下一步的引导,结果因为这个地址,没有mut,而初始化成了,空。造成下一步,成功后也无法更新。这就让后面的所有请求是失败的。我一开始一直在怀疑cookie不能跨域fun。因为在一个fun里是好的。为此还找了cookiestore的本地文件json在实现。结果还是一样。直到后来找到了真实原因是一个变量可变的声明,

  1. 建立图形界面,调查对比后使用slint。
  2. 提交reqwest,分form.和json数据,cookie保存登陆状态,取回response并且regex分析结果,解析json结果。
  3. 更新界面状态,使用两个线程,一个交互web server结果保存在全局变量,一个刷新全局变量到界面状态。
  4. 编码用户密码以方便登陆,用户明文到AES和MD5加密,然后post去后台。

按部就班

老实的看了几个小时的教程,参数,变量,引用,数组,字符串。发现这个言语会劲量发现错的,直到按他要求来,才能通过,当然所有语言都这样。但是还是挺喜欢他的味道。和js,python形成鲜明的对比。 fn要用什么参数,传回什么类型,都要提前说好。而且,Result,Option,这样的东西,? <>这样的字符。都有自己的用处。接下了学了要用到的regex。就像reqwest、它要实现的功能都是老的,只有工具是新的。而且说心里,它跨平台,在鸿蒙也是能跑的,而且资源这么多,多好。regex r#“”#这是原始字符。以前那些提取,基本是照样出来的。

图形界面

捎带又了角一个新的slint框架,他是跨语言的,有自己的slint文件,进行窗口程序的布局。安装也像R一样,又无声又快,只是我没在vscode上,找到可拖放的插件。 在线的倒是有一个。用了半天时间,放了两个输入,一个状态,一个计数按钮。 这是从它的github,example下载来的。cargo build,cargo run。 一下就打开了。想像有一天在鸿蒙也hell world一下。但是真想不到有什么像样的任务要做。 它的in- out变量,可以在main中,set, get。在完成了后台以后,这里有一个小难点。就是状态的适时刷新。
Cargo.toml

[package]
name = "slint-rust-template"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
slint = "1.7.2"
reqwest = { version = "0.12.7", features = ["json", "cookies","blocking","gzip"] }
tokio= {version= "1" ,features= ["full"] }
regex = "1.10.6"
#recode_rs="1.0.6"
encoding_rs="0.8.34"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

main.rs

// Prevent console window in addition to Slint window in Windows release builds when, e.g., starting the app via file manager. Ignored on other platforms.
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
mod wjc;
use slint::Weak;
use wjc::kkuser;
use std::error::Error;
use std::sync::MutexGuard;
//use reqwest::Client;
use reqwest::blocking::Client;
use std::{thread, time::Duration};
use reqwest;
use regex::Regex;
use std::collections::HashMap;
slint::include_modules!();

fn main() -> Result<(), Box<dyn Error>> {
  
    let ui = AppWindow::new()?;
    let handle_weak = ui.as_weak();
    let thread = std::thread::spawn(move || {
        //更新状态
       loop{
        handle_weak.upgrade_in_event_loop(move |handle|{ 
           unsafe { 
            handle.set_counter(kkuser::progbar);
           
        handle.set_status(kkuser::thestat.unwrap().into());
            }
        });
        thread::sleep(Duration::from_millis(500));
        }
    });
    ui.on_request_increase_value({
        let ui_handle = ui.as_weak();
        move || {
            let ui = ui_handle.unwrap();
            ui.set_counter(ui.get_counter() + 0.01);
            kkuser::test( );
        }
    });


    ui.run()?;

    Ok(())
}

 

感受一下,另一个主文件
appwindow.slint


export component AppWindow inherits Window {
    in-out property <float> counter: 0.42;
    in-out property <string> user: "";
    in-out property <string> status: "";
    in-out property <string> pass: "";
    callback request-increase-value();
    preferred-width: 600px;
    VerticalBox {
    
        Text {
            text: "用户:";
        }
        LineEdit{
            text<=> root.user;
            placeholder-text:"";
        }
        Text {
            text: "密码:";
        }
        LineEdit{
            text <=> root.pass;
            placeholder-text: "";
        }
        ProgressIndicator {
            preferred-width: 100%;
            height: 25px;
            progress <=> counter;
            
          
        }
        Text {
            text: "状态: \{root.status}用户: \{root.user}密码: \{root.pass}";
        }
        Button {
            text: "登陆";
            clicked => {
                root.request-increase-value();
            }
        }
    }
}

完成上线

前面的reqwest中的cookie解决以后,用了一天,折腾regex,把以前定义的两三个提取,请求,再实现了一把。 又细细看了几个regex演示。学不来,学不会, 这玩意真是和R语言一样,太复杂了。我只是按照旧方式实现了。然后,任务做成了长时的。界面就在转圈。于是在改成,后才thread前。我试着让任务和界面通信。把ui传递给,网页处理程序。结果总是不行。然后找了共享全局变量的办法,static mut &。这一串下来,把全局变量,从main,移动到了reqwest主程序的模块。让它处一个独立thread、去完成上线。上main里的ui,独立运行一个loop。长久的2秒,取一个全局变量,set给一个界面元素。到于slint 里的todolist。model这一类的代码,看得一头雾水。有点早。
在main.rs下建立wjc文件夹,作为mod在练习。建立两个文件,一个
mod.rs

pub mod kkuser;
pub mod jscrypto;

kkuser.rs

use reqwest::blocking::Client;
use reqwest;
use regex::Regex;
use std::{collections::HashMap, fmt::format};
use std::error::Error;
use reqwest::{cookie::Jar, Url};
use serde::{Deserialize, Serialize};
use std::{thread, time::Duration};
use serde_json::json;  
// 共享状态
pub static mut thestat: Option< &str> = Some(""); 
pub static mut progbar:f32=0.001;
pub struct KKUser {
    active: bool,
    username: String,
    passwd: String,
    client: Client,
   
} 
pub fn build_kkuser(username: String, passwd: String) -> Result<KKUser,Box<dyn Error>>{
   let client = Client::builder()
   .cookie_store(true)
   .build()?;
    let ret= KKUser {
        active: false,
        username,
        passwd,
         client,
    };
    Ok(ret)

}
impl KKUser {
    fn getloginurl(&self)->Result<String,Box<dyn Error>>{
             
         let re = Regex::new(
            r#"form_login_true" action="(.+?)""#).unwrap();
         let ret =self.client
           .get(BURL)
           .send()?
           .text_with_charset("GBK")?;
        let cap=re.captures(&*ret).unwrap() ;  
        println!("{:?}",&cap[1]);
        let id=String::from(&cap[1]);
        Ok(id)

    }
    pub    fn login(&self )->Result<bool,Box<dyn Error >> {
        let id=self.getloginurl().unwrap();  
       // let check=self.getloginurl(&client).unwrap();
        let var_name = format!("{BURL}{id}");
        let mut map = HashMap::new();
        map.insert("u_dlcode", self.username.as_str());
        map.insert("p_dlcode", self.passwd.as_str());
        let ret:String =  self.client
     .post(var_name)
     .form(&map)
     .send()?
   .text_with_charset("GBK")?;
      println!("{ret}\n");
      assert_eq!(true,ret.contains("home"));
     Ok(ret.to_string().contains("home"))
   }
  }
pub fn test() -> Result<(), Box<dyn Error>> {
     
     let handle= std::thread::spawn(||{
     let  u =build_kkuser("V/JNlfP3SBG8tUJW5tIAo+UogWKJ6StCzwbt4zzm4=".to_string(), "E1Kf42cdpAwXknHXIy6eqIDhtQj85wCqwer6nUTzw".to_string())
      .unwrap(); 
      let r=u.login().unwrap() ;
      let ee=format!("{r}");
        u.v_jiaru().unwrap();
    //更新全局变量,用时间较长。
        u.v_ksxx(  ).unwrap() ;
      Ok(())
    }

在这里插入图片描述

设置密码

这个网站的密码和用户名是AES-MD5,加密的串。算法是js实现 的、为模拟用的是现在加密过的,为了真实使用,还需要有自己的加密算法。由于是浏览器 的算法,我就算是web从服务器来一个询问都是做不到的。为此大学AES一天24小时。也考虑从rust,访问js脚本和语句。用了两个库,都是失败的。虽然有声称可用的。我想,他会加大程序 的体积和依赖外部环境。失去灵动能力。无耐,rust本身,一大堆的半成品。从中总算发现一个现成的实现。其实是发现了两个,一个不含ZeroPading。是js正用的。另一个倒是含有。我算过了大概的一致参数,却不能得到一致结果。后来就想改写js到rust。https://www.codeconvert.ai/free-converter 它会转换js到R代码,在折腾了快一半的时候,深感难。后来看AES的文章说,算法和参数一样,就会有一样的结果。我就又回头比对参数。从cha数组 u8,数组,分析,第个参数,是传过去的什么值。 型号浏览器devtool。看起js的内容,那太方便。才知道刚好差不多。而rust最终给的 [u8] 不是最后js得到的,js最后很像BASE64,最后证明真是,完成后的长充40-43,用parase,解码成bytest、长度刚好32bits。这和rust取得的结果也挺像的。于是base64,处理过。js和R终于成功会合。另外就md5是套在密码外,然后给AES处理的。于是这就好办了。R有很标准的MD5. 有一个点是,处理出的结果还是 [u8].可以直接做AES的输入。但是要是拿来用,就又不对了。 感谢js的直观。它的md5,得到的u8的十六进制小写字符串。然后给了AES。这就好了,R,结果又安装了个小库, 只为了转成十六进制。看来,语言全靠外挂,怪不得可以跑嵌入式400K内存的板子。 我猜也许AI可以做到很多,我还是纯靠搜索了。
在Cargo.toml加入

[dependencies]
 aes="0.8.4"
 block-padding ="0.3.3"
 cbc="0.1.2" 
 base64="0.22.1"
 hex-literal="0.4.1" 
 md-5 = "0.10.6"
 data-encoding = "2.6.0"

在wjc目录建立新文件jscrypto.rs
在同目录下的kkuser.rs添加use super::jscrypto ;以使用其功能

//前端js,使用crypto-js对数据进行AES加密
//function js_encrypt(text){
//var key = CryptoJS.enc.Latin1.parse('1E785CMD585LLS4S');//为了避免补位,直接用16位的秘钥
//	var iv = CryptoJS.enc.Latin1.parse('1234431890129056');//16位初始向量
//	var encrypted = CryptoJS.AES.encrypt(text, key, {
//	iv: iv,
	//	mode:CryptoJS.mode.CBC,
//		padding:CryptoJS.pad.ZeroPadding
//use std::char;
use block_padding::*;
use data_encoding::{HEXLOWER, DecodeError};
use std::error::Error; 
use base64::prelude::*;
 
use md5::{Md5, Digest};
use aes::cipher::{ BlockEncryptMut, KeyIvInit};
type Aes128CbcEnc = cbc::Encryptor<aes::Aes128>;

pub fn cry_AES(input: &str) -> Result<String, Box<dyn Error>> {

    let mut key= *b"1E785CMD585LLS4S"; 
	let mut iv=*b"1234431890129056";
    let mut buf = [0u8; 48];
    let pt_len = input.len();
    buf[..pt_len].copy_from_slice(&input.as_bytes());
    let ct =Aes128CbcEnc::new(&key.into(), &iv.into())
        .encrypt_padded_mut::<ZeroPadding>(&mut buf, pt_len)
        .unwrap();
       
    let bstr =BASE64_STANDARD.encode(ct);
    Ok(bstr)
         
}
pub fn test() {

    let mut key= *b"1E785CMD585LLS4S"; 
	let mut iv=*b"1234431890129056";

    let ct = cry_AES("username");
    println!("{:?}",ct.unwrap());
    
    let mut hasher = Md5::new();
    hasher.update(b"passwd");
    let     mdu8 = hasher.finalize();
    let encoded = HEXLOWER.encode(&mdu8);

    println!("{:?}",  cry_AES(encoded.as_str()).unwrap() );
    
}



fn main (){

    test();
}

整理完毕

至此完成,生成的程序10M上下,一个前台窗口,一个后台任务。点一下动一下。我是在苹果Mac上开发的,它 的虚拟机是一个win11 X64,拷贝工程前,删除了target目录,才让移动的,不然动不了。也不知道累积到了几百M、 拷贝过去,cargo build
cargo build --release ,都是干一会就好,本来也没啥内容。 把结果运行一下。换个目录再运行一下。感觉还是蛮爽的。

去年做过一个python jupyter下的,相似程序。它在server上运行,是python在wedget编程,后而传给celery任务。我觉得也挺好的,有容了再提交一篇。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2170279.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C# DotNetty客户端

1. 引入DotNetty包 我用的开发工具是VS2022&#xff0c;不同工具引入可能会有差异 工具——>NuGet包管理器——>管理解决方案的NuGet程序包 搜索DotNetty 2.新建EchoClientHandler.cs类 用于接收服务器返回数据 public class EchoClientHandler : SimpleChannelIn…

vs code自动报错

让vs code自动报错&#xff0c; 点击插件 → 搜索error lens → 点击install&#xff0c; 下载完后&#xff0c;编写的代码有问题就会自动报错了。 5、修改默认缩进字符 点击设置&#xff08;settings&#xff09; → 点击常用设置 → 修改字符缩进。

汽车自研算法部署芯片份额浅思

国内汽车行业如火如荼发展,汽车从业的研发人员也激增,从三电到座舱到智能驾驶和动力底盘一体化发展。 芯片承载着算法落地,国内主流的主机厂(OEM)的EE架构规划都基本使用主流的车规级芯片,如 英飞凌(Infineon):德国半导体制造商,行业当前在预控的SOC的MCU选择TC39X…

ROC、TPR、FPR的含义

1、ROC&#xff08;Receiver Operating Characteristic&#xff09; ROC&#xff08;Receiver Operating Characteristic&#xff09;曲线是一种用于评估分类模型性能的工具。它通过绘制真阳性率&#xff08;True Positive Rate, TPR&#xff09;与假阳性率&#xff08;False…

新书速览|Stable Diffusion-ComfyUI AI绘画工作流解析

《Stable Diffusion-ComfyUI AI绘画工作流解析》 本书内容 《Stable Diffusion-ComfyUI AI绘画工作流解析》从零开始&#xff0c;详尽系统地讲解从本地部署ComfyUI、下载安装自定义节点&#xff0c;到搭建各种工作流程的全过程。同时&#xff0c;辅以3D形象转绘、艺术二维码和证…

智能制造的生产力基础设施

由于全球大多数细分市场的半导体工厂都满负荷运转&#xff0c;因此&#xff0c;生产力如今成为整个行业关注的重要问题也就不足为奇了。工厂经理会仔细监控关键绩效指标 (KPI)&#xff0c;以发现任何生产力下降的迹象&#xff0c;以便快速做出反应&#xff0c;找出并解决这些偏…

UE4中 -skipbuild -nocompile 有什么区别

在项目开发中&#xff0c;我看到了在调用 Engine\\Build\\BatchFiles\\RunUAT.bat 相关的命令行中&#xff0c;有 -skipbuild、 -nocompile 两个很像的参数&#xff0c;于是想探究一下它们的区别与含义。 -skipbuild 参数 到底有没有 -skipbuild 这个参数&#xff1f;根据 http…

1.3 熟悉常用的IP相关命令

1.3熟悉常用的IP相关命令 原理概述 华为设备支持多种配置方式&#xff0c;包括Web界面管理等。但作为一名网络工程师&#xff0c;必须熟悉使用命令行的方式进行设备管理。在工作中&#xff0c;对路由器和交换机最常用的操作命令就是IP相关命令&#xff0c;如配置主机名、IP地…

<Rust>egui学习之部件(十三):如何为文本添加链接Link和超链接HyperLink功能?

前言 本专栏是关于Rust的GUI库egui的部件讲解及应用实例分析&#xff0c;主要讲解egui的源代码、部件属性、如何应用。 环境配置 系统&#xff1a;windows 平台&#xff1a;visual studio code 语言&#xff1a;rust 库&#xff1a;egui、eframe 概述 本文是本专栏的第十三篇…

ROS与无人驾驶学习笔记(零)——问题汇总

文章目录 ubuntu相关问题 ubuntu中中文输入法没有输入框 在ubuntu中使用双拼输入 ros卸载重装报错的问题 在学习ubuntu、ros以及无人驾驶过程中遇到的问题我都记在在这里 ubuntu相关问题 ❤ 2024.9.20 ❤ ubuntu中中文输入法没有输入框 因为我用的是arm平台&#xff0c;于…

软件对比 | 历史气象数据哪里找?

中国气象网和羲和能源气象大数据平台两个平台当然没有“绝对”哪个好的说法&#xff0c;各自特点都在下图进行总结&#xff0c;到底用哪个还是根据自己需求自己抉择。 希望可以帮助到大家~

Maven中 <parent > 的<version>可以使用变量吗

答案&#xff1a; 不可以&#xff01; 在 Maven 中&#xff0c;父 POM 的 <version> 元素不能直接使用变量。父 POM 的版本号必须是硬编码的&#xff0c;不能通过变量来动态设置。这是因为父 POM 的版本号在子模块中引用时&#xff0c;需要是一个固定的值&#xff0c;以…

记录:ubuntu20.04的安装和必要的开发准备

记录ubuntu20.04的安装和必要的开发准备 准备1. 安装ubuntu20.04时的Tips2. 屏幕亮度调节问题3. 解决 "No Wi-Fi Adapter Found"4. Nvidia Driver && cuda5. 修改安装源6. ssh 远程开发7. 安装 anaconda 准备 没有装双系统&#xff0c;只有 ubuntu20.04&…

【ZYNQ 开发】填坑!双核数据采集系统LWIP TCP发送,运行一段时间不再发送且无法ping通的问题解决

问题描述 之所以说是填坑&#xff0c;是因为之前写了一篇关于这个双核数据采集系统的调试记录&#xff0c;问题的具体表现是系统会在运行一段时间后&#xff08;随机不定时&#xff0c;长了可能将近两小时&#xff0c;短则几分钟&#xff09;&#xff0c;突然间就不向电脑发送数…

电脑文件夹如何加密保护?文件夹加密方法有哪些?

在信息时代&#xff0c;数据安全已成为广大用户关注的焦点。电脑文件夹中往往存放着重要的文档、照片、账单等隐私信息&#xff0c;一旦泄露&#xff0c;后果不堪设想。因此&#xff0c;为电脑文件夹加密保护显得尤为重要。本文将介绍几种常见的文件夹加密方法&#xff0c;帮助…

【二叉平衡搜索树】Treap

前置 本篇是平衡树-treap的补充学习笔记。 Treap - 树堆 学习基础&#xff1a;适合一定基础的&#xff1a;比如&#xff0c;实现了经典二叉搜索树&#xff08;常用的几个函数写过&#xff09;&#xff0c; 和二叉堆&#xff08;数组的上浮下沉会写吗&#xff1f;&#xff09;&a…

LDRA Testbed(TBrun)软件集成测试(部件测试)_操作指南

系列文章目录 LDRA Testbed软件静态分析_操作指南 LDRA Testbed软件静态分析_自动提取静态分析数据生成文档 LDRA Testbed软件静态分析_Jenkins持续集成&#xff08;自动静态分析并用邮件自动发送分析结果&#xff09; LDRA Testbed软件静态分析_软件质量度量 LDRA Testbed软件…

工厂模式和抽象工厂模式的实验报告

1. 实验结果&#xff1a; 记录并附上不同模型对象&#xff08;例如&#xff1a;士兵、机器人、骑士&#xff09;的展示效果截图。 2. 性能分析&#xff1a; 记录并比较抽象工厂模式与直接实例化的性能测试结果&#xff0c;分析它们在不同数量级对象创建时的开销与效益。 2.1…

系统架构设计师 - 案例特训专题 - 数据库设计篇

案例特训专题 - 数据库设计篇 数据库设计篇规范化与反规范化 ★★★规范化 - 范式反规范化 数据库索引数据库视图数据库分区分表分库分区分区的常见方式 分表分库 分布式数据库 ★★★NoSQL ★★★其他数据库扩展知识 ★★★数据库性能优化集中式数据库优化分布式数据库优化 大…

Thingsboard规则链:Related Device Attributes节点详解

引言 在物联网&#xff08;IoT&#xff09;领域&#xff0c;Thingsboard作为一款强大的物联网平台&#xff0c;其规则链功能为企业提供了高度定制化的数据处理和自动化控制方案。其中&#xff0c;Related Device Attributes节点是一个特别实用的组件&#xff0c;它能够访问和操…