module Web.Cuid.Internal where
import Control.Monad (liftM)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Char (ord)
import Data.IORef (IORef, newIORef, atomicModifyIORef')
import Data.Text (Text)
import Data.Time.Clock.POSIX (getPOSIXTime)
import Formatting (Format, base, fitLeft, fitRight, left, (%.))
import Network.HostName (getHostName)
import System.IO.Unsafe (unsafePerformIO)
import System.Random (randomRIO)
#if defined(mingw32_HOST_OS)
import System.Win32 (ProcessId, failIfZero)
#else
import System.Posix.Process (getProcessID)
#endif
getFingerprint :: IO (Int, Int)
getFingerprint = do
pid <- getPid
hostname <- getHostName
let hostSum = 36 + length hostname + sum (map ord hostname)
return (pid, hostSum)
getRandomValue :: IO Int
getRandomValue = randomRIO (0, maxCount)
counter :: IORef Int
counter = unsafePerformIO (newIORef 0)
getNextCount :: IO Int
getNextCount = postIncrement counter
postIncrement :: MonadIO m => IORef Int -> m Int
postIncrement c = liftIO (atomicModifyIORef' c incrementAndWrap) where
incrementAndWrap count = (succ count `mod` maxCount, count)
formatBase, blockSize, maxCount :: Int
formatBase = 36
blockSize = 4
maxCount = formatBase ^ blockSize
number, numberPadded, twoOfNum, firstOfNum, lastOfNum :: Format Text (Int -> Text)
number = base formatBase
numberPadded = left blockSize '0' %. number
twoOfNum = fitRight 2 %. number
lastOfNum = fitRight 1 %. number
firstOfNum = fitLeft 1 %. number
getTimestamp :: IO Int
getTimestamp = liftM toMillis getPOSIXTime where
toMillis posix = round (posix * 1000)
getPid :: MonadIO m => m Int
#if defined(mingw32_HOST_OS)
foreign import stdcall unsafe "windows.h GetCurrentProcessId"
c_GetCurrentProcessId :: IO ProcessId
getCurrentProcessId :: IO ProcessId
getCurrentProcessId = failIfZero "GetCurrentProcessId" c_GetCurrentProcessId
getPid = liftM fromIntegral (liftIO getCurrentProcessId)
#else
getPid = liftM fromIntegral (liftIO getProcessID)
#endif