コード例 #1
0
        private void HandleErrOutput(DataReceivedEventArgs arguments, Track track)
        {
            LoggerBundle.Trace($"Processing error response of track '{track}'...");
            try
            {
                String output = arguments?.Data?.Trim();
                if (String.IsNullOrEmpty(output))
                {
                    return;
                }

                LoggerBundle.Warn(new CalculationException(output));
                track.FingerprintError           = output;
                track.LastFingerprintCalculation = DateTime.Now;

                using (DataContext dataContext = DataContextFactory.GetInstance())
                {
                    LoggerBundle.Trace($"Saving track '{track}'...");
                    dataContext.SetTracks.Attach(track);
                    dataContext.Entry(track).State = EntityState.Modified;
                    dataContext.SaveChanges();
                    LoggerBundle.Debug($"Successfully updated track '{track}'...");
                }
            }
            catch (Exception ex)
            {
                LoggerBundle.Error(ex);
            }
            finally
            {
                _buffer.Remove(track);
            }
        }
コード例 #2
0
        private Program()
        {
            using (DataContext dc = DataContextFactory.GetInstance())
            {
                LoggerBundle.Debug("Trying to load data of every model type...");

                foreach (Type t in Types)
                {
                    LoggerBundle.Trace($"Loading data for set of type '{t.Name}'...");
                    MethodInfo setMethod        = dc.GetType().GetMethods().First(x => x.Name.Equals("Set"));
                    MethodInfo setMethodGeneric = setMethod.MakeGenericMethod(t);
                    Object     set        = setMethodGeneric.Invoke(dc, new Object[] { });
                    MethodInfo methodLoad = typeof(EntityFrameworkQueryableExtensions).GetMethods()
                                            .First(x => x.Name.Equals("Load"));
                    MethodInfo methodLoadGeneric = methodLoad.MakeGenericMethod(t);
                    methodLoadGeneric.Invoke(set
                                             , new[]
                    {
                        set
                    });

                    dc.SetTracks.Load();
                    LoggerBundle.Trace("Loading data done.");
                }

                LoggerBundle.Debug("Done.");
            }
        }
コード例 #3
0
        protected override void Process(String[] args)
        {
            OnProcessStarting();
            TriggerActions(args.ToList());

            List <Track> tracks;

            do
            {
                using (DataContext dataContext = DataContextFactory.GetInstance())
                {
                    LoggerBundle.Debug("Preloading data...");
                    Stopwatch sw = new Stopwatch();
                    sw.Start();
                    tracks = _includeFailed
                        ? dataContext.SetTracks.Where(x => !x.LastFingerprintCalculation.HasValue || null != x.FingerprintError)
                             .Take(_config.BufferSize)
                             .ToList()
                        : dataContext.SetTracks.Where(x => !x.LastFingerprintCalculation.HasValue)
                             .Take(_config.BufferSize)
                             .ToList();

                    sw.Stop();
                    LoggerBundle.Debug($"Getting data finished in {sw.ElapsedMilliseconds}ms");
                }
                LoggerBundle.Inform($"Batch contains {tracks.Count} record(s).");

                foreach (Track track in tracks)
                {
                    LoggerBundle.Trace($"Initializing process for track '{track}'...");
                    while (_buffer.Count >= _config.ParallelProcesses)
                    {
                        Thread.Sleep(1);
                    }

                    LoggerBundle.Trace($"Starting process for track '{track}'...");
                    Process p = new Process
                    {
                        StartInfo =
                        {
                            FileName                 = FingerprintCalculationExecutablePath
                            , Arguments              = $"-json \"{track.Path}\""
                            , CreateNoWindow         = true
                            , RedirectStandardError  = true
                            , RedirectStandardInput  = true
                            , RedirectStandardOutput = true
                            , UseShellExecute        = false
                        }
                    };
                    p.OutputDataReceived += (_, arguments) => HandleStdOutput(arguments, track);
                    p.ErrorDataReceived  += (_, arguments) => HandleErrOutput(arguments, track);
                    _buffer.Add(track);
                    LoggerBundle.Trace($"Starting computation process for file '{track}'...");
                    p.Start();
                    p.BeginOutputReadLine();
                    p.BeginErrorReadLine();
                    LoggerBundle.Debug($"Computation process started for file '{track}'");
                }
            }while (tracks.Count > 0);
        }
