data types and xml generation/parsing for xmpp push
This commit is contained in:
parent
dbff2a1d73
commit
950c62e6fc
3 changed files with 95 additions and 24 deletions
|
@ -13,6 +13,7 @@ import Assistant.Pairing
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Control.Concurrent.STM
|
import Control.Concurrent.STM
|
||||||
import Control.Concurrent.MSampleVar
|
import Control.Concurrent.MSampleVar
|
||||||
|
import Data.ByteString (ByteString)
|
||||||
|
|
||||||
{- Messages that can be sent out of band by a network messager. -}
|
{- Messages that can be sent out of band by a network messager. -}
|
||||||
data NetMessage
|
data NetMessage
|
||||||
|
@ -23,6 +24,16 @@ data NetMessage
|
||||||
-- notification about a stage in the pairing process,
|
-- notification about a stage in the pairing process,
|
||||||
-- involving a client identified by the Text, and a UUID.
|
-- involving a client identified by the Text, and a UUID.
|
||||||
| PairingNotification PairStage Text UUID
|
| PairingNotification PairStage Text UUID
|
||||||
|
-- request that a git push be sent over the out of band network
|
||||||
|
| PushRequest
|
||||||
|
-- indicates that a PushRequest has been seen and a push is starting
|
||||||
|
| StartingPush
|
||||||
|
-- a chunk of output of git receive-pack
|
||||||
|
| ReceivePackOutput ByteString
|
||||||
|
-- a chuck of output of git send-pack
|
||||||
|
| SendPackOutput ByteString
|
||||||
|
-- sent when git receive-pack exits, with its exit code
|
||||||
|
| ReceivePackDone ExitCode
|
||||||
deriving (Show)
|
deriving (Show)
|
||||||
|
|
||||||
data NetMessagerControl = NetMessagerControl
|
data NetMessagerControl = NetMessagerControl
|
||||||
|
|
|
@ -5,25 +5,34 @@
|
||||||
- Licensed under the GNU GPL version 3 or higher.
|
- Licensed under the GNU GPL version 3 or higher.
|
||||||
-}
|
-}
|
||||||
|
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
module Assistant.XMPP where
|
module Assistant.XMPP where
|
||||||
|
|
||||||
import Assistant.Common
|
import Assistant.Common
|
||||||
import Assistant.Types.NetMessager
|
import Assistant.Types.NetMessager
|
||||||
import Assistant.Pairing
|
import Assistant.Pairing
|
||||||
|
|
||||||
import Network.Protocol.XMPP
|
import Network.Protocol.XMPP hiding (Node)
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
|
import Data.ByteString (ByteString)
|
||||||
|
import qualified Data.ByteString as B
|
||||||
import Data.XML.Types
|
import Data.XML.Types
|
||||||
|
import qualified Codec.Binary.Base64 as B64
|
||||||
|
|
||||||
{- Name of the git-annex tag, in our own XML namespace.
|
{- Name of the git-annex tag, in our own XML namespace.
|
||||||
- (Not using a namespace URL to avoid unnecessary bloat.) -}
|
- (Not using a namespace URL to avoid unnecessary bloat.) -}
|
||||||
gitAnnexTagName :: Name
|
gitAnnexTagName :: Name
|
||||||
gitAnnexTagName = Name (T.pack "git-annex") (Just $ T.pack "git-annex") Nothing
|
gitAnnexTagName = "{git-annex}git-annex"
|
||||||
|
|
||||||
{- Creates a git-annex tag containing a particular attribute and value. -}
|
{- Creates a git-annex tag containing a particular attribute and value. -}
|
||||||
gitAnnexTag :: Name -> Text -> Element
|
gitAnnexTag :: Name -> Text -> Element
|
||||||
gitAnnexTag attr val = Element gitAnnexTagName [(attr, [ContentText val])] []
|
gitAnnexTag attr val = gitAnnexTagContent attr val []
|
||||||
|
|
||||||
|
{- Also with some content. -}
|
||||||
|
gitAnnexTagContent :: Name -> Text -> [Node] -> Element
|
||||||
|
gitAnnexTagContent attr val = Element gitAnnexTagName [(attr, [ContentText val])]
|
||||||
|
|
||||||
isGitAnnexTag :: Element -> Bool
|
isGitAnnexTag :: Element -> Bool
|
||||||
isGitAnnexTag t = elementName t == gitAnnexTagName
|
isGitAnnexTag t = elementName t == gitAnnexTagName
|
||||||
|
@ -66,8 +75,11 @@ gitAnnexSignature :: Presence
|
||||||
gitAnnexSignature = gitAnnexPresence $ Element gitAnnexTagName [] []
|
gitAnnexSignature = gitAnnexPresence $ Element gitAnnexTagName [] []
|
||||||
|
|
||||||
{- A message with a git-annex tag in it. -}
|
{- A message with a git-annex tag in it. -}
|
||||||
gitAnnexMessage :: Element -> Message
|
gitAnnexMessage :: Element -> JID -> JID -> Message
|
||||||
gitAnnexMessage = insertGitAnnexTag silentMessage
|
gitAnnexMessage elt tojid fromjid = (insertGitAnnexTag silentMessage elt)
|
||||||
|
{ messageTo = Just tojid
|
||||||
|
, messageFrom = Just fromjid
|
||||||
|
}
|
||||||
|
|
||||||
{- A notification that we've pushed to some repositories, listing their
|
{- A notification that we've pushed to some repositories, listing their
|
||||||
- UUIDs. -}
|
- UUIDs. -}
|
||||||
|
@ -75,10 +87,10 @@ pushNotification :: [UUID] -> Presence
|
||||||
pushNotification = gitAnnexPresence . gitAnnexTag pushAttr . encodePushNotification
|
pushNotification = gitAnnexPresence . gitAnnexTag pushAttr . encodePushNotification
|
||||||
|
|
||||||
pushAttr :: Name
|
pushAttr :: Name
|
||||||
pushAttr = Name (T.pack "push") Nothing Nothing
|
pushAttr = "push"
|
||||||
|
|
||||||
uuidSep :: T.Text
|
uuidSep :: Text
|
||||||
uuidSep = T.pack ","
|
uuidSep = ","
|
||||||
|
|
||||||
encodePushNotification :: [UUID] -> Text
|
encodePushNotification :: [UUID] -> Text
|
||||||
encodePushNotification = T.intercalate uuidSep . map (T.pack . fromUUID)
|
encodePushNotification = T.intercalate uuidSep . map (T.pack . fromUUID)
|
||||||
|
@ -91,21 +103,15 @@ presenceQuery :: Presence
|
||||||
presenceQuery = gitAnnexPresence $ gitAnnexTag queryAttr T.empty
|
presenceQuery = gitAnnexPresence $ gitAnnexTag queryAttr T.empty
|
||||||
|
|
||||||
queryAttr :: Name
|
queryAttr :: Name
|
||||||
queryAttr = Name (T.pack "query") Nothing Nothing
|
queryAttr = "query"
|
||||||
|
|
||||||
{- A notification about a stage of pairing. -}
|
{- A notification about a stage of pairing. -}
|
||||||
pairingNotification :: PairStage -> UUID -> JID -> JID -> Message
|
pairingNotification :: PairStage -> UUID -> JID -> JID -> Message
|
||||||
pairingNotification pairstage u tojid fromjid =
|
pairingNotification pairstage u = gitAnnexMessage $
|
||||||
(gitAnnexMessage tag)
|
gitAnnexTag pairAttr $ encodePairingNotification pairstage u
|
||||||
{ messageTo = Just tojid
|
|
||||||
, messageFrom = Just fromjid
|
|
||||||
}
|
|
||||||
where
|
|
||||||
tag = gitAnnexTag pairAttr $
|
|
||||||
encodePairingNotification pairstage u
|
|
||||||
|
|
||||||
pairAttr :: Name
|
pairAttr :: Name
|
||||||
pairAttr = Name (T.pack "pair") Nothing Nothing
|
pairAttr = "pair"
|
||||||
|
|
||||||
encodePairingNotification :: PairStage -> UUID -> Text
|
encodePairingNotification :: PairStage -> UUID -> Text
|
||||||
encodePairingNotification pairstage u = T.unwords $ map T.pack
|
encodePairingNotification pairstage u = T.unwords $ map T.pack
|
||||||
|
@ -122,6 +128,57 @@ decodePairingNotification t msg = parse $ words $ T.unpack t
|
||||||
<*> pure (toUUID u)
|
<*> pure (toUUID u)
|
||||||
parse _ = Nothing
|
parse _ = Nothing
|
||||||
|
|
||||||
|
pushRequest :: JID -> JID -> Message
|
||||||
|
pushRequest = gitAnnexMessage $ gitAnnexTag pushRequestAttr T.empty
|
||||||
|
|
||||||
|
pushRequestAttr :: Name
|
||||||
|
pushRequestAttr = "pushrequest"
|
||||||
|
|
||||||
|
startingPush :: JID -> JID -> Message
|
||||||
|
startingPush = gitAnnexMessage $ gitAnnexTag startingPushAttr T.empty
|
||||||
|
|
||||||
|
startingPushAttr :: Name
|
||||||
|
startingPushAttr = "startingpush"
|
||||||
|
|
||||||
|
receivePackOutput :: ByteString -> JID -> JID -> Message
|
||||||
|
receivePackOutput = gitAnnexMessage .
|
||||||
|
gitAnnexTagContent receivePackAttr T.empty . encodeTagContent
|
||||||
|
|
||||||
|
receivePackAttr :: Name
|
||||||
|
receivePackAttr = "rp"
|
||||||
|
|
||||||
|
sendPackOutput :: ByteString -> JID -> JID -> Message
|
||||||
|
sendPackOutput = gitAnnexMessage .
|
||||||
|
gitAnnexTagContent sendPackAttr T.empty . encodeTagContent
|
||||||
|
|
||||||
|
sendPackAttr :: Name
|
||||||
|
sendPackAttr = "sp"
|
||||||
|
|
||||||
|
receivePackDone :: ExitCode -> JID -> JID -> Message
|
||||||
|
receivePackDone = gitAnnexMessage . gitAnnexTag receivePackAttr . T.pack . show . toi
|
||||||
|
where
|
||||||
|
toi (ExitSuccess) = 0
|
||||||
|
toi (ExitFailure i) = i
|
||||||
|
|
||||||
|
decodeReceivePackDone :: Text -> ExitCode
|
||||||
|
decodeReceivePackDone t = fromMaybe (ExitFailure 1) $
|
||||||
|
fromi <$> readish (T.unpack t)
|
||||||
|
where
|
||||||
|
fromi 0 = ExitSuccess
|
||||||
|
fromi i = ExitFailure i
|
||||||
|
|
||||||
|
receivePackDoneAttr :: Name
|
||||||
|
receivePackDoneAttr = "rpdone"
|
||||||
|
|
||||||
|
{- Base 64 encoding a ByteString to use as the content of a tag. -}
|
||||||
|
encodeTagContent :: ByteString -> [Node]
|
||||||
|
encodeTagContent b = [NodeContent $ ContentText $ T.pack $ B64.encode $ B.unpack b]
|
||||||
|
|
||||||
|
decodeTagContent :: Element -> Maybe ByteString
|
||||||
|
decodeTagContent elt = B.pack <$> B64.decode s
|
||||||
|
where
|
||||||
|
s = T.unpack $ T.concat $ elementText elt
|
||||||
|
|
||||||
{- The JID without the client part. -}
|
{- The JID without the client part. -}
|
||||||
baseJID :: JID -> JID
|
baseJID :: JID -> JID
|
||||||
baseJID j = JID (jidNode j) (jidDomain j) Nothing
|
baseJID j = JID (jidNode j) (jidDomain j) Nothing
|
||||||
|
@ -133,12 +190,11 @@ silentMessage = (emptyMessage MessageChat)
|
||||||
{ messagePayloads = [ emptybody ] }
|
{ messagePayloads = [ emptybody ] }
|
||||||
where
|
where
|
||||||
emptybody = Element
|
emptybody = Element
|
||||||
{ elementName = Name (T.pack "body") Nothing Nothing
|
{ elementName = "body"
|
||||||
, elementAttributes = []
|
, elementAttributes = []
|
||||||
, elementNodes = []
|
, elementNodes = []
|
||||||
}
|
}
|
||||||
|
|
||||||
{- Add to a presence to mark its client as extended away. -}
|
{- Add to a presence to mark its client as extended away. -}
|
||||||
extendedAway :: Element
|
extendedAway :: Element
|
||||||
extendedAway = Element (Name (T.pack "show") Nothing Nothing) []
|
extendedAway = Element "show" [] [NodeContent $ ContentText "xa"]
|
||||||
[NodeContent $ ContentText $ T.pack "xa"]
|
|
||||||
|
|
|
@ -58,7 +58,7 @@ For pairing, a chat message is sent, containing:
|
||||||
|
|
||||||
To request that a peer push to us, a chat message can be sent:
|
To request that a peer push to us, a chat message can be sent:
|
||||||
|
|
||||||
<git-annex xmlns='git-annex' startpush="" />
|
<git-annex xmlns='git-annex' pushrequest="" />
|
||||||
|
|
||||||
When a peer is ready to send a git push, it sends:
|
When a peer is ready to send a git push, it sends:
|
||||||
|
|
||||||
|
@ -67,11 +67,15 @@ When a peer is ready to send a git push, it sends:
|
||||||
The receiver runs `git receive-pack`, and sends back its output in
|
The receiver runs `git receive-pack`, and sends back its output in
|
||||||
one or more chat messages:
|
one or more chat messages:
|
||||||
|
|
||||||
<git-annex xmlns='git-annex' rp="007b27ca394d26a05d9b6beefa1b07da456caa2157d7 refs/heads/git-annex report-status delete-refs side-band-64k quiet ofs-delta" />
|
<git-annex xmlns='git-annex' rp="">
|
||||||
|
007b27ca394d26a05d9b6beefa1b07da456caa2157d7 refs/heads/git-annex report-status delete-refs side-band-64k quiet ofs-delta
|
||||||
|
</git-annex>
|
||||||
|
|
||||||
The sender replies with the data from `git push`:
|
The sender replies with the data from `git push`:
|
||||||
|
|
||||||
<git-annex xmlns='git-annex' sp="data" />
|
<git-annex xmlns='git-annex' sp="">
|
||||||
|
data
|
||||||
|
</git-annex>
|
||||||
|
|
||||||
When `git receive-pack` edits, the receiver indicates its exit
|
When `git receive-pack` edits, the receiver indicates its exit
|
||||||
status:
|
status:
|
||||||
|
|
Loading…
Reference in a new issue