Failed() public method

public Failed ( string text ) : void
text string
return void
Example #1
0
        public static bool Handle(EndpointRegistration endpointRegistration, IRequestInfo info, CollectionSettings collectionSettings, Book.Book currentBook)
        {
            var request = new ApiRequest(info, collectionSettings, currentBook);

            try
            {
                if (Program.RunningUnitTests)
                {
                    endpointRegistration.Handler(request);
                }
                else
                {
                    var label = "";
                    if (endpointRegistration.DoMeasure && (endpointRegistration.FunctionToGetLabel != null))
                    {
                        label = endpointRegistration.FunctionToGetLabel();
                    }
                    else if (endpointRegistration.DoMeasure)
                    {
                        label = endpointRegistration.MeasurementLabel;
                    }
                    using (endpointRegistration.DoMeasure ? PerformanceMeasurement.Global?.Measure(label) : null)
                    {
                        // Note: If the user is still interacting with the application, openForms could change and become empty
                        var formForSynchronizing = Application.OpenForms.Cast <Form>().LastOrDefault();
                        if (endpointRegistration.HandleOnUIThread && formForSynchronizing != null &&
                            formForSynchronizing.InvokeRequired)
                        {
                            InvokeWithErrorHandling(endpointRegistration, formForSynchronizing, request);
                        }
                        else
                        {
                            endpointRegistration.Handler(request);
                        }
                    }
                }
                if (!info.HaveOutput)
                {
                    throw new ApplicationException(string.Format("The EndpointHandler for {0} never called a Succeeded(), Failed(), or ReplyWith() Function.", info.RawUrl.ToString()));
                }
            }
            catch (System.IO.IOException e)
            {
                var shortMsg = String.Format(L10NSharp.LocalizationManager.GetDynamicString("Bloom", "Errors.CannotAccessFile", "Cannot access {0}"), info.RawUrl);
                var longMsg  = String.Format("Bloom could not access {0}.  The file may be open in another program.", info.RawUrl);
                NonFatalProblem.Report(ModalIf.None, PassiveIf.All, shortMsg, longMsg, e);
                request.Failed(shortMsg);
                return(false);
            }
            catch (Exception e)
            {
                //Hard to reproduce, but I got one of these supertooltip disposal errors in a yellow box
                //while switching between publish tabs (e.g. /bloom/api/publish/android/cleanup).
                //I don't think these are worth alarming the user about, so let's be sensitive to what channel we're on.
                NonFatalProblem.Report(ModalIf.Alpha, PassiveIf.All, "Error in " + info.RawUrl, exception: e);
                request.Failed("Error in " + info.RawUrl);
                return(false);
            }
            return(true);
        }
 /// <summary>
 /// Called by the server to handle API calls for page thumbnails.
 /// </summary>
 public void HandleThumbnailRequest(ApiRequest request)
 {
     var filePath = request.LocalPath().Replace("api/pageTemplateThumbnail/","");
     var pathToExistingOrGeneratedThumbnail = FindOrGenerateThumbnail(filePath);
     if(string.IsNullOrEmpty(pathToExistingOrGeneratedThumbnail) || !File.Exists(pathToExistingOrGeneratedThumbnail))
     {
         request.Failed("Could not make a page thumbnail for "+filePath);
         return;
     }
     request.ReplyWithImage(pathToExistingOrGeneratedThumbnail);
 }
Example #3
0
        public void ProcessDirectoryWatcher(ApiRequest request)
        {
            // thread synchronization is done in the calling BloomApiHandler.
            var dirName = request.RequiredPostValue("dir");

            if (dirName == "Sample Texts")
            {
                CheckForSampleTextChanges(request);
            }
            else
            {
                request.Failed();
            }
        }
        private IPage GetPageTemplate(ApiRequest request)
        {
            var requestData = DynamicJson.Parse(request.RequiredPostJson());
            //var templateBookUrl = request.RequiredParam("templateBookUrl");
            var templateBookPath = HttpUtility.HtmlDecode(requestData.templateBookPath);
            var templateBook = _sourceCollectionsList.FindAndCreateTemplateBookByFullPath(templateBookPath);
            if(templateBook == null)
            {
                request.Failed("Could not find template book " + requestData.templateBookUrl);
                return null;
            }

            var pageDictionary = templateBook.GetTemplatePagesIdDictionary();
            IPage page = null;
            if(pageDictionary.TryGetValue(requestData.pageId, out page))
            {
                return page;
            }
            else
            {
                request.Failed("Could not find the page " + requestData.pageId + " in the template book " + requestData.templateBookUrl);
                return null;
            }
        }
Example #5
0
        /// <summary>
        /// Get a json of stats about the image. It is used to populate a tooltip when you hover over an image container
        /// </summary>
        private void HandleImageInfo(ApiRequest request)
        {
            try
            {
                var fileName = request.RequiredFileNameOrPath("image");
                Guard.AgainstNull(_bookSelection.CurrentSelection, "CurrentBook");
                var plainfilename = fileName.NotEncoded;
                // The fileName might be URL encoded.  See https://silbloom.myjetbrains.com/youtrack/issue/BL-3901.
                var path = UrlPathString.GetFullyDecodedPath(_bookSelection.CurrentSelection.FolderPath, ref plainfilename);
                RequireThat.File(path).Exists();
                var     fileInfo = new FileInfo(path);
                dynamic result   = new ExpandoObject();
                result.name  = plainfilename;
                result.bytes = fileInfo.Length;

                // Using a stream this way, according to one source,
                // http://stackoverflow.com/questions/552467/how-do-i-reliably-get-an-image-dimensions-in-net-without-loading-the-image,
                // supposedly avoids loading the image into memory when we only want its dimensions
                using (var stream = RobustFile.OpenRead(path))
                    using (var img = Image.FromStream(stream, false, false))
                    {
                        result.width  = img.Width;
                        result.height = img.Height;
                        switch (img.PixelFormat)
                        {
                        case PixelFormat.Format32bppArgb:
                        case PixelFormat.Format32bppRgb:
                        case PixelFormat.Format32bppPArgb:
                            result.bitDepth = "32";
                            break;

                        case PixelFormat.Format24bppRgb:
                            result.bitDepth = "24";
                            break;

                        case PixelFormat.Format16bppArgb1555:
                        case PixelFormat.Format16bppGrayScale:
                            result.bitDepth = "16";
                            break;

                        case PixelFormat.Format8bppIndexed:
                            result.bitDepth = "8";
                            break;

                        case PixelFormat.Format1bppIndexed:
                            result.bitDepth = "1";
                            break;

                        default:
                            result.bitDepth = "unknown";
                            break;
                        }
                    }
                request.ReplyWithJson((object)result);
            }
            catch (Exception e)
            {
                Logger.WriteEvent("Error in server imageInfo/: url was " + request.LocalPath());
                Logger.WriteEvent("Error in server imageInfo/: exception is " + e.Message);
                request.Failed(e.Message);
                NonFatalProblem.Report(ModalIf.None, PassiveIf.Alpha, "Request Error", request.LocalPath(), e);
            }
        }
Example #6
0
        public void HandleI18nRequest(ApiRequest request)
        {
            var lastSegment = request.LocalPath().Split(new char[] { '/' }).Last();

            switch (lastSegment)
            {
            case "loadStrings":
                var d    = new Dictionary <string, string>();
                var post = request.GetPostDataWhenFormEncoded();

                if (post != null)
                {
                    foreach (string key in post.Keys)
                    {
                        try
                        {
                            if (d.ContainsKey(key))
                            {
                                continue;
                            }

                            var translation = GetTranslationDefaultMayNotBeEnglish(key, post[key]);
                            d.Add(key, translation);
                        }
                        catch (Exception error)
                        {
                            Debug.Fail("Debug Only:" + error.Message + Environment.NewLine + "A bug reported at this location is BL-923");
                            //Until BL-923 is fixed (hard... it's a race condition, it's better to swallow this for users
                        }
                    }
                }
                request.ReplyWithJson(JsonConvert.SerializeObject(d));
                break;

            case "translate":
                var    parameters  = request.Parameters;
                string id          = parameters["key"];
                string englishText = parameters["englishText"];
                string langId      = parameters["langId"];
                langId = langId.Replace("V", request.CurrentCollectionSettings.Language1Iso639Code);
                langId = langId.Replace("N1", request.CurrentCollectionSettings.Language2Iso639Code);
                langId = langId.Replace("N2", request.CurrentCollectionSettings.Language3Iso639Code);
                langId = langId.Replace("UI", LocalizationManager.UILanguageId);
                string localizedString;
                if (GetSomeTranslation(id, langId, out localizedString))
                {
                    // Ensure that we actually have a value for localized string.  (This should already be true, but I'm paranoid.)
                    if (localizedString == null)
                    {
                        localizedString = englishText;
                    }
                    request.ReplyWithJson(new { text = localizedString, success = true });
                }
                else
                {
                    var idFound = true;
                    // Don't report missing strings if they are numbers
                    // Enhance: We might get the Javascript to do locale specific numbers someday
                    // The C# side doesn't currently have the smarts to do DigitSubstitution
                    // See Remark at https://msdn.microsoft.com/en-us/library/system.globalization.numberformatinfo.digitsubstitution(v=vs.110).aspx
                    if (IsInteger(id))
                    {
                        englishText = id;
                    }
                    else
                    {
                        // Now that end users can create templates, it's annoying to report that their names,
                        // page labels, and page descriptions don't have localizations.
                        if (IsTemplateBookKey(id))
                        {
                            englishText = englishText.Trim();
                        }
                        else
                        {
                            // it's ok if we don't have a translation, but if the string isn't even in the list of things that need translating,
                            // then we want to remind the developer to add it to the english xlf file.
                            if (!LocalizationManager.GetIsStringAvailableForLangId(id, "en"))
                            {
                                ReportL10NMissingString(id, englishText, UrlPathString.CreateFromUrlEncodedString(parameters["comment"] ?? "").NotEncoded);
                                idFound = false;
                            }
                            else
                            {
                                //ok, so we don't have it translated yet. Make sure it's at least listed in the things that can be translated.
                                // And return the English string, which is what we would do the next time anyway.  (BL-3374)
                                LocalizationManager.GetDynamicString("Bloom", id, englishText);
                            }
                        }
                    }
                    request.ReplyWithJson(new { text = englishText, success = idFound });
                }
                break;

            default:
                request.Failed();
                break;
            }
        }
Example #7
0
        public void HandleRequest(ApiRequest request)
        {
            if (CurrentBook == null)
            {
                Debug.Fail("BL-836 reproduction?");
                // ReSharper disable once HeuristicUnreachableCode
                request.Failed("CurrentBook is null");
                return;
            }
            if (request.CurrentCollectionSettings == null)
            {
                Debug.Fail("BL-836 reproduction?");
                // ReSharper disable once HeuristicUnreachableCode
                request.Failed("CurrentBook.CollectionSettings is null");
                return;
            }

            var lastSegment = request.LocalPath().Split(new char[] { '/' }).Last();

            switch (lastSegment)
            {
            case "test":
                request.Succeeded();
                break;

            case "readerToolSettings":
                if (request.HttpMethod == HttpMethods.Get)
                {
                    request.ReplyWithJson(GetReaderSettings(request.CurrentCollectionSettings));
                }
                else
                {
                    var path    = DecodableReaderTool.GetReaderToolsSettingsFilePath(request.CurrentCollectionSettings);
                    var content = request.RequiredPostJson();
                    RobustFile.WriteAllText(path, content, Encoding.UTF8);
                    request.Succeeded();
                }
                break;


            //note, this endpoint is confusing because it appears that ultimately we only use the word list out of this file (see "sampleTextsList").
            //This ends up being written to a ReaderToolsWords-xyz.json (matching its use, if not it contents).
            case "synphonyLanguageData":
                //This is the "post". There is no direct "get", but the name of the file is given in the "sampleTextList" reply, below:
                SaveSynphonyLanguageData(request.RequiredPostJson());
                request.Succeeded();
                break;

            case "sampleTextsList":
                //note, as part of this reply, we send the path of the "ReaderToolsWords-xyz.json" which is *written* by the "synphonyLanguageData" endpoint above
                request.ReplyWithText(GetSampleTextsList(request.CurrentCollectionSettings.SettingsFilePath));
                break;

            case "sampleFileContents":
                request.ReplyWithText(GetTextFileContents(request.RequiredParam("fileName"), WordFileType.SampleFile));
                break;

            case "textOfContentPages":
                request.ReplyWithText(GetTextOfContentPagesAsJson());
                break;

            case "makeLetterAndWordList":
                MakeLetterAndWordList(request.RequiredPostValue("settings"), request.RequiredPostValue("allWords"));
                request.Succeeded();
                break;

            case "openTextsFolder":
                OpenTextsFolder();
                request.Succeeded();
                break;

            case "chooseAllowedWordsListFile":
                lock (request)
                {
                    request.ReplyWithText(ShowSelectAllowedWordsFileDialog());
                }
                break;

            case "allowedWordsList":
                switch (request.HttpMethod)
                {
                case HttpMethods.Delete:
                    RecycleAllowedWordListFile(request.RequiredParam("fileName"));
                    request.Succeeded();
                    break;

                case HttpMethods.Get:
                    var fileName = request.RequiredParam("fileName");
                    request.ReplyWithText(RemoveEmptyAndDupes(GetTextFileContents(fileName, WordFileType.AllowedWordsFile)));
                    break;

                default:
                    request.Failed("Http verb not handled");
                    break;
                }
                break;

            default:
                request.Failed("Don't understand '" + lastSegment + "' in " + request.LocalPath());
                break;
            }
        }
