This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

Documentation

Basic idea

The Lockval engine treats the entire environment (including front-end data) as one ACID database. When you write code that changes the value. The modified data will be synchronized to the background database and also to the front end.

Lockval Engine base architecture:

architecture

1 - Getting Started

This page is not complete.

you can learn how to use and build Lockval Engine by visiting apidemo

If you can, please click “Edit this page” on the right to help our improve it

Lockval Engine base architecture:

architecture

2 - Examples

You can check some examples here

https://apidemo.lockval.com

3 - Multi-language Support

Support multiple languages in your server.

For a wider range of use, Lockval Engine supports multiple languages. You can use one of the languages to develop your background program according to your own habits

Support languages

import { Dict, DBOperate } from "../libs/lockvalserver"

export function main(input: DBOperate<any>) {
  input.GetSubVal(input.UID, "mBase", "Count")
  input.GetAndLock()

  let c = input.GetResp.IDKey[input.UID]?.KeySub["mBase"]?.SubVal["Count"]

  let ci = Number(c)
  ci++
  c = ci.toString()

  input.PutSubVal(input.UID, "mBase", "Count", c)
  input.PutAndUnlock()

  return { Hello: "JS" }
}
return require("umd").define({
    "exports",
    "other/helper",
}, function(exports, helper)

    function exports.main(input)

        input.GetSubVal(input.UID, "mBase", "Count")
        input.GetAndLock()

        local c = helper.GetResp(input, input.UID, "mBase", "Count")
        if c == "" then
            c = "0"
        end
        local ci = tonumber(c)
        ci = ci + 1
        c = tostring(ci)

        input.PutSubVal(input.UID, "mBase", "Count", c)
        input.PutAndUnlock()

        local retval = {}
        retval.Hello = "Lua"
        return retval
    end

end)
def main(input):
  input.GetSubVal(input.UID, "mBase", "Count")
  input.GetAndLock()

  c = input.GetResp.IDKey[input.UID].KeySub["mBase"].SubVal["Count"]

  if c=="":
    c="0"
  ci = int(c)
  ci+=1
  c = str(ci)

  input.PutSubVal(input.UID, "mBase", "Count", c)
  input.PutAndUnlock()

  return {"Hello":"Starlark"}
package usr

import (
	"GoPluginMagicModule/src/helper"
	"strconv"

	"github.com/lockval/go2plugin"
)

func (e export) Export_testBaseCount(input *go2plugin.Input) map[string]any {
	input.GetSubVal(input.UID, "mBase", "Count")
	input.GetAndLock()

	c := helper.GetResp(input, input.UID, "mBase", "Count")

	ci, _ := strconv.Atoi(c)
	ci++
	c = strconv.Itoa(ci)

	input.PutSubVal(input.UID, "mBase", "Count", c)
	input.PutAndUnlock()

	return map[string]any{"Hello": "Go"}
}

Demo

You can view the demo here or build your own environment to test:

https://apidemo.lockval.com

4 - Architecture

Lockval Engine core:

gw: provides the function of synchronizing data with the front end

api: Provide multiple languages to support your program logic development.

db: implements acid database

trigger: provides a method for external access to Locval Engine

Lockval Engine base architecture:

architecture

4.1 - api

The api provides support for multiple languages at the application layer. And is closely related to gw and db. Achieve consistent reading and modification of data.

4.2 - db

The db provides an interface for obtaining and modifying data for the API. The db locks the data when the api gets the data, and unlocks the data after modifying the data

4.3 - gw

gw is connected to the front end through websocket.

The front end can send the request protocol through gw and receive the returned result.

And gw will automatically synchronize the results of modifying the database at the back end to the front end.

4.4 - trigger

Triggers provide the following functionality:

(cron) cron periodically executes api scripts (debug) Upload the script directly via http and execute it (timer) Timers provided to api scripts (caller) Execute the api script through the http interface

about ‘config.yaml’

config.yaml is the trigger configuration file.

key: 1111 # update this file and (cron) password
pwd: 2222 # (debug) password
chk: 3333 # (caller) password

task:
  life:
    sayHi: usr/testChat 0 */1 * * * * {"text":"I am TriggerCron. Hi"}
    SayBye: usr/testChat 30 */1 * * * * {"text":"I am TriggerCron. Bye"}

inst:
  life:
    - worldBoss:1
    - worldBoss:2
  • key: 1111 # update this file and (cron) password
  • pwd: 2222 # (debug) password
  • chk: 3333 # (caller) password

trigger http api

# update config.yaml
curl --insecure "https://localhost:59102/upd?key=admin" -X POST --data-binary @config_new.yaml
# cat config.yaml
curl --insecure "https://localhost:59102/cat?key=admin"
# execute a task of an instance
curl --insecure "https://localhost:59102/cmd?key=admin&inst=life&task=sayHi"

# update and debug script
curl --insecure "https://localhost:59102/js?pwd=admin" -X POST --data-binary @main.js
curl --insecure "https://localhost:59102/lua?pwd=admin" -X POST --data-binary @main.lua
curl --insecure "https://localhost:59102/star?pwd=admin" -X POST --data-binary @main.star

# call a script function
curl --insecure "http://localhost:59102/call?chk=3333&uid=???&cmd=sys/testItsTime" -X POST -d '{"n":1}'

5 - Build

you can learn how to use and build Lockval Engine by visiting apidemo

6 - Configuration

For basic usage, please refer to ‘start.sh’. More configuration methods can be viewed by executing the -help parameter on the program

0. Prepare a linux system

lockval only supports running in a Linux 64bit(arm/amd) environment, so you need to prepare a Linux operating environment. Then continue the following steps in the Linux environment

1. start the Lockval Engine

  • unzip the zip file you downloaded
  • run ‘start.sh’

7 - Learn

you can learn how to use and build Lockval Engine by visiting apidemo

8 - Reference

Low level reference docs for your project.

8.1 - Global API Reference

We provide a global set of Builtin functions

// MakeKSUID make a ID
func MakeKSUID() string 

// MapKeys Traverse m callback key to f
func MapKeys(m any, f func(k any))

// WatchKick kick off uid
func WatchKick(watchuid string, uid string)

// WatchClear clear all watch
func WatchClear(watchuid string)

And we also provide the Go plugin method to support more functions.

Generate api.*.so files by writing plug-ins to support more functions for server-side script codes When the api starts, it will search for api.*.so and add all of them to become available functions of the script This “lockval” plugin can click here to view the source code

After loading some plugins. Your plugin will be in G[“YourPluginName”]


How to use, let’s give a simple example:

import { Dict, DBOperate } from "../libs/lockvalserver"

export function main(input: DBOperate<any>) {
  let c=globalThis.G["lockval"].Sum("a","b")
  return { Hello: globalThis.Builtin.MakeKSUID() }
}
return require("umd").define({
    "exports",
    "other/helper",
}, function(exports, helper)

    function exports.main(input)
        local c = _G.G["lockval"].Sum("a","b")
        return {Hello = _G.Builtin.MakeKSUID()}
    end

end)
def main(input):
  c=globalThis.G["lockval"].Sum("a","b")
  return {"Hello":globalThis.Builtin.MakeKSUID()}

8.2 - Main API Reference

In the call main function, there is a parameter, which we usually define as the variable “input”, which provides the following members and methods. Because the bottom layer of Lockval Engine is implemented in Go, we directly show the Go code

UID      string         // Which user called (call,login,watch)
KSUID    string         // system call ID (system call)
Info     string         // login Info(login)
WATCHUID string         // Which ID to observe (watch)
Requ     map[string]any // User Request Parameters (call)

Json any // Json object

GetResp *GetAndLockResp // Data returned from GetAndLock

Throw            func(Code int, Error string)                    // Throw throw an error to the client
Log              func(v any)                                     // Log Output an arbitrary data to the console
Sleep            func(ms int64, ksuid, cmd string, obj any)      // Sleep Call cmd("xxx/xxx", obj) after timing ms, ksuid:must have value
GetSubValAll     func(id, key string) *GetOpt                    // GetSubValAll Get all the data of the key
GetAndLock       func()                                          // GetAndLock Acquire and lock (can only be called once)
DiscardAndUnlock func() (resp *PutAndUnlockResp)                 // DiscardAndUnlock discard all edits (can only be called once)
PutAndUnlock     func() (resp *PutAndUnlockResp)                 // PutAndUnlock change and unlock (can only be called once)
GetSubVal        func(id, key string, subkeys ...string) *GetOpt // GetSubVal Get some data, when the subkeys are empty, it is to get all
PutSubVal        func(id, key string, kvs ...string) *PutOpt     // PutSubVal set key value

The code can be viewed here:

https://github.com/lockval/go2plugin/blob/main/input.go

How to use, let’s give a simple example:

import { Dict, DBOperate } from "../libs/lockvalserver"

export function main(input: DBOperate<any>) {
  input.GetSubVal(input.UID, "mBase", "Count")
  input.GetAndLock()

  let c = input.GetResp.IDKey[input.UID]?.KeySub["mBase"]?.SubVal["Count"]

  let ci = Number(c)
  ci++
  c = ci.toString()

  input.PutSubVal(input.UID, "mBase", "Count", c)
  input.PutAndUnlock()

  return { Hello: "JS" }
}
return require("umd").define({
    "exports",
    "other/helper",
}, function(exports, helper)

    function exports.main(input)

        input.GetSubVal(input.UID, "mBase", "Count")
        input.GetAndLock()

        local c = helper.GetResp(input, input.UID, "mBase", "Count")
        if c == "" then
            c = "0"
        end
        local ci = tonumber(c)
        ci = ci + 1
        c = tostring(ci)

        input.PutSubVal(input.UID, "mBase", "Count", c)
        input.PutAndUnlock()

        local retval = {}
        retval.Hello = "Lua"
        return retval
    end

end)
def main(input):
  input.GetSubVal(input.UID, "mBase", "Count")
  input.GetAndLock()

  c = input.GetResp.IDKey[input.UID].KeySub["mBase"].SubVal["Count"]

  if c=="":
    c="0"
  ci = int(c)
  ci+=1
  c = str(ci)

  input.PutSubVal(input.UID, "mBase", "Count", c)
  input.PutAndUnlock()

  return {"Hello":"Starlark"}
package usr

import (
	"GoPluginMagicModule/src/helper"
	"strconv"

	"github.com/lockval/go2plugin"
)

func (e export) Export_testBaseCount(input *go2plugin.Input) map[string]any {
	input.GetSubVal(input.UID, "mBase", "Count")
	input.GetAndLock()

	c := helper.GetResp(input, input.UID, "mBase", "Count")

	ci, _ := strconv.Atoi(c)
	ci++
	c = strconv.Itoa(ci)

	input.PutSubVal(input.UID, "mBase", "Count", c)
	input.PutAndUnlock()

	return map[string]any{"Hello": "Go"}
}