add buddy list to pairing UI
This commit is contained in:
parent
2ae43e71e0
commit
6a61829e2d
18 changed files with 252 additions and 84 deletions
|
@ -103,7 +103,7 @@ pairListenerThread urlrenderer = NamedThread "PairListener" $ do
|
||||||
pairReqReceived :: Bool -> UrlRenderer -> PairMsg -> Assistant ()
|
pairReqReceived :: Bool -> UrlRenderer -> PairMsg -> Assistant ()
|
||||||
pairReqReceived True _ _ = noop -- ignore our own PairReq
|
pairReqReceived True _ _ = noop -- ignore our own PairReq
|
||||||
pairReqReceived False urlrenderer msg = do
|
pairReqReceived False urlrenderer msg = do
|
||||||
url <- liftIO $ renderUrl urlrenderer (FinishPairR msg) []
|
url <- liftIO $ renderUrl urlrenderer (FinishLocalPairR msg) []
|
||||||
close <- asIO1 removeAlert
|
close <- asIO1 removeAlert
|
||||||
void $ addAlert $ pairRequestReceivedAlert repo
|
void $ addAlert $ pairRequestReceivedAlert repo
|
||||||
AlertButton
|
AlertButton
|
||||||
|
|
|
@ -14,16 +14,37 @@ import Common.Annex
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
import Control.Concurrent.STM
|
import Control.Concurrent.STM
|
||||||
import Utility.NotificationBroadcaster
|
import Utility.NotificationBroadcaster
|
||||||
|
import Data.Text as T
|
||||||
|
|
||||||
{- When XMPP is enabled, this is an XMPP buddy map.
|
{- For simplicity, dummy types are defined even when XMPP is disabled. -}
|
||||||
- Otherwise, it's an empty map, for simplicity. -}
|
|
||||||
#ifdef WITH_XMPP
|
#ifdef WITH_XMPP
|
||||||
import Assistant.XMPP.Buddies
|
import Network.Protocol.XMPP
|
||||||
|
import Data.Set as S
|
||||||
|
import Data.Ord
|
||||||
|
|
||||||
|
newtype Client = Client JID
|
||||||
|
deriving (Eq, Show)
|
||||||
|
|
||||||
|
instance Ord Client where
|
||||||
|
compare = comparing show
|
||||||
|
|
||||||
|
data Buddy = Buddy
|
||||||
|
{ buddyPresent :: S.Set Client
|
||||||
|
, buddyAway :: S.Set Client
|
||||||
|
, buddyAssistants :: S.Set Client
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
type Buddies = M.Map String Buddy
|
|
||||||
data Buddy
|
data Buddy
|
||||||
deriving (Eq)
|
|
||||||
#endif
|
#endif
|
||||||
|
deriving (Eq, Show)
|
||||||
|
|
||||||
|
data BuddyID = BuddyID T.Text
|
||||||
|
deriving (Eq, Ord, Show, Read)
|
||||||
|
|
||||||
|
data BuddyKey = BuddyKey T.Text
|
||||||
|
deriving (Eq, Ord, Show)
|
||||||
|
|
||||||
|
type Buddies = M.Map BuddyKey Buddy
|
||||||
|
|
||||||
{- A list of buddies, and a way to notify when it changes. -}
|
{- A list of buddies, and a way to notify when it changes. -}
|
||||||
type BuddyList = (TMVar Buddies, NotificationBroadcaster)
|
type BuddyList = (TMVar Buddies, NotificationBroadcaster)
|
||||||
|
@ -39,6 +60,9 @@ newBuddyList = (,)
|
||||||
getBuddyList :: BuddyList -> IO [Buddy]
|
getBuddyList :: BuddyList -> IO [Buddy]
|
||||||
getBuddyList (v, _) = M.elems <$> atomically (readTMVar v)
|
getBuddyList (v, _) = M.elems <$> atomically (readTMVar v)
|
||||||
|
|
||||||
|
getBuddyBroadcaster :: BuddyList -> NotificationBroadcaster
|
||||||
|
getBuddyBroadcaster (_, h) = h
|
||||||
|
|
||||||
{- Applies a function to modify the buddy list, and if it's changed,
|
{- Applies a function to modify the buddy list, and if it's changed,
|
||||||
- sends notifications to any listeners. -}
|
- sends notifications to any listeners. -}
|
||||||
updateBuddyList :: (Buddies -> Buddies) -> BuddyList -> IO ()
|
updateBuddyList :: (Buddies -> Buddies) -> BuddyList -> IO ()
|
||||||
|
@ -50,8 +74,3 @@ updateBuddyList a (v, caster) = do
|
||||||
return $ buds /= buds'
|
return $ buds /= buds'
|
||||||
when changed $
|
when changed $
|
||||||
sendNotification caster
|
sendNotification caster
|
||||||
|
|
||||||
{- Allocates a notification handle for a client to use to listen for
|
|
||||||
- changes to the buddy list. -}
|
|
||||||
newBuddyListNotificationHandle :: BuddyList -> IO NotificationHandle
|
|
||||||
newBuddyListNotificationHandle (_, caster) = newNotificationHandle caster
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ module Assistant.WebApp where
|
||||||
|
|
||||||
import Assistant.WebApp.Types
|
import Assistant.WebApp.Types
|
||||||
import Assistant.Common
|
import Assistant.Common
|
||||||
import Assistant.DaemonStatus
|
|
||||||
import Utility.NotificationBroadcaster
|
import Utility.NotificationBroadcaster
|
||||||
import Utility.Yesod
|
import Utility.Yesod
|
||||||
import Locations.UserConfig
|
import Locations.UserConfig
|
||||||
|
@ -95,18 +94,15 @@ runAnnex fallback a = ifM (noAnnex <$> getYesod)
|
||||||
, liftAssistant $ liftAnnex a
|
, liftAssistant $ liftAnnex a
|
||||||
)
|
)
|
||||||
|
|
||||||
waitNotifier :: forall sub. (DaemonStatus -> NotificationBroadcaster) -> NotificationId -> GHandler sub WebApp ()
|
waitNotifier :: forall sub. (Assistant NotificationBroadcaster) -> NotificationId -> GHandler sub WebApp ()
|
||||||
waitNotifier selector nid = do
|
waitNotifier getbroadcaster nid = liftAssistant $ do
|
||||||
notifier <- getNotifier selector
|
b <- getbroadcaster
|
||||||
liftIO $ waitNotification $ notificationHandleFromId notifier nid
|
liftIO $ waitNotification $ notificationHandleFromId b nid
|
||||||
|
|
||||||
newNotifier :: forall sub. (DaemonStatus -> NotificationBroadcaster) -> GHandler sub WebApp NotificationId
|
newNotifier :: forall sub. (Assistant NotificationBroadcaster) -> GHandler sub WebApp NotificationId
|
||||||
newNotifier selector = do
|
newNotifier getbroadcaster = liftAssistant $ do
|
||||||
notifier <- getNotifier selector
|
b <- getbroadcaster
|
||||||
liftIO $ notificationHandleToId <$> newNotificationHandle notifier
|
liftIO $ notificationHandleToId <$> newNotificationHandle b
|
||||||
|
|
||||||
getNotifier :: forall sub. (DaemonStatus -> NotificationBroadcaster) -> GHandler sub WebApp NotificationBroadcaster
|
|
||||||
getNotifier selector = selector <$> liftAssistant getDaemonStatus
|
|
||||||
|
|
||||||
{- Adds the auth parameter as a hidden field on a form. Must be put into
|
{- Adds the auth parameter as a hidden field on a form. Must be put into
|
||||||
- every form. -}
|
- every form. -}
|
||||||
|
|
|
@ -14,6 +14,8 @@ import Assistant.Pairing
|
||||||
import Assistant.WebApp
|
import Assistant.WebApp
|
||||||
import Assistant.WebApp.Types
|
import Assistant.WebApp.Types
|
||||||
import Assistant.WebApp.SideBar
|
import Assistant.WebApp.SideBar
|
||||||
|
import Assistant.WebApp.Configurators.XMPP
|
||||||
|
import Assistant.Types.Buddies
|
||||||
import Utility.Yesod
|
import Utility.Yesod
|
||||||
#ifdef WITH_PAIRING
|
#ifdef WITH_PAIRING
|
||||||
import Assistant.Common
|
import Assistant.Common
|
||||||
|
@ -26,6 +28,10 @@ import Utility.Verifiable
|
||||||
import Utility.Network
|
import Utility.Network
|
||||||
import Annex.UUID
|
import Annex.UUID
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef WITH_XMPP
|
||||||
|
import Assistant.XMPP.Client
|
||||||
|
import Network.Protocol.XMPP
|
||||||
|
#endif
|
||||||
import Utility.UserInfo
|
import Utility.UserInfo
|
||||||
|
|
||||||
import Yesod
|
import Yesod
|
||||||
|
@ -39,22 +45,55 @@ import qualified Control.Exception as E
|
||||||
import Control.Concurrent
|
import Control.Concurrent
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{- Starts sending out pair requests. -}
|
{- Starts either kind of pairing. -}
|
||||||
getStartPairR :: Handler RepHtml
|
getStartPairR :: Handler RepHtml
|
||||||
|
#ifdef WITH_XMPP
|
||||||
|
getStartPairR = pairPage $ do
|
||||||
|
xmppconfigured <- lift $ isJust <$> runAnnex Nothing getXMPPCreds
|
||||||
#ifdef WITH_PAIRING
|
#ifdef WITH_PAIRING
|
||||||
getStartPairR = promptSecret Nothing $ startPairing PairReq noop pairingAlert Nothing
|
let localsupported = True
|
||||||
#else
|
#else
|
||||||
getStartPairR = noPairing
|
let localsupported = False
|
||||||
|
#endif
|
||||||
|
$(widgetFile "configurators/pairing/start")
|
||||||
|
#else
|
||||||
|
#ifdef WITH_PAIRING
|
||||||
|
getStartPairR = redirect StartLocalPairR
|
||||||
|
#else
|
||||||
|
getStartPairR = noPairing "local or jabber"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
{- Runs on the system that responds to a pair request; sets up the ssh
|
{- Starts pairing with an XMPP buddy. -}
|
||||||
|
getStartXMPPPairR :: BuddyID -> Handler RepHtml
|
||||||
|
#ifdef WITH_XMPP
|
||||||
|
getStartXMPPPairR (BuddyID bid) = case parseJID bid of
|
||||||
|
Nothing -> error "bad JID"
|
||||||
|
Just jid -> error "TODO"
|
||||||
|
#else
|
||||||
|
getStartXMPPPairR _ = noPairing "XMPP"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{- Starts local pairing. -}
|
||||||
|
getStartLocalPairR :: Handler RepHtml
|
||||||
|
#ifdef WITH_PAIRING
|
||||||
|
getStartLocalPairR = promptSecret Nothing $
|
||||||
|
startLocalPairing PairReq noop pairingAlert Nothing
|
||||||
|
#else
|
||||||
|
getStartLocalPairR = noLocalPairing
|
||||||
|
|
||||||
|
noLocalPairing :: Handler RepHtml
|
||||||
|
noLocalPairing = noPairing "local"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
{- Runs on the system that responds to a local pair request; sets up the ssh
|
||||||
- authorized key first so that the originating host can immediately sync
|
- authorized key first so that the originating host can immediately sync
|
||||||
- with us. -}
|
- with us. -}
|
||||||
getFinishPairR :: PairMsg -> Handler RepHtml
|
getFinishLocalPairR :: PairMsg -> Handler RepHtml
|
||||||
#ifdef WITH_PAIRING
|
#ifdef WITH_PAIRING
|
||||||
getFinishPairR msg = promptSecret (Just msg) $ \_ secret -> do
|
getFinishLocalPairR msg = promptSecret (Just msg) $ \_ secret -> do
|
||||||
liftIO $ setup
|
liftIO $ setup
|
||||||
startPairing PairAck cleanup alert uuid "" secret
|
startLocalPairing PairAck cleanup alert uuid "" secret
|
||||||
where
|
where
|
||||||
alert = pairRequestAcknowledgedAlert (pairRepo msg) . Just
|
alert = pairRequestAcknowledgedAlert (pairRepo msg) . Just
|
||||||
setup = setupAuthorizedKeys msg
|
setup = setupAuthorizedKeys msg
|
||||||
|
@ -62,21 +101,21 @@ getFinishPairR msg = promptSecret (Just msg) $ \_ secret -> do
|
||||||
remoteSshPubKey $ pairMsgData msg
|
remoteSshPubKey $ pairMsgData msg
|
||||||
uuid = Just $ pairUUID $ pairMsgData msg
|
uuid = Just $ pairUUID $ pairMsgData msg
|
||||||
#else
|
#else
|
||||||
getFinishPairR _ = noPairing
|
getFinishLocalPairR _ = noLocalPairing
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
getInprogressPairR :: SecretReminder -> Handler RepHtml
|
getRunningLocalPairR :: SecretReminder -> Handler RepHtml
|
||||||
#ifdef WITH_PAIRING
|
#ifdef WITH_PAIRING
|
||||||
getInprogressPairR s = pairPage $ do
|
getRunningLocalPairR s = pairPage $ do
|
||||||
let secret = fromSecretReminder s
|
let secret = fromSecretReminder s
|
||||||
$(widgetFile "configurators/pairing/inprogress")
|
$(widgetFile "configurators/pairing/local/inprogress")
|
||||||
#else
|
#else
|
||||||
getInprogressPairR _ = noPairing
|
getRunningLocalPairR _ = noLocalPairing
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WITH_PAIRING
|
#ifdef WITH_PAIRING
|
||||||
|
|
||||||
{- Starts pairing, at either the PairReq (initiating host) or
|
{- Starts local pairing, at either the PairReq (initiating host) or
|
||||||
- PairAck (responding host) stage.
|
- PairAck (responding host) stage.
|
||||||
-
|
-
|
||||||
- Displays an alert, and starts a thread sending the pairing message,
|
- Displays an alert, and starts a thread sending the pairing message,
|
||||||
|
@ -85,8 +124,8 @@ getInprogressPairR _ = noPairing
|
||||||
-
|
-
|
||||||
- Redirects to the pairing in progress page.
|
- Redirects to the pairing in progress page.
|
||||||
-}
|
-}
|
||||||
startPairing :: PairStage -> IO () -> (AlertButton -> Alert) -> Maybe UUID -> Text -> Secret -> Widget
|
startLocalPairing :: PairStage -> IO () -> (AlertButton -> Alert) -> Maybe UUID -> Text -> Secret -> Widget
|
||||||
startPairing stage oncancel alert muuid displaysecret secret = do
|
startLocalPairing stage oncancel alert muuid displaysecret secret = do
|
||||||
urlrender <- lift getUrlRender
|
urlrender <- lift getUrlRender
|
||||||
reldir <- fromJust . relDir <$> lift getYesod
|
reldir <- fromJust . relDir <$> lift getYesod
|
||||||
|
|
||||||
|
@ -106,7 +145,7 @@ startPairing stage oncancel alert muuid displaysecret secret = do
|
||||||
startSending pip stage $ sendrequests sender
|
startSending pip stage $ sendrequests sender
|
||||||
void $ liftIO $ forkIO thread
|
void $ liftIO $ forkIO thread
|
||||||
|
|
||||||
lift $ redirect $ InprogressPairR $ toSecretReminder displaysecret
|
lift $ redirect $ RunningLocalPairR $ toSecretReminder displaysecret
|
||||||
where
|
where
|
||||||
{- Sends pairing messages until the thread is killed,
|
{- Sends pairing messages until the thread is killed,
|
||||||
- and shows an activity alert while doing it.
|
- and shows an activity alert while doing it.
|
||||||
|
@ -164,7 +203,7 @@ promptSecret msg cont = pairPage $ do
|
||||||
u <- T.pack <$> liftIO myUserName
|
u <- T.pack <$> liftIO myUserName
|
||||||
let sameusername = username == u
|
let sameusername = username == u
|
||||||
let authtoken = webAppFormAuthToken
|
let authtoken = webAppFormAuthToken
|
||||||
$(widgetFile "configurators/pairing/prompt")
|
$(widgetFile "configurators/pairing/local/prompt")
|
||||||
|
|
||||||
{- This counts unicode characters as more than one character,
|
{- This counts unicode characters as more than one character,
|
||||||
- but that's ok; they *do* provide additional entropy. -}
|
- but that's ok; they *do* provide additional entropy. -}
|
||||||
|
@ -189,8 +228,8 @@ sampleQuote = T.unwords
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
noPairing :: Handler RepHtml
|
noPairing :: Text -> Handler RepHtml
|
||||||
noPairing = pairPage $
|
noPairing pairingtype = pairPage $
|
||||||
$(widgetFile "configurators/pairing/disabled")
|
$(widgetFile "configurators/pairing/disabled")
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -12,13 +12,17 @@ module Assistant.WebApp.Configurators.XMPP where
|
||||||
|
|
||||||
import Assistant.WebApp
|
import Assistant.WebApp
|
||||||
import Assistant.WebApp.Types
|
import Assistant.WebApp.Types
|
||||||
|
import Assistant.WebApp.Notifications
|
||||||
import Assistant.WebApp.SideBar
|
import Assistant.WebApp.SideBar
|
||||||
|
import Assistant.Types.Buddies
|
||||||
import Assistant.Alert
|
import Assistant.Alert
|
||||||
import Assistant.DaemonStatus
|
import Assistant.DaemonStatus
|
||||||
import Utility.Yesod
|
import Utility.Yesod
|
||||||
#ifdef WITH_XMPP
|
import Utility.NotificationBroadcaster
|
||||||
import Assistant.Common
|
import Assistant.Common
|
||||||
|
#ifdef WITH_XMPP
|
||||||
import Assistant.XMPP.Client
|
import Assistant.XMPP.Client
|
||||||
|
import Assistant.XMPP.Buddies
|
||||||
import Assistant.Pushes
|
import Assistant.Pushes
|
||||||
import Utility.SRV
|
import Utility.SRV
|
||||||
#endif
|
#endif
|
||||||
|
@ -45,7 +49,23 @@ xmppNeeded = whenM (isNothing <$> runAnnex Nothing getXMPPCreds) $ do
|
||||||
|
|
||||||
getXMPPR :: Handler RepHtml
|
getXMPPR :: Handler RepHtml
|
||||||
#ifdef WITH_XMPP
|
#ifdef WITH_XMPP
|
||||||
getXMPPR = xmppPage $ do
|
getXMPPR = getXMPPR' ConfigR
|
||||||
|
#else
|
||||||
|
getXMPPR = xmppPage $
|
||||||
|
$(widgetFile "configurators/xmpp/disabled")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
getXMPPForPairingR :: Handler RepHtml
|
||||||
|
#ifdef WITH_XMPP
|
||||||
|
getXMPPForPairingR = getXMPPR' StartPairR
|
||||||
|
#else
|
||||||
|
getXMPPForPairingR = xmppPage $
|
||||||
|
$(widgetFile "configurators/xmpp/disabled")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WITH_XMPP
|
||||||
|
getXMPPR' :: Route WebApp -> Handler RepHtml
|
||||||
|
getXMPPR' redirto = xmppPage $ do
|
||||||
((result, form), enctype) <- lift $ do
|
((result, form), enctype) <- lift $ do
|
||||||
oldcreds <- runAnnex Nothing getXMPPCreds
|
oldcreds <- runAnnex Nothing getXMPPCreds
|
||||||
runFormGet $ renderBootstrap $ xmppAForm $
|
runFormGet $ renderBootstrap $ xmppAForm $
|
||||||
|
@ -61,12 +81,33 @@ getXMPPR = xmppPage $ do
|
||||||
storecreds creds = do
|
storecreds creds = do
|
||||||
void $ runAnnex undefined $ setXMPPCreds creds
|
void $ runAnnex undefined $ setXMPPCreds creds
|
||||||
liftAssistant notifyRestart
|
liftAssistant notifyRestart
|
||||||
redirect ConfigR
|
redirect redirto
|
||||||
#else
|
|
||||||
getXMPPR = xmppPage $
|
|
||||||
$(widgetFile "configurators/xmpp/disabled")
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
{- Called by client to get a list of buddies.
|
||||||
|
-
|
||||||
|
- Returns a div, which will be inserted into the calling page.
|
||||||
|
-}
|
||||||
|
getBuddyListR :: NotificationId -> Handler RepHtml
|
||||||
|
getBuddyListR nid = do
|
||||||
|
waitNotifier getBuddyListBroadcaster nid
|
||||||
|
|
||||||
|
page <- widgetToPageContent $ buddyListDisplay
|
||||||
|
hamletToRepHtml $ [hamlet|^{pageBody page}|]
|
||||||
|
|
||||||
|
buddyListDisplay :: Widget
|
||||||
|
buddyListDisplay = do
|
||||||
|
autoUpdate ident NotifierBuddyListR (10 :: Int) (10 :: Int)
|
||||||
|
#ifdef WITH_XMPP
|
||||||
|
buddies <- lift $ liftAssistant $ catMaybes . map buddySummary
|
||||||
|
<$> (getBuddyList <<~ buddyList)
|
||||||
|
#else
|
||||||
|
let buddies = []
|
||||||
|
#endif
|
||||||
|
$(widgetFile "configurators/xmpp/buddylist")
|
||||||
|
where
|
||||||
|
ident = "buddylist"
|
||||||
|
|
||||||
#ifdef WITH_XMPP
|
#ifdef WITH_XMPP
|
||||||
|
|
||||||
data XMPPForm = XMPPForm
|
data XMPPForm = XMPPForm
|
||||||
|
|
|
@ -71,7 +71,7 @@ simplifyTransfers (v@(t1, _):r@((t2, _):l))
|
||||||
-}
|
-}
|
||||||
getTransfersR :: NotificationId -> Handler RepHtml
|
getTransfersR :: NotificationId -> Handler RepHtml
|
||||||
getTransfersR nid = do
|
getTransfersR nid = do
|
||||||
waitNotifier transferNotifier nid
|
waitNotifier getTransferBroadcaster nid
|
||||||
|
|
||||||
page <- widgetToPageContent $ transfersDisplay False
|
page <- widgetToPageContent $ transfersDisplay False
|
||||||
hamletToRepHtml $ [hamlet|^{pageBody page}|]
|
hamletToRepHtml $ [hamlet|^{pageBody page}|]
|
||||||
|
|
|
@ -12,6 +12,8 @@ module Assistant.WebApp.Notifications where
|
||||||
import Assistant.Common
|
import Assistant.Common
|
||||||
import Assistant.WebApp
|
import Assistant.WebApp
|
||||||
import Assistant.WebApp.Types
|
import Assistant.WebApp.Types
|
||||||
|
import Assistant.DaemonStatus
|
||||||
|
import Assistant.Types.Buddies
|
||||||
import Utility.NotificationBroadcaster
|
import Utility.NotificationBroadcaster
|
||||||
import Utility.Yesod
|
import Utility.Yesod
|
||||||
|
|
||||||
|
@ -40,9 +42,9 @@ autoUpdate ident geturl ms_delay ms_startdelay = do
|
||||||
- of NotificationIds when noscript pages are loaded. This constructs a
|
- of NotificationIds when noscript pages are loaded. This constructs a
|
||||||
- notifier url for a given Route and NotificationBroadcaster.
|
- notifier url for a given Route and NotificationBroadcaster.
|
||||||
-}
|
-}
|
||||||
notifierUrl :: (NotificationId -> Route WebApp) -> (DaemonStatus -> NotificationBroadcaster) -> Handler RepPlain
|
notifierUrl :: (NotificationId -> Route WebApp) -> Assistant NotificationBroadcaster -> Handler RepPlain
|
||||||
notifierUrl route selector = do
|
notifierUrl route broadcaster = do
|
||||||
(urlbits, _params) <- renderRoute . route <$> newNotifier selector
|
(urlbits, _params) <- renderRoute . route <$> newNotifier broadcaster
|
||||||
webapp <- getYesod
|
webapp <- getYesod
|
||||||
return $ RepPlain $ toContent $ T.concat
|
return $ RepPlain $ toContent $ T.concat
|
||||||
[ "/"
|
[ "/"
|
||||||
|
@ -52,7 +54,19 @@ notifierUrl route selector = do
|
||||||
]
|
]
|
||||||
|
|
||||||
getNotifierTransfersR :: Handler RepPlain
|
getNotifierTransfersR :: Handler RepPlain
|
||||||
getNotifierTransfersR = notifierUrl TransfersR transferNotifier
|
getNotifierTransfersR = notifierUrl TransfersR getTransferBroadcaster
|
||||||
|
|
||||||
getNotifierSideBarR :: Handler RepPlain
|
getNotifierSideBarR :: Handler RepPlain
|
||||||
getNotifierSideBarR = notifierUrl SideBarR alertNotifier
|
getNotifierSideBarR = notifierUrl SideBarR getAlertBroadcaster
|
||||||
|
|
||||||
|
getNotifierBuddyListR :: Handler RepPlain
|
||||||
|
getNotifierBuddyListR = notifierUrl BuddyListR getBuddyListBroadcaster
|
||||||
|
|
||||||
|
getTransferBroadcaster :: Assistant NotificationBroadcaster
|
||||||
|
getTransferBroadcaster = transferNotifier <$> getDaemonStatus
|
||||||
|
|
||||||
|
getAlertBroadcaster :: Assistant NotificationBroadcaster
|
||||||
|
getAlertBroadcaster = alertNotifier <$> getDaemonStatus
|
||||||
|
|
||||||
|
getBuddyListBroadcaster :: Assistant NotificationBroadcaster
|
||||||
|
getBuddyListBroadcaster = getBuddyBroadcaster <$> getAssistant buddyList
|
||||||
|
|
|
@ -59,7 +59,7 @@ sideBarDisplay = do
|
||||||
-}
|
-}
|
||||||
getSideBarR :: NotificationId -> Handler RepHtml
|
getSideBarR :: NotificationId -> Handler RepHtml
|
||||||
getSideBarR nid = do
|
getSideBarR nid = do
|
||||||
waitNotifier alertNotifier nid
|
waitNotifier getAlertBroadcaster nid
|
||||||
|
|
||||||
{- This 0.1 second delay avoids very transient notifications from
|
{- This 0.1 second delay avoids very transient notifications from
|
||||||
- being displayed and churning the sidebar unnecesarily.
|
- being displayed and churning the sidebar unnecesarily.
|
||||||
|
|
|
@ -14,6 +14,7 @@ import Assistant.Common
|
||||||
import Assistant.Ssh
|
import Assistant.Ssh
|
||||||
import Assistant.Alert
|
import Assistant.Alert
|
||||||
import Assistant.Pairing
|
import Assistant.Pairing
|
||||||
|
import Assistant.Types.Buddies
|
||||||
import Utility.NotificationBroadcaster
|
import Utility.NotificationBroadcaster
|
||||||
import Utility.WebApp
|
import Utility.WebApp
|
||||||
import Logs.Transfer
|
import Logs.Transfer
|
||||||
|
@ -88,3 +89,7 @@ instance PathPiece SecretReminder where
|
||||||
instance PathPiece UUID where
|
instance PathPiece UUID where
|
||||||
toPathPiece = pack . show
|
toPathPiece = pack . show
|
||||||
fromPathPiece = readish . unpack
|
fromPathPiece = readish . unpack
|
||||||
|
|
||||||
|
instance PathPiece BuddyID where
|
||||||
|
toPathPiece = pack . show
|
||||||
|
fromPathPiece = readish . unpack
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
/config ConfigR GET
|
/config ConfigR GET
|
||||||
/config/repository RepositoriesR GET
|
/config/repository RepositoriesR GET
|
||||||
/config/xmpp XMPPR GET
|
/config/xmpp XMPPR GET
|
||||||
|
/config/xmpp/for/pairing XMPPForPairingR GET
|
||||||
|
|
||||||
/config/repository/new/first FirstRepositoryR GET
|
/config/repository/new/first FirstRepositoryR GET
|
||||||
/config/repository/new NewRepositoryR GET
|
/config/repository/new NewRepositoryR GET
|
||||||
|
@ -26,17 +27,24 @@
|
||||||
/config/repository/add/cloud/S3 AddS3R GET
|
/config/repository/add/cloud/S3 AddS3R GET
|
||||||
|
|
||||||
/config/repository/pair/start StartPairR GET
|
/config/repository/pair/start StartPairR GET
|
||||||
/config/repository/pair/inprogress/#SecretReminder InprogressPairR GET
|
/config/repository/pair/local/start StartLocalPairR GET
|
||||||
/config/repository/pair/finish/#PairMsg FinishPairR GET
|
/config/repository/pair/local/running/#SecretReminder RunningLocalPairR GET
|
||||||
|
/config/repository/pair/local/finish/#PairMsg FinishLocalPairR GET
|
||||||
|
/config/repository/pair/xmpp/start/#BuddyID StartXMPPPairR GET
|
||||||
|
|
||||||
/config/repository/enable/rsync/#UUID EnableRsyncR GET
|
/config/repository/enable/rsync/#UUID EnableRsyncR GET
|
||||||
/config/repository/enable/directory/#UUID EnableDirectoryR GET
|
/config/repository/enable/directory/#UUID EnableDirectoryR GET
|
||||||
/config/repository/enable/S3/#UUID EnableS3R GET
|
/config/repository/enable/S3/#UUID EnableS3R GET
|
||||||
|
|
||||||
/transfers/#NotificationId TransfersR GET
|
/transfers/#NotificationId TransfersR GET
|
||||||
/sidebar/#NotificationId SideBarR GET
|
|
||||||
/notifier/transfers NotifierTransfersR GET
|
/notifier/transfers NotifierTransfersR GET
|
||||||
|
|
||||||
|
/sidebar/#NotificationId SideBarR GET
|
||||||
/notifier/sidebar NotifierSideBarR GET
|
/notifier/sidebar NotifierSideBarR GET
|
||||||
|
|
||||||
|
/buddylist/#NotificationId BuddyListR GET
|
||||||
|
/notifier/buddylist NotifierBuddyListR GET
|
||||||
|
|
||||||
/alert/close/#AlertId CloseAlert GET
|
/alert/close/#AlertId CloseAlert GET
|
||||||
/alert/click/#AlertId ClickAlert GET
|
/alert/click/#AlertId ClickAlert GET
|
||||||
/filebrowser FileBrowserR GET POST
|
/filebrowser FileBrowserR GET POST
|
||||||
|
|
|
@ -9,32 +9,32 @@ module Assistant.XMPP.Buddies where
|
||||||
|
|
||||||
import Assistant.XMPP
|
import Assistant.XMPP
|
||||||
import Common.Annex
|
import Common.Annex
|
||||||
|
import Assistant.Types.Buddies
|
||||||
|
|
||||||
import Network.Protocol.XMPP
|
import Network.Protocol.XMPP
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
import qualified Data.Set as S
|
import qualified Data.Set as S
|
||||||
import Data.Ord
|
import Data.Text (Text)
|
||||||
|
import qualified Data.Text as T
|
||||||
|
|
||||||
newtype Client = Client JID
|
genBuddyID :: JID -> BuddyID
|
||||||
deriving (Eq, Show)
|
genBuddyID j = BuddyID $ formatJID j
|
||||||
|
|
||||||
instance Ord Client where
|
genKey :: JID -> BuddyKey
|
||||||
compare = comparing show
|
genKey j = BuddyKey $ formatJID $ JID (jidNode j) (jidDomain j) Nothing
|
||||||
|
|
||||||
data Buddy = Buddy
|
{- Summary of info about a buddy.
|
||||||
{ buddyPresent :: S.Set Client
|
-
|
||||||
, buddyAway :: S.Set Client
|
- If the buddy has no clients at all anymore, returns Nothing. -}
|
||||||
, buddyAssistants :: S.Set Client
|
buddySummary :: Buddy -> Maybe (Text, Bool, Bool, BuddyID)
|
||||||
}
|
buddySummary b = case clients of
|
||||||
deriving (Eq, Show)
|
((Client j):_) -> Just (buddyname j, away, canpair, genBuddyID j)
|
||||||
|
[] -> Nothing
|
||||||
{- Note that the buddy map includes one buddy for the user's own JID,
|
where
|
||||||
- so that we can track other git-annex assistant's sharing the same
|
buddyname j = maybe (T.pack "") strNode (jidNode j)
|
||||||
- account. -}
|
away = S.null (buddyPresent b) && S.null (buddyAssistants b)
|
||||||
type Buddies = M.Map String Buddy
|
canpair = not $ S.null (buddyAssistants b)
|
||||||
|
clients = S.toList $ buddyPresent b `S.union` buddyAway b `S.union` buddyAssistants b
|
||||||
genKey :: JID -> String
|
|
||||||
genKey j = show $ JID (jidNode j) (jidDomain j) Nothing
|
|
||||||
|
|
||||||
{- Updates the buddies with XMPP presence info. -}
|
{- Updates the buddies with XMPP presence info. -}
|
||||||
updateBuddies :: Presence -> Buddies -> Buddies
|
updateBuddies :: Presence -> Buddies -> Buddies
|
||||||
|
|
BIN
doc/assistant/buddylist.png
Normal file
BIN
doc/assistant/buddylist.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
|
@ -1,5 +1,5 @@
|
||||||
<div .span9 .hero-unit>
|
<div .span9 .hero-unit>
|
||||||
<h2>
|
<h2>
|
||||||
Pairing not supported
|
not supported
|
||||||
<p>
|
<p>
|
||||||
This build of git-annex does not support pairing. Sorry!
|
This build of git-annex does not support #{pairingtype} pairing. Sorry!
|
||||||
|
|
25
templates/configurators/pairing/start.hamlet
Normal file
25
templates/configurators/pairing/start.hamlet
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
<div .span9 .hero-unit>
|
||||||
|
<h2>
|
||||||
|
Pairing with another computer
|
||||||
|
<p>
|
||||||
|
Pairing with a another computer combines both git-annex repositories #
|
||||||
|
into a single shared repository, with changes kept in sync.
|
||||||
|
$if localsupported
|
||||||
|
<p>
|
||||||
|
Is the computer you want to pair with located nearby, on the same #
|
||||||
|
local network? (Or sharing a VPN?)
|
||||||
|
<br>
|
||||||
|
If so, the best choice is local pairing.
|
||||||
|
<br>
|
||||||
|
<a .btn .btn-primary href="@{StartLocalPairR}">
|
||||||
|
Start local pairing
|
||||||
|
<p>
|
||||||
|
Or, you can pair with any of your friends using jabber, or with another #
|
||||||
|
computer that shares your jabber account.
|
||||||
|
<p>
|
||||||
|
$if xmppconfigured
|
||||||
|
^{buddyListDisplay}
|
||||||
|
$else
|
||||||
|
First, you need to #
|
||||||
|
<a .btn .btn-primary href="@{XMPPForPairingR}">
|
||||||
|
configure a jabber account
|
|
@ -44,12 +44,10 @@
|
||||||
|
|
||||||
<h3>
|
<h3>
|
||||||
<a href="@{StartPairR}">
|
<a href="@{StartPairR}">
|
||||||
<i .icon-plus-sign></i> Local computer
|
<i .icon-plus-sign></i> Pair with another computer
|
||||||
<p>
|
<p>
|
||||||
Pair with a local computer to automatically keep files in sync #
|
Connect with another computer used by you, or by a friend,
|
||||||
between computers on your local network.
|
that is also running git-annex.
|
||||||
<p>
|
|
||||||
For easy sharing with family and friends, or between your devices.
|
|
||||||
|
|
||||||
<h3>
|
<h3>
|
||||||
<i .icon-plus-sign></i> Phone
|
<i .icon-plus-sign></i> Phone
|
||||||
|
|
23
templates/configurators/xmpp/buddylist.hamlet
Normal file
23
templates/configurators/xmpp/buddylist.hamlet
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
<div .span9 ##{ident}>
|
||||||
|
<table .table>
|
||||||
|
<tbody>
|
||||||
|
$if null buddies
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
Nobody is currently available.
|
||||||
|
$else
|
||||||
|
$forall (name, away, canpair, buddyid) <- buddies
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<i .icon-user></i> #
|
||||||
|
$if away
|
||||||
|
<span .muted>
|
||||||
|
#{name}
|
||||||
|
$else
|
||||||
|
#{name}
|
||||||
|
<td>
|
||||||
|
$if canpair
|
||||||
|
<a .btn .btn-primary .btn-small href="@{StartXMPPPairR buddyid}">
|
||||||
|
Start pairing
|
||||||
|
$else
|
||||||
|
not using git-annex
|
Loading…
Add table
Add a link
Reference in a new issue