Example #8
0
        public void HandleRequest(ApiRequest request)
        {
            if (CurrentBook == null)
            {
                Debug.Fail("BL-836 reproduction?");
                // ReSharper disable once HeuristicUnreachableCode
                request.Failed("CurrentBook is null");
                return;
            }
            if (request.CurrentCollectionSettings == null)
            {
                Debug.Fail("BL-836 reproduction?");
                // ReSharper disable once HeuristicUnreachableCode
                request.Failed("CurrentBook.CollectionSettings is null");
                return;
            }

            var lastSegment = request.LocalPath().Split(new char[] { '/' }).Last();

            switch (lastSegment)
            {
            case "test":
                request.PostSucceeded();
                break;

            case "readerToolSettings":
                if (request.HttpMethod == HttpMethods.Get)
                {
                    request.ReplyWithJson(GetReaderSettings(request.CurrentCollectionSettings));
                }
                else
                {
                    var path    = DecodableReaderToolSettings.GetReaderToolsSettingsFilePath(request.CurrentCollectionSettings);
                    var content = request.RequiredPostJson();
                    RobustFile.WriteAllText(path, content, Encoding.UTF8);
                    request.PostSucceeded();
                }
                break;


            //note, this endpoint is confusing because it appears that ultimately we only use the word list out of this file (see "sampleTextsList").
            //This ends up being written to a ReaderToolsWords-xyz.json (matching its use, if not it contents).
            case "synphonyLanguageData":
                //This is the "post". There is no direct "get", but the name of the file is given in the "sampleTextList" reply, below.
                // We've had situations (BL-4313 and friends) where reading the posted data fails. This seems to be due to situations
                // where we have a very large block of data and are rapidly switching between books. But as far as I can tell, the only
                // case where it's at all important to capture the new language data is if the user has been changing settings and
                // in particular editing the word list. Timing out the save in that situation seems very unlikely to fail.
                // So, in the interests of preventing the crash when switching books fast, we will ignore failure to read all the
                // json, and just not update the file. We would in any case keep only the version of the data sent to us by
                // the last book which sends it, and that one is unlikely to get interrupted.
                string langdata;
                try
                {
                    langdata = request.RequiredPostJson();
                }
                catch (IOException e)
                {
                    SIL.Reporting.Logger.WriteError("Saving synphonyLanguageData failed to get Json", e);
                    break;
                }

                SaveSynphonyLanguageData(langdata);
                request.PostSucceeded();
                break;

            case "sampleTextsList":
                //note, as part of this reply, we send the path of the "ReaderToolsWords-xyz.json" which is *written* by the "synphonyLanguageData" endpoint above
                request.ReplyWithText(GetSampleTextsList(request.CurrentCollectionSettings.SettingsFilePath));
                break;

            case "sampleFileContents":
                request.ReplyWithText(GetTextFileContents(request.RequiredParam("fileName"), WordFileType.SampleFile));
                break;

            case "textOfContentPages":
                request.ReplyWithText(GetTextOfContentPagesAsJson());
                break;

            case "makeLetterAndWordList":
                MakeLetterAndWordList(request.RequiredPostValue("settings"), request.RequiredPostValue("allWords"));
                request.PostSucceeded();
                break;

            case "openTextsFolder":
                OpenTextsFolder();
                request.PostSucceeded();
                break;

            case "chooseAllowedWordsListFile":
                lock (request)
                {
                    request.ReplyWithText(ShowSelectAllowedWordsFileDialog());
                }
                break;

            case "allowedWordsList":
                switch (request.HttpMethod)
                {
                case HttpMethods.Delete:
                    RecycleAllowedWordListFile(request.RequiredParam("fileName"));
                    request.PostSucceeded();
                    break;

                case HttpMethods.Get:
                    var fileName = request.RequiredParam("fileName");
                    request.ReplyWithText(RemoveEmptyAndDupes(GetTextFileContents(fileName, WordFileType.AllowedWordsFile)));
                    break;

                default:
                    request.Failed("Http verb not handled");
                    break;
                }
                break;

            case "defaultLevel":
                if (request.HttpMethod == HttpMethods.Get)
                {
                    request.ReplyWithText(Settings.Default.CurrentLevel.ToString());
                }
                else
                {
                    int level;
                    if (int.TryParse(request.RequiredParam("level"), out level))
                    {
                        Settings.Default.CurrentLevel = level;
                        Settings.Default.Save();
                    }
                    else
                    {
                        // Don't think any sort of runtime failure is worthwhile here.
                        Debug.Fail("could not parse level number");
                    }
                    request.PostSucceeded();                             // technically it didn't if we didn't parse the number
                }
                break;

            case "defaultStage":
                if (request.HttpMethod == HttpMethods.Get)
                {
                    request.ReplyWithText(Settings.Default.CurrentStage.ToString());
                }
                else
                {
                    int stage;
                    if (int.TryParse(request.RequiredParam("stage"), out stage))
                    {
                        Settings.Default.CurrentStage = stage;
                        Settings.Default.Save();
                    }
                    else
                    {
                        // Don't think any sort of runtime failure is worthwhile here.
                        Debug.Fail("could not parse stage number");
                    }
                    request.PostSucceeded();                             // technically it didn't if we didn't parse the number
                }
                break;

            default:
                request.Failed("Don't understand '" + lastSegment + "' in " + request.LocalPath());
                break;
            }
        }
