1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/// Provide custom error with links for when application panics (unrecoverable error).
#[macro_export]
macro_rules! setup_panic {
    () => {
        #[allow(unused_imports)]
        use colored::*;
        #[allow(unused_imports)]
        use std::panic::{self, PanicInfo};

        // This code is inspired by the `human-panic` crate.
        // Only use custom panic when in release mode.
        #[cfg(not(debug_assertions))]
        match ::std::env::var("RUST_BACKTRACE") {
            Err(_) => {
                panic::set_hook(Box::new(move |info: &PanicInfo| {
                    let payload = info.payload();
                    let panic_message = if let Some(s) = payload.downcast_ref::<&str>() {
                        s.to_string()
                    } else if let Some(s) = payload.downcast_ref::<String>() {
                        s.clone()
                    } else if let Some(s) = payload.downcast_ref::<failure::Error>() {
                        s.to_string()
                    } else {
                        String::new()
                    };
                    if let Some(message) = git_panic::check_if_common_errors(&panic_message) {
                        println!(
                            "{}: The application encountered an error it could not recover from.\n\
                            This is a known issue: {}\n\
                            Panic message: {}\n",
                            "PANIC".bright_red(),
                            message,
                            panic_message,
                        );
                    } else {
                        let mut file = "unknown file";
                        let mut line = 0;
                        let mut column = 0;
                        if let Some(location) = info.location() {
                            file = location.file();
                            line = location.line();
                            column = location.column();
                        }
                        let panic_location = format!("{}:{}:{}", file, line, column);

                        let issue = df_st_core::GitIssue::<String> {
                            title: format!("Panic: {} in {}", panic_message, file),
                            message: format!(
                                "A panic occurred during execution.\n\n\
                                * Message: `{}`\n\
                                * Path: `{}`",
                                panic_message, panic_location,
                            ),
                            labels: vec!["Panic".to_owned()],
                            debug_info_string: None,
                            debug_info_json: None,
                            add_steps: true,
                            ask_add_files: true,
                            include_backtrace: true,
                        };
                        // Print panic message
                        println!("{}: {}", "PANIC".bright_red(), panic_message);
                        // Print report issue links
                        println!(
                            "{}: The application encountered an error it could not recover from.\n\
                        If you report this we might be able to fix this in the future.\n\
                        {}",
                            "PANIC".bright_red(),
                            issue.create_message()
                        );
                    }
                }));
            }
            Ok(_) => {}
        }
    };
}

#[allow(dead_code)]
pub fn check_if_common_errors(error_message: &str) -> Option<String> {
    use colored::*;
    match error_message {
        "Error saving worlds: DatabaseError(UniqueViolation, \"UNIQUE constraint failed: worlds.id\")" => {
            Some(format!("world_id already exist, change `-w X` to an other number.\n\
            For more info see: {}", df_st_core::git_issue::link_to_issue_nr(61).dimmed().bright_cyan()))
        },
        "This version is unsafe. Please update." => {
            Some(format!("The version you are using is marked as unsafe or is outdated.\n\
            Please download the latest version of DF Storyteller.\n\
            For more info see: {}", df_st_core::git_issue::link_to_issue_nr(65).dimmed().bright_cyan()))
        },
        "Tamper prevention in place. Please update to the latest version." => {
            Some(format!("We detected that something weird is happening.\n\
            Please download the latest version of DF Storyteller.\n\
            For more info see: {}", df_st_core::git_issue::link_to_issue_nr(71).dimmed().bright_cyan()))
        },
        "You are using a SQLite build but the config is set to an other service" => {
            Some(format!("You are using a SQLite build but the config is set to an other service\n\
            Update the `df_storyteller-config.json -> database -> service` to `\"sqlite\"`.\n\
            For more info see: {}", df_st_core::git_issue::link_to_issue_nr(69).dimmed().bright_cyan()))
        },
        "You are using a Postgres build but the config is set to an other service" => {
            Some(format!("You are using a Postgres build but the config is set to an other service\n\
            Update the `df_storyteller-config.json -> database -> service` to `\"postgres\"`.\n\
            For more info see: {}", df_st_core::git_issue::link_to_issue_nr(69).dimmed().bright_cyan()))
        },
        "Error connecting to database." | "Failed to connect to database." => {
            Some(format!("DF Storyteller could not connect to the database.\n\
            This might be because it is not installed or on a different port (like 5433).\n\
            For more info see: {}", df_st_core::git_issue::link_to_issue_nr(70).dimmed().bright_cyan()))
        },
        "No database url found in config." => {
            Some("You have a misconfigured `df_storyteller-config.json` file.\n\
            change `df_storyteller-config.json -> database -> service` to \"sqlite\" or \"postgres\".".to_owned())
        },
        "Couldn't get db connection from pool." => {
            Some("There is something wrong with your database.\n\
            I think the connection timed out.".to_owned())
        },
        // "Could not get the list of worlds from that database." => { More info needed }
        "Could not look in the folder." => {
            Some("While looking for the files to import it could not look into the folder provided.\n\
            You might want to check the permissions of this folder.".to_owned())
        },
        "File is not in folder?" => {
            Some("I don't know what you did there. Are you in the root folder of your pc?\n\
            Try specifying another path.".to_owned())
        },
        "File found with non UTF-8 characters" => {
            Some("We found a file in the provided folder that has some \
            non UTF-8 characters (aka very special characters).\n\
            Try renaming that file and try again.".to_owned())
        },
        "Database already exists." => {
            Some(format!("While wanting to create the the new database it found the database already exists. \
            It will not remove the data present by itself. Make sure you no longer need the data \
            and use the flag `--drop-db` to drop/delete the existing database first. \n\
            {}\nFor more info see: {}",
            "WARNING this will delete all stored data in this database! Also check the database name above!".bright_red(),
            df_st_core::git_issue::link_to_issue_nr(72).dimmed().bright_cyan()))
        },
        "Found a database without tables." => {
            Some("We did a test to check if the database was setup correctly.\n\
            And it turns out it was not setup correctly.\n\
            Run: `./df_storyteller database --postgres` to setup the database\n\
            Then you can try again.".to_owned())
        },
        "Must be owner of database to drop database." => {
            Some("We tried to drop/delete the database, but we are not the owner of this database.\n\
            Is the database use by some other application?\n\
            ---Be careful with what you do!--\n\
            If you are sure you want to drop the database use pgAdmin or connect to you database \
            in some other way and delete or rename the existing database.\n\
            Then you can try again.".to_owned())
        },
        "Address/Port binding error." => {
            Some("We got a Address/Port binding error.\n\
            You most likely already have DF Storyteller open somewhere. \
            Because the port is already in use. If this is not the case an other app \
            is using this port. You can change the port in the config file.\n\
            Change the port `df_storyteller-config.json -> server -> port.\n\
            Change the value to 20351 and try again.".to_owned())
        },
        "API IO error." => {
            Some("An API IO error was returned. We don't know why exactly. \
            Please report this error with the link above.".to_owned())
        },
        "API Collision error." => {
            Some("This is an error made by the developers, we are sorry. \
            Please report this error with the link above.".to_owned())
        },
        "API Fairing error." => {
            Some("An API Fairing error was returned. We don't know why exactly. \
            Please report this error with the link above.".to_owned())
        },
        "API Unknown error." => {
            Some("An API Unknown error was returned. We don't know why exactly. \
            Please report this error with the link above.".to_owned())
        },
        "Unexpected EOF during importing." => {
            Some(format!("The file you are trying to import is not complete. \
            You might have stopped the exporting of the file early. \
            Fix: Re-export the files again using DF or DFHack and try again.\n\
            For more info see: {}", df_st_core::git_issue::link_to_issue_nr(106).dimmed().bright_cyan()))
        },
        "File is empty." => {
            Some("The file you are trying to import is most likely empty. \
            Try re-exporting the files.".to_owned())
        },
        _ => {
            None
        },
    }
}