Closed ITwrx closed 12 months ago
These problems should be solvable by first assigning the string to a let variable (that has an address). If the string is known at compile time, some clever use of {.static.} or {.compileTime.} can avoid run-time generation of the string: Something like this:
import guildenstern/[dispatcher, httpserver]
include "xmlGen.nimf" # https://nim-lang.org/docs/filters.html
let s = newHttpServer(proc() =
let r = static(generateXML("John Smith","42"))
reply(r))
s.start(5050)
joinThread(s.thread)
thanks a lot for that detailed answer. I never would have guessed it had to do with compile time vs runtime generation for the string. I didn't understand how to get a ptr string
. :)
I tried to use static(), and that seems like it would have worked, but part of the SCF is using results from my sqlite DB, via tiny_sqlite, and that doesn't seem like it can be compile time, as it's handling errors, etc.
//my_code (getAllSiteSections() is from site_section_model.)
import "templates/bko/site_structure.nimf"
import "models/site_section_model"
proc handleGet() =
let siteSections = static(getAllSiteSections())
let siteStructureString = static(bkSiteStructureTemplate(siteSections))
reply(siteStructureString)
//compile error
/guildenstern/tiny_sqlite/src/tiny_sqlite.nim(316, 29) Error: cannot 'importc' variable at compile time; column_count
//tiny_sqlite.nim (last line is ln 316)
iterator iterate(db: DbConn, stmtOrHandle: sqlite.Stmt | SqlStatement, params: varargs[DbValue],
errorRc: var int32): ResultRow =
let stmtHandle = when stmtOrHandle is sqlite.Stmt: stmtOrHandle else: stmtOrHandle.handle
errorRc = db.bindParams(stmtHandle, params)
if errorRc in SqliteRcOk:
var rowLen = sqlite.column_count(stmtHandle)
So is there a way to reply with runtime string/data? Or some other way to handle this?
thanks
Well, if the string cannot be generated at compiletime, then just don't static, like so:
proc handleGet() =
let siteSections = getAllSiteSections()
let siteStructureString = bkSiteStructureTemplate(siteSections)
reply(siteStructureString)
Note that GuildenStern is a multithreading server: requests are processed in parallel. To get the benefits out of it, you should use a DB wrapper that supports it, like SQLiteral. (Concurrent operation requires SQLite to be in WAL mode, etc).
i had tried that before too, but got:
/.../gs.nim(44, 30) Error: type mismatch
Expression: newHttpServer(handleGet)
[1] handleGet: proc (){.gcsafe.}
Expected one of (first mismatch at [position]):
[1] proc newHttpServer(onrequestcallback: proc () {.gcsafe, nimcall, raises: [].};
loglevel = LogLevel.WARN; parserequestline = true;
hascontent = true): HttpServer
not sure what to do with my handleGet() proc to make it happy.
Thanks for the note about sqlite. I see your library just got an update. I'll see if i can understand the API/docs without too much trouble. :) tiny_sqlite is pretty easy to use. :)
From the snippet it looks like you are breaking the {.gcsafe.} effect, which happens when some code tries to access a global variable. You can make a global variable thread local with the {.threadvar.} pragma, or you can tell the compiler that the access is safe by wrapping the access inside {.gcsafe.} pragma block.
As far as I understand, marking access to a global let variable to be {.gcsafe.} is ok when using mm:arc/mm:orc, but I really don't know for sure, so if you are writing some critical software, better consult someone more knowledgeable. In general, accessing any global mutating global variable is not safe. To make it safe, use locking or other mechanism to prevent the parallel processing from blowing up your program.
The type mismatch from the handler is related to my db access using tiny_sqlite. i can return the SCF template fine as long as i don't try to get data from the DB and use it in the SCF template. I'll close this now. Thanks for the help.
Hi,
When using httpserver, Instead of replying with a string literal like the GuildenStern example, i'm trying to reply with the string returned by a nim SCF proc:
reply(bkSiteStructureTemplate(siteSections))
but i get:fatal error: posix.send requires taking pointer to body, but body has no address
I know this is not likely to be a problem with Guildenstern, but i've run out of energy for floundering, so i thought i'd ask. :)
thanks