Example #9
0
        public void HandleRequest(ApiRequest request)
        {
            if (CurrentBook == null)
            {
                Debug.Fail("BL-836 reproduction?");
                // ReSharper disable once HeuristicUnreachableCode
                request.Failed("CurrentBook is null");
                return;
            }
            if (request.CurrentCollectionSettings == null)
            {
                Debug.Fail("BL-836 reproduction?");
                // ReSharper disable once HeuristicUnreachableCode
                request.Failed("CurrentBook.CollectionSettings is null");
                return;
            }

            var lastSegment = request.LocalPath().Split(new char[] { '/' }).Last();

            switch (lastSegment)
            {
            case "test":
                request.PostSucceeded();
                break;

            case "readerSettingsEditForbidden":
                request.ReplyWithText(_tcManager.OkToEditCollectionSettings
                                                ? ""
                                                : WorkspaceView.MustBeAdminMessage);
                break;

            case "readerToolSettings":
                if (request.HttpMethod == HttpMethods.Get)
                {
                    request.ReplyWithJson(GetReaderSettings(request.CurrentBook.BookData));
                }
                else
                {
                    var path    = DecodableReaderToolSettings.GetReaderToolsSettingsFilePath(request.CurrentCollectionSettings);
                    var content = request.RequiredPostJson();
                    RobustFile.WriteAllText(path, content, Encoding.UTF8);
                    request.PostSucceeded();
                }
                break;


            //note, this endpoint is confusing because it appears that ultimately we only use the word list out of this file (see "sampleTextsList").
            //This ends up being written to a ReaderToolsWords-xyz.json (matching its use, if not it contents).
            case "synphonyLanguageData":
                //This is the "post". There is no direct "get", but the name of the file is given in the "sampleTextList" reply, below.
                // We've had situations (BL-4313 and friends) where reading the posted data fails. This seems to be due to situations
                // where we have a very large block of data and are rapidly switching between books. But as far as I can tell, the only
                // case where it's at all important to capture the new language data is if the user has been changing settings and
                // in particular editing the word list. Timing out the save in that situation seems very unlikely to fail.
                // So, in the interests of preventing the crash when switching books fast, we will ignore failure to read all the
                // json, and just not update the file. We would in any case keep only the version of the data sent to us by
                // the last book which sends it, and that one is unlikely to get interrupted.
                string langdata;
                try
                {
                    langdata = request.RequiredPostJson();
                }
                catch (IOException e)
                {
                    SIL.Reporting.Logger.WriteError("Saving synphonyLanguageData failed to get Json", e);
                    break;
                }

                SaveSynphonyLanguageData(langdata);
                request.PostSucceeded();
                break;

            case "sampleTextsList":
                //note, as part of this reply, we send the path of the "ReaderToolsWords-xyz.json" which is *written* by the "synphonyLanguageData" endpoint above
                request.ReplyWithText(GetSampleTextsList(request.CurrentCollectionSettings.SettingsFilePath));
                break;

            case "sampleFileContents":
                request.ReplyWithText(GetTextFileContents(request.RequiredParam("fileName"), WordFileType.SampleFile));
                break;

            case "textOfContentPages":
                request.ReplyWithText(GetTextOfContentPagesAsJson());
                break;

            case "makeLetterAndWordList":
                MakeLetterAndWordList(request.RequiredPostString("settings"), request.RequiredPostString("allWords"));
                request.PostSucceeded();
                break;

            case "openTextsFolder":
                OpenTextsFolder();
                request.PostSucceeded();
                break;

            case "chooseAllowedWordsListFile":
                lock (request)
                {
                    request.ReplyWithText(ShowSelectAllowedWordsFileDialog());
                }
                break;

            case "allowedWordsList":
                switch (request.HttpMethod)
                {
                case HttpMethods.Delete:
                    RecycleAllowedWordListFile(request.RequiredParam("fileName"));
                    request.PostSucceeded();
                    break;

                case HttpMethods.Get:
                    var fileName = request.RequiredParam("fileName");
                    request.ReplyWithText(RemoveEmptyAndDupes(GetTextFileContents(fileName, WordFileType.AllowedWordsFile)));
                    break;

                default:
                    request.Failed("Http verb not handled");
                    break;
                }
                break;

            case "defaultLevel":
                if (request.HttpMethod == HttpMethods.Get)
                {
                    request.ReplyWithText(Settings.Default.CurrentLevel.ToString());
                }
                else
                {
                    int level;
                    if (int.TryParse(request.RequiredParam("level"), out level))
                    {
                        Settings.Default.CurrentLevel = level;
                        Settings.Default.Save();
                    }
                    else
                    {
                        // Don't think any sort of runtime failure is worthwhile here.
                        Debug.Fail("could not parse level number");
                    }
                    request.PostSucceeded();                             // technically it didn't if we didn't parse the number
                }
                break;

            case "defaultStage":
                if (request.HttpMethod == HttpMethods.Get)
                {
                    request.ReplyWithText(Settings.Default.CurrentStage.ToString());
                }
                else
                {
                    int stage;
                    if (int.TryParse(request.RequiredParam("stage"), out stage))
                    {
                        Settings.Default.CurrentStage = stage;
                        Settings.Default.Save();
                    }
                    else
                    {
                        // Don't think any sort of runtime failure is worthwhile here.
                        Debug.Fail("could not parse stage number");
                    }
                    request.PostSucceeded();                             // technically it didn't if we didn't parse the number
                }
                break;

            case "copyBookStatsToClipboard":
                // See https://issues.bloomlibrary.org/youtrack/issue/BL-10018.
                string bookStatsString;
                try
                {
                    bookStatsString = request.RequiredPostJson();
                    dynamic bookStats  = DynamicJson.Parse(bookStatsString);
                    var     headerBldr = new StringBuilder();
                    var     dataBldr   = new StringBuilder();
                    headerBldr.Append("Book Title");
                    var title = _bookSelection.CurrentSelection.Title;
                    title = title.Replace("\"", "\"\"");                                // Double double quotes to get Excel to recognize them.
                    dataBldr.AppendFormat("\"{0}\"", title);
                    headerBldr.Append("\tLevel");
                    dataBldr.AppendFormat("\t\"Level {0}\"", bookStats["levelNumber"]);
                    headerBldr.Append("\tNumber of Pages with Text");
                    dataBldr.AppendFormat("\t{0}", bookStats["pageCount"]);
                    headerBldr.Append("\tTotal Number of Words");
                    dataBldr.AppendFormat("\t{0}", bookStats["actualWordCount"]);
                    headerBldr.Append("\tTotal Number of Sentences");
                    dataBldr.AppendFormat("\t{0}", bookStats["actualSentenceCount"]);
                    headerBldr.Append("\tAverage No of Words per Page with Text");
                    dataBldr.AppendFormat("\t{0:0.#}", bookStats["actualAverageWordsPerPage"]);
                    headerBldr.Append("\tAverage No of Sentences per Page with Text");
                    dataBldr.AppendFormat("\t{0:0.#}", bookStats["actualAverageSentencesPerPage"]);
                    headerBldr.Append("\tNumber of Unique Words");
                    dataBldr.AppendFormat("\t{0}", bookStats["actualUniqueWords"]);
                    headerBldr.Append("\tAverage Word Length");
                    dataBldr.AppendFormat("\t{0:0.#}", bookStats["actualAverageGlyphsPerWord"]);
                    headerBldr.Append("\tAverage Sentence Length");
                    dataBldr.AppendFormat("\t{0:0.#}", bookStats["actualAverageWordsPerSentence"]);
                    headerBldr.Append("\tMaximum Word Length");
                    dataBldr.AppendFormat("\t{0}", bookStats["actualMaxGlyphsPerWord"]);
                    headerBldr.Append("\tMaximum Sentence Length");
                    dataBldr.AppendFormat("\t{0}", bookStats["actualMaxWordsPerSentence"]);
                    // "actualWordsPerPageBook" is the maximum number of words on a page in the book
                    // It's in the json data, but not asked for in the clipboard copying.
                    var stringToSave = headerBldr.ToString() + Environment.NewLine + dataBldr.ToString();
                    PortableClipboard.SetText(stringToSave);
                }
                catch (IOException e)
                {
                    SIL.Reporting.Logger.WriteError("Copying book statistics to clipboard failed to get Json", e);
                    break;
                }
                request.PostSucceeded();
                break;

            default:
                request.Failed("Don't understand '" + lastSegment + "' in " + request.LocalPath());
                break;
            }
        }
