Example #1
0
        public void Start(Book.Book book, CollectionSettings collectionSettings, Color backColor)
        {
            if (_wifiAdvertiser != null)
            {
                Stop();
            }

            // This listens for a BloomReader to request a book.
            // It requires a firewall hole allowing Bloom to receive messages on _portToListen.
            // We initialize it before starting the Advertiser to avoid any chance of a race condition
            // where a BloomReader manages to request an advertised book before we start the listener.
            _wifiListener = new BloomReaderUDPListener();
            _wifiListener.NewMessageReceived += (sender, args) =>
            {
                var json = Encoding.UTF8.GetString(args.Data);
                try
                {
                    dynamic settings = JsonConvert.DeserializeObject(json);
                    // The property names used here must match the ones in BloomReader, doInBackground method of SendMessage,
                    // a private class of NewBookListenerService.
                    var androidIpAddress = (string)settings.deviceAddress;

                    var androidName = (string)settings.deviceName;
                    // This prevents the device (or other devices) from queuing up requests while we're busy with this one.
                    // In effect, the Android is only allowed to request a retry after we've given up this try at sending.
                    // Of course, there are async effects from network latency. But if we do get another request while
                    // handling this one, we will ignore it, since StartSendBook checks for a transfer in progress.
                    _wifiAdvertiser.Paused = true;
                    StartSendBookOverWiFi(book, androidIpAddress, androidName, backColor);
                    // Returns immediately. But we don't resume advertisements until the async send completes.
                }
                // If there's something wrong with the JSON (maybe an obsolete or newer version of reader?)
                // just ignore the request.
                catch (Exception ex) when(ex is JsonReaderException || ex is JsonSerializationException)
                {
                    _progress.Error(id: "BadBookRequest",
                                    message: "Got a book request we could not process. Possibly the device is running an incompatible version of BloomReader?");

                    //this is too technical/hard to translate
                    _progress.ErrorWithoutLocalizing($" Request contains {json}; trying to interpret as JSON we got {ex.Message}");
                }
            };

            var pathHtmlFile = book.GetPathHtmlFile();

            _wifiAdvertiser = new WiFiAdvertiser(_progress)
            {
                BookTitle     = BookStorage.SanitizeNameForFileSystem(book.Title),             // must be the exact same name as the file we will send if requested
                TitleLanguage = collectionSettings.Language1Iso639Code,
                BookVersion   = Book.Book.MakeVersionCode(File.ReadAllText(pathHtmlFile), pathHtmlFile)
            };

            AndroidView.CheckBookLayout(book, _progress);
            _wifiAdvertiser.Start();

            _progress.Message(id: "WifiInstructions1",
                              message: "On the Android, run Bloom Reader, open the menu and choose 'Receive Books from computer'.");
            _progress.Message(id: "WifiInstructions2",
                              message: "You can do this on as many devices as you like. Make sure each device is connected to the same network as this computer.");
        }
Example #2
0
 public void Stop()
 {
     // Locked to avoid contention with code in the thread that reports a transfer complete,
     // which disposes of _wifiSender and tries to restart the advertiser.
     lock (this)
     {
         if (_wifiAdvertiser != null)
         {
             _wifiAdvertiser.Stop();
             _wifiAdvertiser.Dispose();
             _wifiAdvertiser = null;
         }
         if (_wifiSender != null)
         {
             _wifiSender.CancelAsync();
             Debug.WriteLine("attempting async cancel send");
         }
         if (_uploadTimer != null)
         {
             _uploadTimer.Stop();
             _uploadTimer.Dispose();
             _uploadTimer = null;
         }
     }
     // To avoid leaving a thread around when quitting, try to wait for the sender to cancel or complete.
     // We expect another thread to set _wifiSender to null in the UploadDataCompleted event
     // (which is supposed to be triggered also by canceling).
     for (int i = 0; i < 30 && _wifiSender != null; i++)
     {
         Thread.Sleep(100);
     }
     lock (this)
     {
         if (_wifiSender != null)
         {
             // If it's still null we give up on the Cancel and try to shut it down any way we can.
             // Note that if the cancelAsync didn't work, as it generally seems not to, this could
             // cancel a file transfer rather abruptly. But the alternative is to leave the thread
             // running, possibly after Bloom has otherwise exited, causing problems like BL-5272.
             // (In practice even aborting this thread doesn't seem to force the file transfer to
             // stop, nor does anything else I've tried, so we just do our best to make sure
             // the thread won't outlive the application by much. Not allowing requests to queue
             // up is one thing that helps. At worst there's only one in progress that either
             // finishes or aborts before too long.)
             _wifiSender.Dispose();
             _wifiSender = null;
             Debug.WriteLine("had to force dispose sender");
         }
     }
     if (_wifiListener != null)
     {
         {
             _wifiListener.StopListener();
             _wifiListener = null;
         }
     }
 }