Hi!

I've been playing around with Nim, and to get my head around core concepts I've 
rewritten my existing Telegram bot in Nim. I've used 
[Telebot](https://github.com/ba0f3/telebot.nim) for this. The core update 
handler loop looks somewhat like this (abridged version):
    
    
    import regex
    import unicode
    import httpclient
    import telebot, asyncdispatch, logging, options
    import timezones
    import times
    import json
    import options
    
    const OH_PATTERN = 
re(r"(?i)(\b[oо]+|\b[аa]+|\b[ы]+|\b[еe]+|\b[уy]+|\b[э]+)[xх]+\b")
    const API_KEY = getEnv("BOT_TOKEN")
    
    proc fromJson*(json: JsonNode): DateTime {.gcsafe.} =
      let timezone = tz"Asia/Yekaterinburg"
      let response = to(json, seq[ApiResponse])
      let responseDate: DateTime =  parse("1970-01-01", "yyyy-MM-dd")
      for item in response:
        if item.category.isSome() and item.date.isSome():
          case item.category.get():
          of "holiday":
            date = parseDateTime(item.date.get(), timezone)
    //  ...some other cases...
          else: discard
      return responseDate
    
    proc updateHandler(b: Telebot, u: Update): Future[bool] {.async.} =
      if not u.message.isSome:
        return true
      var response = u.message.get
      if not response.text.isSome:
        return true
      let text = response.text.get
      var m: RegexMatch
      if text.find(OH_PATTERN, m):
        let vowel = m.groupFirstCapture(0, text)
        discard await b.sendMessage(response.chat.id, generateOh(vowel))
      elif text.toLower().contains("some request"):
        let client = newHttpClient()
        let content = client.getContent("https://example.com/some_api";)
        let jsonNode = parseJson(content)
        let response = fromJson(jsonNode["items"])
        discard await b.sendMessage(response.chat.id, $response)
    //  ...some other cases...
    
    let bot = newTeleBot(API_KEY)
    bot.onUpdate(updateHandler)
    bot.poll(timeout=300)
    
    
    Run

So my main problem with this is the fact that `updateHandler` has to be 
gc-safe, which leads to some awkward coding for me, but I'm hoping that there's 
a better way to do things (which is why I'm here). Here are my questions:

  1. Coming from other languages like Java/C#/Python/Go I'm used to the fact 
that httpclient is usually created once and then it's reused without any 
gimmicks, as it's threadsafe. So the first thing I did here was `let content = 
client.getContent("https://example.com/some_api";)` just outside of 
`updateHandler`. But then it complains that `updateHandler` is not gc-safe 
anymore and I can't compile this. So for now I create a new client with every 
request, but how do I do this properly? I've heard about `threadvar` but not 
sure if it's applicable here?
  2. You may have noticed that I'm using `regex` and not `re` from stdlib. And 
the reason is exactly the same: it's my understanding that to use compiled 
regex patterns inside of `updateHandler` they either have to be constants 
(which you can't do with `re`), or they have to be created inside of 
`updateHandler`. But there's no reason to compile the same patterns over and 
over with each request, so the question is the same: can I use standard `re` 
_and_ create it just once outside of `updateHandler`?
  3. The final question is about timezones. Again, coming from languages like 
Java and Python I was very surprised to find that there's basically no tzdata 
support in the language. So I've found 
[timezones](https://github.com/GULPF/timezones) and 
[chrono](https://github.com/treeform/chrono). `Chrono` seems to bring with it a 
whole lot of things for manipulating dates which I don't really need, so I 
didn't want to use that. `Timezones` works, but it also inflates the binary 
size: I was honestly expecting something <1MB in size, originally but with 
`-d:ssl` and imported `unicode` and `regex` package it's already at 1.5MB even 
with `-d:release` and `--opt:size`. So when I add timezones it results in 4MB 
binary. It's not critical for me by any means, but I was just wondering: what's 
the usual approach here? All I need is data for one specific timezone for the 
next few years, but I also want the code to be readable and the ability to 
easily change the timezone if I need (I saw `newTimeZone` in `times` and that 
doesn't look very supportable nor readable)



I would be glad if someone could clarify these things for me and show what's 
the idiomatic way to solve these problems. Thanks!

Reply via email to