コード例 #4
0
ファイル: Program.cs プロジェクト: tobiaswuerth/mux-cli
        private static Dictionary <String, PluginBase> InitializePlugin(List <PluginBase> pluginsToLoad)
        {
            Dictionary <String, PluginBase> plugins = new Dictionary <String, PluginBase>();

            pluginsToLoad.ForEach(x =>
            {
                // initialize
                Boolean initialized = x.Initialize();

                if (!initialized)
                {
                    LoggerBundle.Warn($"Plugin '{x.Name}' cannot be initialized. This plugin will be deactivated.");
                    return;
                }

                LoggerBundle.Debug($"Plugin '{x.Name}' initialized successfully. Validating...");

                // validate
                String pcName = x.Name.ToLower().Trim();
                if (plugins.ContainsKey(pcName))
                {
                    LoggerBundle.Warn($"Plugin '{x.Name}' does not pass validation because a plugin with the same name has already been registered. This plugin will be deactivated.");
                }

                LoggerBundle.Debug($"Plugin '{x.Name}' passed validation");

                // add to plugin registry
                plugins.Add(pcName, x);
                LoggerBundle.Inform($"Plugin '{x.Name}' activated");
            });
            return(plugins);
        }
コード例 #5
0
        public static T Request <T>(String path) where T : class
        {
            LoggerBundle.Debug($"Requested configuration '{path}'");

            if (!File.Exists(path))
            {
                LoggerBundle.Trace($"File '{path}' not found. Trying to create it...");
                FileInterface.Save(Activator.CreateInstance <T>(), path);
                LoggerBundle.Trace($"Successfully created file '{path}'");

                LoggerBundle.Inform(
                    $"Changes to the newly created file '{path}' will take effect after restarting the executable. Adjust default value as needed and restart the application.");
            }

            LoggerBundle.Trace($"Trying to read file '{path}'...");
            (T result, Boolean success) = FileInterface.Read <T>(path);
            if (!success)
            {
                LoggerBundle.Warn(new ProcessAbortedException());
                return(null);
            }

            LoggerBundle.Debug($"Successfully read configuration file '{path}'");
            return(result);
        }
コード例 #6
0
        protected override void OnInitialize()
        {
            LoggerBundle.Debug($"Initializing plugin '{Name}'...");

            LoggerBundle.Trace("Requesting config...");
            _config = RequestConfig <Config>();
            LoggerBundle.Trace("Done.");
        }
コード例 #7
0
ファイル: PluginImport.cs プロジェクト: tobiaswuerth/mux-cli
        protected override void Process(String[] args)
        {
            OnProcessStarting();
            TriggerActions(args.ToList());

            List <String> paths = args.Distinct().Select(x => x.Trim()).ToList();

            if (paths.Count.Equals(0))
            {
                LoggerBundle.Fatal(new ArgumentException("no argument given"));
                Environment.Exit(1);
            }

            foreach (String path in paths)
            {
                LoggerBundle.Inform($"Processing path '{path}'...");
                if (!Directory.Exists(path))
                {
                    LoggerBundle.Warn($"Path '{path}' not found. Skipping.");
                    continue;
                }

                LoggerBundle.Debug("Preloading data...");
                List <String> tracks;
                Stopwatch     sw = new Stopwatch();
                sw.Start();
                using (DataContext dataContext = DataContextFactory.GetInstance())
                {
                    tracks = dataContext.SetTracks.AsNoTracking().Select(x => x.Path).ToList();
                }
                sw.Stop();
                LoggerBundle.Debug($"Getting data finished in {sw.ElapsedMilliseconds}ms");

                List <String>       buffer = new List <String>();
                DataSource <String> ds     = new PathDataSource(path, _config.Extensions);

                LoggerBundle.Inform($"Start to crawl path '{path}'...");
                foreach (String file in ds.Get())
                {
                    buffer.Add(file);

                    Int32 bufferCount = buffer.Count;
                    if (bufferCount < _config.BufferSize)
                    {
                        if (bufferCount % (_config.BufferSize < 1337 ? _config.BufferSize : 1337) == 0)
                        {
                            LoggerBundle.Trace($"Adding files to buffer [{bufferCount}/{_config.BufferSize}] ...");
                        }
                        continue;
                    }

                    ProcessBuffer(ref buffer, ref tracks);
                }

                ProcessBuffer(ref buffer, ref tracks);
            }
        }
コード例 #8
0
        protected override void OnInitialize()
        {
            LoggerBundle.Debug($"Initializing plugin '{Name}'...");

            LoggerBundle.Trace("Requesting config...");
            _config = RequestConfig <Config>();
            LoggerBundle.Trace("Done");

            RegisterAction("include-failed", () => _includeFailed = true);
        }
コード例 #9
0
ファイル: Program.cs プロジェクト: tobiaswuerth/mux-core
 private static void Main(String[] args)
 {
     // mainly for debugging
     LoggerBundle.Trace("TEST");
     LoggerBundle.Debug("TEST");
     LoggerBundle.Inform("TEST");
     LoggerBundle.Warn(new Exception());
     LoggerBundle.Error(new Exception());
     LoggerBundle.Fatal(new Exception());
 }
コード例 #10
0
        private void HandleStdOutput(DataReceivedEventArgs arguments, Track track)
        {
            LoggerBundle.Trace($"Processing response of track '{track}'...");
            try
            {
                String output = arguments?.Data?.Trim();
                if (String.IsNullOrEmpty(output))
                {
                    return;
                }

                LoggerBundle.Debug(Logger.DefaultLogFlags & ~LogFlags.SuffixNewLine
                                   , $"Trying to serialize computation output of file '{track}'...");
                JsonFingerprint jfp = JsonConvert.DeserializeObject <JsonFingerprint>(output);
                LoggerBundle.Debug(Logger.DefaultLogFlags & ~LogFlags.PrefixLoggerType & ~LogFlags.PrefixTimeStamp, "Ok.");

                track.LastFingerprintCalculation = DateTime.Now;
                track.FingerprintHash            = _hasher.Compute(jfp.Fingerprint);
                track.FingerprintError           = null;

                LoggerBundle.Trace($"Fingerprint hash: {track.FingerprintHash} for fingerprint {jfp.Fingerprint}");

                using (DataContext dataContext = DataContextFactory.GetInstance())
                {
                    LoggerBundle.Trace($"Checking for duplicates for file '{track}'...");
                    if (dataContext.SetTracks.AsNoTracking().Any(x => x.FingerprintHash.Equals(track.FingerprintHash)))
                    {
                        LoggerBundle.Debug($"File with same fingerprint already in database. Path '{track}' will be skipped");
                        track.FingerprintError = "duplicate";
                    }
                    else
                    {
                        LoggerBundle.Trace($"No duplicate found for file '{track}'");
                        track.Duration    = jfp.Duration;
                        track.Fingerprint = jfp.Fingerprint;
                        LoggerBundle.Trace($"New meta data duration '{track.Duration}' and fingerprint '{jfp.Fingerprint}'");
                    }

                    LoggerBundle.Trace($"Saving file '{track.Path}'...");
                    dataContext.SetTracks.Attach(track);
                    dataContext.Entry(track).State = EntityState.Modified;
                    dataContext.SaveChanges();
                    LoggerBundle.Debug($"Successfully saved file '{track}'...");
                }
            }
            catch (Exception ex)
            {
                LoggerBundle.Error(ex);
            }
            finally
            {
                _buffer.Remove(track);
            }
        }
コード例 #11
0
ファイル: DataContext.cs プロジェクト: tobiaswuerth/mux-data
        public DataContext(DbContextOptions <DataContext> options) : base(options)
        {
            LoggerBundle.Debug("Initializing data context...");
            try
            {
                _config = Configurator.Request <DatabaseConfig>(DatabaseSettingsFilePath);
            }
            catch (Exception ex)
            {
                LoggerBundle.Fatal("Could not load database config file", ex);
                Environment.Exit(1);
            }

            LoggerBundle.Debug("Context initialized.");
        }
コード例 #12
0
        public void TriggerAction(String key)
        {
            if (key == null)
            {
                LoggerBundle.Warn(new ArgumentNullException(nameof(key)));
                return;
            }

            if (!_actions.ContainsKey(key))
            {
                LoggerBundle.Debug(new KeyNotFoundException($"No action with name '{key}' found"));
                return;
            }

            _actions[key].Invoke();
        }
