vbeam

package module
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Dec 16, 2024 License: MIT Imports: 23 Imported by: 0

README

Introduction

VBeam is a minimal web app engine.

Its core distinguishing feature is allowing you to define server side procedures that can be called from the client side (RPC).

It exposes the ServeMux so you can customize it and add your own routes if you so wish.

Procedure Basics

A procedure that can be registered as an RPC must follow a signature like this:

func PublicName(ctx *vbeam.Context, request InputParams) (response OutputData, err error) {

}

The InputParams and OutputData change depending on the procedure.

The context and error parameters are mandetory.

You may notice that nothing about the procedure's definition has anything to do with HTTP.

Yes, there's a mysterious 'ctx' parameter, but it does not in fact have any info about the http request, as we will see below.

This means that this procedure can also be called in different ways. For example, you can create a small "script"; a stand along program that imports your package and calls its public procedures.

The Context

The context serves two purposes:

  • Extract information from the HTTP request that mediated this procedure call
  • Maintain the database transaction and switch between read/write modes.

This frees the procedure from the burden of having to release the transaction, and of having to parse incoming http request or serialize the response data or error.

There are only three properties on the context:

  • The Application Name
  • The Session Token
  • The vbolt Transaction

The meaning of the session token is application specific, but the expectation is that it maps internally to a user session and that you can use it to extract the logged in user id.

If you call a procedure like this from a "script", you need to have a valid session token. Perhaps you can first generate a session and then add its session token to the context before you call the procedure.

The database

VBeam assumes you want to use VBolt: a simple and robust data storage and retrival system. Refer to its documentation.

In essense, it gives you a programmatic interface for storing and retriving data. No textual query lanuage, no impedence mismatch between your domain models and persistence models.

"ReST"

VBeam does not respect the notion of "RESTful APIs". There are no "resources", just procedures. All remote procedure calls use the http POST method. We don't care about the ReST jargon.

Application

You start by creating an instance of vbeam.Application, and registering the procedures on it in this way:

    app := MakeApplication(...) // returns *vbeam.Application
    vbeam.RegisterProc(app, MyProc1)
    vbeam.RegisterProc(app, MyProc2)
    vbeam.RegisterProc(app, MyProc3)
    vbeam.RegisterProc(app, MyProc4)

The app fulfill the role of an HTTP server in the Go program. It also contains a reference to the VBolt database to be used for all procedure calls.

In addition to that, it's configured out of the box to serve the frontend files and static files.

We make a distinction because frontend files are the result of bundling the frontend's javascript files, and you would always have them available in local dev mode.

Static files are different. They are things that you don't commit to your git repository, instead, they are a part of the deployment environment, and might contain things like user uploaded images.

Generating typescript bindings

In development mode, you can add a line like this to your main function, after you register all the procs:

    vbeam.GenerateTSBindings(app, "frontend/src/server.ts")

This will generate a Typescript file at the given path, and it will contain type definitions for all input and output parameters for all procedures, as well as helper procedures that have the exact same name as their server side counter parts.

When you call the function from client side, you provde the input params, and you get back the output and the error message (string).

    let [response, error] = await server.PublicName({....})

If the function returned an error, the response will be null.

Local development mode

VBeam comes with a set of helper functions for running the server on your local machine with minimal hassle.

  • Frontend building and typechecking embedded in the server itself.
  • TUI shows server log feed and typechecking status

Production mode

TODO

Working with core_server

TODO

Frontend library

TODO

Documentation

Index

Constants

View Source
const PREFIX_DATA = "/data/"
View Source
const PREFIX_RPC = "/rpc/"
View Source
const PREFIX_STATIC = "/static/"

Variables

View Source
var ErrorType = reflect.TypeOf((*error)(nil)).Elem()
View Source
var ProcedureNotFound = errors.New("Procedure Not Found")

Functions

func CloseContext

func CloseContext(ctx *Context)

func DigitsIn

func DigitsIn(n int) int

func GenerateTSBindings

func GenerateTSBindings(app *Application, targetFile string)

func InitRotatingLogger

func InitRotatingLogger(name string)

func ModifiedRequestPath

func ModifiedRequestPath(req *http.Request, npath string) *http.Request

func NiceStackTraceOnPanic

func NiceStackTraceOnPanic()

func PrintFileQuote

func PrintFileQuote(buf io.Writer, fq FileQuote)

func PrintReport

func PrintReport(report TSReport)

func PrintStacktraceElements

func PrintStacktraceElements(buf io.Writer, trace []StackTraceElement)

func PrintTSDiagnosticQuote

func PrintTSDiagnosticQuote(b *strings.Builder, diag Diagnostic)

func PrintUsefulStackTrace

func PrintUsefulStackTrace(buf io.Writer)

func RegisterDataProc

func RegisterDataProc[Input any](app *Application, proc func(*Context, Input) (ContentDownload, error))

func RegisterProc

func RegisterProc[Input, Output any](app *Application, proc func(*Context, Input) (Output, error))

func RegisterProcRawInput

func RegisterProcRawInput[Output any](app *Application, proc func(*Context, *http.Request) (Output, error), maxBytes int)

func Respond

func Respond(w *ResponseWriter, object interface{})

func RespondContentDownload

func RespondContentDownload(w *ResponseWriter, content *ContentDownload)

func RespondError

func RespondError(w http.ResponseWriter, err error)

func RunBackServer

func RunBackServer(port int)

func ServerTimingHeaderValue

func ServerTimingHeaderValue(dur time.Duration) string

func TSWatch

func TSWatch(dirlist []string, ch chan TSReport)

func UseWriteTx

func UseWriteTx(ctx *Context)

func WriteProcTSBinding

func WriteProcTSBinding(p *ProcedureInfo, w io.Writer)

Types

type Application

type Application struct {
	Name       string
	Frontend   fs.FS
	StaticData fs.FS

	DB *vbolt.DB

	*http.ServeMux
	// contains filtered or unexported fields
}

func NewApplication

func NewApplication(name string, db *vbolt.DB) *Application

NewApplication creates a new Application instance

func (*Application) HandleData

func (app *Application) HandleData(w http.ResponseWriter, request *http.Request)

func (*Application) HandleFunc

func (app *Application) HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))

func (*Application) HandleRPC

func (app *Application) HandleRPC(w http.ResponseWriter, request *http.Request)

func (*Application) HandleRoot

func (app *Application) HandleRoot(w http.ResponseWriter, request *http.Request)

func (*Application) HandleStatic

func (app *Application) HandleStatic(w http.ResponseWriter, request *http.Request)

func (*Application) ServeHTTP

func (app *Application) ServeHTTP(wp http.ResponseWriter, request *http.Request)

type ContentDownload

type ContentDownload struct {
	ContentType string
	Filename    string
	WriteTo     func(w *bufio.Writer)
}

type Context

type Context struct {
	AppName string // because same proc can be used by multiple applications
	Token   string
	*vbolt.Tx
}

func MakeContext

func MakeContext(app *Application, req *http.Request) (ctx Context)

type DataProcInfo

type DataProcInfo struct {
	ProcValue reflect.Value
	ProcName  string
	InputType reflect.Type
}

data procs are called at the address bar and return downloadable content

type Diagnostic

type Diagnostic struct {
	Type  string
	Begin bool

	Category  string
	Filename  string
	Line      int
	Character int
	Length    int
	Code      int
	Message   string
}

type Empty

type Empty struct{}

type FileLine

type FileLine struct {
	Number int
	Text   string
}

type FileQuote

type FileQuote struct {
	Filename         string
	Line             int
	Character        int // 0 for unspecified, 1-index based
	SurroundingLines []FileLine
}

func (*FileQuote) Read

func (fq *FileQuote) Read(countBefore int, counteAfter int)

type ProcedureInfo

type ProcedureInfo struct {
	ProcValue reflect.Value
	ProcName  string

	// for typescript generation
	InputType  reflect.Type
	OutputType reflect.Type

	// for preventing malicious inputs
	MaxBytes int
}

type ResponseWriter

type ResponseWriter struct {
	http.ResponseWriter
	// contains filtered or unexported fields
}

ResponseWriter helps us capture the statusCode that was written

func WrapHttpResponeWriter

func WrapHttpResponeWriter(w http.ResponseWriter) *ResponseWriter

func (*ResponseWriter) WriteHeader

func (w *ResponseWriter) WriteHeader(statusCode int)

type StackTraceElement

type StackTraceElement struct {
	Package  string // prefix of function
	Function string
	FileQuote
}

func UsefulStackTrace

func UsefulStackTrace() []StackTraceElement

type TSReport

type TSReport struct {
	Time        time.Time
	Diagnostics []Diagnostic
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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