nodejsでもやったから次はRustどと思いました
環境:
OS: MacOS
editor: vscode
同じWiFiにつながってないと他のパソコンや端末からアクセスできません!
デレクトリ
.
├── Cargo.lock
├── Cargo.toml
├── src
│ └── main.rs
└── static
└── index.html
3 directories, 4 files
コード
cargo new server
cargo.toml
[package]
name = "Server"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
warp = "0.3"
tokio = { version = "1", features = ["full"] }
main.rs
use warp::Filter;
use std::{sync::{Arc, Mutex}, time::Duration};
use tokio::time::interval;
#[tokio::main]
async fn main() {
// isSelectedの状態を保持する
let is_running = Arc::new(Mutex::new(false));
// HTMLファイルを読み込む
let html = std::fs::read_to_string("static/index.html").expect("HTMLファイルが見つかりません");
// GETリクエスト用のフィルター
let get_route = warp::path::end()
.map(move || warp::reply::html(html.clone()));
// POSTリクエスト用のフィルター
let post_route = warp::path("toggle")
.and(warp::post())
.and(warp::body::json())
.map({
let is_running = Arc::clone(&is_running);
move |body: std::collections::HashMap<String, bool>| {
let is_selected = body.get("isSelected").copied().unwrap_or(false);
let mut running = is_running.lock().unwrap();
if is_selected && !*running {
*running = true;
println!("処理を開始します...");
tokio::spawn({
let is_running = Arc::clone(&is_running);
async move {
let mut interval = interval(Duration::from_secs(1));
while *is_running.lock().unwrap() {
interval.tick().await;
println!("処理中...");
}
}
});
} else if !is_selected && *running {
*running = false;
println!("処理を停止します...");
}
warp::reply::json(&"State received")
}
});
// ルートを結合
let routes = get_route.or(post_route);
let addr = ([127, 0, 0, 1], 8000); // ここで addr を定義
println!("Server running on http://{}", format!("{}:{}", addr.0.iter().map(|b| b.to_string()).collect::<Vec<_>>().join("."), addr.1));
// サーバーを起動
warp::serve(routes).run(([127, 0, 0, 1], 8000)).await;
}
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>遠隔操作ボタン</title>
<style>
body {
background-color: #1a1a1a;
color: #fff;
font-family: 'Arial', sans-serif;
overflow: hidden;
}
.center {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
position: relative;
}
.toggle-btn {
background-color: #007bff;
color: #fff;
padding: 15px 30px;
border: none;
border-radius: 10px;
cursor: pointer;
font-size: 1.5em;
position: relative;
outline: none;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.8);
transition: transform 0.3s;
z-index: 1;
}
.selected {
background-color: #26ff00;
animation: glow 1s infinite alternate;
}
@keyframes glow {
from {
box-shadow: 0 0 20px rgba(47, 255, 0, 0.5);
}
to {
box-shadow: 0 0 40px rgb(94, 255, 0);
}
}
.error-message {
color: rgb(115, 255, 0);
font-weight: bold;
position: absolute;
top: 0; /* ボタンの上に表示 */
left: 50%;
transform: translateX(-50%);
display: none; /* 初期は非表示 */
z-index: 2;
}
.server-message {
color: blue;
font-weight: bold;
position: absolute;
top: 0; /* ボタンの上に表示 */
left: 50%;
transform: translateX(-50%);
display: none; /* 初期は非表示 */
z-index: 2;
}
.server_err {
background-color: rgb(251, 59, 59);
color: #fff;
padding: 15px 30px;
border: none;
border-radius: 10px;
/*cursor: pointer;*/
font-size: 1.5em;
position: relative;
outline: none;
/*box-shadow: 0 0 10px rgba(0, 0, 0, 0.8);*/
transition: transform 0.3s;
z-index: 1;
}
.server_sf {
background-color: rgb(78, 99, 255);
color: #fff;
padding: 15px 30px;
border: none;
border-radius: 10px;
/*cursor: pointer;*/
font-size: 1.5em;
position: relative;
outline: none;
/*box-shadow: 0 0 10px rgba(0, 0, 0, 0.8);*/
transition: transform 0.3s;
z-index: 1;
}
</style>
</head>
<body>
<div class="center">
<div class="server_sf" id="serverMessage">安全</div>
<div class="server_err" id="errorMessage">エラー</div>
<button class="toggle-btn" id="toggleButton">実行</button>
</div>
<script>
const button = document.getElementById('toggleButton');
const errorMessage = document.getElementById('errorMessage');
const serverMassage = document.getElementById('serverMessage');
let isSelected = false;
errorMessage.style.display = 'none'; // 正常な応答時にエラーメッセージを非表示
serverMassage.style.display = 'block'; // 正常な応答時にエラーメッセージを非表示
button.addEventListener('click', () => {
isSelected = !isSelected;
button.classList.toggle('selected', isSelected);
button.textContent = isSelected ? "運転中..." : "実行";
fetch('/toggle', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ isSelected })
})
.then(response => {
console.log('サーバーの応答:', response); // サーバー応答のデバッグ
if (!response.ok) {
throw new Error("サーバーの応答が不正です");
}
return response.json();
})
.then(data => {
console.log('サーバーからの応答:', data);
errorMessage.style.display = 'none'; // 正常な応答時にエラーメッセージを非表示
serverMassage.style.display = 'block'; // 正常な応答時にエラーメッセージを非表示
})
.catch(error => {
console.error('エラー:', error);
console.error('サーバーからの応答')
errorMessage.style.display = 'block'; // エラー時にエラーメッセージを表示
serverMassage.style.display = 'none'; // 正常な応答時にエラーメッセージを非表示
});
});
</script>
</body>
</html>
実行
cargo run
最後に
% ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
inet 127.0.0.1 netmask 0xff000000 <= この行!
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
nd6 options=201<PERFORMNUD,DAD> ...
つまり他のパソコンや端末で動かすためには、
調べたやつ:127.0.0.1
:8000
ということなのでhttp://127.0.0.1:8000に行けばうまくいきます
よくわからない時はGemini
やChatGPT
に聞くとわかったりします