コード例 #13
0
        public Object Get(String id)
        {
            LoggerBundle.Debug($"Get request for id '{id}'...");
            while ((DateTime.Now - _lastRequest).TotalMilliseconds < DELAY_BETWEEN_REQUESTS)
            {
                Thread.Sleep(1);
            }

            String url = String.Format(URI_API_MUSICBRAINZ, id ?? String.Empty);

            LoggerBundle.Trace($"Posting to '{url}'");

            Assembly coreAssembly = typeof(PluginBase).Assembly;
            Version  coreVersion  = coreAssembly.GetName().Version;

            HttpRequestMessage req = new HttpRequestMessage(HttpMethod.Get, url);

            String userAgent = $"Mux/{coreVersion} ( mail @fooo.ooo ) - Instance {_guid}";

            req.Headers.Add("User-Agent", userAgent);
            LoggerBundle.Trace($"User-Agent: {userAgent}");

            _lastRequest = DateTime.Now;
            LoggerBundle.Trace(Logger.DefaultLogFlags & ~LogFlags.SuffixNewLine, "Sending async request...");
            Task <HttpResponseMessage> response = _client.SendAsync(req);

            LoggerBundle.Trace(Logger.DefaultLogFlags & ~LogFlags.PrefixTimeStamp & ~LogFlags.PrefixLoggerType, "Ok.");

            Task <String> responseString = response.Result.Content.ReadAsStringAsync();
            String        responseBody   = responseString.Result.Trim();

            LoggerBundle.Trace($"Response: {responseBody}");

            LoggerBundle.Trace(Logger.DefaultLogFlags & ~LogFlags.SuffixNewLine, "Trying to deserialize object...");
            JsonErrorMusicBrainz status = JsonConvert.DeserializeObject <JsonErrorMusicBrainz>(responseBody);

            LoggerBundle.Trace(Logger.DefaultLogFlags & ~LogFlags.PrefixTimeStamp & ~LogFlags.PrefixLoggerType, "Ok.");

            if (null == status.Error)
            {
                // no error found
                return(JsonConvert.DeserializeObject <JsonMusicBrainzRequest>(responseBody));
            }

            return(status);
        }
コード例 #14
0
ファイル: Program.cs プロジェクト: tobiaswuerth/mux-cli
        private static void CreateGlobalDirectories()
        {
            List <String> paths = new List <String>
            {
                Location.ApplicationDataDirectoryPath
                , Location.PluginsDirectoryPath
                , Location.LogsDirectoryPath
            };

            paths.Where(x => !Directory.Exists(x))
            .ToList()
            .ForEach(x =>
            {
                LoggerBundle.Debug(Logger.DefaultLogFlags & ~LogFlags.SuffixNewLine, $"Trying to create directory '{x}'...");
                Directory.CreateDirectory(x);
                LoggerBundle.Debug(Logger.DefaultLogFlags & ~LogFlags.PrefixLoggerType & ~LogFlags.PrefixTimeStamp, "Ok.");
            });
        }
コード例 #15
0
        protected override void OnInitialize()
        {
            LoggerBundle.Debug($"Initializing plugin '{Name}'...");

            if (!File.Exists(FingerprintCalculationExecutablePath))
            {
                LoggerBundle.Fatal(new FileNotFoundException(
                                       $"File '{FingerprintCalculationExecutablePath}' not found. Visit https://github.com/acoustid/chromaprint/releases to download the latest version."
                                       , FingerprintCalculationExecutablePath));
                Environment.Exit(1);
            }

            LoggerBundle.Trace("Requesting config...");
            _config = RequestConfig <Config>();
            LoggerBundle.Trace("Done");

            RegisterAction("include-failed", () => _includeFailed = true);
        }
コード例 #16
0
ファイル: PluginImport.cs プロジェクト: tobiaswuerth/mux-cli
        private void ProcessBuffer(ref List <String> buffer, ref List <String> tracks)
        {
            LoggerBundle.Debug("Buffer full. Searching new entries...");
            List <String> newPaths      = buffer.Except(tracks).ToList();
            Int32         newPathsCount = newPaths.Count;

            LoggerBundle.Debug($"{newPathsCount} new files found");

            LoggerBundle.Debug("Saving to database...");
            Stopwatch sw = new Stopwatch();

            sw.Start();
            using (DataContext dataContext = DataContextFactory.GetInstance())
            {
                dataContext.ChangeTracker.AutoDetectChangesEnabled = false;
                // todo disable validation on save

                for (Int32 i = 0; i < newPathsCount; i++)
                {
                    dataContext.SetTracks.Add(new Track
                    {
                        Path = newPaths[i]
                    });
                    if (i % 1337 != 0)
                    {
                        continue;
                    }

                    dataContext.SaveChanges();
                    LoggerBundle.Trace($"Saved {i + 1}/{newPathsCount}...");
                }

                dataContext.SaveChanges();
            }

            sw.Stop();
            Int64 elms = sw.ElapsedMilliseconds;

            LoggerBundle.Debug($"Saved {newPathsCount} items in {elms}ms ({(Double) elms / newPathsCount}ms per item average)");

            tracks.AddRange(newPaths);
            buffer.Clear();
            LoggerBundle.Debug("Finished processing buffer. Returning.");
        }
