Commit e59fcc94 authored by 陈冲's avatar 陈冲

create h5, large

parent 889c6ad0
......@@ -757,32 +757,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
[[package]]
name = "fc-backend"
version = "0.1.0"
dependencies = [
"aes",
"async-trait",
"base64",
"bytes",
"cbc",
"chrono",
"dashmap",
"lazy_static",
"md-5",
"rand 0.10.0",
"rmp-serde",
"rust-embed",
"salvo",
"serde",
"serde_json",
"socketioxide",
"sqlx",
"tokio",
"tower",
"tower-http",
]
[[package]]
name = "find-msvc-tools"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
......@@ -1637,6 +1611,32 @@ dependencies = [
]
[[package]]
name = "minigame"
version = "0.1.0"
dependencies = [
"aes",
"async-trait",
"base64",
"bytes",
"cbc",
"chrono",
"dashmap",
"lazy_static",
"md-5",
"rand 0.10.0",
"rmp-serde",
"rust-embed",
"salvo",
"serde",
"serde_json",
"socketioxide",
"sqlx",
"tokio",
"tower",
"tower-http",
]
[[package]]
name = "miniz_oxide"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
......
[package]
name = "fc-backend"
name = "minigame"
version = "0.1.0"
edition = "2024"
......@@ -7,7 +7,7 @@ edition = "2024"
bytes = "1.10.1"
chrono = { version = "0.4.44", features = ["serde"] }
async-trait = "0.1.89"
sqlx = { version = "0.8.2", features = ["runtime-tokio", "tls-rustls-ring-native-roots", "postgres", "chrono", "json"] }
sqlx = { version = "0.8.2", features = ["runtime-tokio", "tls-rustls-ring-native-roots", "postgres", "mysql", "chrono", "json"] }
rand = "0.10.0"
rust-embed = { version = "8.11.0", features = ["debug-embed"] }
salvo = { version = "0.90.1", features = ["serve-static", "tower-compat"] }
......@@ -27,9 +27,9 @@ cbc = { version = "0.1.2", features = ["alloc"] }
md5 = { version = "0.10.6", package = "md-5" }
[[bin]]
name = "fc-backend"
name = "minigame"
# [target.aarch64-unknown-linux-gnu]
# linker = "aarch64-linux-gnu-gcc"
[target.x86_64-unknown-linux-musl]
linker = "rust-lld"
# cross build --release --target aarch64-unknown-linux-gnu
# cargo zigbuild --release --target x86_64-unknown-linux-musl
DROP TABLE IF EXISTS tb_game;
CREATE TABLE tb_game
(
event_date DATE,
wechat_id VARCHAR(50),
nickname VARCHAR(50),
avatar VARCHAR(200),
round_num INT NOT NULL,
item_num INT NOT NULL,
score INT NOT NULL DEFAULT 0,
create_date DATETIME,
UNIQUE KEY uk_tb_game_player_item (event_date, wechat_id, round_num, item_num)
);
DROP TABLE IF EXISTS tb_log;
CREATE TABLE tb_log
(
id BIGINT AUTO_INCREMENT PRIMARY KEY,
msg TEXT,
params JSON,
create_date DATETIME
);
DROP TABLE IF EXISTS tb_manager;
CREATE TABLE tb_manager
(
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(20),
`password` VARCHAR(20),
token VARCHAR(36)
);
INSERT INTO tb_manager(username, `password`, token)
VALUES ('admin', '123456', '88236aeb-8d3f-6d56-fdf5-3adca3961dfb');
use crate::commons::utils::CONFIG as config;
use crate::db::mysql::MysqlDb;
use crate::db::pg::PgDb;
use async_trait::async_trait;
use serde_json::Value;
use tokio::sync::OnceCell;
pub mod pg;
pub mod mysql;
pub mod models;
pub mod pg;
#[async_trait]
trait DbDriver: Send + Sync {
......@@ -18,6 +20,7 @@ static DB_CONN: OnceCell<Box<dyn DbDriver>> = OnceCell::const_new();
pub async fn init_db() -> Result<(), String> {
let conn: Box<dyn DbDriver> = match config.db.kind.as_str() {
"postgresql" => Box::new(PgDb::new().await?),
"mysql" => Box::new(MysqlDb::new().await?),
other => {
return Err(format!("unsupported db kind: {other}"));
}
......
......@@ -12,14 +12,14 @@ pub struct Manager {
pub enum ManagerLogin {
/// username / password
unpw(String, String),
user(String, String),
token(String),
}
impl Manager {
pub async fn Login(m: ManagerLogin) -> Result<Self, String> {
match m {
ManagerLogin::unpw(username, password) => {
ManagerLogin::user(username, password) => {
let rows = crate::db::db_query(
r#"select id,username,password,token from tb_manager where username=? and password=? limit 1;"#,
vec![json!(username), json!(password)],
......
use crate::commons::utils::CONFIG as config;
use crate::db::DbDriver;
use async_trait::async_trait;
use serde_json::{Value, json};
use sqlx::mysql::{MySqlArguments, MySqlPoolOptions, MySqlRow};
use sqlx::{Column, MySql, MySqlPool, Row, TypeInfo};
pub struct MysqlDb {
pool: MySqlPool,
}
impl MysqlDb {
pub async fn new() -> Result<Self, String> {
let pool = MySqlPoolOptions::new()
.max_connections(16)
.connect(&config.db.uri)
.await
.map_err(|err| err.to_string())?;
Ok(Self { pool })
}
}
#[async_trait]
impl DbDriver for MysqlDb {
async fn query(&self, sql: &str, params: Vec<Value>) -> Result<Vec<Value>, String> {
let mut conn = self.pool.acquire().await.map_err(|err| err.to_string())?;
mysql_query_rows(&mut *conn, sql, params).await
}
async fn transaction(&self, queries: Vec<Value>) -> Result<Vec<Value>, String> {
let mut tx = self.pool.begin().await.map_err(|err| err.to_string())?;
let mut results = Vec::with_capacity(queries.len());
for query in queries.iter() {
let sql = query
.get("query")
.or_else(|| query.get("sql"))
.and_then(|value| value.as_str())
.unwrap_or("")
.trim();
if sql.is_empty() {
return Err("transaction query sql is empty".to_string());
}
let params = query
.get("params")
.and_then(|value| value.as_array())
.cloned()
.unwrap_or_default();
let rows = mysql_query_rows(&mut *tx, sql, params).await?;
results.push(Value::Array(rows));
}
tx.commit().await.map_err(|err| err.to_string())?;
Ok(results)
}
}
async fn mysql_query_rows<'e, E>(
executor: E,
sql: &str,
params: Vec<Value>,
) -> Result<Vec<Value>, String>
where
E: sqlx::Executor<'e, Database = MySql>,
{
let sql = normalize_sql(sql);
let mut query = sqlx::query(sql.as_str());
for param in params.into_iter() {
query = mysql_bind_param(query, param);
}
let rows = query
.fetch_all(executor)
.await
.map_err(|err| err.to_string())?;
rows.into_iter()
.map(mysql_row_to_json)
.collect::<Result<Vec<_>, _>>()
}
fn normalize_sql(sql: &str) -> String {
sql.replace("?::date", "?")
.replace("?::jsonb", "?")
.replace("?::json", "?")
}
fn mysql_bind_param<'q>(
query: sqlx::query::Query<'q, MySql, MySqlArguments>,
value: Value,
) -> sqlx::query::Query<'q, MySql, MySqlArguments> {
match value {
Value::Bool(v) => query.bind(v),
Value::Number(v) => {
if let Some(v) = v.as_i64() {
query.bind(v)
} else {
let v = v.as_f64().unwrap_or_default();
if v.fract() == 0.0 {
query.bind(v as i64)
} else {
query.bind(v)
}
}
}
Value::String(v) => query.bind(v),
Value::Array(v) => query.bind(sqlx::types::Json(Value::Array(v))),
Value::Object(v) => query.bind(sqlx::types::Json(Value::Object(v))),
Value::Null => query.bind(Option::<String>::None),
}
}
fn mysql_row_to_json(row: MySqlRow) -> Result<Value, String> {
let mut item = serde_json::Map::new();
for (index, column) in row.columns().iter().enumerate() {
let type_name = column.type_info().name().to_ascii_uppercase();
let value = match type_name.as_str() {
"BOOLEAN" | "BOOL" => json!(
row.try_get::<Option<bool>, _>(index)
.map_err(|err| err.to_string())?
),
"TINYINT" => json!(
row.try_get::<Option<i8>, _>(index)
.map_err(|err| err.to_string())?
),
"SMALLINT" => json!(
row.try_get::<Option<i16>, _>(index)
.map_err(|err| err.to_string())?
),
"INT" | "INTEGER" | "MEDIUMINT" => json!(
row.try_get::<Option<i32>, _>(index)
.map_err(|err| err.to_string())?
),
"BIGINT" => json!(
row.try_get::<Option<i64>, _>(index)
.map_err(|err| err.to_string())?
),
"FLOAT" => json!(
row.try_get::<Option<f32>, _>(index)
.map_err(|err| err.to_string())?
),
"DOUBLE" | "REAL" => json!(
row.try_get::<Option<f64>, _>(index)
.map_err(|err| err.to_string())?
),
"VARCHAR" | "CHAR" | "TEXT" | "TINYTEXT" | "MEDIUMTEXT" | "LONGTEXT" => json!(
row.try_get::<Option<String>, _>(index)
.map_err(|err| err.to_string())?
),
"JSON" => row
.try_get::<Option<sqlx::types::Json<Value>>, _>(index)
.map_err(|err| err.to_string())?
.map(|value| value.0)
.unwrap_or(Value::Null),
"DATE" => json!(
row.try_get::<Option<chrono::NaiveDate>, _>(index)
.map_err(|err| err.to_string())?
.map(|date| date.to_string())
),
"DATETIME" | "TIMESTAMP" => {
let value = row
.try_get::<Option<chrono::NaiveDateTime>, _>(index)
.map_err(|err| err.to_string())?
.map(|ts| ts.and_utc().timestamp_millis())
.unwrap_or(0);
json!(value)
}
_ => json!(type_name),
};
item.insert(column.name().to_string(), value);
}
Ok(Value::Object(item))
}
use crate::commons::utils::CONFIG as config;
use crate::db::{DbDriver};
use crate::db::DbDriver;
use async_trait::async_trait;
use serde_json::{Value, json};
use sqlx::postgres::{PgPoolOptions, PgRow};
......
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>小游戏-大屏</title>
<style>body{background: #FA6047;}</style>
<script type="module" crossorigin src="/assets/index-uTGyaFOd.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-BMxx4b9P.css">
</head>
<body>
<div id="app"></div>
</body>
</html>
......@@ -36,7 +36,7 @@ mod tests {
// dbg!(&res);
let res = crate::db::models::manager::Manager::Login(
crate::db::models::manager::ManagerLogin::unpw(
crate::db::models::manager::ManagerLogin::user(
"admin".to_string(),
"123456".to_string(),
),
......
......@@ -6,19 +6,38 @@ mod router;
use commons::utils::CONFIG as config;
use db::init_db;
#[derive(rust_embed::RustEmbed)]
#[folder = "src/web"]
struct Assets;
// #[derive(rust_embed::RustEmbed)]
// #[folder = "src/web"]
// struct AssetsWeb;
// #[derive(rust_embed::RustEmbed)]
// #[folder = "src/large"]
// struct AssetsLarge;
// #[derive(rust_embed::RustEmbed)]
// #[folder = "src/wechat"]
// struct AssetsWechat;
#[tokio::main]
async fn main() {
if let Err(err) = init_db().await {
panic!("init db failed: {err}");
}
let router = Router::new().push(router::config_router()).push(
Router::with_path("/web/{**path}")
.get(salvo::serve_static::static_embed::<Assets>().fallback("index.html")),
);
let router = Router::new()
.push(router::config_router())
// .push(
// Router::with_path("/web/{**path}")
// .get(salvo::serve_static::static_embed::<AssetsWeb>().fallback("index.html")),
// )
// .push(
// Router::with_path("/wechat/{**path}")
// .get(salvo::serve_static::static_embed::<AssetsWechat>().fallback("index.html")),
// )
// .push(
// Router::with_path("/large/{**path}")
// .get(salvo::serve_static::static_embed::<AssetsLarge>().fallback("index.html")),
// )
;
let host = config.host.clone();
dbg!(&config);
println!("http://{}", host);
......
This diff is collapsed.
......@@ -25,6 +25,7 @@ pub fn config_router() -> Router {
.goal(hello),
)
.push(Router::with_path("/manager/login").post(crate::protocols::socket_io::login))
.push(Router::with_path("/manager/getConn").post(crate::protocols::socket_io::getConn))
}
pub fn config_catcher() -> Catcher {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment