rewrite backend in rust #32

Merged
lbailly merged 14 commits from rewrite into master 2024-06-13 13:20:05 +02:00
5 changed files with 222 additions and 82 deletions
Showing only changes of commit e3aea1494d - Show all commits

1
Cargo.lock generated
View file

@ -1566,6 +1566,7 @@ dependencies = [
name = "traque"
version = "0.1.0"
dependencies = [
"rand",
"rocket",
"rocket_dyn_templates",
]

View file

@ -5,6 +5,9 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
rand = "0.8.5"
[dependencies.rocket]
version = "0.5.0"
features = ["json"]

View file

@ -1,5 +1,6 @@
#[macro_use]
extern crate rocket;
use rand::Rng;
use rocket::{
fs::{relative, FileServer},
response::stream::{Event, EventStream},
@ -18,7 +19,7 @@ enum TrackedState {
invisible: bool,
blurred: bool,
captured: bool,
malette: bool,
mallette: bool,
invisibility_codes: u32,
blur_codes: u32,
},
@ -28,29 +29,98 @@ enum TrackedState {
},
}
use TrackedState::{Conscrit, Vieux};
const BLURRED_MOVE: (f32, f32) = (0.0005, 0.0005);
impl TrackedState {
fn invisible(&self) -> bool {
match self {
Conscrit { invisible, .. } => *invisible,
Vieux { invisible, .. } => *invisible,
}
}
fn blurred(&self) -> bool {
match self {
Conscrit { blurred, .. } => *blurred,
Vieux { .. } => false,
}
}
fn global_viewed(&self) -> bool {
match self {
Conscrit {
captured,
mallette,
invisible,
..
} => (*captured || *mallette) && !*invisible,
Vieux { invisible, .. } => !*invisible,
}
}
fn color(&self) -> u8 {
match self {
Vieux { color, .. } => *color,
Conscrit { captured, .. } => {
if *captured {
1
} else {
0
}
}
}
}
fn admin_color(&self) -> u8 {
match self {
Vieux { color, invisible } => {
if *invisible {
2
} else {
*color
}
}
Conscrit {
invisible,
captured,
..
} => {
if *invisible {
2
} else if *captured {
1
} else {
0
}
}
}
}
}
struct Tracked {
id: String,
name: String,
pos: (f32, f32),
state: TrackedState,
}
fn build_conscrit(name: String) -> Tracked {
fn build_conscrit(id: String, name: String) -> Tracked {
Tracked {
id: id,
name: name,
pos: (0.0, 0.0),
state: TrackedState::Conscrit {
invisible: false,
blurred: false,
captured: false,
malette: false,
mallette: false,
invisibility_codes: 0,
blur_codes: 0,
},
}
}
fn build_vieux(name: String) -> Tracked {
fn build_vieux(id: String, name: String) -> Tracked {
Tracked {
id: id,
name: name,
pos: (0.0, 0.0),
state: TrackedState::Vieux {
@ -67,6 +137,64 @@ type Tracking = RwLock<HashMap<String, RwLock<Tracked>>>;
struct TrackedInfo {
name: String,
pos: (f32, f32),
me: bool,
color: u8,
}
fn base_view(team: &Tracked) -> TrackedInfo {
TrackedInfo {
name: team.name.clone(),
pos: team.pos,
me: false,
color: team.state.color(),
}
}
fn admin_view(team: &Tracked) -> TrackedInfo {
TrackedInfo {
name: team.name.clone(),
pos: team.pos,
me: false,
color: team.state.admin_color(),
}
}
fn apparent_info(watcher: &Tracked, team: &Tracked) -> Option<TrackedInfo> {
if watcher.id == team.id {
Some(TrackedInfo {
me: true,
..admin_view(team)
})
} else if let Conscrit {
captured, mallette, ..
} = watcher.state
{
if captured {
if team.state.invisible() {
None
} else if team.state.blurred() {
let mut rng = rand::thread_rng();
let (lat, lon) = team.pos;
Some(TrackedInfo {
pos: (
lat + BLURRED_MOVE.0 * (rng.gen::<f32>() * 2.0 - 1.0),
lon + BLURRED_MOVE.1 * (rng.gen::<f32>() * 2.0 - 1.0),
),
..base_view(team)
})
} else {
Some(base_view(team))
}
} else {
if mallette || team.state.global_viewed() {
Some(base_view(team))
} else {
None
}
}
} else {
Some(admin_view(team))
}
}
#[get("/track/<id>?<gpslog>")]
@ -88,6 +216,18 @@ fn tracked_view(id: &str, gpslog: Option<bool>, tracking: &State<Tracking>) -> O
}
}
fn info_to_send(id: &String, tracking: &Tracking) -> Vec<TrackedInfo> {
let tracking_lock = tracking.read().unwrap();
let watcher = tracking_lock.get(id).unwrap().read().unwrap();
let mut infos: Vec<TrackedInfo> = Vec::new();
for (_, tracked) in tracking_lock.iter() {
if let Some(info) = apparent_info(&watcher, &tracked.read().unwrap()) {
infos.push(info);
}
}
infos
}
#[get("/track/<id>/events")]
fn tracked_events<'a>(
id: &'a str,
@ -99,13 +239,8 @@ fn tracked_events<'a>(
let mut interval = time::interval(Duration::from_secs(5));
loop {
select!{
_ = interval.tick() => {
let info = TrackedInfo {
name: id.to_string(),
pos: tracking.read().unwrap().get(&id.to_string()).unwrap().read().unwrap().pos
};
yield Event::json(&info).event("coords")
},
_ = interval.tick() =>
yield Event::json(&info_to_send(&id.to_string(), &tracking)).event("coords"),
_ = &mut shutdown => break
}
}
@ -132,19 +267,19 @@ fn rocket() -> _ {
let tracking = HashMap::<String, RwLock<Tracked>>::from([
(
"team00".to_string(),
RwLock::new(build_conscrit("Équipe 0".to_string())),
RwLock::new(build_conscrit("team00".to_string(), "Équipe 0".to_string())),
),
(
"team01".to_string(),
RwLock::new(build_conscrit("Équipe 1".to_string())),
RwLock::new(build_conscrit("team01".to_string(), "Équipe 1".to_string())),
),
(
"npc0".to_string(),
RwLock::new(build_vieux("PNJ 0".to_string())),
RwLock::new(build_vieux("npc0".to_string(), "PNJ 0".to_string())),
),
(
"npc1".to_string(),
RwLock::new(build_vieux("PNJ 1".to_string())),
RwLock::new(build_vieux("npc1".to_string(), "PNJ 1".to_string())),
),
]);
rocket::build()

View file

@ -1,9 +1,5 @@
var protocol = location.protocol;
var server = location.hostname;
var port = location.port;
var socket;
var id;
var markers = {};
var evtsource;
var markers = [];
var CircleIcon = L.Icon.extend({
options: {
@ -69,57 +65,67 @@ var map;
function setup_map(){
map = L.map('map').setView([48.8448, 2.3550], 13);
L.tileLayer('https://stamen-tiles.a.ssl.fastly.net/toner/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© OpenStreetMap'
L.tileLayer('https://tiles.stadiamaps.com/tiles/stamen_toner/{z}/{x}/{y}{r}.{ext}', {
maxZoom: 20,
minZoom: 0,
attribution: '&copy; <a href="https://www.stadiamaps.com/" target="_blank">Stadia Maps</a> &copy; <a href="https://www.stamen.com/" target="_blank">Stamen Design</a> &copy; <a href="https://openmaptiles.org/" target="_blank">OpenMapTiles</a> &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
ext: 'png'
}).addTo(map);
L.polyline(map_border, {color: 'red'}).addTo(map);
}
//////////////////////////////////////////////////////////////////////////////
// SOCKET
// EVENT LISTENNING
function setup_socket_common(){
socket.on("moving", function(data){
console.log("moving", data);
if(!(data.id in markers)){
if(data.id == id){
markers[data.id] = L.marker(data.position, {"icon": self_icons[data.color]}).addTo(map);
markers[data.id].setZIndexOffset(10000);
function setup_evtlisten_common(){
evtSource.addEventListener("coords", (event) => {
const data = JSON.parse(event.data);
console.log(data);
var i = 0;
for (tracked of data) {
if (i == markers.length) {
markers.push(L.marker([0,0], {"icon": icons[0] }).addTo(map));
markers[i].bindPopup("");
}
else
markers[data.id] = L.marker(data.position, {"icon": icons[data.color]}).addTo(map);
markers[data.id].bindPopup(data.id);
} else{
markers[data.id].setLatLng(data.position);
if(data.id == id)
markers[data.id].setIcon(self_icons[data.color]);
else
markers[data.id].setIcon(icons[data.color]);
markers[i].setLatLng(tracked.pos);
markers[i].setPopupContent(tracked.name);
if (tracked.me) {
markers[i].setIcon(self_icons[tracked.color]);
markers[i].setZIndexOffset(1000);
} else {
markers[i].setIcon(icons[tracked.color]);
markers[i].setZIndexOffset(0);
}
++i;
}
for (; i < markers.length; ++i) {
markers[i].setLatLng([0,0]);
}
});
socket.on("popup", function(data){
alert(data.content);
});
//socket.on("popup", function(data){
// alert(data.content);
//});
socket.on("remove", function(data){
if(data.id in markers)
markers[data.id].remove();
});
//socket.on("remove", function(data){
// if(data.id in markers)
// markers[data.id].remove();
//});
socket.on("newTracker", function(data){
L.marker(data.position, {"icon": icons[1]}).addTo(map);
});
//socket.on("newTracker", function(data){
// L.marker(data.position, {"icon": icons[1]}).addTo(map);
//});
}
//////////////////////////////////////////////////////////////////////////////
// GEOLOCALISATION
function setup_geoLoc(){
const requestOptions = { method: 'PUT' };
function geoLoc_success(pos) {
fetch("/log?id="+id+"&lat="+pos.coords.latitude+"&lon="+pos.coords.longitude);
fetch("/log/"+id+"?lat="+pos.coords.latitude+"&long="+pos.coords.longitude, requestOptions);
}
function geoLoc_error(err) {

View file

@ -24,7 +24,7 @@
}
</style>
<!-- <script type="text/javascript" src="/utils.js"></script> -->
<script type="text/javascript" src="/utils.js"></script>
</head>
<body>
<div id="map"></div><br/>
@ -36,21 +36,16 @@
</div>
<script type="text/javascript">
const evtSource = new EventSource("/track/{{id}}/events");
evtSource.addEventListener("coords", (event) => {
console.log(event);
});
// //////////////////////////////////////////////////////////////////////////////
// // SETUP MAP
//////////////////////////////////////////////////////////////////////////////
// SETUP MAP
// setup_map();
setup_map();
// //////////////////////////////////////////////////////////////////////////////
// // SOCKET
//////////////////////////////////////////////////////////////////////////////
// EVENT LISTENNING
// id = "{{id}}";
// socket = io({rejectUnauthorized: false, auth: {id: id, type:"conscrit"}});
// setup_socket_common();
evtSource = new EventSource("/track/{{id}}/events");
setup_evtlisten_common();
// //////////////////////////////////////////////////////////////////////////////
// // SETTINGS -- CODE