コード例 #17
0
        private void CleanInvisible()
        {
            List <Track> data;

            do
            {
                LoggerBundle.Inform("Removing invisible data");
                LoggerBundle.Debug("Getting data...");
                using (DataContext dataContext = DataContextFactory.GetInstance())
                {
                    data = dataContext.SetTracks.Where(x => null != x.LastAcoustIdApiCall).Where(x => 1 > x.AcoustIdResults.Count).OrderBy(x => x.UniqueId).Take(_config.BufferSize).ToList();

                    LoggerBundle.Inform($"Batch containing: {data.Count} entries");

                    foreach (Track track in data)
                    {
                        try
                        {
                            LoggerBundle.Debug($"Processing track '{track}'...");

                            if (File.Exists(track.Path))
                            {
                                File.Delete(track.Path);
                            }

                            dataContext.SetTracks.Remove(track);
                            dataContext.SaveChanges();

                            LoggerBundle.Trace("Processing done");
                        }
                        catch (Exception ex)
                        {
                            LoggerBundle.Error(ex);
                        }
                    }
                }
            }while (data.Count > 0);
        }
コード例 #18
0
 protected override void OnInitialize()
 {
     LoggerBundle.Debug($"Initializing plugin '{Name}'...");
     RegisterAction("add", AddUser);
 }
コード例 #19
0
        protected override void Process(String[] args)
        {
            base.OnProcessStarting();
            TriggerActions(args.ToList());

            List <Track> data;

            do
            {
                using (DataContext dataContext = DataContextFactory.GetInstance())
                {
                    LoggerBundle.Debug("Loading batch...");

                    data = _includeFailed
                        ? dataContext.SetTracks
                           .Where(x => null != x.LastFingerprintCalculation &&
                                  null == x.FingerprintError &&
                                  null == x.LastAcoustIdApiCall ||
                                  x.LastAcoustIdApiCall.HasValue && null != x.AcoustIdApiError)
                           .Take(_config.BufferSize)
                           .ToList()
                        : dataContext.SetTracks
                           .Where(x => null != x.LastFingerprintCalculation &&
                                  null == x.FingerprintError &&
                                  null == x.LastAcoustIdApiCall)
                           .Take(_config.BufferSize)
                           .ToList();

                    LoggerBundle.Inform($"Batch containing {data.Count} entries");

                    foreach (Track track in data)
                    {
                        LoggerBundle.Debug($"Posting metadata of track '{track}'...");

                        track.LastAcoustIdApiCall = DateTime.Now;

                        Object response = _apiHandler.Post(track.Duration ?? 0d, track.Fingerprint);
                        LoggerBundle.Trace($"Response: {response}");

                        switch (response)
                        {
                        case JsonErrorAcoustId jea:
                        {
                            LoggerBundle.Warn(new AcoustIdApiException($"Error {jea.Error.Code}: {jea.Error.Message}"));
                            track.AcoustIdApiError     = jea.Error.Message;
                            track.AcoustIdApiErrorCode = jea.Error.Code;
                            break;
                        }

                        case JsonAcoustIdRequest air:
                        {
                            HandleResponse(dataContext, track, air);
                            break;
                        }

                        default:
                        {
                            LoggerBundle.Trace(Logger.DefaultLogFlags & ~LogFlags.SuffixNewLine
                                               , "Trying to serialize unknown response object...");
                            String serializedResponse = "<unknown>";
                            try
                            {
                                serializedResponse = JsonConvert.SerializeObject(response);
                            }
                            catch (Exception ex)
                            {
                                LoggerBundle.Error(ex);
                            }
                            LoggerBundle.Trace(Logger.DefaultLogFlags
                                               & ~LogFlags.PrefixTimeStamp
                                               & ~LogFlags.PrefixLoggerType
                                               , "Ok.");
                            LoggerBundle.Warn(new AcoustIdApiException($"Unknown response: {serializedResponse}"));
                            track.AcoustIdApiError = serializedResponse;
                            break;
                        }
                        }

                        dataContext.SaveChanges();
                    }
                }
            }while (data.Count > 0);
        }
