aboutsummaryrefslogtreecommitdiff
path: root/tprint/src/Main.hs
blob: 0f88a8631d5eb1cf8140ac8743f9af59e9b0ae0b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
{-# LANGUAGE RecordWildCards, RankNTypes #-}

import Thermoprint
import Thermoprint.Api

import qualified BBCode (parse, make)

import Options.Applicative

import Data.Either
import Data.Maybe
import Control.Monad
import Control.Monad.Trans.Either

import System.IO
import qualified System.IO as IO
import System.Exit
import System.Environment

import Data.Proxy
import Servant.API
import Servant.Client

import Data.Int (Int64)

thermoprintApi :: Proxy ThermoprintApi
thermoprintApi = Proxy

data TPrint = TPrint TPrintMode TPrintOptions

data TPrintOptions = TPrintOptions
                     { baseUrl :: BaseUrl
                     }

data TPrintMode = Print PrintOptions
                | PrintDraft PrintDraftOptions
                | Query QueryOptions
                | Add AddOptions
                | Get GetOptions
                | Write WriteOptions
                | Del DelOptions

data PrintOptions = PrintOptions
                    { printerId :: Integer
                    , dryRun :: Bool
                    }

data PrintDraftOptions = PrintDraftOptions
                         { printOptions :: PrintOptions
                         , pDraftId :: Int64
                         , deleteAfter :: Bool
                         }

data QueryOptions = QueryOptions

data AddOptions = AddOptions
                  { title :: String
                  }

data GetOptions = GetOptions
                  { gDraftId :: Int64
                  , getTitle :: Bool
                  }

data WriteOptions = WriteOptions
                    { wDraftId :: Int64
                    , newTitle :: Maybe String
                    }

data DelOptions = DelOptions
                  { dDraftId :: Int64
                  }
  

main :: IO ()
main = do
  envUrl <- lookupEnv "TPRINT"
  let
    defaultUrl = fromMaybe (BaseUrl Http "localhost" 8080) (envUrl >>= either (const Nothing) Just . parseBaseUrl)
  execParser (opts defaultUrl) >>= main'
  where
    opts url = info (helper <*> opts' url) (
      fullDesc
      <> header "tprint - A cli tool for interfacing with the REST api as provided by thermoprint-servant"
      )
    opts' url = TPrint
            <$> modeSwitch
            <*> commonOpts url
    commonOpts url = TPrintOptions
                 <$> option baseUrlReader (
                   long "url"
                   <> short 'u'
                   <> metavar "URL"
                   <> help "The base url of the api. Also reads TPRINT from environment."
                   <> value url
                   <> showDefaultWith showBaseUrl
                   )
    baseUrlReader = str >>= either readerError return . parseBaseUrl
    modeSwitch = subparser $ mconcat $ map (\(n, f, h) -> command n $ info (helper <*> f) $ progDesc h)
                 [ ("print", print, "Read bbcode from stdin and send it to be printed")
                 , ("print-draft", printD, "Send a draft to be printed")
                 , ("query", query, "List drafts")
                 , ("add", add, "Read bbcode from stdin and add it as a draft")
                 , ("get", get, "Get a draft and print it as bbcode to stdout")
                 , ("write", write, "Read bbcode from stdin and overwrite an existing draft")
                 , ("del", del, "Delete a draft")
                 ]
    draftN s = option auto (
      long "draft"
      <> short 'n'
      <> metavar "INT"
      <> help s
      )
    print = Print <$> print'
    print' = PrintOptions
            <$> option auto (
              long "printer"
              <> short 'p'
              <> metavar "INT"
              <> help "The number of the printer to use"
              <> value 0
              <> showDefault
              )
            <*> flag False True (
              long "dry-run"
              <> short 'd'
              <> help "Instead of sending data to printer output the parsed stream to stderr"
              <> showDefault
              )
    printD = (PrintDraft <$>) $ PrintDraftOptions
             <$> print'
             <*> draftN "The number of the draft to print"
             <*> flag False True (
               long "delete"
               <> help "Delete the draft after printing"
               )
    query = (Query <$>) $ pure QueryOptions
    add = (Add <$>) $ AddOptions
          <$> strArgument (
            metavar "TITLE"
            <> help "The human readable title for the new draft"
            )
    get = (Get <$>) $ GetOptions
          <$> draftN "The number of the draft to retrieve"
          <*> flag False True (
            long "title"
            <> short 't'
            <> help "Get title instead of content"
            )
    write = (Write <$>) $ WriteOptions
            <$> draftN "The number of the draft to overwrite"
            <*> optional ( strArgument (
                               metavar "TITLE"
                               <> help "The human readable title for the updated draft (defaults to retrieving the old one before overwriting)"
                               )
                         )
    del = (Del <$>) $ DelOptions
          <$> draftN "The number of the draft to delete"

either' :: (a -> String) -> EitherT a IO b -> IO b
either' f a = either (die . f) return =<< runEitherT a

main' (TPrint mode TPrintOptions{..}) = do
  let
    -- print :: Integer -> Block String -> EitherT ServantError IO ()
    -- queryDrafts :: EitherT ServantError IO [(Integer, String)]
    -- addDraft :: (String, Block String) -> EitherT ServantError IO Int64
    -- getDraft :: Int64 -> EitherT ServantError IO (String, Block String)
    -- writeDraft :: Int64 -> (String, Block String) -> EitherT ServantError IO Int64
    -- delDraft :: Int64 -> EitherT ServantError IO ()
    (print :<|> queryDrafts :<|> addDraft :<|> getDraft :<|> writeDraft :<|> delDraft) = client thermoprintApi baseUrl
  case mode of
    Print PrintOptions{..} -> do
      input <- BBCode.parse `liftM` getContents
      input' <- either (die . ("Parse error: " ++)) return input
      case dryRun of
        False -> do
          res <- runEitherT $ print printerId input'
          case res of
            Left err -> hPutStrLn stderr $ show err
            Right _ -> exitSuccess
        True -> do
          hPutStrLn stderr $ show input'
    PrintDraft PrintDraftOptions{..} -> do
      let PrintOptions{..} = printOptions
      (_, input) <- either' (\e -> "Error while retrieving draft: " ++ show e) $ getDraft pDraftId
      case dryRun of
        False -> do
          res <- runEitherT $ print printerId input
          case res of
            Left err -> hPutStrLn stderr $ show err
            Right _ -> when deleteAfter $ either' (\e -> "Error while deleting draft: " ++ show e) $ delDraft pDraftId
        True -> do
          hPutStrLn stderr $ show input
    Query QueryOptions -> do
      drafts <- either' (\e -> "Error while retrieving drafts: " ++ show e) queryDrafts
      mapM_ (\(n, t) -> putStrLn $ "[" ++ show n ++ "]\n" ++ (unlines $ map (\s -> "  " ++ s) $ lines t)) drafts
      when (null drafts) $ hPutStrLn stderr "No drafts"
    Add AddOptions{..} -> do
      input <- BBCode.parse `liftM` getContents
      input' <- either (die . ("Parse error: " ++)) return input
      n <- either' (\e -> "Error while saving draft: " ++ show e) $ addDraft (title, input')
      IO.print n
    Get GetOptions{..} -> do
      (title, draft) <- either' (\e -> "Error while retrieving draft: " ++ show e) $ getDraft gDraftId
      case getTitle of
        False -> putStr $ BBCode.make draft
        True -> putStrLn title
    Write WriteOptions{..} -> do
      input <- BBCode.parse `liftM` getContents
      input' <- either (die . ("Parse error: " ++)) return input
      title <- case newTitle of
        Just new -> return new
        Nothing -> fst <$> (either' (\e -> "Error while retrieving draft: " ++ show e) $ getDraft wDraftId)
      either' (\e -> "Error while overwriting draft: " ++ show e) $ writeDraft wDraftId (title, input')
    Del DelOptions{..} -> either' (\e -> "Error while deleting draft: " ++ show e) $ delDraft dDraftId
    _ -> undefined