Example #10
0
        private void HandleEndRecord(ApiRequest request)
        {
            #if __MonoCS__
            #else
            if (Recorder.RecordingState != RecordingState.Recording)
            {
                //usually, this is a result of us getting the "end" before we actually started, because it was too quick
                if(TestForTooShortAndSendFailIfSo(request))
                {
                    _startRecordingTimer.Enabled = false;//we don't want it firing in a few milliseconds from now
                    return;
                }

                //but this would handle it if there was some other reason
                request.Failed("Got endRecording, but was not recording");
                return;
            }
            try
            {
                Debug.WriteLine("Stop recording");
                Recorder.Stopped += Recorder_Stopped;
                //note, this doesn't actually stop... more like... starts the stopping. It does mark the time
                //we requested to stop. A few seconds later (2, looking at the library code today), it will
                //actually close the file and raise the Stopped event
                Recorder.Stop();
                request.Succeeded();
                //ReportSuccessfulRecordingAnalytics();
            }
            catch (Exception)
            {
                //swallow it. One reason (based on HearThis comment) is that they didn't hold it down long enough, we detect this below.
            }

            TestForTooShortAndSendFailIfSo(request);
            #endif
        }
Example #11
0
 // Does this page have any audio at all? Used to enable 'Listen to the whole page'.
 private void HandleEnableListenButton(ApiRequest request)
 {
     var ids = request.RequiredParam("ids");
     foreach (var id in ids.Split(','))
     {
         if (RobustFile.Exists(GetPathToSegment(id)))
         {
             request.Succeeded();
             return;
         }
     }
     request.Failed("no audio");
 }
