dva/dva.nim

122 lines
4.9 KiB
Nim

import json, logging, os, strformat, times, uri
import bakalari, users
when not defined(release):
let consoleLogger = newConsoleLogger()
consoleLogger.addHandler
const
iso8601 = initTimeFormat("yyyy-MM-dd'T'HH:mm:sszzz")
let
configDir = getConfigDir() / "dva"
userConfigDir = configDir / "userconfig"
userCredentialsDir = configDir / "usercredentials"
userDataDir = configDir / "userdata"
iterator usersFromUserConfigDir*(userConfigDir: string): User =
if not existsDir(userConfigDir):
fatal "User configuration diractory not found, quitting"
quit QuitFailure
for userConfigFile in walkFiles(userConfigDir / "*.json"):
let userName = userConfigFile.extractFilename.changeFileExt("")
info &"Loading configuration of user {userName}"
let userConfigNode = userConfigFile.readFile.parseJson
var userConfig: UserConfig
userConfig.email = userConfigNode{"email"}.getStr
for serviceNode in userConfigNode{"services"}:
let kindStr = serviceNode{"kind"}.getStr
case kindStr
of "bakalari_message_forwarding":
userConfig.services.add(Service(kind: srvBakalariMessageForwarding))
of "bakalari_mark_forwarding":
userConfig.services.add(Service(kind: srvBakalariMarkForwarding))
of "bakalari_daily_timetable":
userConfig.services.add(Service(kind: srvBakalariDailyTimetable))
else:
warn &"Unknown service kind: \"{kindStr}\""
yield User(name: userName, config: userConfig, data: UserData(lastServeTime: 0.fromUnix.utc))
proc loadCredentials(user: User, userCredentialsDir: string) =
info &"Loading credentials of user {user.name}"
let userCredentialsFile = userCredentialsDir / user.name.addFileExt("json")
if existsFile(userCredentialsFile):
let userCredentialsNode = userCredentialsFile.readFile.parseJson
let bakalariNode = userCredentialsNode{"bakalari"}
block bakalari:
if bakalariNode != nil:
if "website" notin bakalariNode or "refresh_token" notin bakalariNode:
error "Bakaláři credentials don't include website and refresh token"
break bakalari
user.bakalari = newBakalari(
bakalariNode{"website"}.getStr.parseUri,
bakalariNode{"refresh_token"}.getStr,
)
proc storeCredentials(user: User, userCredentialsDir: string) =
info &"Storing credentials of user {user.name}"
let userCredentialsFile = userCredentialsDir / user.name.addFileExt("json")
let userCredentialsNode = newJObject()
block bakalari:
if user.bakalari != nil:
userCredentialsNode{"bakalari"} = %*{
"website": $user.bakalari.website,
"refresh_token": user.bakalari.refreshToken,
}
userCredentialsFile.writeFile userCredentialsNode.pretty
proc loadData(user: User, userDataDir: string) =
info &"Loading data of user {user.name}"
let userDataFile = userDataDir / user.name.addFileExt("json")
if existsFile(userDataFile):
let userDataNode = userDataFile.readFile.parseJson
user.data.lastServeTime = userDataNode{"last_serve_time"}.getStr.parse(iso8601)
proc storeData(user: User, userDataDir: string) =
info &"Storing data of user {user.name}"
let userDataFile = userDataDir / user.name.addFileExt("json")
let userDataNode = %*{
"last_serve_time": user.data.lastServeTime.format(iso8601)
}
userDataFile.writeFile userDataNode.pretty
proc serve*(user: User, userCredentialsDir: string, userDataDir: string) =
user.loadCredentials(userCredentialsDir)
user.loadData(userDataDir)
info &"Serving user {user.name}"
let serveTime = now()
for service in user.config.services:
case service.kind
of srvBakalariMessageForwarding:
if user.bakalari == nil:
error "Bakaláři message forwarding service is enabled, but user is not logged in to Bakaláři"
continue
for message in user.bakalari.messages:
if message.sentTime >= user.data.lastServeTime:
debug "Sending a message"
else: discard
user.data.lastServeTime = serveTime
user.storeData(userDataDir)
when isMainModule:
if "--login-bakalari" in commandLineParams():
stdout.write "User: "
let userName = stdin.readLine
for user in usersFromUserConfigDir(userConfigDir):
if user.name == userName:
user.loadCredentials(userCredentialsDir)
stdout.write "Bakalari website: "
let bakalariWebsite = stdin.readLine.parseUri
stdout.write "Bakalari username: "
let bakalariUsername = stdin.readLine
stdout.write "Bakalari password: "
let bakalariPassword = stdin.readLine
user.bakalari = newBakalari(bakalariWebsite, bakalariUsername, bakalariPassword)
user.storeCredentials(userCredentialsDir)
break
for user in usersFromUserConfigDir(userConfigDir):
try:
user.serve(userCredentialsDir, userDataDir)
except:
error &"An exception was raised while processing user:\n {getCurrentExceptionMsg()}\n{getCurrentException().getStackTrace}"