Refactored spells import, working on level_1
This commit is contained in:
@@ -8,6 +8,4 @@ DATABASE_PORT=5432
|
||||
|
||||
SERVICE_HOST=localhost
|
||||
SERVICE_PORT=5000
|
||||
|
||||
DISCORD_TOKEN=
|
||||
OPENAI_API_KEY=
|
||||
DATA_DIR_PATH=
|
||||
48
service/data/layout.json
Normal file
48
service/data/layout.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "",
|
||||
"school": "",
|
||||
"level": 1,
|
||||
"ritual": false,
|
||||
"casting_time": {
|
||||
"value": 1,
|
||||
"unit": "action"
|
||||
},
|
||||
"saving_throw": [],
|
||||
"attack_type": [],
|
||||
"damage_inflict": [],
|
||||
"damage_resist": [],
|
||||
"conditions": [],
|
||||
"range": {
|
||||
"type": "point",
|
||||
"value": 1,
|
||||
"unit": "feet"
|
||||
},
|
||||
"area": {
|
||||
"type": "cube",
|
||||
"size": 1,
|
||||
"unit": "feet"
|
||||
},
|
||||
"components": {
|
||||
"verbal": false,
|
||||
"somatic": false,
|
||||
"material": false,
|
||||
"materials_needed": "",
|
||||
"materials_cost": 0,
|
||||
"materials_consumed": false
|
||||
},
|
||||
"durations": [
|
||||
{
|
||||
"type": "instantaneous",
|
||||
"value": 1,
|
||||
"unit": "minute"
|
||||
}
|
||||
],
|
||||
"classes": [],
|
||||
"sources": [ { "source": "", "page": 0 } ],
|
||||
"tags": [],
|
||||
"description": {
|
||||
"entries": [
|
||||
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -213,8 +213,7 @@
|
||||
"entries": [
|
||||
"You choose nonmagical flame that you can see within range and that fits within a 5-foot cube. You affect it in one of the following ways:",
|
||||
{
|
||||
"type": "list",
|
||||
"items": [
|
||||
"list": [
|
||||
"You instantaneously expand the flame 5 feet in one direction, provided that wood or other fuel is present in the new location.",
|
||||
"You instantaneously extinguish the flames within the cube.",
|
||||
"You double or halve the area of bright light and dim light cast by the flame, change its color, or both. The change lasts for 1 hour.",
|
||||
@@ -253,7 +252,7 @@
|
||||
{
|
||||
"type": "concentration",
|
||||
"value": 1,
|
||||
"unit": "minutes"
|
||||
"unit": "minute"
|
||||
}
|
||||
],
|
||||
"classes": ["artificer", "druid", "sorcerer", "warlock", "wizard"],
|
||||
@@ -293,7 +292,7 @@
|
||||
{
|
||||
"type": "concentration",
|
||||
"value": 1,
|
||||
"unit": "minutes"
|
||||
"unit": "minute"
|
||||
}
|
||||
],
|
||||
"classes": ["artificer", "bard", "sorcerer", "wizard"],
|
||||
@@ -341,8 +340,7 @@
|
||||
"entries": [
|
||||
"Whispering to the spirits of nature, you create one of the following effects within range:",
|
||||
{
|
||||
"type": "list",
|
||||
"items": [
|
||||
"list": [
|
||||
"You create a tiny, harmless sensory effect that predicts what the weather will be at your location for the next 24 hours. The effect might manifest as a golden orb for clear skies, a cloud for rain, falling snowflakes for snow, and so on. This effect persists for 1 round.",
|
||||
"You instantly make a flower blossom, a seed pod open, or a leaf bud bloom.",
|
||||
"You create an instantaneous, harmless sensory effect, such as falling leaves, a puff of wind, the sound of a small animal, or the faint odor of skunk. The effect must fit in a 5-foot cube.",
|
||||
@@ -490,7 +488,7 @@
|
||||
{
|
||||
"type": "concentration",
|
||||
"value": 1,
|
||||
"unit": "minutes"
|
||||
"unit": "minute"
|
||||
}
|
||||
],
|
||||
"classes": ["bard", "sorcerer", "warlock", "wizard"],
|
||||
@@ -611,7 +609,7 @@
|
||||
{
|
||||
"type": "concentration",
|
||||
"value": 1,
|
||||
"unit": "minutes"
|
||||
"unit": "minute"
|
||||
}
|
||||
],
|
||||
"classes": ["artificer", "cleric", "druid"],
|
||||
@@ -658,8 +656,7 @@
|
||||
"entries": [
|
||||
"You seize the air and compel it to create one of the following effects at a point you can see within range:",
|
||||
{
|
||||
"type": "list",
|
||||
"items": [
|
||||
"list": [
|
||||
"One Medium or smaller creature that you choose must succeed on a Strength saving throw or be pushed up to 5 feet away from you.",
|
||||
"You create a small blast of air capable of moving one object that is neither held nor carried and that weighs no more than 5 pounds. The object is pushed up to 10 feet away from you. It isn't pushed with enough force to cause damage.",
|
||||
"You create a harmless sensory effect using air, such as causing leaves to rustle, wind to slam shutters shut, or your clothing to ripple in a breeze."
|
||||
@@ -820,7 +817,7 @@
|
||||
{
|
||||
"type": "timed",
|
||||
"value": 1,
|
||||
"unit": "minutes"
|
||||
"unit": "minute"
|
||||
}
|
||||
],
|
||||
"classes": ["artificer", "bard", "sorcerer", "warlock", "wizard"],
|
||||
@@ -861,7 +858,7 @@
|
||||
{
|
||||
"type": "timed",
|
||||
"value": 1,
|
||||
"unit": "minutes"
|
||||
"unit": "minute"
|
||||
}
|
||||
],
|
||||
"classes": ["artificer", "druid", "warlock"],
|
||||
@@ -882,7 +879,7 @@
|
||||
"ritual": false,
|
||||
"casting_time": {
|
||||
"value": 1,
|
||||
"unit": "minutes"
|
||||
"unit": "minute"
|
||||
},
|
||||
"range": {
|
||||
"type": "touch"
|
||||
@@ -1014,7 +1011,7 @@
|
||||
{
|
||||
"type": "timed",
|
||||
"value": 1,
|
||||
"unit": "minutes"
|
||||
"unit": "minute"
|
||||
}
|
||||
],
|
||||
"classes": ["bard", "sorcerer", "warlock", "wizard"],
|
||||
@@ -1073,8 +1070,7 @@
|
||||
"entries": [
|
||||
"You choose a portion of dirt or stone that you can see within range and that fits within a 5-foot cube. You manipulate it in one of the following ways:",
|
||||
{
|
||||
"type": "list",
|
||||
"items": [
|
||||
"list": [
|
||||
"If you target an area of loose earth, you can instantaneously excavate it, move it along the ground, and deposit it up to 5 feet away. This movement doesn't have enough force to cause damage.",
|
||||
"You cause shapes, colors, or both to appear on the dirt or stone, spelling out words, creating images, or shaping patterns. The changes last for 1 hour.",
|
||||
"If the dirt or stone you target is on the ground, you cause it to become difficult terrain. Alternatively, you can cause the ground to become normal terrain if it is already difficult terrain. This change lasts for 1 hour."
|
||||
@@ -1162,8 +1158,7 @@
|
||||
"entries": [
|
||||
"This spell is a minor magical trick that novice spellcasters use for practice. You create one of the following magical effects within range:",
|
||||
{
|
||||
"type": "list",
|
||||
"items": [
|
||||
"list": [
|
||||
"You create an instantaneous, harmless sensory effect, such as a shower of sparks, a puff of wind, faint musical notes, or an odd odor.",
|
||||
"You instantaneously light or snuff out a candle, a torch, or a small campfire.",
|
||||
"You instantaneously clean or soil an object no larger than 1 cubic foot.",
|
||||
@@ -1402,7 +1397,7 @@
|
||||
"type": "instantaneous"
|
||||
}
|
||||
],
|
||||
"classes": [],
|
||||
"classes": ["wizard"],
|
||||
"sources": [
|
||||
{ "source": "EGW", "page": 189 }
|
||||
],
|
||||
@@ -1455,8 +1450,7 @@
|
||||
"entries": [
|
||||
"You choose an area of water that you can see within range and that fits within a 5-foot cube. You manipulate it in one of the following ways:",
|
||||
{
|
||||
"type": "list",
|
||||
"items": [
|
||||
"list": [
|
||||
"You instantaneously move or otherwise change the flow of the water as you direct, up to 5 feet in any direction. This movement doesn't have enough force to cause damage.",
|
||||
"You cause the water to form into simple shapes and animate at your direction. This change lasts for 1 hour.",
|
||||
"You change the water's color or opacity. The water must be changed in the same way throughout. This change lasts for 1 hour.",
|
||||
@@ -1493,7 +1487,7 @@
|
||||
{
|
||||
"type": "timed",
|
||||
"value": 1,
|
||||
"unit": "minutes"
|
||||
"unit": "minute"
|
||||
}
|
||||
],
|
||||
"classes": ["druid"],
|
||||
@@ -1642,7 +1636,7 @@
|
||||
{
|
||||
"type": "timed",
|
||||
"value": 1,
|
||||
"unit": "minutes"
|
||||
"unit": "minute"
|
||||
}
|
||||
],
|
||||
"classes": ["cleric"],
|
||||
@@ -1654,17 +1648,16 @@
|
||||
"entries": [
|
||||
"You manifest a minor wonder, a sign of supernatural power, within range. You create one of the following magical effects within range:",
|
||||
{
|
||||
"type": "list",
|
||||
"items": [
|
||||
"Your voice booms up to three times as loud as normal for 1 minutes.",
|
||||
"You cause flames to flicker, brighten, dim, or change color for 1 minutes.",
|
||||
"You cause harmless tremors in the ground for 1 minutes.",
|
||||
"list": [
|
||||
"Your voice booms up to three times as loud as normal for 1 minute.",
|
||||
"You cause flames to flicker, brighten, dim, or change color for 1 minute.",
|
||||
"You cause harmless tremors in the ground for 1 minute.",
|
||||
"You create an instantaneous sound that originates from a point of your choice within range, such as a rumble of thunder, the cry of a raven, or ominous whispers.",
|
||||
"You instantaneously cause an unlocked door or window to fly open or slam shut.",
|
||||
"You alter the appearance of your eyes for 1 minutes."
|
||||
"You alter the appearance of your eyes for 1 minute."
|
||||
]
|
||||
},
|
||||
"If you cast this spell multiple times, you can have up to three of its 1-minutes effects active at a time, and you can dismiss such an effect as an action."
|
||||
"If you cast this spell multiple times, you can have up to three of its 1-minute effects active at a time, and you can dismiss such an effect as an action."
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -51,6 +51,6 @@ pub fn connection() -> Result<DbConnection, ServiceError> {
|
||||
.map_err(|e| ServiceError::new(500, format!("Failed getting db connection: {}", e)))
|
||||
}
|
||||
|
||||
pub fn load_data() {
|
||||
spells::load_data();
|
||||
pub fn load_data(data_dir_path: &str) {
|
||||
spells::load_data(data_dir_path);
|
||||
}
|
||||
|
||||
@@ -2,46 +2,57 @@ mod model;
|
||||
mod routes;
|
||||
mod types;
|
||||
|
||||
use std::{fs::{metadata, File, read_dir}, path::Path, io::BufReader};
|
||||
|
||||
use log::{warn, trace};
|
||||
pub use model::*;
|
||||
pub use types::*;
|
||||
pub use routes::init_routes;
|
||||
|
||||
pub fn load_data() {
|
||||
let root_path = std::env::current_dir().unwrap();
|
||||
let files = [
|
||||
"cantrips.json", "level_1.json", "level_2.json", "level_3.json", "level_4.json", "level_5.json", "level_6.json", "level_7.json", "level_8.json", "level_9.json"
|
||||
];
|
||||
let mut spells: Vec<Spell> = vec![];
|
||||
for file in files {
|
||||
let mut data_path = std::path::PathBuf::from(&root_path);
|
||||
data_path.push(format!("data/spells/{}", file));
|
||||
let path = data_path.to_str().unwrap();
|
||||
match std::fs::read_to_string(path) {
|
||||
Ok(data) => {
|
||||
log::debug!("Loading spells from {}", path);
|
||||
match serde_json::from_str::<serde_json::Value>(&data) {
|
||||
Ok(json) => {
|
||||
match serde_json::from_value::<Vec<Spell>>(json) {
|
||||
Ok(mut new_spells) => spells.append(&mut new_spells),
|
||||
Err(err) => log::error!("Failed to parse spells data: {}", err)
|
||||
pub fn load_data(data_dir_path: &str) {
|
||||
if Path::new(data_dir_path).exists() {
|
||||
let meta = metadata(data_dir_path).unwrap();
|
||||
if meta.is_dir() {
|
||||
let spells_dir_path = format!("{}/spells", data_dir_path);
|
||||
if Path::new(&spells_dir_path).exists() {
|
||||
let meta = metadata(&spells_dir_path).unwrap();
|
||||
if meta.is_dir() {
|
||||
for entry in read_dir(&spells_dir_path).unwrap() {
|
||||
let entry = entry.unwrap();
|
||||
let path = entry.path();
|
||||
if path.is_file() {
|
||||
let file = File::open(path).unwrap();
|
||||
let reader = BufReader::new(file);
|
||||
let result: Result<Vec<Spell>, serde_json::Error> = serde_json::from_reader(reader);
|
||||
match result {
|
||||
Ok(spells) => {
|
||||
for spell in spells {
|
||||
let mut filters = QueryFilters::default();
|
||||
filters.by_name = Some(spell.name.clone());
|
||||
match QuerySpell::get_all(&filters, 100, 1) {
|
||||
Ok(spells) => {
|
||||
if spells.len() > 0 {
|
||||
trace!("Spell '{}' already exists", spell.name);
|
||||
continue;
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
warn!("Error checking if spell '{}' exists: {}", spell.name, err);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let spell = InsertSpell::insert(spell.into()).unwrap();
|
||||
trace!("Inserted spell: {}", spell.name);
|
||||
}
|
||||
},
|
||||
Err(err) => warn!("Error reading spells from file: {}", err)
|
||||
};
|
||||
}
|
||||
},
|
||||
Err(err) => log::error!("Failed to parse spells data to value: {}", err)
|
||||
};
|
||||
},
|
||||
Err(err) => log::error!("Failed to read from {}: {}", file, err)
|
||||
};
|
||||
}
|
||||
let count = QuerySpell::get_count(&QueryFilters::default()).unwrap();
|
||||
if count >= spells.len() as i64 {
|
||||
log::warn!("Spell data is already loaded");
|
||||
return;
|
||||
}
|
||||
for spell in spells {
|
||||
let spell_name = spell.name.clone();
|
||||
match InsertSpell::insert(spell.into()) {
|
||||
Ok(_) => {},
|
||||
Err(err) => log::error!("Failed to insert '{}' spell: {}", spell_name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warn!("Data path '{}' does not exist, no data imported", data_dir_path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use siren::ServiceError;
|
||||
|
||||
use crate::db::{schema::spells::{self}, classes::AbilityType, conditions::ConditionType};
|
||||
|
||||
use super::{SchoolType, CastingTime, CastingType, SpellAttackType, SpellDamageType, Range, Area, Components, Duration, Source, Description, DurationType};
|
||||
use super::{SchoolType, CastingTime, SpellAttackType, SpellDamageType, Range, Area, Components, Duration, Source, Description, DurationType, Effect};
|
||||
|
||||
#[derive(Queryable, QueryableByName, Serialize, Deserialize)]
|
||||
#[diesel(table_name = spells)]
|
||||
@@ -198,6 +198,8 @@ pub struct Spell {
|
||||
pub ritual: bool,
|
||||
pub casting_time: CastingTime,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub effect: Option<Effect>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub saving_throw: Option<Vec<AbilityType>>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub attack_type: Option<SpellAttackType>,
|
||||
@@ -232,7 +234,8 @@ impl From<QuerySpell> for Spell {
|
||||
school: SchoolType::Abjuration,
|
||||
level: 0,
|
||||
ritual: false,
|
||||
casting_time: CastingTime { value: 0, casting_type: CastingType::Action },
|
||||
casting_time: CastingTime { value: 0, casting_type: "".to_string(), note: None },
|
||||
effect: None,
|
||||
saving_throw: None,
|
||||
attack_type: None,
|
||||
damage_inflict: None,
|
||||
|
||||
@@ -58,50 +58,10 @@ impl FromStr for SchoolType {
|
||||
pub struct CastingTime {
|
||||
pub value: i32,
|
||||
#[serde(rename = "unit")]
|
||||
pub casting_type: CastingType
|
||||
pub casting_type: String,
|
||||
pub note: Option<String>
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum CastingType {
|
||||
#[serde(rename = "action")]
|
||||
Action,
|
||||
#[serde(rename = "bonus")]
|
||||
BonusAction,
|
||||
#[serde(rename = "reaction")]
|
||||
Reaction,
|
||||
#[serde(rename = "minutes")]
|
||||
Minutes,
|
||||
#[serde(rename = "hours")]
|
||||
Hours
|
||||
}
|
||||
|
||||
// impl CastingType {
|
||||
// pub fn to_string(&self) -> String {
|
||||
// match self {
|
||||
// CastingType::Action => "action".to_string(),
|
||||
// CastingType::BonusAction => "bonus".to_string(),
|
||||
// CastingType::Reaction => "reaction".to_string(),
|
||||
// CastingType::Minutes => "minutes".to_string(),
|
||||
// CastingType::Hours => "hours".to_string()
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl FromStr for CastingType {
|
||||
// type Err = ();
|
||||
|
||||
// fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
// match s {
|
||||
// "action" => Ok(CastingType::Action),
|
||||
// "bonus" => Ok(CastingType::BonusAction),
|
||||
// "reaction" => Ok(CastingType::Reaction),
|
||||
// "minutes" => Ok(CastingType::Minutes),
|
||||
// "hours" => Ok(CastingType::Hours),
|
||||
// _ => Err(())
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum SpellAttackType {
|
||||
#[serde(rename = "melee")]
|
||||
@@ -303,8 +263,15 @@ pub struct Description {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Entry {
|
||||
pub entry_type: String,
|
||||
pub items: Vec<String>
|
||||
pub text: Option<Vec<String>>,
|
||||
pub list: Option<Vec<String>>,
|
||||
pub table: Option<EntryTable>
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct EntryTable {
|
||||
pub headers: Vec<String>,
|
||||
pub rows: Vec<Vec<String>>
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Entry {
|
||||
@@ -312,36 +279,82 @@ impl<'de> Deserialize<'de> for Entry {
|
||||
let value = serde_json::Value::deserialize(deserializer)?;
|
||||
match value {
|
||||
serde_json::Value::String(s) => Ok(Entry {
|
||||
entry_type: "string".to_string(),
|
||||
items: vec![s]
|
||||
text: Some(vec![s]),
|
||||
list: None,
|
||||
table: None,
|
||||
}),
|
||||
serde_json::Value::Object(o) => {
|
||||
let entry_type = match o.get("type") {
|
||||
Some(t) => match t.as_str() {
|
||||
Some(s) => s.to_string(),
|
||||
None => return Err(serde::de::Error::custom("Invalid entry type"))
|
||||
},
|
||||
None => return Err(serde::de::Error::custom("Missing entry type"))
|
||||
};
|
||||
let items = match o.get("items") {
|
||||
let list = match o.get("list") {
|
||||
Some(i) => match i.as_array() {
|
||||
Some(a) => {
|
||||
let mut items = Vec::new();
|
||||
let mut list = Vec::new();
|
||||
for item in a {
|
||||
match item.as_str() {
|
||||
Some(s) => items.push(s.to_string()),
|
||||
None => return Err(serde::de::Error::custom("Invalid entry item"))
|
||||
Some(s) => list.push(s.to_string()),
|
||||
None => return Err(serde::de::Error::custom("Invalid entry list item"))
|
||||
}
|
||||
}
|
||||
items
|
||||
Some(list)
|
||||
},
|
||||
None => return Err(serde::de::Error::custom("Invalid entry items"))
|
||||
None => return Err(serde::de::Error::custom("Invalid entry list items"))
|
||||
},
|
||||
None => return Err(serde::de::Error::custom("Missing entry items"))
|
||||
None => None
|
||||
};
|
||||
let table = match o.get("table") {
|
||||
Some(t) => match t.as_object() {
|
||||
Some(o) => {
|
||||
let mut headers = Vec::new();
|
||||
let mut rows = Vec::new();
|
||||
match o.get("headers") {
|
||||
Some(c) => match c.as_array() {
|
||||
Some(a) => {
|
||||
for item in a {
|
||||
match item.as_str() {
|
||||
Some(s) => headers.push(s.to_string()),
|
||||
None => return Err(serde::de::Error::custom("Invalid entry table header"))
|
||||
}
|
||||
}
|
||||
},
|
||||
None => return Err(serde::de::Error::custom("Invalid entry table headers"))
|
||||
},
|
||||
None => return Err(serde::de::Error::custom("Missing entry table headers"))
|
||||
};
|
||||
match o.get("rows") {
|
||||
Some(r) => match r.as_array() {
|
||||
Some(a) => {
|
||||
for row in a {
|
||||
match row.as_array() {
|
||||
Some(a) => {
|
||||
let mut row = Vec::new();
|
||||
for item in a {
|
||||
match item.as_str() {
|
||||
Some(s) => row.push(s.to_string()),
|
||||
None => return Err(serde::de::Error::custom("Invalid entry table row item"))
|
||||
}
|
||||
}
|
||||
rows.push(row);
|
||||
},
|
||||
None => return Err(serde::de::Error::custom("Invalid entry table row"))
|
||||
}
|
||||
}
|
||||
},
|
||||
None => return Err(serde::de::Error::custom("Invalid entry table rows"))
|
||||
},
|
||||
None => return Err(serde::de::Error::custom("Missing entry table rows"))
|
||||
};
|
||||
Some(EntryTable {
|
||||
headers,
|
||||
rows
|
||||
})
|
||||
},
|
||||
None => return Err(serde::de::Error::custom("Invalid entry table"))
|
||||
},
|
||||
None => None
|
||||
};
|
||||
Ok(Entry {
|
||||
entry_type,
|
||||
items
|
||||
text: None,
|
||||
list,
|
||||
table
|
||||
})
|
||||
},
|
||||
_ => Err(serde::de::Error::custom("Invalid entry"))
|
||||
@@ -351,15 +364,17 @@ impl<'de> Deserialize<'de> for Entry {
|
||||
|
||||
impl Serialize for Entry {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: serde::Serializer {
|
||||
match self.entry_type.as_str() {
|
||||
"string" => serializer.serialize_str(&self.items[0]),
|
||||
_ => {
|
||||
let mut map = serializer.serialize_map(Some(2))?;
|
||||
map.serialize_entry("type", &self.entry_type)?;
|
||||
map.serialize_entry("items", &self.items)?;
|
||||
map.end()
|
||||
}
|
||||
let mut map = serializer.serialize_map(Some(1))?;
|
||||
if let Some(text) = &self.text {
|
||||
map.serialize_entry("text", text)?;
|
||||
}
|
||||
if let Some(list) = &self.list {
|
||||
map.serialize_entry("list", list)?;
|
||||
}
|
||||
if let Some(table) = &self.table {
|
||||
map.serialize_entry("table", table)?;
|
||||
}
|
||||
map.end()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,3 +390,8 @@ pub struct Components {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub materials_consumed: Option<bool>
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Effect {
|
||||
pub effect_type: Option<String>
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use actix_cors::Cors;
|
||||
use actix_web::{HttpServer, App};
|
||||
|
||||
use dotenv::dotenv;
|
||||
use log::{error, info};
|
||||
use log::{error, info, warn};
|
||||
|
||||
mod db;
|
||||
|
||||
@@ -17,7 +17,10 @@ async fn main() -> std::io::Result<()> {
|
||||
dotenv().ok();
|
||||
env_logger::init_from_env(env_logger::Env::default().filter_or("RUST_LOG", "warn,siren=info"));
|
||||
db::init();
|
||||
db::load_data();
|
||||
match env::var("DATA_DIR_PATH") {
|
||||
Ok(data_dir_path) => db::load_data(&data_dir_path),
|
||||
Err(err) => warn!("Unable to load initial database data: {}", err)
|
||||
};
|
||||
|
||||
let host = env::var("SERVICE_HOST").unwrap_or("localhost".to_string());
|
||||
let port = env::var("SERVICE_PORT").unwrap_or("5000".to_string());
|
||||
|
||||
Reference in New Issue
Block a user