Example #12
0
        /// <returns>true if the recording started successfully</returns>
        public void HandleStartRecording(ApiRequest request)
        {
            #if __MonoCS__
                        MessageBox.Show("Recording does not yet work on Linux", "Cannot record");
                        return;
            #else
            if(Recording)
            {
                request.Failed("Already recording");
                return;
            }

            string segmentId = request.RequiredParam("id");
            PathToCurrentAudioSegment = GetPathToSegment(segmentId);
            PathToTemporaryWav = Path.GetTempFileName();

            if (Recorder.RecordingState == RecordingState.RequestedStop)
            {
                request.Failed(LocalizationManager.GetString("EditTab.Toolbox.TalkingBook.BadState",
                    "Bloom recording is in an unusual state, possibly caused by unplugging a microphone. You will need to restart.","This is very low priority for translation."));
            }

            // If someone unplugged the microphone we were planning to use switch to another.
            // This also triggers selecting the first one initially.
            if (!RecordingDevice.Devices.Contains(RecordingDevice))
            {
                RecordingDevice = RecordingDevice.Devices.FirstOrDefault();
            }
            if (RecordingDevice == null)
            {
                ReportNoMicrophone();
                request.Failed("No Microphone");
                return ;
            }

            if(Recording)
            {
                request.Failed( "Already Recording");
                return;
            }

            if (RobustFile.Exists(PathToCurrentAudioSegment))
            {
                //Try to deal with _backPath getting locked (BL-3160)
                try
                {
                    RobustFile.Delete(_backupPath);
                }
                catch(IOException)
                {
                    _backupPath = System.IO.Path.GetTempFileName();
                }
                try
                {
                    RobustFile.Copy(PathToCurrentAudioSegment, _backupPath, true);
                }
                catch (Exception err)
                {
                    ErrorReport.NotifyUserOfProblem(err,
                        "Bloom cold not copy "+PathToCurrentAudioSegment+" to "+_backupPath+" If things remains stuck, you may need to restart your computer.");
                    request.Failed( "Problem with backup file");
                    return;
                }
                try
                {
                    RobustFile.Delete(PathToCurrentAudioSegment);
                    //DesktopAnalytics.Analytics.Track("Re-recorded a clip", ContextForAnalytics);
                }
                catch (Exception err)
                {
                    ErrorReport.NotifyUserOfProblem(err,
                        "The old copy of the recording at " + PathToCurrentAudioSegment + " is locked up, so Bloom can't record over it at the moment. If it remains stuck, you may need to restart your computer.");
                    request.Failed( "Audio file locked");
                    return;
                }
            }
            else
            {
                RobustFile.Delete(_backupPath);
                //DesktopAnalytics.Analytics.Track("Recording clip", ContextForAnalytics);
            }
            _startRecording = DateTime.Now;
            _startRecordingTimer.Start();
            request.ReplyWithText("starting record soon");
            return;
            #endif
        }
Example #13
0
 public void HandleCurrentRecordingDevice(ApiRequest request)
 {
     #if __MonoCS__
     #else
     if(request.HttpMethod == HttpMethods.Post)
     {
         var name = request.RequiredPostString();
         foreach (var dev in RecordingDevice.Devices)
         {
             if(dev.ProductName == name)
             {
                 RecordingDevice = dev;
                 request.Succeeded();
                 return;
             }
         }
         request.Failed("Could not find the device named " + name);
     }
     else request.Failed("Only Post is currently supported");
     #endif
 }
Example #14
0
        /// <summary>
        /// Returns a json string like {"devices":["microphone", "Logitech Headset"], "productName":"Logitech Headset", "genericName":"Headset"},
        /// except that in practice currrently the generic and product names are the same and not as helpful as the above.
        /// Devices is a list of product names (of available recording devices), the productName and genericName refer to the
        /// current selection (or will be null, if no current device).
        /// </summary>
        public void HandleAudioDevices(ApiRequest request)
        {
            #if __MonoCS__
            request.Failed("Not supported on Linux");
            #else
            var sb = new StringBuilder("{\"devices\":[");
            sb.Append(string.Join(",", RecordingDevice.Devices.Select(d => "\""+d.ProductName+"\"")));
            sb.Append("],\"productName\":");
            if (CurrentRecording.RecordingDevice != null)
                sb.Append("\"" + CurrentRecording.RecordingDevice.ProductName + "\"");
            else
                sb.Append("null");

            sb.Append(",\"genericName\":");
            if (CurrentRecording.RecordingDevice != null)
                sb.Append("\"" + CurrentRecording.RecordingDevice.GenericName + "\"");
            else
                sb.Append("null");

            sb.Append("}");
            request.ReplyWithJson(sb.ToString());
            #endif
        }
