nim-libnx/src/libnx/account.nim
2018-07-18 11:04:09 +09:00

254 lines
5.8 KiB
Nim

import strutils
import libnx/wrapper/acc
import libnx/results
import libnx/wrapper/types
import libnx/ext/integer128
import libnx/service
import libnx/utils
type
AccountError* = object of Exception
AccountInitError* = object of AccountError
AccountImageSizeError* = object of AccountError
AccountUserProfileError* = object of AccountError
AccountUserCountError* = object of AccountError
AccountUserListError* = object of AccountError
AccountUserNotSelectedError* = object of AccountError
AccountUserDataError* = object of AccountError
AccountActiveUserError* = object of AccountError
AccountImageLoadError* = object of AccountError
User* = ref object
id*: u128
selected*: bool
username*: string
lastEdited*: uint64
iconID*: uint32
iconBgColorID*: uint8
miiID*: array[0x10, uint8]
Profile* = ref object
service*: Service
AccountImage* = ref object
data: seq[uint8]
imageSize: int
var enabled = false
proc getService*(): Service =
let serv = accountGetService()[]
result = newService(serv)
proc init() =
## Initializes the account service. Should not
## be used in client code
let service = getService()
if service.isActive:
return
let code = accountInitialize().newResult
if code.failed:
raiseEx(
AccountInitError,
"Error, account api could not be initialized", code
)
enabled = true
proc exit() =
## Exits and closes the Account service
let service = getService()
if not service.isActive:
return
accountExit()
enabled = false
proc close*(profile: AccountProfile) =
accountProfileClose(profile.unsafeAddr)
template withAccountService*(code: untyped): typed =
init()
code
exit()
proc ensureEnabled() =
if not enabled:
raiseEx(AccountError, "Use withAccountService to access account functions.")
proc getImageSize*(profile: AccountProfile): int =
ensureEnabled()
var res = 0.csize
result = 0
let code = accountProfileGetImageSize(profile.unsafeAddr, res.addr).newResult
if code.failed:
raiseEx(AccountImageSizeError, "Error, could not get image size", code)
result = res.int
proc imageSize*(user: User): int =
ensureEnabled()
var prof: AccountProfile
var size: csize
let res = accountProfileGetImageSize(prof.addr, size.addr).newResult
if res.failed:
raiseEx(AccountImageSizeError, "Error, could not get image size", res)
result = size.int
proc getProfileHelper(userID: u128): AccountProfile =
let res = accountGetProfile(result.addr, userID).newResult
if res.failed:
raiseEx(AccountUserProfileError, "Error, could not get user profile", res)
proc loadImage*(user: User): AccountImage =
ensureEnabled()
result = new(AccountImage)
let imSize = user.imageSize()
var size: csize
var prof = getProfileHelper(user.id)
result.data = newSeq[uint8](imSize)
let res = accountProfileLoadImage(
prof.addr, result.data[0].addr,
imSize, result.imageSize.addr
).newResult
if res.failed:
prof.close()
raiseEx(AccountImageLoadError, "Error, could not load image", res)
prof.close()
proc userID*(user: User): string =
$user.id
proc getUser*(userID: u128): User =
ensureEnabled()
result = new(User)
result.id = userID
result.selected = false
var
prof: AccountProfile = getProfileHelper(userID)
userData: AccountUserData
profBase: AccountProfileBase
let res = accountProfileGet(prof.addr, userData.addr, profBase.addr).newResult
if res.failed:
raiseEx(AccountUserDataError, "Error, could not get user data", res)
result.username = profBase.username.join("")
result.lastEdited = profBase.lastEditTimestamp
result.iconID = userData.iconID
result.iconBgColorID = userData.iconBackgroundColorID
result.miiID = userData.miiID
prof.close()
proc getActiveUser*(): User =
ensureEnabled()
result = new(User)
var
userID: u128 = newUInt128(0,0)
selected: bool
var res = accountGetActiveUser(userID.addr, selected.addr).newResult
if res.failed:
raiseEx(AccountActiveUserError, "Error, could not get active user ID", res)
if not selected:
raiseEx(AccountUserNotSelectedError, "No user currently selected!")
result.id = userID
result.selected = selected
var
prof: AccountProfile = getProfileHelper(userID)
userData: AccountUserData
profBase: AccountProfileBase
res = accountProfileGet(prof.addr, userData.addr, profBase.addr).newResult
if res.failed:
raiseEx(AccountUserDataError, "Error, could not get user data", res)
result.username = profBase.username.join("")
result.lastEdited = profBase.lastEditTimestamp
result.iconID = userData.iconID
result.iconBgColorID = userData.iconBackgroundColorID
result.miiID = userData.miiID
prof.close()
proc getProfile*(user: User): Profile =
ensureEnabled()
result = new(Profile)
var prof: AccountProfile
let res = accountGetProfile(prof.addr, user.id).newResult
if res.failed:
raiseEx(
AccountUserProfileError,
"Error, could not get account profile", res
)
result.service = newService(prof.s)
prof.close()
proc getUserCount*(): int32 =
## Gets the number of users on the switch
ensureEnabled()
var count: int32
let res = accountGetUserCount(count.addr).newResult
if res.failed:
raiseEx(
AccountUserCountError,
"Error, could not get user count", res
)
result = count
proc listAllUsers*(): seq[User] =
## Gets a list of all users currently on the switch
ensureEnabled()
result = @[]
var
userIDs: array[ACC_USER_LIST_SIZE, u128]
usersReturned: csize
let res = accountListAllUsers(
userIDs[0].addr,
ACC_USER_LIST_SIZE,
usersReturned.addr
).newResult
if res.failed:
raiseEx(
AccountUserListError,
"Error, could not list users", res
)
for i in 0 ..< usersReturned.int:
result.add(getUser(userIDs[i]))