Browse Source

Implement avatar status image

master
Emery Hemingway 2 years ago
parent
commit
fb7359d89d
  1. 1
      .gitignore
  2. 72
      src/hqtoxbot.nim

1
.gitignore

@ -1,3 +1,4 @@
hqtoxbot
result
hqtoxbot.save
avatar.png

72
src/hqtoxbot.nim

@ -1,21 +1,27 @@
import toxcore
import std/asyncdispatch, std/base64, std/json, std/httpclient, std/os, std/strutils
import std/asyncdispatch, std/asyncfile, std/base64, std/json, std/httpclient,
std/os, std/strutils, std/uri
{.passL: "-lcrypto".}
const
readmeText = readFile "README.md"
spaceApiUrl = "http://spaceapi.hq.c3d2.de:3000/spaceapi.json"
shalterLockUrl = "http://172.22.99.204/door/lock"
shalterUnlockUrl = "http://172.22.99.204/door/unlock"
# These are IP addresses so the door can be unlocked without DNS
saveFileName = "hqtoxbot.save"
iconFilename = "avatar.png"
adminIds = [
toAddress "DF0AC9107E0A30E7201C6832B017AC836FBD1EDAC390EE99B68625D73C3FD929FB47F1872CA4"
# Emery
]
proc bootstrap(bot: Tox) =
const servers = [
( "tox.neuland.technology",
("tox.neuland.technology",
"15E9C309CFCB79FDDF0EBA057DABB49FE15F3803B1BFF06536AE2E5BA5E4690E".toPublicKey
)
]
@ -29,16 +35,48 @@ proc addAdmin(bot: Tox; id: Address) =
except ToxError:
discard
proc updateStatus(bot: Tox; http: AsyncHttpClient) {.async.} =
proc sendAvatar(bot: Tox; friend: Friend) =
discard bot.send(
friend, TOX_FILE_KIND_AVATAR.uint32,
iconFilename.getFileSize, iconFilename)
proc sendAvatarChunk(bot: Tox; friend: Friend; file: FileTransfer; pos: uint64;
size: int) {.async.} =
let iconFile = openAsync(iconFilename, fmRead)
iconFile.setFilePos(pos.int64);
let chunk = await iconFile.read(size)
close iconFile
bot.sendChunk(friend, file, pos, chunk)
proc updateAvatar(bot: Tox) =
assert(iconFilename != "")
for friend in bot.friends:
if bot.connectionStatus(friend) != TOX_CONNECTION_NONE:
bot.sendAvatar(friend)
proc updateStatus(bot: Tox) {.async.} =
try:
let
http = newAsyncHttpClient()
rsp = await http.get(spaceApiUrl)
body = await rsp.body
space = parseJson body
status = $(space["status"])
status = space["status"].getStr
open = space["state"]["open"].getBool
if bot.statusMessage != status:
bot.statusMessage = unescape $(space["status"])
bot.statusMessage = status
if open:
bot.status = TOX_USER_STATUS_NONE
let iconUrl = space["icon"]["open"].getStr.parseUri
await http.downloadFile($iconUrl, iconFilename)
else:
bot.status = TOX_USER_STATUS_AWAY
let iconUrl = space["icon"]["closed"].getStr.parseUri
await http.downloadFile($iconUrl, iconFilename)
bot.updateAvatar()
close http
except:
echo getCurrentExceptionMsg()
bot.statusMessage = "status update failed"
type Command = enum
@ -48,12 +86,11 @@ type Command = enum
lock,
readme,
revoke,
unlock,
unlock
proc setup(bot: Tox) =
let http = newAsyncHttpClient()
addTimer(20*1000, oneshot = false) do (fd: AsyncFD) -> bool:
asyncCheck updateStatus(bot, http)
asyncCheck updateStatus(bot)
let schalterClient = newAsyncHttpClient()
schalterClient.headers = newHttpHeaders()
@ -64,9 +101,7 @@ proc setup(bot: Tox) =
bot.onFriendConnectionStatus do (f: Friend; status: Connection):
if status != TOX_CONNECTION_NONE:
bot.invite(f, conference)
bot.onFriendReadReceipt do (f: friend; id; MessageId):
discard """TODO some commands should be defered until a read receipt is acquired. Maybe just revoke."""
bot.sendAvatar(f)
bot.onFriendMessage do (f: Friend; msg: string; kind: MessageType):
proc reply(msg: string) =
@ -114,16 +149,15 @@ proc setup(bot: Tox) =
of invite:
for id in words[1..words.high]:
try:
let
address = id.toAddress
other = bot.addFriend(address, "You have been invited to the $1 by $2 ($3)" % [ bot.name, bot.name(f), $bot.publicKey(f) ])
bot.invite(other, conference)
discard bot.addFriend(id.toAddress,
"You have been invited to the $1 by $2 ($3)" % [bot.name,
bot.name(f), $bot.publicKey(f)])
except:
reply(getCurrentExceptionMsg())
of lock:
bot.typing(f, true)
let fut = schalterClient.post("http://schalter.hq.c3d2.de/door/lock")
let fut = schalterClient.post(shalterLockUrl)
fut.addCallback do ():
bot.typing(f, false)
if fut.failed:
@ -140,7 +174,7 @@ proc setup(bot: Tox) =
of unlock:
bot.typing(f, true)
let fut = schalterClient.post("http://schalter.hq.c3d2.de/door/unlock")
let fut = schalterClient.post(shalterUnlockUrl)
fut.addCallback do ():
bot.typing(f, false)
if fut.failed:
@ -150,6 +184,10 @@ proc setup(bot: Tox) =
except:
reply(getCurrentExceptionMsg())
bot.onFileChunkRequest do (friend: Friend; file: FileTransfer; pos: uint64; size: int):
if size != 0:
asyncCheck bot.sendAvatarChunk(friend, file, pos, size)
proc newBot(name: string): Tox =
result = newTox do (opts: Options):
opts.localDiscoveryEnabled = true

Loading…
Cancel
Save