packages feed

hellage-0.1: hellage.hs

import Control.Concurrent.STM
import Control.Monad
import Control.Monad.Trans
import Data.List
import qualified Data.Map as Map
import Data.Maybe
import Hellnet.Meta
import Hellnet.Storage
import Hellnet.Network
import Hellnet.URI
import Hellnet.Utils
import Network.HTTP.Lucu
import Network.HTTP.Lucu.MIMEType
import qualified Data.ByteString.Lazy as BSL
import Network
import Safe
import System.Console.GetOpt
import System.Environment
import Text.JSON.JPath
import Text.HJson
import Text.Regex.PCRE

data Opts = Opts { serverPort :: PortNumber }

defaultOptions = Opts { serverPort = 6609 }

options :: [OptDescr (Opts -> Opts)]
options = [
	Option ['p'] ["port"]
		(ReqArg (\s o -> o {serverPort = maybe (error "Couldn't parse port number") (fromIntegral) $ readMay s}) "<port>") "Server port to listen on"
	]

main = do
	(optz, argz, errs) <- return . getOpt Permute options =<< getArgs
	let opts = processOptions defaultOptions optz
	case argz of
		[keyIdHex, mname] -> do
			keyid <- resolveKeyName keyIdHex
			runHellage keyid mname $ serverPort opts

serve jsDataVar packageName packageVersion = do
	jsData <- liftIO $ atomically $ readTVar jsDataVar
	case jPath' (intercalate "/" ["packages", packageName, packageVersion]) jsData of
		[] -> setStatus NotFound
		[JString uS] -> do
			case parseHellnetURI uS of
				Nothing -> error "Broken hellnet URI!"
				Just u -> do
					datM <- liftIO $ findURI u
					case datM of
						Nothing -> setStatus InternalServerError
						Just d -> do
							setContentType $ parseMIMEType "application/x-gzip"
							outputLBS d


packageHandler jsDataVar = do
	pInfo <- getPathInfo
	case pInfo of
		[packageTar] -> do
			case headMay $ (packageTar =~ "(.*)-(.*)\\.tar\\.gz" :: [[String]]) of
				Just [_, packageName, packageVersion] -> serve jsDataVar packageName packageVersion
				otherwise -> setStatus BadRequest
		otherwise -> do
			setStatus NotFound

indexHandler jsDataVar = do
	jsData <- liftIO $ atomically $ readTVar jsDataVar
	case jPath' "index" jsData of
		[] -> setStatus InternalServerError
		[JString uS] -> case parseHellnetURI uS of
			Nothing -> error "Broken hellnet URI!"
			Just u -> do
				datM <- liftIO $ findURI u
				case datM of
					Nothing -> setStatus InternalServerError
					Just d -> do
						setContentType $ parseMIMEType "application/x-gzip"
						outputLBS d

updateHandler jsDataVar keyid mname = do
	liftIO $ fetchMeta keyid mname
	jsDataM <- liftIO $ findMetaContentByName keyid mname
	case jsDataM of
		Nothing -> output "Failed"
		Just jsData -> do
			liftIO $ atomically $ writeTVar jsDataVar jsData
			output "Success"

runHellage keyid mname serverPort = do
	jsData <- findMetaContentByName keyid mname >>=
		return . fromMaybe (JObject $ Map.empty)
	jsDataVar <- atomically $ newTVar jsData
	let packageRes = ResourceDef {
		resUsesNativeThread = False,
		resIsGreedy = True,
		resGet = Just $ packageHandler jsDataVar,
		resHead = Nothing,
		resPost = Nothing,
		resPut = Nothing,
		resDelete = Nothing
		}
	let indexRes = ResourceDef {
		resUsesNativeThread = False,
		resIsGreedy = False,
		resGet = Just $ indexHandler jsDataVar,
		resHead = Nothing,
		resPost = Nothing,
		resPut = Nothing,
		resDelete = Nothing
		}
	let updateRes = ResourceDef {
		resUsesNativeThread = False,
		resIsGreedy = False,
		resGet = Just $ updateHandler jsDataVar keyid mname,
		resHead = Nothing,
		resPost = Nothing,
		resPut = Nothing,
		resDelete = Nothing
		}
	let resources = mkResTree [
		(["package"], packageRes),
		(["00-index.tar.gz"], indexRes),
		(["update"], updateRes)
		]
	let config = defaultConfig { cnfServerPort = PortNumber serverPort };
	runHttpd config resources []