コード例 #20
0
        protected override void Process(String[] args)
        {
            OnProcessStarting();
            TriggerActions(args.ToList());

            List <MusicBrainzRecord> data;

            do
            {
                LoggerBundle.Debug("Getting data...");
                using (DataContext dataContext = DataContextFactory.GetInstance())
                {
                    data = dataContext.SetMusicBrainzRecords.Where(x => null == x.LastMusicBrainzApiCall)
                           .Include(x => x.MusicBrainzAliasMusicBrainzRecords)
                           .ThenInclude(x => x.MusicBrainzAlias)
                           .Include(x => x.MusicBrainzArtistCreditMusicBrainzRecords)
                           .ThenInclude(x => x.MusicBrainzArtistCredit)
                           .Include(x => x.MusicBrainzReleaseMusicBrainzRecords)
                           .ThenInclude(x => x.MusicBrainzRelease)
                           .Include(x => x.MusicBrainzTagMusicBrainzRecords)
                           .ThenInclude(x => x.MusicBrainzTag)
                           .OrderBy(x => x.UniqueId)
                           .Take(_config.BatchSize)
                           .ToList();

                    LoggerBundle.Inform($"Batch containing: {data.Count} entries");

                    foreach (MusicBrainzRecord mbr in data)
                    {
                        try
                        {
                            LoggerBundle.Debug($"Processing record '{mbr}'...");

                            DateTime requestTime = DateTime.Now;
                            Object   o           = _api.Get(mbr.MusicbrainzId);

                            Stopwatch sw = new Stopwatch();
                            sw.Start();

                            switch (o)
                            {
                            case JsonMusicBrainzRequest req:
                                HandleResponse(mbr, req, dataContext);
                                break;

                            case JsonErrorMusicBrainz err:
                                mbr.MusicBrainzApiCallError = err.Error?.Trim() ?? "<unknown>";
                                LoggerBundle.Warn(new MusicBrainzApiException($"Error: {mbr.MusicBrainzApiCallError}"));
                                break;
                            }

                            mbr.LastMusicBrainzApiCall = requestTime;
                            dataContext.SaveChanges();

                            sw.Stop();
                            LoggerBundle.Debug($"Processing done in {sw.ElapsedMilliseconds}ms");
                        }
                        catch (Exception ex)
                        {
                            LoggerBundle.Error(ex);
                        }
                    }
                }
            }while (data.Count > 0);
        }
コード例 #21
0
        private void AddUser()
        {
            LoggerBundle.Debug("Starting process to add new user...");
            try
            {
                // read username
                LoggerBundle.Inform(Logger.DefaultLogFlags & ~LogFlags.SuffixNewLine, "Enter a username: "******"";

                if (String.IsNullOrWhiteSpace(username))
                {
                    LoggerBundle.Fatal(new ArgumentException("Username cannot be empty"));
                    Environment.Exit(1);
                }

                // check existance
                LoggerBundle.Debug("Checking if user already exists...");
                Boolean exists;
                using (DataContext dataContext = DataContextFactory.GetInstance())
                {
                    exists = dataContext.SetUsers.Any(x => x.Username.ToLower().Equals(username.ToLower()));
                }
                if (exists)
                {
                    LoggerBundle.Fatal(new ArgumentException("Username already exists"));
                    Environment.Exit(1);
                }

                LoggerBundle.Trace("User not found database. Allowed to proceed forward");

                // get password
                LoggerBundle.Inform(Logger.DefaultLogFlags & ~LogFlags.SuffixNewLine, "Enter a password: "******"Confirm password: "******"Passwords do not match"));
                    Environment.Exit(1);
                }

                // hash password
                Sha512HashPipe hashPipe = new Sha512HashPipe();
                String         hashedPw = hashPipe.Process(pw1);

                // save model
                User user = new User
                {
                    Username   = username
                    , Password = hashedPw
                };
                using (DataContext dataContext = DataContextFactory.GetInstance())
                {
                    dataContext.SetUsers.Add(user);
                    dataContext.SaveChanges();
                }
                LoggerBundle.Inform(
                    $"Successfully created user '{user.Username}' created with unique identifier '{user.UniqueId}'");
            }
            catch (Exception ex)
            {
                LoggerBundle.Error(ex);
            }
        }