feat: use ward info
This commit is contained in:
parent
dc4fc02e71
commit
db2cfcfb94
|
@ -7,6 +7,7 @@ namespace OrangeGuidanceTomestone;
|
|||
[JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))]
|
||||
public class MessageRequest {
|
||||
public uint Territory { get; set; }
|
||||
public uint? Ward { get; set; }
|
||||
public float X { get; set; }
|
||||
public float Y { get; set; }
|
||||
public float Z { get; set; }
|
||||
|
|
|
@ -153,6 +153,8 @@ internal class Messages : IDisposable {
|
|||
return;
|
||||
}
|
||||
|
||||
var ward = this.Plugin.Common.Functions.Housing.Location?.Ward;
|
||||
|
||||
if (this.Plugin.Config.DisableTrials && this.Trials.Contains(territory)) {
|
||||
return;
|
||||
}
|
||||
|
@ -173,18 +175,23 @@ internal class Messages : IDisposable {
|
|||
|
||||
Task.Run(async () => {
|
||||
try {
|
||||
await this.DownloadMessages(territory);
|
||||
await this.DownloadMessages(territory, ward);
|
||||
} catch (Exception ex) {
|
||||
PluginLog.LogError(ex, $"Failed to get messages for territory {territory}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async Task DownloadMessages(ushort territory) {
|
||||
private async Task DownloadMessages(ushort territory, ushort? ward) {
|
||||
var route = $"/messages/{territory}";
|
||||
if (ward != null) {
|
||||
route += $"?ward={ward}";
|
||||
}
|
||||
|
||||
var resp = await ServerHelper.SendRequest(
|
||||
this.Plugin.Config.ApiKey,
|
||||
HttpMethod.Get,
|
||||
$"/messages/{territory}"
|
||||
route
|
||||
);
|
||||
var json = await resp.Content.ReadAsStringAsync();
|
||||
var messages = JsonConvert.DeserializeObject<Message[]>(json)!;
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
<PackageReference Include="DalamudPackager" Version="2.1.10"/>
|
||||
<PackageReference Include="Fody" Version="6.6.4" PrivateAssets="all"/>
|
||||
<PackageReference Include="Resourcer.Fody" Version="1.8.0" PrivateAssets="all"/>
|
||||
<PackageReference Include="XivCommon" Version="7.0.0-alpha.1" PrivateAssets="all"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
@ -7,6 +7,7 @@ using Dalamud.Game.Gui;
|
|||
using Dalamud.IoC;
|
||||
using Dalamud.Plugin;
|
||||
using OrangeGuidanceTomestone.MiniPenumbra;
|
||||
using XivCommon;
|
||||
|
||||
namespace OrangeGuidanceTomestone;
|
||||
|
||||
|
@ -38,6 +39,7 @@ public class Plugin : IDalamudPlugin {
|
|||
internal GameGui GameGui { get; init; }
|
||||
|
||||
internal Configuration Config { get; }
|
||||
internal XivCommonBase Common { get; }
|
||||
internal Vfx Vfx { get; }
|
||||
internal PluginUi Ui { get; }
|
||||
internal Messages Messages { get; }
|
||||
|
@ -51,6 +53,7 @@ public class Plugin : IDalamudPlugin {
|
|||
this.AvfxFilePath = this.CopyAvfxFile();
|
||||
|
||||
this.Config = this.Interface!.GetPluginConfig() as Configuration ?? new Configuration();
|
||||
this.Common = new XivCommonBase();
|
||||
this.Vfx = new Vfx();
|
||||
this.Messages = new Messages(this);
|
||||
this.Ui = new PluginUi(this);
|
||||
|
@ -70,6 +73,7 @@ public class Plugin : IDalamudPlugin {
|
|||
this.Ui.Dispose();
|
||||
this.Messages.Dispose();
|
||||
this.Vfx.Dispose();
|
||||
this.Common.Dispose();
|
||||
}
|
||||
|
||||
internal void SaveConfig() {
|
||||
|
|
|
@ -231,6 +231,7 @@ internal class Write : ITab {
|
|||
if (ImGui.Button("Write") && valid && !inAir && this.Plugin.ClientState.LocalPlayer is { } player) {
|
||||
var req = new MessageRequest {
|
||||
Territory = this.Plugin.ClientState.TerritoryType,
|
||||
Ward = this.Plugin.Common.Functions.Housing.Location?.Ward,
|
||||
X = player.Position.X,
|
||||
Y = player.Position.Y,
|
||||
Z = player.Position.Z,
|
||||
|
|
|
@ -24,6 +24,12 @@
|
|||
"NETStandard.Library": "1.6.1"
|
||||
}
|
||||
},
|
||||
"XivCommon": {
|
||||
"type": "Direct",
|
||||
"requested": "[7.0.0-alpha.1, )",
|
||||
"resolved": "7.0.0-alpha.1",
|
||||
"contentHash": "4Yy4Wg3bnI/g9BSEYAqOZALmVMJZS0wcP847VlUIThBqIS/47O6tw2BI84he4KuPSTfIsYOzrcz3vAia8+Pn3g=="
|
||||
},
|
||||
"Microsoft.NETCore.Platforms": {
|
||||
"type": "Transitive",
|
||||
"resolved": "1.1.0",
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -7,7 +7,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
base64 = "0.13"
|
||||
base64 = "0.21"
|
||||
bytes = "1"
|
||||
chrono = "0.4"
|
||||
if_chain = "1"
|
||||
|
@ -16,7 +16,7 @@ serde = { version = "1", features = ["derive"] }
|
|||
serde_yaml = "0.9"
|
||||
sha3 = "0.10"
|
||||
sqlx = { version = "0.6", features = ["runtime-tokio-rustls", "sqlite", "chrono"] }
|
||||
toml = "0.5"
|
||||
toml = "0.7"
|
||||
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
|
||||
tokio-stream = { version = "0.1", default-features = false, features = ["net"] }
|
||||
uuid = { version = "1", features = ["serde", "v4"] }
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
alter table messages
|
||||
add column ward int;
|
||||
create index messages_ward_idx on messages (ward);
|
|
@ -1,9 +1,7 @@
|
|||
#![feature(drain_filter)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fs::Permissions;
|
||||
use std::net::SocketAddr;
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -11,7 +9,6 @@ use anyhow::{Context, Result};
|
|||
use sqlx::{Executor, Pool, Sqlite};
|
||||
use sqlx::migrate::Migrator;
|
||||
use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
|
||||
use tokio::fs::File;
|
||||
use tokio::net::{TcpListener, UnixListener};
|
||||
use tokio::runtime::Handle;
|
||||
use tokio::sync::RwLock;
|
||||
|
@ -54,7 +51,7 @@ impl State {
|
|||
let text = match tokio::fs::read_to_string(entry.path()).await {
|
||||
Ok(t) => t,
|
||||
Err(e) => {
|
||||
eprintln!("error reading pack: {:#?}", e);
|
||||
eprintln!("error reading pack: {e:#?}");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
@ -119,10 +116,10 @@ async fn main() -> Result<()> {
|
|||
|
||||
let address = state.config.address.clone();
|
||||
let server = warp::serve(web::routes(state));
|
||||
println!("listening at {}", address);
|
||||
println!("listening at {address}");
|
||||
|
||||
if address.starts_with("unix:") {
|
||||
let listener = UnixListener::bind(&address[5..])?;
|
||||
if let Some(path) = address.strip_prefix("unix:") {
|
||||
let listener = UnixListener::bind(path)?;
|
||||
let stream = UnixListenerStream::new(listener);
|
||||
server.run_incoming(stream).await;
|
||||
} else {
|
||||
|
@ -141,16 +138,13 @@ fn spawn_command_reader(state: Arc<State>, handle: Handle) {
|
|||
while let Ok(size) = std::io::stdin().read_line(&mut line) {
|
||||
let read = line[..size].trim();
|
||||
|
||||
match read {
|
||||
"reload packs" => {
|
||||
let state = Arc::clone(&state);
|
||||
handle.spawn(async move {
|
||||
if let Err(e) = state.update_packs().await {
|
||||
eprintln!("failed to update packs: {:#?}", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
if read == "reload packs" {
|
||||
let state = Arc::clone(&state);
|
||||
handle.spawn(async move {
|
||||
if let Err(e) = state.update_packs().await {
|
||||
eprintln!("failed to update packs: {e:#?}");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
line.clear();
|
||||
|
|
|
@ -22,6 +22,9 @@ pub struct Message {
|
|||
|
||||
#[serde(default = "glyph_default")]
|
||||
pub glyph: i8,
|
||||
|
||||
#[serde(default)]
|
||||
pub ward: Option<u16>,
|
||||
}
|
||||
|
||||
fn glyph_default() -> i8 {
|
||||
|
@ -52,6 +55,7 @@ pub struct RetrievedMessage {
|
|||
pub struct RetrievedMessageTerritory {
|
||||
pub id: String,
|
||||
pub territory: i64,
|
||||
pub ward: Option<i64>,
|
||||
pub x: f64,
|
||||
pub y: f64,
|
||||
pub z: f64,
|
||||
|
@ -69,6 +73,7 @@ pub struct RetrievedMessageTerritory {
|
|||
pub struct OwnMessage {
|
||||
pub id: String,
|
||||
pub territory: i64,
|
||||
pub ward: Option<i64>,
|
||||
pub x: f64,
|
||||
pub y: f64,
|
||||
pub z: f64,
|
||||
|
|
|
@ -1,8 +1,54 @@
|
|||
use base64::Engine;
|
||||
use base64::prelude::BASE64_STANDARD;
|
||||
use sha3::{Digest, Sha3_384};
|
||||
|
||||
// TerritoryIntendedUse = 13 or 14
|
||||
pub const HOUSING_ZONES: &[u32] = &[
|
||||
282,
|
||||
283,
|
||||
284,
|
||||
339,
|
||||
340,
|
||||
341,
|
||||
342,
|
||||
343,
|
||||
344,
|
||||
345,
|
||||
346,
|
||||
347,
|
||||
384,
|
||||
385,
|
||||
386,
|
||||
423,
|
||||
424,
|
||||
425,
|
||||
573,
|
||||
574,
|
||||
575,
|
||||
608,
|
||||
609,
|
||||
610,
|
||||
641,
|
||||
649,
|
||||
650,
|
||||
651,
|
||||
652,
|
||||
653,
|
||||
654,
|
||||
655,
|
||||
979,
|
||||
980,
|
||||
981,
|
||||
982,
|
||||
983,
|
||||
984,
|
||||
985,
|
||||
999,
|
||||
];
|
||||
|
||||
pub fn hash(input: &str) -> String {
|
||||
let mut hasher = Sha3_384::default();
|
||||
hasher.update(input.as_bytes());
|
||||
let result = hasher.finalize();
|
||||
base64::encode(result)
|
||||
BASE64_STANDARD.encode(result)
|
||||
}
|
||||
|
|
|
@ -73,6 +73,8 @@ pub enum WebError {
|
|||
TooManyMessages,
|
||||
NoSuchMessage,
|
||||
InvalidExtraCode,
|
||||
MissingWard,
|
||||
UnnecessaryWard,
|
||||
}
|
||||
|
||||
impl Reject for WebError {}
|
||||
|
@ -92,22 +94,24 @@ async fn handle_rejection(err: Rejection) -> Result<impl Reply, Infallible> {
|
|||
WebError::TooManyMessages => (StatusCode::BAD_REQUEST, "too_many_messages", "you have run out of messages - delete one and try again".into()),
|
||||
WebError::NoSuchMessage => (StatusCode::NOT_FOUND, "no_such_message", "no message with that id was found".into()),
|
||||
WebError::InvalidExtraCode => (StatusCode::BAD_REQUEST, "invalid_extra_code", "that extra code was not found".into()),
|
||||
WebError::MissingWard => (StatusCode::BAD_REQUEST, "missing_ward", "a ward was not provided - try updating the plugin".into()),
|
||||
WebError::UnnecessaryWard => (StatusCode::BAD_REQUEST, "unnecessar_ward", "a ward was provided but not necessary - try updating the plugin".into()),
|
||||
}
|
||||
} else if err.is_not_found() {
|
||||
(StatusCode::NOT_FOUND, "not_found", "route was unknown to the server".into())
|
||||
} else if let Some(e) = err.find::<BodyDeserializeError>() {
|
||||
(StatusCode::BAD_REQUEST, "invalid_body", format!("invalid body: {}", e))
|
||||
} else if let Some(_) = err.find::<MethodNotAllowed>() {
|
||||
(StatusCode::BAD_REQUEST, "invalid_body", format!("invalid body: {e}"))
|
||||
} else if err.find::<MethodNotAllowed>().is_some() {
|
||||
(StatusCode::METHOD_NOT_ALLOWED, "method_not_allowed", "that http method is not allowed on that route".into())
|
||||
} else if let Some(AnyhowRejection(e)) = err.find::<AnyhowRejection>() {
|
||||
eprintln!("{:#?}", e);
|
||||
eprintln!("{e:#?}");
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
"internal_error",
|
||||
"an internal logic error occured".into(),
|
||||
)
|
||||
} else {
|
||||
eprintln!("{:#?}", err);
|
||||
eprintln!("{err:#?}");
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
"internal_error",
|
||||
|
|
|
@ -4,12 +4,14 @@ use anyhow::Context;
|
|||
use chrono::{Duration, Utc};
|
||||
use rand::Rng;
|
||||
use rand::seq::SliceRandom;
|
||||
use serde::Deserialize;
|
||||
use warp::{Filter, Rejection, Reply};
|
||||
use warp::filters::BoxedFilter;
|
||||
|
||||
use crate::message::RetrievedMessage;
|
||||
use crate::State;
|
||||
use crate::web::AnyhowRejection;
|
||||
use crate::util::HOUSING_ZONES;
|
||||
use crate::web::{AnyhowRejection, WebError};
|
||||
|
||||
pub fn get_location(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
||||
warp::get()
|
||||
|
@ -17,11 +19,27 @@ pub fn get_location(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
|||
.and(warp::path::param())
|
||||
.and(warp::path::end())
|
||||
.and(super::get_id(Arc::clone(&state)))
|
||||
.and_then(move |location: u32, (id, _)| logic(Arc::clone(&state), id, location))
|
||||
.and(warp::query::<GetLocationQuery>())
|
||||
.and_then(move |location: u32, (id, _), query| logic(Arc::clone(&state), id, location, query))
|
||||
.boxed()
|
||||
}
|
||||
|
||||
async fn logic(state: Arc<State>, id: i64, location: u32) -> Result<impl Reply, Rejection> {
|
||||
#[derive(Deserialize)]
|
||||
pub struct GetLocationQuery {
|
||||
#[serde(default)]
|
||||
ward: Option<u32>,
|
||||
}
|
||||
|
||||
async fn logic(state: Arc<State>, id: i64, location: u32, query: GetLocationQuery) -> Result<impl Reply, Rejection> {
|
||||
let housing = HOUSING_ZONES.contains(&location);
|
||||
if housing && query.ward.is_none() {
|
||||
return Err(warp::reject::custom(WebError::MissingWard));
|
||||
}
|
||||
|
||||
if !housing && query.ward.is_some() {
|
||||
return Err(warp::reject::custom(WebError::UnnecessaryWard));
|
||||
}
|
||||
|
||||
let location = location as i64;
|
||||
let mut messages = sqlx::query_as!(
|
||||
RetrievedMessage,
|
||||
|
@ -44,10 +62,11 @@ async fn logic(state: Arc<State>, id: i64, location: u32) -> Result<impl Reply,
|
|||
left join votes v on m.id = v.message
|
||||
left join votes v2 on m.id = v2.message and v2.user = ?
|
||||
inner join users u on m.user = u.id
|
||||
where m.territory = ?
|
||||
where m.territory = ? and m.ward = ?
|
||||
group by m.id"#,
|
||||
id,
|
||||
location,
|
||||
query.ward,
|
||||
)
|
||||
.fetch_all(&state.db)
|
||||
.await
|
||||
|
|
|
@ -27,6 +27,7 @@ async fn logic(state: Arc<State>, id: i64, message_id: Uuid) -> Result<impl Repl
|
|||
r#"
|
||||
select m.id,
|
||||
m.territory,
|
||||
m.ward,
|
||||
m.x,
|
||||
m.y,
|
||||
m.z,
|
||||
|
|
|
@ -31,6 +31,7 @@ async fn logic(state: Arc<State>, id: i64, extra: i64, mut query: HashMap<String
|
|||
r#"
|
||||
select m.id,
|
||||
m.territory,
|
||||
m.ward,
|
||||
m.x,
|
||||
m.y,
|
||||
m.z,
|
||||
|
|
|
@ -7,6 +7,7 @@ use warp::filters::BoxedFilter;
|
|||
|
||||
use crate::message::Message;
|
||||
use crate::State;
|
||||
use crate::util::HOUSING_ZONES;
|
||||
use crate::web::{AnyhowRejection, WebError};
|
||||
|
||||
pub fn write(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
||||
|
@ -21,6 +22,15 @@ pub fn write(state: Arc<State>) -> BoxedFilter<(impl Reply, )> {
|
|||
}
|
||||
|
||||
async fn logic(state: Arc<State>, id: i64, extra: i64, message: Message) -> Result<impl Reply, Rejection> {
|
||||
let housing = HOUSING_ZONES.contains(&message.territory);
|
||||
if housing && message.ward.is_none() {
|
||||
return Err(warp::reject::custom(WebError::MissingWard));
|
||||
}
|
||||
|
||||
if !housing && message.ward.is_some() {
|
||||
return Err(warp::reject::custom(WebError::UnnecessaryWard));
|
||||
}
|
||||
|
||||
let text = {
|
||||
let packs = state.packs.read().await;
|
||||
let pack = packs.get(&message.pack_id)
|
||||
|
@ -57,10 +67,11 @@ async fn logic(state: Arc<State>, id: i64, extra: i64, message: Message) -> Resu
|
|||
|
||||
sqlx::query!(
|
||||
// language=sqlite
|
||||
"insert into messages (id, user, territory, x, y, z, yaw, message, glyph) values (?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
"insert into messages (id, user, territory, ward, x, y, z, yaw, message, glyph) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
message_id,
|
||||
id,
|
||||
territory,
|
||||
message.ward,
|
||||
message.x,
|
||||
message.y,
|
||||
message.z,
|
||||
|
|
Loading…
Reference in New Issue