add an alert while a locally initiated pairing request is in progress
Has a button to cancel the request.
This commit is contained in:
parent
ded8517545
commit
16cefae7f2
5 changed files with 65 additions and 21 deletions
|
@ -32,7 +32,7 @@ data AlertName
|
|||
= FileAlert TenseChunk
|
||||
| SanityCheckFixAlert
|
||||
| WarningAlert String
|
||||
| PairRequestAlert String
|
||||
| PairRequestReceivedAlert String
|
||||
deriving (Eq)
|
||||
|
||||
{- The first alert is the new alert, the second is an old alert.
|
||||
|
@ -148,6 +148,7 @@ makeAlertFiller success alert
|
|||
{ alertClass = if c == Activity then c' else c
|
||||
, alertPriority = Filler
|
||||
, alertClosable = True
|
||||
, alertButton = Nothing
|
||||
, alertIcon = Just $ if success then SuccessIcon else ErrorIcon
|
||||
}
|
||||
where
|
||||
|
@ -285,8 +286,15 @@ sanityCheckFixAlert msg = Alert
|
|||
alerthead = "The daily sanity check found and fixed a problem:"
|
||||
alertfoot = "If these problems persist, consider filing a bug report."
|
||||
|
||||
pairRequestAlert :: String -> String -> AlertButton -> Alert
|
||||
pairRequestAlert repo msg button = Alert
|
||||
pairRequestAlert :: AlertButton -> Alert
|
||||
pairRequestAlert button = baseActivityAlert
|
||||
{ alertData = [ UnTensed "Pairing request in progress" ]
|
||||
, alertPriority = High
|
||||
, alertButton = Just button
|
||||
}
|
||||
|
||||
pairRequestReceivedAlert :: String -> String -> AlertButton -> Alert
|
||||
pairRequestReceivedAlert repo msg button = Alert
|
||||
{ alertClass = Message
|
||||
, alertHeader = Nothing
|
||||
, alertMessageRender = tenseWords
|
||||
|
@ -295,7 +303,7 @@ pairRequestAlert repo msg button = Alert
|
|||
, alertPriority = High
|
||||
, alertClosable = True
|
||||
, alertIcon = Just InfoIcon
|
||||
, alertName = Just $ PairRequestAlert repo
|
||||
, alertName = Just $ PairRequestReceivedAlert repo
|
||||
, alertCombiner = Just $ dataCombiner $ const id
|
||||
, alertButton = Just button
|
||||
}
|
||||
|
|
|
@ -41,8 +41,8 @@ data DaemonStatus = DaemonStatus
|
|||
, lastAlertId :: AlertId
|
||||
-- Ordered list of remotes to talk to.
|
||||
, knownRemotes :: [Remote]
|
||||
-- Pairing requests that are in progress.
|
||||
, pairingInProgress :: [PairingInProgress]
|
||||
-- Pairing request that is in progress.
|
||||
, pairingInProgress :: Maybe PairingInProgress
|
||||
-- Broadcasts notifications about all changes to the DaemonStatus
|
||||
, changeNotifier :: NotificationBroadcaster
|
||||
-- Broadcasts notifications when queued or current transfers change.
|
||||
|
@ -66,7 +66,7 @@ newDaemonStatus = DaemonStatus
|
|||
<*> pure M.empty
|
||||
<*> pure firstAlertId
|
||||
<*> pure []
|
||||
<*> pure []
|
||||
<*> pure Nothing
|
||||
<*> newNotificationBroadcaster
|
||||
<*> newNotificationBroadcaster
|
||||
<*> newNotificationBroadcaster
|
||||
|
@ -260,3 +260,10 @@ alertWhile' dstatus alert a = do
|
|||
(ok, r) <- a
|
||||
updateAlertMap dstatus $ mergeAlert i $ makeAlertFiller ok alert'
|
||||
return r
|
||||
|
||||
{- Displays an alert while performing an activity, then removes it. -}
|
||||
alertDuring :: DaemonStatusHandle -> Alert -> IO a -> IO a
|
||||
alertDuring dstatus alert a = do
|
||||
let alert' = alert { alertClass = Activity }
|
||||
i <- addAlert dstatus alert'
|
||||
removeAlert dstatus i `after` a
|
||||
|
|
|
@ -14,7 +14,6 @@ import Utility.ThreadScheduler
|
|||
import Network.Multicast
|
||||
import Network.Info
|
||||
import Network.Socket
|
||||
import Control.Concurrent
|
||||
import Control.Exception (bracket)
|
||||
import qualified Data.Map as M
|
||||
|
||||
|
@ -31,8 +30,8 @@ multicastAddress :: SomeAddr -> HostName
|
|||
multicastAddress (IPv4Addr _) = "224.0.0.1"
|
||||
multicastAddress (IPv6Addr _) = "ff02::1"
|
||||
|
||||
{- Multicasts a message repeatedly on all interfaces until its thread
|
||||
- is killed, with a 2 second delay between each transmission.
|
||||
{- Multicasts a message repeatedly on all interfaces forever,
|
||||
- with a 2 second delay between each transmission.
|
||||
-
|
||||
- The remoteHostAddress is set to the interface's IP address.
|
||||
-
|
||||
|
@ -40,8 +39,8 @@ multicastAddress (IPv6Addr _) = "ff02::1"
|
|||
- but it allows new network interfaces to be used as they come up.
|
||||
- On the other hand, the expensive DNS lookups are cached.
|
||||
-}
|
||||
multicastPairMsg :: (SomeAddr -> PairMsg) -> IO ThreadId
|
||||
multicastPairMsg mkmsg = forkIO $ go M.empty
|
||||
multicastPairMsg :: (SomeAddr -> PairMsg) -> IO ()
|
||||
multicastPairMsg mkmsg = go M.empty
|
||||
where
|
||||
go cache = do
|
||||
addrs <- activeNetworkAddresses
|
||||
|
|
|
@ -56,7 +56,7 @@ pairListenerThread st dstatus urlrenderer = thread $ withSocketsDo $ do
|
|||
pairReqAlert :: DaemonStatusHandle -> UrlRenderer -> PairMsg -> IO ()
|
||||
pairReqAlert dstatus urlrenderer msg = unlessM myreq $ do
|
||||
url <- renderUrl urlrenderer (FinishPairR msg) []
|
||||
void $ addAlert dstatus $ pairRequestAlert repo
|
||||
void $ addAlert dstatus $ pairRequestReceivedAlert repo
|
||||
(repo ++ " is sending a pair request.") $
|
||||
AlertButton
|
||||
{ buttonUrl = url
|
||||
|
@ -74,16 +74,18 @@ pairReqAlert dstatus urlrenderer msg = unlessM myreq $ do
|
|||
, ":"
|
||||
, (remoteDirectory pairdata)
|
||||
]
|
||||
{- Filter out our own pair requests, by checking if we
|
||||
- can verify using the secrets of any of them. -}
|
||||
myreq = any (verified v . inProgressSecret) . pairingInProgress
|
||||
<$> getDaemonStatus dstatus
|
||||
{- Filter out our own pair request, by checking if we
|
||||
- can verify using its secret. -}
|
||||
myreq = maybe False (verified v . inProgressSecret)
|
||||
. pairingInProgress
|
||||
<$> getDaemonStatus dstatus
|
||||
{- Remove the button when it's clicked, and change the
|
||||
- alert to be in progress. This alert cannot be entirely
|
||||
- removed since more pair request messages are coming in
|
||||
- and would re-add it. -}
|
||||
onclick i = updateAlert dstatus i $ \alert -> Just $ alert
|
||||
{ alertButton = Nothing
|
||||
, alertClass = Activity
|
||||
, alertIcon = Just ActivityIcon
|
||||
, alertData = [UnTensed $ T.pack $ "pair request with " ++ repo ++ " in progress"]
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import Assistant.Pairing
|
|||
#ifdef WITH_PAIRING
|
||||
import Assistant.Pairing.Network
|
||||
import Assistant.Common
|
||||
import Assistant.Alert
|
||||
import Assistant.DaemonStatus
|
||||
import Utility.Verifiable
|
||||
import Utility.Network
|
||||
|
@ -49,22 +50,49 @@ import qualified Data.Text.Encoding as T
|
|||
import qualified Data.ByteString.Lazy as B
|
||||
import Data.Char
|
||||
import System.Posix.User
|
||||
import qualified Control.Exception as E
|
||||
import Control.Concurrent
|
||||
#endif
|
||||
|
||||
getStartPairR :: Handler RepHtml
|
||||
#ifdef WITH_PAIRING
|
||||
getStartPairR = promptSecret Nothing $ \rawsecret secret -> do
|
||||
dstatus <- daemonStatus <$> lift getYesod
|
||||
urlrender <- lift getUrlRender
|
||||
let homeurl = urlrender HomeR
|
||||
hostname <- liftIO $ getHostname
|
||||
username <- liftIO $ getUserName
|
||||
reldir <- fromJust . relDir <$> lift getYesod
|
||||
let sshkey = "" -- TODO generate/read ssh key
|
||||
let mkmsg addr = PairMsg $ mkVerifiable
|
||||
(PairReq, PairData hostname addr username reldir sshkey) secret
|
||||
pip <- liftIO $ PairingInProgress secret <$> multicastPairMsg mkmsg
|
||||
dstatus <- daemonStatus <$> lift getYesod
|
||||
liftIO $ modifyDaemonStatus_ dstatus $
|
||||
\s -> s { pairingInProgress = pip : pairingInProgress s }
|
||||
liftIO $ do
|
||||
pip <- PairingInProgress secret
|
||||
<$> sendrequests mkmsg dstatus homeurl
|
||||
oldpip <- modifyDaemonStatus dstatus $
|
||||
\s -> (s { pairingInProgress = Just pip }, pairingInProgress s)
|
||||
maybe noop stopold oldpip
|
||||
lift $ redirect $ InprogressPairR rawsecret
|
||||
where
|
||||
{- Sends pairing messages until the thread is killed,
|
||||
- and shows an activity alert while doing it.
|
||||
-
|
||||
- The button returns the user to the HomeR. This is
|
||||
- not ideal, but they have to be sent somewhere, and could
|
||||
- have been on a page specific to the in-process pairing
|
||||
- that just stopped.
|
||||
-}
|
||||
sendrequests mkmsg dstatus homeurl = forkIO $ do
|
||||
tid <- myThreadId
|
||||
let selfdestruct = AlertButton
|
||||
{ buttonLabel = "Cancel"
|
||||
, buttonUrl = homeurl
|
||||
, buttonAction = Just $ const $ killThread tid
|
||||
}
|
||||
alertDuring dstatus (pairRequestAlert selfdestruct) $ do
|
||||
_ <- E.try (multicastPairMsg mkmsg) :: IO (Either E.SomeException ())
|
||||
return ()
|
||||
stopold = killThread . inProgressThreadId
|
||||
#else
|
||||
getStartPairR = noPairing
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue