rewrite backend in rust #32
5 changed files with 222 additions and 82 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1566,6 +1566,7 @@ dependencies = [
|
|||
name = "traque"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rand",
|
||||
"rocket",
|
||||
"rocket_dyn_templates",
|
||||
]
|
||||
|
|
|
@ -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"]
|
||||
|
|
165
src/main.rs
165
src/main.rs
|
@ -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()
|
||||
|
|
114
static/utils.js
114
static/utils.js
|
@ -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: {
|
||||
|
@ -67,70 +63,80 @@ var map_border = [
|
|||
var map;
|
||||
|
||||
function setup_map(){
|
||||
map = L.map('map').setView([48.8448, 2.3550], 13);
|
||||
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'
|
||||
}).addTo(map);
|
||||
L.tileLayer('https://tiles.stadiamaps.com/tiles/stamen_toner/{z}/{x}/{y}{r}.{ext}', {
|
||||
maxZoom: 20,
|
||||
minZoom: 0,
|
||||
attribution: '© <a href="https://www.stadiamaps.com/" target="_blank">Stadia Maps</a> © <a href="https://www.stamen.com/" target="_blank">Stamen Design</a> © <a href="https://openmaptiles.org/" target="_blank">OpenMapTiles</a> © <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
|
||||
ext: 'png'
|
||||
}).addTo(map);
|
||||
|
||||
L.polyline(map_border, {color: 'red'}).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);
|
||||
}
|
||||
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]);
|
||||
}
|
||||
});
|
||||
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("");
|
||||
}
|
||||
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(){
|
||||
function geoLoc_success(pos) {
|
||||
fetch("/log?id="+id+"&lat="+pos.coords.latitude+"&lon="+pos.coords.longitude);
|
||||
}
|
||||
const requestOptions = { method: 'PUT' };
|
||||
|
||||
function geoLoc_error(err) {
|
||||
console.error(`ERROR(${err.code}): ${err.message}`);
|
||||
}
|
||||
function geoLoc_success(pos) {
|
||||
fetch("/log/"+id+"?lat="+pos.coords.latitude+"&long="+pos.coords.longitude, requestOptions);
|
||||
}
|
||||
|
||||
var options = {
|
||||
enableHighAccuracy: false,
|
||||
timeout: 5000,
|
||||
maximumAge: 0
|
||||
};
|
||||
function geoLoc_error(err) {
|
||||
console.error(`ERROR(${err.code}): ${err.message}`);
|
||||
}
|
||||
|
||||
navigator.geolocation.watchPosition(geoLoc_success, geoLoc_error, options);
|
||||
var options = {
|
||||
enableHighAccuracy: false,
|
||||
timeout: 5000,
|
||||
maximumAge: 0
|
||||
};
|
||||
|
||||
navigator.geolocation.watchPosition(geoLoc_success, geoLoc_error, options);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue