use actix_web::{App, HttpResponse, HttpServer, Responder, Result, post, web}; use db::create_pool; use reqwest::Client; use serde::{Deserialize, Serialize}; use sqlx::postgres::PgPool; mod db; mod models; use models::WeatherData; // 定义请求体结构 #[derive(Debug, Deserialize)] struct OpenIdRequest { openid: String, } // 定义成功响应结构 #[derive(Debug, Serialize)] struct UserIdResponse { user_id: i32, } // 微信登录请求结构 #[derive(Debug, Deserialize)] struct WeChatLoginRequest { code: String, } // 微信API响应结构 #[derive(Debug, Deserialize)] struct WeChatApiResponse { openid: Option, errcode: Option, errmsg: Option, } // 我们的API响应结构 #[derive(Debug, Serialize)] struct OpenIdResponse { openid: String, } #[derive(Debug, Serialize)] struct ErrorResponse { error: String, errcode: Option, errmsg: Option, } // 新增:根据openid获取用户ID的端点 #[post("/getmyid")] async fn get_user_id(pool: web::Data, request: web::Json) -> impl Responder { let openid = &request.openid; // 查询用户ID let query = r#" SELECT id FROM users WHERE openid = $1 "#; let result: Result, sqlx::Error> = sqlx::query_as::<_, (i32,)>(query) .bind(openid) .fetch_optional(pool.get_ref()) .await; match result { Ok(Some(user_id)) => { println!("Found user ID {} for openid {}", user_id.0, openid); HttpResponse::Ok().json(UserIdResponse { user_id: user_id.0 }) } Ok(None) => { println!("No user found with openid: {}", openid); HttpResponse::NotFound().json(ErrorResponse { error: format!("未找到openid为 {} 的用户", openid), errcode: Some(404), // 添加错误码 errmsg: Some("用户不存在".to_string()), // 添加错误消息 }) } Err(e) => { eprintln!("Database error: {}", e); HttpResponse::InternalServerError().json(ErrorResponse { error: format!("数据库查询错误: {}", e), errcode: Some(500), // 添加错误码 errmsg: Some(e.to_string()), // 添加错误消息 }) } } } // 获取openid的API端点 #[post("/getopenid")] async fn get_openid( pool: web::Data, req: web::Json, http_client: web::Data, ) -> impl Responder { // 从环境变量获取微信小程序配置 let appid = match std::env::var("WECHAT_APPID") { Ok(id) => id, Err(_) => { return HttpResponse::InternalServerError().json(ErrorResponse { error: "服务器配置错误:缺少微信小程序appid".to_string(), errcode: None, errmsg: None, }); } }; let secret = match std::env::var("WECHAT_SECRET") { Ok(secret) => secret, Err(_) => { return HttpResponse::InternalServerError().json(ErrorResponse { error: "服务器配置错误:缺少微信小程序secret".to_string(), errcode: None, errmsg: None, }); } }; // 构建微信API请求URL let url = format!( "https://api.weixin.qq.com/sns/jscode2session?appid={}&secret={}&js_code={}&grant_type=authorization_code", appid, secret, req.code ); // 调用微信API let wechat_response = match http_client.get(&url).send().await { Ok(response) => response, Err(e) => { eprintln!("请求微信API失败: {}", e); return HttpResponse::InternalServerError().json(ErrorResponse { error: "请求微信服务失败".to_string(), errcode: None, errmsg: None, }); } }; // 解析微信API响应 let wechat_data: WeChatApiResponse = match wechat_response.json().await { Ok(data) => data, Err(e) => { eprintln!("解析微信API响应失败: {}", e); return HttpResponse::InternalServerError().json(ErrorResponse { error: "解析微信响应失败".to_string(), errcode: None, errmsg: None, }); } }; // 检查微信API响应中的错误 if let Some(errcode) = wechat_data.errcode { return HttpResponse::BadRequest().json(ErrorResponse { error: "微信登录失败".to_string(), errcode: Some(errcode), errmsg: wechat_data.errmsg, }); } // 获取openid let openid = match wechat_data.openid { Some(id) => id, None => { return HttpResponse::InternalServerError().json(ErrorResponse { error: "微信API未返回openid".to_string(), errcode: None, errmsg: None, }); } }; // 检查用户是否已存在,不存在则创建 let query = r#" INSERT INTO users (openid) VALUES ($1) ON CONFLICT (openid) DO NOTHING RETURNING id "#; let result = sqlx::query_as::<_, (i32,)>(query) .bind(&openid) .fetch_optional(pool.get_ref()) .await; match result { Ok(Some(user_id)) => { println!("用户已存在,ID: {}", user_id.0); } Ok(None) => { println!("新用户已创建,openid: {}", openid); } Err(e) => { eprintln!("数据库操作失败: {}", e); // 即使数据库操作失败,我们仍然返回openid,因为微信登录已经成功 } } // 返回openid给前端 HttpResponse::Ok().json(OpenIdResponse { openid }) } #[post("/weather-test")] async fn post_weather_data( data: web::Json, pool: web::Data, ) -> impl Responder { // 打印接收的数据 println!("Received weather data: {:#?}", data); // 1. 根据openid查询user_id let openid = &data.openid; let query_user = r#" SELECT id FROM users WHERE openid = $1 "#; let user_id_result: Result, sqlx::Error> = sqlx::query_as::<_, (i32,)>(query_user) .bind(openid) .fetch_optional(pool.get_ref()) .await; let user_id = match user_id_result { Ok(Some((id,))) => id, Ok(None) => { let error_msg = format!("未找到openid为 {} 的用户", openid); eprintln!("{}", error_msg); // 返回200状态码,但success为false return HttpResponse::Ok().json(serde_json::json!({ "success": false, "errcode": 404, "errmsg": error_msg })); } Err(e) => { let error_msg = format!("查询用户失败: {}", e); eprintln!("{}", error_msg); return HttpResponse::Ok().json(serde_json::json!({ "success": false, "errcode": 500, "errmsg": error_msg })); } }; // 2. 将天气数据插入数据库 let insert_query = r#" INSERT INTO weather_data ( user_id, title, date, hour, min, longitude, latitude, daysincejanfirst, theta, solardeclination, sunaltitude, overallcloudiness, lowcloudiness, cloudindex, solarradiationlevel, hasmeasuredwindspeed, measuredwindspeed, convertedwindspeed, measurementheight, areatype, pointwindspeed, atmosphericstability, suitabilitydegree, winddirection, averagewinddirection, winddirectionstandarddeviation, windspeed, averagewindspeed, windspeedsuitability, winddirectionsuitability, overallsuitability, inspectiontype, assignmentnumber, calculatedwindspeed ) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34 ) RETURNING id "#; // 转换经纬度为字符串 let longitude_str = data.longitude.to_string(); let latitude_str = data.latitude.to_string(); // 执行插入操作 let result = sqlx::query_as::<_, (i32,)>(insert_query) .bind(user_id) .bind(&data.title) .bind(&data.date) .bind(data.hours) .bind(data.min) .bind(&longitude_str) .bind(&latitude_str) .bind(data.day_since_jan_first) .bind(data.theta) .bind(data.solar_declination) .bind(data.sun_altitude) .bind(&data.overall_cloudiness) .bind(&data.low_cloudiness) .bind(&data.cloud_index) .bind(data.solar_radiation_level as i32) .bind(data.has_measured_wind_speed) .bind(data.measured_wind_speed) .bind(data.converted_wind_speed as i32) .bind(data.measurement_height) .bind(&data.area_type) .bind(data.point_wind_speed) .bind(&data.atmospheric_stability) .bind(&data.suitability_degree) .bind(serde_json::to_value(&data.wind_direction).unwrap()) .bind(data.average_wind_direction) .bind(data.wind_direction_standard_deviation) .bind(serde_json::to_value(&data.wind_speed).unwrap()) .bind(data.average_wind_speed) .bind(&data.wind_speed_suitability) .bind(&data.wind_direction_suitability) .bind(&data.overall_suitability) .bind(&data.inspection_type) .bind(&data.assignment_number) .bind(data.calculated_wind_speed) .fetch_one(pool.get_ref()) .await; match result { Ok((inserted_id,)) => { println!( "Successfully inserted weather data with id: {}", inserted_id ); HttpResponse::Ok().json(serde_json::json!({ "success": true, // 前端期望的成功标识 "message": "Weather data inserted successfully", "inserted_id": inserted_id, "received_assignment": data.assignment_number })) } Err(e) => { let error_msg = format!("插入数据失败: {}", e); eprintln!("{}", error_msg); HttpResponse::Ok().json(serde_json::json!({ "success": false, // 前端期望的失败标识 "errcode": 500, "errmsg": error_msg })) } } } // 创建服务器配置的函数 fn create_server_config( pool: PgPool, http_client: Client, ) -> App< impl actix_web::dev::ServiceFactory< actix_web::dev::ServiceRequest, Config = (), Response = actix_web::dev::ServiceResponse, Error = actix_web::Error, InitError = (), >, > { App::new() .app_data(web::Data::new(pool)) .app_data(web::Data::new(http_client)) .service(get_user_id) .service(get_openid) .service(post_weather_data) } #[actix_web::main] async fn main() -> std::io::Result<()> { // 初始化数据库连接池 let pool = match create_pool().await { Ok(pool) => pool, Err(e) => { eprintln!("Failed to create database pool: {}", e); eprintln!("Please check your database connection configuration in .env file"); std::process::exit(1); } }; // 初始化HTTP客户端 let http_client = Client::new(); println!("Attempting to start server..."); // 尝试多个端口 let ports = vec![8080, 3000, 8000, 8888]; let mut server = None; for port in ports { let addr = format!("0.0.0.0:{}", port); println!("Trying to bind to {}", addr); // 为每个服务器创建克隆的连接池和HTTP客户端 let pool_clone = pool.clone(); let http_client_clone = http_client.clone(); match HttpServer::new(move || { create_server_config(pool_clone.clone(), http_client_clone.clone()) }) .bind(&addr) { Ok(s) => { println!("Successfully bound to {}", addr); server = Some(s); break; } Err(e) => { eprintln!("Failed to bind to {}: {}", addr, e); if e.kind() == std::io::ErrorKind::PermissionDenied { eprintln!(" -> Permission denied. Try running with sudo or use a port > 1024"); } continue; } } } match server { Some(s) => { println!("Server started successfully"); s.run().await } None => { eprintln!("Failed to bind to any port. Please check your system configuration."); std::process::exit(1); } } }