Example #15
0
        /// <summary>
        /// Get a json of stats about the image. It is used to populate a tooltip when you hover over an image container
        /// </summary>
        private void HandleImageInfo(ApiRequest request)
        {
            try
            {
                var fileName = request.RequiredParam("image");
                Guard.AgainstNull(_bookSelection.CurrentSelection, "CurrentBook");
                var path = Path.Combine(_bookSelection.CurrentSelection.FolderPath, fileName);
                if (!File.Exists(path))
                {
                    // We can be fed doubly-encoded filenames.  So try to decode a second time and see if that works.
                    // See https://silbloom.myjetbrains.com/youtrack/issue/BL-3749.
                    fileName = System.Web.HttpUtility.UrlDecode(fileName);
                    path = Path.Combine(_bookSelection.CurrentSelection.FolderPath, fileName);
                }
                RequireThat.File(path).Exists();
                var fileInfo = new FileInfo(path);
                dynamic result = new ExpandoObject();
                result.name = fileName;
                result.bytes = fileInfo.Length;

                // Using a stream this way, according to one source,
                // http://stackoverflow.com/questions/552467/how-do-i-reliably-get-an-image-dimensions-in-net-without-loading-the-image,
                // supposedly avoids loading the image into memory when we only want its dimensions
                using (var stream = File.OpenRead(path))
                using (var img = Image.FromStream(stream, false, false))
                {
                    result.width = img.Width;
                    result.height = img.Height;
                    switch (img.PixelFormat)
                    {
                        case PixelFormat.Format32bppArgb:
                        case PixelFormat.Format32bppRgb:
                        case PixelFormat.Format32bppPArgb:
                            result.bitDepth = "32";
                            break;
                        case PixelFormat.Format24bppRgb:
                            result.bitDepth = "24";
                            break;
                        case PixelFormat.Format16bppArgb1555:
                        case PixelFormat.Format16bppGrayScale:
                            result.bitDepth = "16";
                            break;
                        case PixelFormat.Format8bppIndexed:
                            result.bitDepth = "8";
                            break;
                        case PixelFormat.Format1bppIndexed:
                            result.bitDepth = "1";
                            break;
                        default:
                            result.bitDepth = "unknown";
                            break;
                    }
                }
                request.ReplyWithJson((object)result);
            }
            catch (Exception e)
            {
                Logger.WriteEvent("Error in server imageInfo/: url was " + request.LocalPath());
                Logger.WriteEvent("Error in server imageInfo/: exception is " + e.Message);
                request.Failed(e.Message);
            }
        }
        /// <summary>
        /// Get a json of stats about the image. It is used to populate a tooltip when you hover over an image container
        /// </summary>
        private void HandleImageInfo(ApiRequest request)
        {
            try
            {
                var fileName = request.RequiredFileNameOrPath("image");
                Guard.AgainstNull(_bookSelection.CurrentSelection, "CurrentBook");
                var plainfilename = fileName.NotEncoded;
                // The fileName might be URL encoded.  See https://silbloom.myjetbrains.com/youtrack/issue/BL-3901.
                var path = UrlPathString.GetFullyDecodedPath(_bookSelection.CurrentSelection.FolderPath, ref plainfilename);
                RequireThat.File(path).Exists();
                var fileInfo = new FileInfo(path);
                dynamic result = new ExpandoObject();
                result.name = plainfilename;
                result.bytes = fileInfo.Length;

                // Using a stream this way, according to one source,
                // http://stackoverflow.com/questions/552467/how-do-i-reliably-get-an-image-dimensions-in-net-without-loading-the-image,
                // supposedly avoids loading the image into memory when we only want its dimensions
                using(var stream = RobustFile.OpenRead(path))
                using(var img = Image.FromStream(stream, false, false))
                {
                    result.width = img.Width;
                    result.height = img.Height;
                    switch(img.PixelFormat)
                    {
                        case PixelFormat.Format32bppArgb:
                        case PixelFormat.Format32bppRgb:
                        case PixelFormat.Format32bppPArgb:
                            result.bitDepth = "32";
                            break;
                        case PixelFormat.Format24bppRgb:
                            result.bitDepth = "24";
                            break;
                        case PixelFormat.Format16bppArgb1555:
                        case PixelFormat.Format16bppGrayScale:
                            result.bitDepth = "16";
                            break;
                        case PixelFormat.Format8bppIndexed:
                            result.bitDepth = "8";
                            break;
                        case PixelFormat.Format1bppIndexed:
                            result.bitDepth = "1";
                            break;
                        default:
                            result.bitDepth = "unknown";
                            break;
                    }
                }
                request.ReplyWithJson((object) result);
            }
            catch(Exception e)
            {
                Logger.WriteEvent("Error in server imageInfo/: url was " + request.LocalPath());
                Logger.WriteEvent("Error in server imageInfo/: exception is " + e.Message);
                request.Failed(e.Message);
                NonFatalProblem.Report(ModalIf.None, PassiveIf.Alpha, "Request Error", request.LocalPath(), e);
            }
        }
Example #17
0
 private bool TestForTooShortAndSendFailIfSo(ApiRequest request)
 {
     if ((DateTime.Now - _startRecording) < TimeSpan.FromSeconds(0.5))
     {
         CleanUpAfterPressTooShort();
         var msg = LocalizationManager.GetString("EditTab.Toolbox.TalkingBook.PleaseHoldMessage",
             "Please hold the button down until you have finished recording",
             "Appears when the speak/record button is pressed very briefly");
         request.Failed(msg);
         return true;
     }
     return false;
 }