commit c7e3ffa8d8070a2a4aa77bbb7368fc38bfe5d7a8
parent bb6a692840a0ace15a90f40a617e8892108ad0a9
Author: lash <dev@holbrook.no>
Date: Mon, 1 May 2023 20:31:00 +0100
Add description of resource implementation
Diffstat:
5 files changed, 131 insertions(+), 71 deletions(-)
diff --git a/doc/texinfo/cache.texi b/doc/texinfo/cache.texi
@@ -12,6 +12,7 @@ It can be used to:
@end itemize
+@anchor{load_handler}
@section The @code{LOAD} handler
In the @emph{golang} code, the handler of the @code{LOAD} instruction is an implementation of the @code{resource.Resource} interface.
diff --git a/doc/texinfo/dev.texi b/doc/texinfo/dev.texi
@@ -1,5 +1,5 @@
@node dev
-@chapter Development
+@chapter Developing with vise
@section Code repository structure
@@ -28,6 +28,127 @@ Defines instructions, and applies transformations according to the instructions.
@end table
+@section Interacting with @code{vise}
+
+Implementers of @code{vise} should interface with the system using the @code{engine} module.
+
+The engine comes in two implementations, one volatile base implemetnation and a subclass that includes persistent state.
+
+
+@subsection Modes of operation
+
+The @code{engine} module provides three different modes of operation for the engine implementations.
+
+
+@subsubsection Manual operation
+
+Directly interaction with an @code{engine.Engine} instance.
+
+The engine is manually initialized, and execution must be explicitly triggered with input every time the VM yields control.
+
+Output flushing must also be operated manually.
+
+The interface is the same for both persistent and volatile operation.
+
+
+@subsubsection Synchronous loop
+
+Receives input from a reader and writes into to a writer, and executes the underlying @code{engine.Engine} with given inputs until execution is terminated.
+
+The loop may be either persistent or volatile.
+
+This mode drives the interactive driver execution tool.
+
+
+@subsubsection Asynchronous one-shot
+
+Compatible with e.g. a network socket or HTTP frontend. The @code{engine.RunPersisted} method restores a persisted state and runs one single input until VM yield after which the new state is persisted.
+
+This mode of operation can only be used with persistent state.
+
+
+@subsection Configuration
+
+The engine configuration defines the top-level parameters for the execution environment, including maximum output size, default language, execution entry point and more.
+
+Please refer to @code{engine.Config} for details.
+
+
+@subsection Sessions
+
+The @code{engine.Config.SessionId} is used to disambiguate the end-user that is interacting with the engine.
+
+For example, in a @abbr{USSD} context, the @code{SessionId} may be the @emph{phone number} of the end-user.
+
+
+@anchor{execution_context}
+@subsection Execution context
+
+The engine stores the @code{SessionId} aswell as the current chosen @code{lang.Language} in the execution context. This is passed through to the VM operation, and is available for client code, specifically:
+
+@itemize
+@item When resolving symbols with @code{LOAD}. (@code{resource.EntryFunc}).
+@item When resolving menu symbols (@code{resource.Resource.GetMenu}).
+@item When retrieving node templates (@code{resource.Resource.GetTemplate}).
+@end itemize
+
+
+@section Resolving resources
+
+The core of implementation code is defined by implementing the @code{resource.Resource} interface. This is also described in the @ref{load_handler, LOAD handler} section.
+
+In addition to resolving external code symbols, @code{resource.Resource} implementations also translate @emph{menu labels} and @emph{templates} based on the current language context, and retrieves bytecode for execution nodes.
+
+@subsection Memory resource implementation
+
+One of two reference implementations of @code{resource.Resource} is the @code{resource.MemResource} class. It enables the client to register all node and symbol resolutions at runtime, using its functions prefixed with @code{Add...}.
+
+The @code{resource.MemResource} implementation is primarily useful for use in tests.
+
+
+@subsection Filesystem resource implementation
+
+The Filesystem based resource implemementation is used by the @code{dev/interactive} tool, aswell as the executable examples in @file{examples/} directory.
+
+It is instantiated with a base directory location relative to which all resources are read.
+
+
+@subsubsection Bytecode (@code{resource.Resource.GetCode})
+
+Read from @file{basedir/<node>.bin}.
+
+
+@subsubsection Templates (@code{resource.Resource.GetTemplate})
+
+If language has been set, the template will be read from @file{basedir/<node>_<lang>}. For example, the @emph{norwegian} template for the node @code{root} will be read from @file{basedir/root_nor}.
+
+If reading the language specific template fails (or if no language has been set), template will be read from @file{basedir/<node>}.
+
+A missing template file will result in load failure and program termination.
+
+
+@subsubsection Menus (@code{resource.Resource.GetMenu})
+
+If language has been set, the template will be read from @file{basedir/<label>_<lang>_menu}. For example, the @emph{norwegian} template for the menu label @code{foo} will be read from @file{basedir/foo_nor_menu}.
+
+If reading the language specific menu label fails (or if no language has been set), label will be read from @file{basedir/<label>_menu}.
+
+If this also fails, the implementation returns the original label used for lookup.
+
+
+@subsubsection External symbols (@code{resource.Resource.FuncFor})
+
+The implementation allows setting resolver functions for symbols at runtime, using the @code{resource.FsResource.AddLocalFunc} method. This registers an @code{resource.FsResource.EntryFunc} with the lookup symbol as key. Note that the @code{EntryFunc} receives the language setting through the execution context.
+
+If no function has been registered for the requested symbol, it will be looked up in the filesystem on @file{basedir/<symbol>_<lang>.txt}. For example, the @emph{norwegian} entry for the symbol @code{foo} will be read from @file{basedir/foo_nor.txt}.
+
+If reading the language specific entry fails (or if no language has been set), entry will be read from @file{basedir/<symbol>.txt}.
+
+A missing entry will result in load failure and program termination.
+
+The implementation contains no built-in handling of the @code{SessionId} supplied by the context.
+
+
@section Logging
Loglevels are set at compile-time using the following build tags:
diff --git a/doc/texinfo/engine.texi b/doc/texinfo/engine.texi
@@ -1,64 +0,0 @@
-@node engine
-@chapter Using vise
-
-Implementers of @code{vise} should interface with the system using the @code{engine} module.
-
-The engine comes in two implementations, one volatile base implemetnation and a subclass that includes persistent state.
-
-
-@section Modes of operation
-
-The @code{engine} module provides three different modes of operation for the engine implementations.
-
-
-@subsection Manual operation
-
-Directly interaction with an @code{engine.Engine} instance.
-
-The engine is manually initialized, and execution must be explicitly triggered with input every time the VM yields control.
-
-Output flushing must also be operated manually.
-
-The interface is the same for both persistent and volatile operation.
-
-
-@subsection Synchronous loop
-
-Receives input from a reader and writes into to a writer, and executes the underlying @code{engine.Engine} with given inputs until execution is terminated.
-
-The loop may be either persistent or volatile.
-
-This mode drives the interactive driver execution tool.
-
-
-@subsection Asynchronous one-shot
-
-Compatible with e.g. a network socket or HTTP frontend. The @code{engine.RunPersisted} method restores a persisted state and runs one single input until VM yield after which the new state is persisted.
-
-This mode of operation can only be used with persistent state.
-
-
-@section Configuration
-
-The engine configuration defines the top-level parameters for the execution environment, including maximum output size, default language, execution entry point and more.
-
-Please refer to @code{engine.Config} for details.
-
-
-@section Sessions
-
-The @code{engine.Config.SessionId} is used to disambiguate the end-user that is interacting with the engine.
-
-For example, in a @abbr{USSD} context, the @code{SessionId} may be the @emph{phone number} of the end-user.
-
-
-@anchor{execution_context}
-@section Execution context
-
-The engine stores the @code{SessionId} aswell as the current chosen @code{lang.Language} in the execution context. This is passed through to the VM operation, and is available for client code, specifically:
-
-@itemize
-@item When resolving symbols with @code{LOAD}. (@code{resource.EntryFunc}).
-@item When resolving menu symbols (@code{resource.Resource.GetMenu}).
-@item When retrieving node templates (@code{resource.Resource.GetTemplate}).
-@end itemize
diff --git a/doc/texinfo/index.texi b/doc/texinfo/index.texi
@@ -30,7 +30,6 @@ Released 2023 under AGPL3
@include navigation.texi
@include cache.texi
@include render.texi
-@include engine.texi
@include language.texi
@include cookbook.texi
@include dev.texi
diff --git a/resource/fs.go b/resource/fs.go
@@ -127,14 +127,17 @@ func(fsr FsResource) getFunc(ctx context.Context, sym string, input []byte) (Res
}
func(fsr FsResource) getFuncNoCtx(sym string, input []byte, language *lang.Language) (Result, error) {
- fb := sym + ".txt"
- fp := path.Join(fsr.Path, fb)
- fpl := fp
+ fb := sym
+ fbl := fb
if language != nil {
- fpl += "_" + language.Code
+ fbl += "_" + language.Code
}
+ fb += ".txt"
+ fbl += ".txt"
+ fp := path.Join(fsr.Path, fb)
+ fpl := path.Join(fsr.Path, fbl)
Logg.Debugf("getfunc search dir", "dir", fsr.Path, "path", fp, "lang_path", fpl, "sym", sym, "language", language)
- r, err := ioutil.ReadFile(fp)
+ r, err := ioutil.ReadFile(fpl)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
if fpl != fp {