gopcp

package module
v0.0.0-...-e1bac94 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 3, 2020 License: MIT Imports: 7 Imported by: 15

README

gopcp

A simple Lisp-Style protocol for communication (golang version)

travis-ci build status

Features

  • lisp style composation

  • function sandbox. User can control every function and detail by providing the sandbox.

  • based on json grammer

Quick Example

import (
  "github.com/lock-free/gopcp"
  "errors"
)

// create sandbox
sandBox := gopcp.GetSandbox(map[string]*gopcp.BoxFunc{
	"add": gopcp.ToSandboxFun(func(args []interface{}, pcpServer *gopcpc.PcpServer) (interface{}, error) {
		var res float64
		for _, arg := range args {
			if val, ok := arg.(float64); !ok {
				return nil, errors.New("args should be int")
			} else {
				res += val
			}
		}
		return res, nil
	}),
})

pcpServer := NewPcpServer(sandbox)

// we can just use json array string
// output: 3
r1, e1 := pcpServer.Execute("[\"add\", 1, 2]")

// we can also use PcpClient, instead of raw string
var pcpClient = PcpClient{}
callText, jerr := pcpClient.ToJSON(pcpClient.Call("add", 1, 2))

r2, e2 := pcpServer.Execute(callText)

Documentation

Index

Constants

View Source
const (
	SandboxTypeNormal = 1
	SandboxTypeLazy   = 2
)

SandBoxType

Variables

View Source
var DefBox = &Sandbox{map[string]*BoxFunc{

	"if": ToLazySandboxFun(func(args []interface{}, attachment interface{}, pcpServer *PcpServer) (interface{}, error) {
		if len(args) < 2 || len(args) > 3 {
			return nil, errors.New("if grammer error. if must have at least 2 params, at most 3 params. eg: [\"if\", true, 1, 0], [\"if\", true, 1]")
		}

		conditionExp := args[0]
		successExp := args[1]
		var failExp interface{} = nil
		if len(args) > 2 {
			failExp = args[2]
		}

		conditionRet, cerr := pcpServer.ExecuteAst(conditionExp, attachment)
		if cerr != nil {
			return nil, cerr
		}

		if conditionRet == false || conditionRet == 0.0 || conditionRet == nil {
			return pcpServer.ExecuteAst(failExp, attachment)
		}
		return pcpServer.ExecuteAst(successExp, attachment)
	}),

	"List": ToSandboxFun(func(args []interface{}, attachment interface{}, pcpServer *PcpServer) (interface{}, error) {
		return args, nil
	}),

	"Map": ToSandboxFun(func(args []interface{}, attachment interface{}, pcpServer *PcpServer) (interface{}, error) {
		l := len(args)
		if l%2 == 1 {
			return nil, errors.New("Map grammer error. eg: [\"Map\", \"age\", 3, \"weight\", 45]")
		}

		m := make(map[string]interface{})

		for i := 0; i < l; i += 2 {
			key, ok := args[i].(string)
			if !ok {
				return nil, errors.New("Map grammer error. eg: [\"Map\", \"age\", 3, \"weight\", 45]")
			}
			m[key] = args[i+1]
		}

		return m, nil
	}),

	"prop": ToSandboxFun(func(args []interface{}, attachment interface{}, pcpServer *PcpServer) (interface{}, error) {
		if len(args) != 2 {
			return nil, errors.New("Prop grammer error. eg: [\"Prop\", {\"a\": 1}, \"a\"]")
		}

		obj, ok1 := args[0].(map[string]interface{})
		propName, ok2 := args[1].(string)

		if !ok1 || !ok2 {
			return nil, fmt.Errorf("error types of function prop")
		}
		return obj[propName], nil
	}),

	"error": ToSandboxFun(func(args []interface{}, attachment interface{}, pcpServer *PcpServer) (interface{}, error) {
		l := len(args)
		if l%2 < 1 {
			return nil, errors.New("Must specify error message. eg: [\"error\", \"Exception!\"]")
		}

		msg, ok := args[0].(string)
		if !ok {
			return nil, errors.New("Must specify error message (string). eg: [\"error\", \"Exception!\"]")
		}
		return nil, errors.New(msg)
	}),

	"+": ToSandboxFun(func(args []interface{}, attachment interface{}, pcpServer *PcpServer) (interface{}, error) {
		var res float64 = 0
		for _, arg := range args {
			if val, ok := arg.(float64); !ok {
				return nil, errors.New("args of \"+\" should be float64")
			} else {
				res += val
			}
		}
		return res, nil
	}),

	"*": ToSandboxFun(func(args []interface{}, attachment interface{}, pcpServer *PcpServer) (interface{}, error) {
		var res float64 = 1
		for _, arg := range args {
			if val, ok := arg.(float64); !ok {
				return nil, errors.New("args of \"+\" should be float64")
			} else {
				res *= val
			}
		}
		return res, nil
	}),

	"-": ToSandboxFun(func(args []interface{}, attachment interface{}, pcpServer *PcpServer) (interface{}, error) {
		if len(args) != 2 {
			return nil, errors.New("- must have two arguments")
		}

		v1, ok1 := args[0].(float64)
		v2, ok2 := args[1].(float64)
		if !ok1 || !ok2 {
			return nil, fmt.Errorf("args of \"-\" should be float64, but got v1=%v, v2=%v", v1, v2)
		}
		return v1 - v2, nil
	}),

	"/": ToSandboxFun(func(args []interface{}, attachment interface{}, pcpServer *PcpServer) (interface{}, error) {
		if len(args) != 2 {
			return nil, errors.New("- must have two arguments")
		}

		v1, ok1 := args[0].(float64)
		v2, ok2 := args[1].(float64)
		if !ok1 || !ok2 {
			return nil, fmt.Errorf("args of \"/\" should be float64, but got v1=%v, v2=%v", v1, v2)
		}
		if v2 == 0 {
			return nil, errors.New("divisor can not be 0")
		}
		return v1 / v2, nil
	}),

	"==": ToSandboxFun(func(args []interface{}, attachment interface{}, pcpServer *PcpServer) (interface{}, error) {
		if len(args) != 2 {
			return nil, errors.New("== must have two arguments")
		}

		return args[0] == args[1], nil
	}),

	"!=": ToSandboxFun(func(args []interface{}, attachment interface{}, pcpServer *PcpServer) (interface{}, error) {
		if len(args) != 2 {
			return nil, errors.New("== must have two arguments")
		}

		return args[0] != args[1], nil
	}),
}}

Functions

func JSONMarshal

func JSONMarshal(t interface{}) ([]byte, error)

func ParseAstToJsonObject

func ParseAstToJsonObject(ast interface{}) interface{}

convert ast to source object

func ParseJsonObjectToAst

func ParseJsonObjectToAst(source interface{}) interface{}

convert source object to ast

Types

type BoxFunc

type BoxFunc struct {
	FunType int // SandBoxType
	Fun     GeneralFun
}

BoxFun

func ToLazySandboxFun

func ToLazySandboxFun(fun GeneralFun) *BoxFunc

func ToSandboxFun

func ToSandboxFun(fun GeneralFun) *BoxFunc

type CallResult

type CallResult struct {
	Result interface{}
}

type FunNode

type FunNode struct {
	// contains filtered or unexported fields
}

FunNode function node

type GeneralFun

type GeneralFun = func([]interface{}, interface{}, *PcpServer) (interface{}, error)

(params, attachment, pcpServer) -> (result, error)

type PcpClient

type PcpClient struct{}

PcpClient pcp client

func (*PcpClient) Call

func (c *PcpClient) Call(funName string, params ...interface{}) CallResult

Call call function in pcp server

func (*PcpClient) ToJSON

func (c *PcpClient) ToJSON(callResult CallResult) (str string, err error)

type PcpServer

type PcpServer struct {
	// contains filtered or unexported fields
}

PcpServer simpe calling protocol grammer based on json ["fun1", 1, 2, ["fun2", 3]] => fun1(1, 2, fun2(3))

func NewPcpServer

func NewPcpServer(sandbox *Sandbox) *PcpServer

NewPcpServer merge sandbox with default sandbox

func (*PcpServer) Execute

func (pcpServer *PcpServer) Execute(source string, attachment interface{}) (interface{}, error)

Execute ....

func (*PcpServer) ExecuteAst

func (p *PcpServer) ExecuteAst(ast interface{}, attachment interface{}) (interface{}, error)

func (*PcpServer) ExecuteJsonObj

func (pcpServer *PcpServer) ExecuteJsonObj(arr interface{}, attachment interface{}) (interface{}, error)

@param arr. Pure Json Object.

type Sandbox

type Sandbox struct {
	// contains filtered or unexported fields
}

Sandbox

func GetSandbox

func GetSandbox(box map[string]*BoxFunc) *Sandbox

func (*Sandbox) Extend

func (s *Sandbox) Extend(newSandBox *Sandbox) *Sandbox

Extend merge newSandBox's value to origin sandBox

func (*Sandbox) Get

func (s *Sandbox) Get(name string) (*BoxFunc, error)

Get get sandbox method

func (*Sandbox) Set

func (s *Sandbox) Set(name string, val *BoxFunc)

Set set sandbox method

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL