Created
March 7, 2017 22:30
-
-
Save Jim-Holmstroem/abfa6783ab3e2b05423c84438d15f6dd to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Main where | |
import Prelude | |
import Control.Monad.Eff (Eff) | |
import Control.Monad.Eff.Console (CONSOLE, log, logShow) | |
import Control.Monad.Except | |
import Math (sqrt) | |
import Control.Plus (empty) | |
import Control.MonadZero (guard) | |
import Data.Array ((:)) | |
import Data.Traversable (sequence, foldl) | |
import Data.Maybe (Maybe(..), fromMaybe, fromJust) | |
import Data.Int | |
import Data.Int.Bits (xor) | |
import Data.String | |
import Data.List.Types (NonEmptyList) | |
import Data.Generic | |
import Data.Foreign ( F | |
, ForeignError | |
, unsafeFromForeign | |
, writeObject | |
) | |
import Data.Foreign.Generic | |
import Data.Foreign.Generic.Types | |
import Data.Foreign.Class ( class AsForeign | |
, class IsForeign | |
, readJSON | |
, readProp | |
, (.=) | |
, write | |
) | |
import Control.Monad.Except (runExcept) | |
import Control.Monad.Eff.Class (liftEff) | |
import Control.Monad.Aff (launchAff) | |
import Data.Either (Either(..)) | |
import Data.HTTP.Method (Method(..)) | |
import Network.HTTP.Affjax (get, post, affjax, defaultRequest) | |
import Browser.WebStorage ( EffWebStorage | |
, WebStorage | |
, localStorage | |
, getItem | |
, setItem | |
, removeItem | |
) | |
fromHex :: String -> Maybe Int | |
fromHex = fromStringAs hexadecimal | |
toHex :: Int -> String | |
toHex = toStringAs hexadecimal | |
bytes :: String -> Array (Maybe Int) | |
bytes "" = empty | |
bytes str = fromHex (take 2 str) : bytes (drop 2 str) | |
port :: String | |
port = "5000" | |
solve :: String -> Maybe String | |
solve = map (joinWith "" <<< map (toHex <<< xor 42)) <<< sequence <<< bytes | |
-- TODO(jim) validate with purescript-validate module | |
-- TODO(jim) use generics for decode/encode to remove boilerplate | |
data Challenge = Challenge { challenge :: String | |
} | |
derive instance genericChallenge :: Generic Challenge | |
instance showChallenge :: Show Challenge where | |
show = gShow | |
instance asForeignChallenge :: AsForeign Challenge where | |
write (Challenge challenge) = writeObject [ "challenge" .= challenge.challenge | |
] | |
instance isForeignChallenge :: IsForeign Challenge where | |
read value = do | |
challenge <- readProp "challenge" value | |
pure $ Challenge { challenge: challenge } | |
data Answer = Answer { product :: String | |
, version :: Int | |
, challenge_id :: String | |
, answer :: String | |
} | |
derive instance genericAnswer :: Generic Answer | |
instance showAnswer :: Show Answer where | |
show = gShow | |
instance asForeignAnswer :: AsForeign Answer where | |
write (Answer answer) = writeObject [ "product" .= answer.product | |
, "version" .= answer.version | |
, "challenge_id" .= answer.challenge_id | |
, "answer" .= answer.answer | |
] | |
instance isForeignAnswer :: IsForeign Answer where | |
read value = do | |
product <- readProp "product" value | |
version <- readProp "version" value | |
challenge_id <- readProp "challenge_id" value | |
answer <- readProp "answer" value | |
pure $ Answer { product: product | |
, version: version | |
, challenge_id: challenge_id | |
, answer: answer | |
} | |
data TokenState = TokenState { count :: Int | |
, token :: String | |
} | |
derive instance genericTokenState :: Generic TokenState | |
instance showTokenState :: Show TokenState where | |
show = gShow | |
instance asForeignTokenState :: AsForeign TokenState where | |
write (TokenState tokenState) = writeObject [ "count" .= tokenState.count | |
, "token" .= tokenState.token | |
] | |
instance isForeignTokenState :: IsForeign TokenState where | |
read value = do | |
count <- readProp "count" value | |
token <- readProp "token" value | |
pure $ TokenState { count: count | |
, token: token | |
} | |
defaultTokenState :: TokenState | |
defaultTokenState = TokenState { count: 0 | |
, token: "" | |
} | |
storage = localStorage | |
getTokenState :: forall eff. EffWebStorage eff (Either (NonEmptyList ForeignError) TokenState) | |
getTokenState = do | |
tokenStateSerialized <- getItem storage "tokenState" | |
pure $ case tokenStateSerialized of | |
(Just tokenStateSerialized) -> runExcept $ readJSON tokenStateSerialized :: F TokenState | |
Nothing -> Right defaultTokenState | |
setTokenState :: forall eff. TokenState -> EffWebStorage eff Unit | |
setTokenState tokenState = do | |
tokenStateSerialized <- unsafeFromForeign <<< write $ tokenState | |
setItem storage "tokenState" tokenStateSerialized | |
incrementCount :: TokenState -> TokenState | |
incrementCount (TokenState tokenState@{count: count}) = TokenState $ tokenState {count = count + 1} | |
main = do | |
Right tokenState <- getTokenState | |
logShow tokenState | |
setTokenState $ defaultTokenState | |
--main = launchAff $ do | |
-- res <- get $ "http://localhost:" <> port <> "/v1/challenge?p=product&v=1" | |
-- liftEff $ logShow $ runExcept (readJSON res.response :: F Challenge) | |
--main = do | |
-- log <<< show $ solve "deadbeef" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment