miso

package
v0.0.30 Latest Latest
Warning

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

Go to latest
Published: May 6, 2024 License: Apache-2.0 Imports: 58 Imported by: 0

Documentation

Index

Constants

View Source
const (
	BusRoutingKey   = "#"
	BusExchangeKind = "direct"
)
View Source
const (
	// Service registration status - passing.
	ConsulStatusPassing = "passing"

	// Zero value for empty serviceId
	ServiceIdNil = "nil"
)
View Source
const (
	ServiceStatusUp   = "UP"
	ServiceStatusDown = "DOWN"
)
View Source
const (
	LOOPBACK_LOCALHOST = "localhost"
	LOOPBACK_127       = "127.0.0.1"
	LOCAL_IP_ANY       = "0.0.0.0"
)
View Source
const (
	// whether production mode is turned on (true/false)
	PropProdMode = "mode.production"

	/*
		------------------------------------

		Prop for App

		------------------------------------
	*/
	PropAppName = "app.name"

	/*
		------------------------------------

		Prop for Consul

		------------------------------------
	*/
	PropConsulEnabled                     = "consul.enabled"
	PropConsuleRegisterName               = "consul.registerName"
	PropConsulRegisterAddress             = "consul.registerAddress"
	PropConsulAddress                     = "consul.consulAddress"
	PropConsulHealthcheckUrl              = "consul.healthCheckUrl"
	PropConsulHealthCheckInterval         = "consul.healthCheckInterval"
	PropConsulHealthcheckTimeout          = "consul.healthCheckTimeout"
	PropConsulHealthCheckFailedDeregAfter = "consul.healthCheckFailedDeregisterAfter"
	PropConsulRegisterDefaultHealthcheck  = "consul.registerDefaultHealthCheck"
	PropConsulFetchServerInterval         = "consul.fetchServerInterval"
	PropConsulDeregisterUrl               = "consul.deregisterUrl"
	PropConsulEnableDeregisterUrl         = "consul.enableDeregisterUrl"
	PropConsulMetadata                    = "consul.metadata"

	/*
		------------------------------------

		Prop for ServiceDiscovery

		------------------------------------
	*/
	PropSDSubscrbe = "service-discovery.subscribe"

	/*
		------------------------------------

		Prop for Redis

		------------------------------------
	*/
	PropRedisEnabled  = "redis.enabled"
	PropRedisAddress  = "redis.address"
	PropRedisPort     = "redis.port"
	PropRedisUsername = "redis.username"
	PropRedisPassword = "redis.password"
	PropRedisDatabase = "redis.database"

	/*
		------------------------------------

		Prop for MySQL

		------------------------------------
	*/
	PropMySQLEnabled      = "mysql.enabled"
	PropMySQLUser         = "mysql.user"
	PropMySQLPassword     = "mysql.password"
	PropMySQLSchema       = "mysql.database"
	PropMySQLHost         = "mysql.host"
	PropMySQLPort         = "mysql.port"
	PropMySQLConnParam    = "mysql.connection.parameters"
	PropMySQLConnLifetime = "mysql.connection.lifetime"
	PropMySQLMaxOpenConns = "mysql.connection.open.max"
	PropMySQLMaxIdleConns = "mysql.connection.idle.max"

	PropServerEnabled                    = "server.enabled"
	PropServerHost                       = "server.host"
	PropServerPort                       = "server.port"
	PropServerGracefulShutdownTimeSec    = "server.gracefulShutdownTimeSec"
	PropServerPerfEnabled                = "server.perf.enabled"
	PropServerRequestLogEnabled          = "server.request-log.enabled"
	PropServerPropagateInboundTrace      = "server.trace.inbound.propagate"
	PropServerRequestValidateEnabled     = "server.validate.request.enabled"
	PropServerPprofEnabled               = "server.pprof.enabled"
	PropServerGenerateEndpointDocEnabled = "server.generate-endpoint-doc.enabled"
	PropServerRequestAutoMapHeader       = "server.request.mapping.header"
	PropServerGinValidationDisabled      = "server.gin.validation.disabled"

	PropSqliteFile       = "sqlite.file"
	PropSqliteWalEnabled = "sqlite.wal.enabled"

	PropRabbitMqEnabled     = "rabbitmq.enabled"
	PropRabbitMqHost        = "rabbitmq.host"
	PropRabbitMqPort        = "rabbitmq.port"
	PropRabbitMqUsername    = "rabbitmq.username"
	PropRabbitMqPassword    = "rabbitmq.password"
	PropRabbitMqVhost       = "rabbitmq.vhost"
	PropRabbitMqConsumerQos = "rabbitmq.consumer.qos"

	PropTracingPropagationKeys = "tracing.propagation.keys"

	PropLoggingLevel                  = "logging.level"
	PropLoggingRollingFile            = "logging.rolling.file"
	PropLoggingRollingFileMaxAge      = "logging.file.max-age"
	PropLoggingRollingFileMaxSize     = "logging.file.max-size"
	PropLoggingRollingFileMaxBackups  = "logging.file.max-backups"
	PropLoggingRollingFileRotateDaily = "logging.file.rotate-daily"

	PropTaskSchedulingEnabled = "task.scheduling.enabled"
	PropTaskSchedulingGroup   = "task.scheduling.group"

	PropJwtPublicKey  = "jwt.key.public"
	PropJwtPrivateKey = "jwt.key.private"
	PropJwtIssue      = "jwt.key.issuer"

	PropMetricsEnabled              = "metrics.enabled"
	PropMetricsRoute                = "metrics.route"
	PropMetricsAuthEnabled          = "metrics.auth.enabled"
	PropMetricsAuthBearer           = "metrics.auth.bearer"
	PropMetricsEnableMemStatsLogJob = "metrics.memstat.log.job.enabled"
	PropMetricsMemStatsLogJobCron   = "metrics.memstat.log.job.cron"

	PropConfigExtraFiles = "config.extra.files"
)
View Source
const (
	// Components like database that are essential and must be ready before anything else.
	BootstrapOrderL1 = -20

	// Components that are bootstraped before the web server, such as metrics stuff.
	BootstrapOrderL2 = -15

	// The web server or anything similar, bootstraping web server doesn't really mean that we will receive inbound requests.
	BootstrapOrderL3 = -10

	// Components that introduce inbound requests or job scheduling.
	//
	// When these components bootstrap, the server is considered truly running.
	// For example, service registration (for service discovery), MQ broker connection and so on.
	BootstrapOrderL4 = -5

	ExtraDesc         = "miso-Desc"
	ExtraScope        = "miso-Scope"
	ExtraResource     = "miso-Resource"
	ExtraQueryParam   = "miso-QueryParam"
	ExtraHeaderParam  = "miso-HeaderParam"
	ExtraJsonRequest  = "miso-JsonRequest"
	ExtraJsonResponse = "miso-JsonResponse"

	ScopePublic    = "PUBLIC"
	ScopeProtected = "PROTECTED"

	TagQueryParam  = "form"
	TagHeaderParam = "header"
)
View Source
const (
	XTraceId = "X-B3-TraceId"
	XSpanId  = "X-B3-SpanId"
)
View Source
const (
	TagValidationV1 = "validation" // name of validation tag
	TagValidationV2 = "valid"      // name of validation tag (v2)

	ValidMaxLen = "maxLen" // max length of a string, array, slice, e.g., `valid:"maxLen:10"`

	ValidNotEmpty = "notEmpty" // not empty, supports string, array, slice, map
	ValidNotNil   = "notNil"   // not nil, only validates slice, map, pointer, func

	// must be one of the values listed, e.g., 'valid:"member:PUBLIC|PROTECTED"', means that the tag value must be either PUBLIC or PROTECTED.
	// only string type is supported.
	ValidMember = "member"

	ValidPositive       = "positive"       // greater than 0, only supports int... or string type
	ValidPositiveOrZero = "positiveOrZero" // greater than or equal to 0, only supports int... or string type
	ValidNegative       = "negative"       // less than 0, only supports int... or string type
	ValidNegativeOrZero = "negativeOrZero" // less than or equal to 0, only supports int... or string type
	ValidNotZero        = "notZero"        // not zero, only supports int... or string type
	Validated           = "validated"      // mark a nested struct or pointer validated, nil pointer is ignored, one may combine "notNil,validated"
)
View Source
const (
	BoolStrTrue  = "true"
	BoolStrFalse = "false"
)
View Source
const (
	Bearer = "Bearer"
)
View Source
const (
	DEFAULT_LEN = 35
)
View Source
const (
	DEFAULT_QOS = 68 // default QOS

)
View Source
const (
	// Default File Mode
	DefFileMode = 0666
)
View Source
const (
	DefaultPageLimit = 30
)
View Source
const (
	ErrCodeGeneric = "XXXX"
)
View Source
const (
	TagApiDocDesc = "desc"
)
View Source
const (
	Version = "v0.0.30"
)

Variables

View Source
var (
	// Select Server randomly.
	RandomServerSelector ServerSelector = func(servers []Server) int {
		return rand.Int() % len(servers)
	}

	// Property based ServiceRegistry
	PropBasedServiceRegistry = HardcodedServiceRegistry{}

	// ServerList based ServiceRegistry
	//
	// Server selection can be customized by replacing the Rule.
	DynamicServiceRegistry = ServerListServiceRegistry{Rule: RandomServerSelector}

	ErrMissingServiceName      = errors.New("service name is required")
	ErrServiceInstanceNotFound = errors.New("unable to find any available service instance")
	ErrServerListNotFound      = errors.New("fail to find ServerList implemnetation")

	// Get ServerList implementation
	GetServerList func() ServerList
)
View Source
var (
	ErrMissingPrivateKey  = errors.New("missing private key")
	ErrMissingPublicKey   = errors.New("missing public key")
	ErrExtractClaimFailed = errors.New("unable to extract claims from token")
)
View Source
var (
	PUB_PEM_BEGIN = "-----BEGIN PUBLIC KEY-----"
	PUB_PEM_END   = "-----END PUBLIC KEY-----"

	PRIV_PEM_BEGIN = "-----BEGIN PRIVATE KEY-----"
	PRIV_PEM_END   = "-----END PRIVATE KEY-----"

	ErrDecodePemFailed = errors.New("failed to decode public key pem")
	ErrInvalidKey      = errors.New("invalid key")
)
View Source
var (
	ValidateWalkTagCallbackDeprecated = WalkTagCallback{
		Tag:      TagValidationV1,
		OnWalked: validateOnWalked,
	}
	ValidateWalkTagCallback = WalkTagCallback{
		Tag:      TagValidationV2,
		OnWalked: validateOnWalked,
	}
)
View Source
var (
	ApiDocTypeAlias = map[string]string{
		"ETime":       "int64",
		"*ETime":      "int64",
		"*miso.ETime": "int64",
	}
)
View Source
var (

	// Api for Consul.
	ConsulApi = ConsulApiImpl{}
)
View Source
var (
	ErrGetTimeout = errors.New("future.TimedGet timeout")
)
View Source
var (
	MetricsMemoryMatcher = regexp.MustCompile(`^/memory/.*`)
)
View Source
var (
	MisoDefaultClient *http.Client
)

Functions

func AddHeaders

func AddHeaders(req *http.Request, headers map[string][]string)

Add http headers

func AddHealthIndicator added in v0.0.6

func AddHealthIndicator(hi HealthIndicator)

Add health indicator.

func AddMySQLBootstrapCallback added in v0.0.28

func AddMySQLBootstrapCallback(cbk MySQLBootstrapCallback)

func AddPropagationKey

func AddPropagationKey(key string)

Add propagation key for tracing

func AddPropagationKeys added in v0.0.27

func AddPropagationKeys(keys ...string)

Add propagation key for tracing

func AddRabbitListener

func AddRabbitListener(listener RabbitListener)

Register pending message listener.

Listeners will be started in StartRabbitMqClient func when the connection to broker is established.

For any message that the listener is unable to process (returning error), the message is redelivered indefinitively with a delay of 10 seconds until the message is finally processed without error.

func AddShutdownHook

func AddShutdownHook(hook func())

Register shutdown hook, hook should never panic

func AppendableFile added in v0.0.14

func AppendableFile(name string) (*os.File, error)

Create appendable file with 0666 permission.

func ArgKeyVal

func ArgKeyVal(args []string) map[string][]string

Parse CLI args to key-value map

func BearerAuth added in v0.0.20

func BearerAuth(delegate http.Handler, getExpectedToken func() string) http.HandlerFunc

func BootstrapServer

func BootstrapServer(args []string)

Bootstrap server

This func will attempt to create http server, connect to MySQL, Redis or Consul based on the configuration loaded.

It also handles service registration/de-registration on Consul before Gin bootstraped and after SIGTERM/INTERRUPT signals are received.

Graceful shutdown for the http server is also enabled and can be configured through props.

To configure server, MySQL, Redis, Consul and so on, see PROPS_* in prop.go.

It's also possible to register callbacks that are triggered before/after server bootstrap

server.PreServerBootstrap(func(c Rail) error {
	// do something right after configuration being loaded, but server hasn't been bootstraped yet
});

server.PostServerBootstrapped(func(c Rail) error {
	// do something after the server bootstrap
});

// start the server
server.BootstrapServer(os.Args)

func BuildRollingLogFileWriter

func BuildRollingLogFileWriter(p NewRollingLogFileParam) *lumberjack.Logger

Create rolling file based logger

func ChainValidationError

func ChainValidationError(parentField string, e error) error

func ClientSkipTlsSecureCheck added in v0.0.4

func ClientSkipTlsSecureCheck()

Disable TLS certificate check.

func CollectFields

func CollectFields(ptr any) []reflect.StructField

Get Fields of A Type

func CollectTypeFields

func CollectTypeFields(eleType reflect.Type) []reflect.StructField

Get Fields of A Type

func ConfigureLogging

func ConfigureLogging(rail Rail) error

Configure logging level and output target based on loaded configuration.

func ConsulBootstrap

func ConsulBootstrap(rail Rail) error

func ConsulBootstrapCondition added in v0.0.8

func ConsulBootstrapCondition(rail Rail) (bool, error)

func ContainsProp

func ContainsProp(prop string) bool

Check whether the prop exists

func CopyFilter added in v0.0.29

func CopyFilter[T any](l []T, f func(T) bool) []T

Filter slice value, the original slice is copied before filtering.

func CustomFormatter

func CustomFormatter() logrus.Formatter

Get custom formatter logrus

func Debug added in v0.0.8

func Debug(args ...interface{})

func DebugTimeOp

func DebugTimeOp(r Rail, start time.Time, name string)

Run timer for named operation and print result in log

e.g.,

defer DebugTimeOp(ec, time.Now(), "someOperation")

func Debugf added in v0.0.8

func Debugf(format string, args ...interface{})

func DeclareRabbitBinding

func DeclareRabbitBinding(ch *amqp.Channel, bind BindingRegistration) error

Declare binding using the provided channel immediately

func DeclareRabbitExchange

func DeclareRabbitExchange(ch *amqp.Channel, exchange ExchangeRegistration) error

Declare exchange using the provided channel immediately

func DeclareRabbitQueue

func DeclareRabbitQueue(ch *amqp.Channel, queue QueueRegistration) error

Declare queue using the provided channel immediately

func DecodeJson added in v0.0.6

func DecodeJson(reader io.Reader, ptr any) error

Decode JSON using jsoniter.

func DefaultHealthCheck

func DefaultHealthCheck(ctx *gin.Context)

Create a default health check endpoint that simply doesn't nothing except returing 200

func DefaultMetricDesc added in v0.0.13

func DefaultMetricDesc(matcher *regexp.Regexp) []metrics.Description

func DefaultReadConfig

func DefaultReadConfig(args []string, rail Rail)

Default way to read config file.

Repetitively calling this method overides previously loaded config.

You can also use ReadConfig to load your custom configFile. This func is essentially:

LoadConfigFromFile(GuessConfigFilePath(args))

Notice that the loaded configuration can be overriden by the cli arguments as well by using `KEY=VALUE` syntax.

func DefaultRecovery

func DefaultRecovery(c *gin.Context, e interface{})

Default Recovery func

func DeregisterConsulService added in v0.0.28

func DeregisterConsulService() error

Deregister current service

func DispatchErrMsgJson

func DispatchErrMsgJson(c *gin.Context, msg string)

Dispatch error response in json format

func DispatchJson

func DispatchJson(c *gin.Context, body interface{})

Dispatch a json response

func DispatchJsonCode added in v0.0.18

func DispatchJsonCode(c *gin.Context, code int, body interface{})

Dispatch a json response

func Distinct

func Distinct(l []string) []string

Filter duplicate values

func DistriTaskBootstrap added in v0.0.12

func DistriTaskBootstrap(rail Rail) error

func ERand

func ERand(len int) string

Generate random string with high entrophy

func EnableBasicAuth added in v0.0.30

func EnableBasicAuth(f func(username string, password string, url string, method string) bool)

Enable Basic authorization globally for all registered endpoints.

func EncodeJson added in v0.0.6

func EncodeJson(writer io.Writer, body any) error

Encode JSON using jsoniter.

func Error added in v0.0.8

func Error(args ...interface{})

func Errorf added in v0.0.8

func Errorf(format string, args ...interface{})

func ExtractArgValue

func ExtractArgValue(args []string, predicate Predicate[string]) string

Parse CLI Arg to extract a value from arg, [key]=[value]

e.g.,

To look for 'configFile=?'.

path := ExtractArgValue(args, func(key string) bool { return key == "configFile" }).

func FastDistinct added in v0.0.28

func FastDistinct(l []string) []string

Filter duplicate values, faster but values are sorted, and the slice values are filtered in place.

func Fatal added in v0.0.20

func Fatal(args ...interface{})

func Fatalf added in v0.0.20

func Fatalf(format string, args ...interface{})

func FileExists

func FileExists(path string) (bool, error)

Check if file exists

func Filter added in v0.0.28

func Filter[T any](l []T, f func(T) bool) []T

Filter slice values in place. Be cautious that both slices are backed by the same array.

func FilterMetricDesc added in v0.0.13

func FilterMetricDesc(nameFilter func(name string) bool, kindFilter func(kind metrics.ValueKind) bool) []metrics.Description

func FuncName

func FuncName(f any) string

Get name of func

func FuzzParseTime added in v0.0.18

func FuzzParseTime(formats []string, value string) (time.Time, error)

func GenId

func GenId() (id string)

Generate Id

The id consists of [64 bits long] + [6 digits machine_code] The 64 bits long consists of: [sign bit (1 bit)] + [timestamp (49 bits, ~1487.583 years)] + [sequenceNo (14 bits, 0~16383)]

The max value of Long is 9223372036854775807, which is a string with 19 characters, so the generated id will be of at most 25 characters

This func is thread-safe

func GenIdP

func GenIdP(prefix string) (id string)

Generate Id with prefix

The id consists of [64 bits long] + [6 digits machine_code] The 64 bits long consists of: [sign bit (1 bit)] + [timestamp (49 bits, ~1487.583 years)] + [sequenceNo (14 bits, 0~16383)]

The max value of Long is 9223372036854775807, which is a string with 19 characters, so the generated id will be of at most 25 characters

This func is thread-safe

func GenNo

func GenNo(prefix string) string

generate a random sequence number with specified prefix

func GenNoL

func GenNoL(prefix string, len int) string

generate a random sequence number with specified prefix

func GetConfIntSlice

func GetConfIntSlice(prop string) []int

Get prop as int slice

func GetConsulClient

func GetConsulClient() *api.Client

Get the already created consul client.

InitConsulClient() must be called before this func.

If the client is not already created, this func will panic.

func GetCtxInt

func GetCtxInt(ctx context.Context, key string) (int, bool)

Get value from context as an int.

string is also formatted as int if possible.

func GetCtxStr

func GetCtxStr(ctx context.Context, key string) (string, bool)

Get value from context as a string

int*, unit*, float* types are formatted as string, other types are returned as empty string

func GetEnv

func GetEnv(key string) string

Get environment variable

func GetEnvElse

func GetEnvElse(key string, defVal string) string

Get environment variable with default value

func GetLocalIPV4

func GetLocalIPV4() string

Get local ipv4 address (excluding loopback address)

func GetMySQL

func GetMySQL() *gorm.DB

Get MySQL Connection.

func GetPropBool

func GetPropBool(prop string) bool

Get prop as bool

func GetPropDur added in v0.0.14

func GetPropDur(prop string, unit time.Duration) time.Duration

Get prop as time.Duration

func GetPropInt

func GetPropInt(prop string) int

Get prop as int

func GetPropIntSlice

func GetPropIntSlice(prop string) []int

Get prop as int slice

func GetPropStr

func GetPropStr(prop string) string

Get prop as string

If the value is an argument that can be expanded, the actual value will be resolved if possible.

e.g, for "name" : "${secretName}".

This func will attempt to resolve the actual value for '${secretName}'.

func GetPropStrMap added in v0.0.14

func GetPropStrMap(prop string) map[string]string

Get prop as string based map.

func GetPropStrSlice added in v0.0.3

func GetPropStrSlice(prop string) []string

Get prop as string slice

func GetPropagationKeys

func GetPropagationKeys() []string

Get all existing propagation key

func GetRedis

func GetRedis() *redis.Client

Get Redis client

Must call InitRedis(...) method before this method.

func GetSqlite

func GetSqlite() *gorm.DB

Get sqlite client.

Client is initialized if necessary.

This func looks for prop:

PROP_SQLITE_FILE

func GetStr

func GetStr(key string) (string, error)

Get String

func GuessConfigFilePath

func GuessConfigFilePath(args []string) string

Guess config file path.

It first looks for the arg that matches the pattern "configFile=/path/to/configFile". If none is found, it's by default 'conf.yml'.

func HandleEndpointResult added in v0.0.23

func HandleEndpointResult(inb Inbound, rail Rail, result any, err error)

Handle endpoint's result using the configured EndpointResultHandler.

func HasPrefixIgnoreCase added in v0.0.5

func HasPrefixIgnoreCase(s string, prefix string) bool

Check if s has the prefix in a case-insensitive way.

func HasProp

func HasProp(prop string) bool

Check whether the prop exists

func HasScheduledJobs added in v0.0.9

func HasScheduledJobs() bool

Whether scheduler is initialized

func HasSuffixIgnoreCase added in v0.0.6

func HasSuffixIgnoreCase(s string, suffix string) bool

Check if s has the suffix in a case-insensitive way.

func Info added in v0.0.8

func Info(args ...interface{})

func Infof added in v0.0.8

func Infof(format string, args ...interface{})

func InitConsulClient added in v0.0.14

func InitConsulClient() error

Get or init new consul client

For the first time that the consul client is initialized, this func will look for prop:

"consul.consulAddress"

func InitMySQL

func InitMySQL(rail Rail, p MySQLConnParam) error

Init Handle to the database

If mysql client has been initialized, current func call will be ignored.

func InitMySQLFromProp

func InitMySQLFromProp(rail Rail) error

Init connection to mysql

If mysql client has been initialized, current func call will be ignored.

This func looks for following props:

"mysql.user"
"mysql.password"
"mysql.database"
"mysql.host"
"mysql.port"
"mysql.connection.parameters"

func InitRedis

func InitRedis(rail Rail, p RedisConnParam) (*redis.Client, error)

Initialize redis client

If redis client has been initialized, current func call will be ignored

func InitRedisFromProp

func InitRedisFromProp(rail Rail) (*redis.Client, error)

Initialize redis client from configuration

If redis client has been initialized, current func call will be ignored.

This func looks for following prop:

"redis.address"
"redis.port"
"redis.username"
"redis.password"
"redis.database"

func IsBlankStr

func IsBlankStr(s string) bool

Check if the string is blank

func IsBool

func IsBool(boolStr string) bool

func IsConsulClientInitialized

func IsConsulClientInitialized() bool

Check whether consul client is initialized

func IsConsulServiceRegistered added in v0.0.13

func IsConsulServiceRegistered() bool

Check if current instance is registered on consul.

func IsDebugLevel

func IsDebugLevel() bool

Check whether current log level is DEBUG

func IsFieldExposed

func IsFieldExposed(fieldName string) bool

Check if field is exposed

func IsLocalAddress

func IsLocalAddress(address string) bool

Check whether the address is local (localhost/127.0.0.1)

func IsMySQLInitialized

func IsMySQLInitialized() bool

Check whether mysql client is initialized

func IsMySqlEnabled

func IsMySqlEnabled() bool

Check if mysql is enabled

This func looks for following prop:

"mysql.enabled"

func IsNoneErr added in v0.0.3

func IsNoneErr(err error) bool

Check if the error represents None

func IsProdMode

func IsProdMode() bool

Check whether we are running in production mode

func IsRLockNotObtainedErr

func IsRLockNotObtainedErr(err error) bool

Check whether the error is 'redislock.ErrNotObtained'

func IsRedisClientInitialized

func IsRedisClientInitialized() bool

Check whether redis client is initialized

func IsRedisEnabled

func IsRedisEnabled() bool

Check if redis is enabled

This func looks for following prop:

"redis.enabled"

func IsShuttingDown

func IsShuttingDown() bool

check if the server is shutting down

func IsTaskMaster

func IsTaskMaster(rail Rail) bool

Check if current node is master

func IsTaskSchedulingDisabled

func IsTaskSchedulingDisabled() bool

Check if it's disabled (based on configuration, doesn't affect method call)

func IsTrue

func IsTrue(boolStr string) bool

func IsVoid added in v0.0.22

func IsVoid(t reflect.Type) bool

func JoinQueryParam

func JoinQueryParam(queryParams map[string][]string) string

Join query parameters

func JwtEncode

func JwtEncode(claims jwt.MapClaims, exp time.Duration) (string, error)

func LTimeOp

func LTimeOp(start time.Time, name string)

Run timer for named operation and print result

e.g.,

defer LTimeOp(ec, time.Now(), "someOperation")

func LoadConfigFromFile

func LoadConfigFromFile(configFile string, r Rail) error

Load config from file

Repetitively calling this method overides previously loaded config.

func LoadConfigFromReader added in v0.0.29

func LoadConfigFromReader(reader io.Reader, r Rail) error

Load config from reader.

It's the caller's responsibility to close the provided reader.

Repetitively calling this method overides previously loaded config.

func LoadPrivKey

func LoadPrivKey(content string) (*rsa.PrivateKey, error)

func LoadPropagationKeys added in v0.0.7

func LoadPropagationKeys(r Rail)

Read property and find propagation keys .

This func looks for following property.

"tracing.propagation.keys"

func LoadPubKey

func LoadPubKey(content string) (*rsa.PublicKey, error)

func LowercaseNamingStrategy added in v0.0.3

func LowercaseNamingStrategy(name string) string

Change first rune to lower case.

func ManualBootstrapPrometheus added in v0.0.13

func ManualBootstrapPrometheus()

Caller wants to bootstrap prometheus manually.

This is mainly used for gateway that implements handler for all endpoints.

func ManualPprofRegister added in v0.0.15

func ManualPprofRegister()

Registrer pprof debug endpoint manually.

func MapFirst

func MapFirst[K comparable, V any](m *map[K]*V) *V

Get first from map

func MapKeys

func MapKeys[T comparable, V any](m *map[T]V) []T

Get keys from map

func MapValues

func MapValues[K comparable, V any](m *map[K]V) []V

Copy values of map

func MarkServerShuttingDown

func MarkServerShuttingDown()

mark that the server is shutting down

func MaxInt

func MaxInt(a int, b int) int

func MaxLenStr

func MaxLenStr(s string, max int) string

Substring such that len(s) <= max

func MergeStrPairs

func MergeStrPairs(p ...StrPair) map[string][]any

Merge StrPair into a map

func MinInt

func MinInt(a int, b int) int

func MkdirAll added in v0.0.30

func MkdirAll(path string) error

MkdirAll with 0755 perm.

func MkdirParentAll added in v0.0.30

func MkdirParentAll(path string) error

MkdirAll but only for the parent directory of the path, perm 0755 is used.

The path should always point to a specific file under some directories, as this method always attempts to extract parent dir of the file. It the path fails to fulfill this requirement, the output might be unexpected.

func MustBind

func MustBind(rail Rail, c *gin.Context, ptr any)

Must bind request payload to the given pointer, else panic

func MustCompile added in v0.0.29

func MustCompile(fs embed.FS, s string) *template.Template

func MySQLBootstrap

func MySQLBootstrap(rail Rail) error

func MySQLBootstrapCondition added in v0.0.8

func MySQLBootstrapCondition(rail Rail) (bool, error)

func NewDeleteRequest

func NewDeleteRequest(url string) (*http.Request, error)

Create DELETE request

func NewEventBus

func NewEventBus(name string)

Declare event bus.

It basically is to create an direct exchange and a queue identified by the name, and bind them using routing key '#'.

func NewGetRequest

func NewGetRequest(url string) (*http.Request, error)

Create GET request

func NewHeadRequest

func NewHeadRequest(url string) (*http.Request, error)

Create HEAD request

func NewMySQLConn

func NewMySQLConn(rail Rail, p MySQLConnParam) (*gorm.DB, error)

Create new MySQL connection

func NewOptionsRequest

func NewOptionsRequest(url string) (*http.Request, error)

Create OPTIONS request

func NewPostRequest

func NewPostRequest(url string, body io.Reader) (*http.Request, error)

Create POST request

func NewPromCounter added in v0.0.6

func NewPromCounter(name string) prometheus.Counter

Create new Counter.

The Counter with this name is automatically registered to the prometheus.DefaultRegisterer.

func NewPromHisto added in v0.0.13

func NewPromHisto(name string) prometheus.Histogram

Create new Histogram.

The created Histogram is automatically registered to the prometheus.DefaultRegisterer.

func NewPromHistoVec added in v0.0.13

func NewPromHistoVec(name string, labels []string) *prometheus.HistogramVec

Create new HistogramVec.

The HistogramVec is automatically registered to the prometheus.DefaultRegisterer.

func NewPutRequest

func NewPutRequest(url string, body io.Reader) (*http.Request, error)

Create PUT request

func NewRabbitChan

func NewRabbitChan() (*amqp.Channel, error)

Create new channel from the established connection

func NewSubmitAsyncFunc added in v0.0.30

func NewSubmitAsyncFunc[T any](pool *AsyncPool) func(task func() (T, error)) Future[T]

Create func that calls SubmitAsync(...) with the given pool.

func NewVar added in v0.0.26

func NewVar[T any]() T

func ObtainRLocker

func ObtainRLocker() *redislock.Client

Obtain a locker

func OpenFile added in v0.0.14

func OpenFile(name string, flag int) (*os.File, error)

Open file with 0666 permission.

func PTimeOp

func PTimeOp(start time.Time, name string)

Run timer for named operation and print result in log

e.g.,

defer PTimeOp(time.Now(), "someOperation")

func PadNum

func PadNum(n int, digit int) string

func ParseBearer added in v0.0.13

func ParseBearer(authorization string) (string, bool)

func ParseJson added in v0.0.4

func ParseJson(body []byte, ptr any) error

Parse JSON using jsoniter.

func ParseLogLevel

func ParseLogLevel(logLevel string) (logrus.Level, bool)

Parse log level

func PerfLogExclPath

func PerfLogExclPath(path string)

Ask PerfMiddleware to stop measuring perf of provided path

func PerfMiddleware

func PerfMiddleware() gin.HandlerFunc

Perf Middleware that calculates how much time each request takes

func Pick

func Pick(set []rune) rune

pick random rune from the slice

func PostJobExec added in v0.0.8

func PostJobExec(hook PostJobHook)

Callback triggered after job execution.

Other callbacks will still be executed even if one of them returns error.

Callback will be ignored, if the scheduler is already running.

func PostJson

func PostJson(url string, json string) (*http.Response, error)

Send POST request

func PostServerBootstrapped

func PostServerBootstrapped(callback func(rail Rail) error)

Add listener that is invoked when server is finally bootstrapped

This usually means all server components are started, such as MySQL connection, Redis Connection and so on.

Caller is free to call PostServerBootstrapped inside another PostServerBootstrapped callback.

func PreConfiguredFormatter

func PreConfiguredFormatter() logrus.Formatter

Get pre-configured TextFormatter for logrus

func PreJobExec added in v0.0.8

func PreJobExec(hook PreJobHook)

Callback triggered before job execution.

The job and other callbacks will still be executed even if one of the callback returns error.

Callback will be ignored, if the scheduler is already running.

func PreProcessGin added in v0.0.16

func PreProcessGin(preProcessor GinPreProcessor)

Process *gin.Engine before the web server starts, particularly useful when trying to add middleware.

func PreServerBootstrap

func PreServerBootstrap(callback func(rail Rail) error)

Add listener that is invoked before the server is fully bootstrapped

This usually means that the configuration is loaded, and the logging is configured, but the server components are not yet initialized.

Caller is free to call PostServerBootstrapped or PreServerBootstrap inside another PreServerBootstrap callback.

func PrepareWebStaticFs added in v0.0.29

func PrepareWebStaticFs(fs embed.FS, dir string)

Prepare to serve static files in embedded fs.

Static files are all served by paths with prefix '/static'.

Notice that index.html must be renamed to index.htm or else it won't work.

If you are using Angular framework, you may add extra build param as follows. The idea is still the same for other frameworks.

ng build --baseHref=/static/

func Printlnf added in v0.0.30

func Printlnf(pat string, args ...any)

func PrometheusBootstrap

func PrometheusBootstrap(rail Rail) error

func PrometheusBootstrapCondition added in v0.0.8

func PrometheusBootstrapCondition(rail Rail) (bool, error)

func PrometheusHandler

func PrometheusHandler() http.Handler

Default handler for prometheus metrics.

func PubEventBus

func PubEventBus(rail Rail, eventObject any, name string) error

Send msg to event bus.

It's identical to sending a message to an exchange identified by the name using routing key '#'.

Before calling this method, the NewEventBus(...) should be called at least once to create the necessary components.

func PublishJson

func PublishJson(c Rail, obj any, exchange string, routingKey string) error

Publish json message with confirmation

func PublishMsg

func PublishMsg(c Rail, msg []byte, exchange string, routingKey string, contentType string, headers map[string]any) error

Publish message with confirmation

func PublishText

func PublishText(c Rail, msg string, exchange string, routingKey string) error

Publish plain text message with confirmation

func RLockExec

func RLockExec(ec Rail, key string, runnable Runnable) error

Lock and run the runnable using Redis

The maximum time wait for the lock is 1s, retry every 5ms.

May return 'redislock.ErrNotObtained' when it fails to obtain the lock.

func RLockRun

func RLockRun[T any](rail Rail, key string, runnable LRunnable[T]) (T, error)

Lock and run the runnable using Redis

The maximum time wait for the lock is 1s, retry every 5ms.

May return 'redislock:ErrNotObtained' when it fails to obtain the lock.

func RabbitBootstrap

func RabbitBootstrap(rail Rail) error

func RabbitBootstrapCondition added in v0.0.8

func RabbitBootstrapCondition(rail Rail) (bool, error)

func RabbitConnected

func RabbitConnected() bool

Check if connection exists

func RabbitDisconnect

func RabbitDisconnect(rail Rail) error

Disconnect from RabbitMQ server

func RabbitMQEnabled

func RabbitMQEnabled() bool

Is RabbitMQ Enabled

func RandAlpha

func RandAlpha(n int) string

Generate random alphabetic string with specified length

the generated string will contains [a-zA-Z]

func RandLowerAlpha

func RandLowerAlpha(n int) string

Generate random alphabetic, lowercase string with specified length

the generated string will contains [a-z]

func RandLowerAlphaNumeric

func RandLowerAlphaNumeric(n int) string

Generate random alphabetic, lowercase string with specified length

the generated string will contains [a-z0-9]

func RandLowerAlphaNumeric16 added in v0.0.25

func RandLowerAlphaNumeric16() string

Same as RandLowerAlphaNumeric(16) but with less allocation.

func RandNum

func RandNum(n int) string

Generate random numeric string with specified length

the generated string will contains [0-9]

func RandStr

func RandStr(n int) string

Generate random string with specified length

the generated string will contains [a-zA-Z0-9]

ERand() is preferred for higher entrophy

func RandUpperAlpha

func RandUpperAlpha(n int) string

Generate random alphabetic, uppercase string with specified length

the generated string will contains [A-Z]

func RandUpperAlphaNumeric

func RandUpperAlphaNumeric(n int) string

Generate random alphabetic, uppercase string with specified length

the generated string will contains [A-Z0-9]

func RawAny

func RawAny(url string, handler RawTRouteHandler, extra ...StrPair)

Register ANY request route (raw version)

func ReadFileAll added in v0.0.22

func ReadFileAll(path string) ([]byte, error)

Read all content from file.

func ReadWriteFile added in v0.0.15

func ReadWriteFile(name string) (*os.File, error)

Create readable & writable file with 0666 permission.

func RedisBootstrap

func RedisBootstrap(rail Rail) error

func RedisBootstrapCondition added in v0.0.8

func RedisBootstrapCondition(rail Rail) (bool, error)

func RegisterBootstrapCallback

func RegisterBootstrapCallback(bootstrapComponent ComponentBootstrap)

Register server component bootstrap callback

When such callback is invoked, configuration should be fully loaded, the callback is free to read the loaded configuration and decide whether or not the server component should be initialized, e.g., by checking if the enable flag is true.

func RegisterConsulService added in v0.0.28

func RegisterConsulService() error

Register current instance as a service

If we have already registered before, current method call will be ignored.

This func looks for following prop:

"server.port"
"consul.registerName"
"consul.healthCheckInterval"
"consul.registerAddress"
"consul.healthCheckUrl"
"consul.healthCheckTimeout"
"consul.healthCheckFailedDeregisterAfter"

func RegisterRabbitBinding

func RegisterRabbitBinding(b BindingRegistration)

Declare binding on client initialization

func RegisterRabbitExchange

func RegisterRabbitExchange(e ExchangeRegistration)

Declare exchange on client initialization

func RegisterRabbitQueue

func RegisterRabbitQueue(q QueueRegistration)

Declare queue on client initialization

func ResolveArg

func ResolveArg(arg string) string

Resolve argument, e.g., for arg like '${someArg}', it will in fact look for 'someArg' in os.Env

func ResolveServerHost

func ResolveServerHost(address string) string

Resolve server host, use IPV4 if the given address is empty or '0.0.0.0'

func SWriteJson added in v0.0.29

func SWriteJson(body any) (string, error)

Write JSON as string using jsoniter.

func ScheduleCron

func ScheduleCron(job Job) error

add a cron job to scheduler, note that the cron expression includes second, e.g., '*/1 * * * * *'

this func doesn't start the scheduler

func ScheduleDistributedTask

func ScheduleDistributedTask(t Job) error

Schedule a named distributed task

Applications are grouped together as a cluster (each cluster is differentiated by its group name), only the master node can run the Scheduled tasks.

Tasks are pending until StartTaskSchedulerAsync() is called.

E.g.,

job := miso.Job{
	Name:            "Very important task",
	Cron:            "0/1 * * * * ?",
	CronWithSeconds: true,
	Run: MyTask,
}
ScheduleDistributedTask(job)

func SchedulerBootstrap

func SchedulerBootstrap(rail Rail) error

func SendGet

func SendGet(url string, headers map[string][]string) (*http.Response, error)

Send GET request

func SendPost

func SendPost(url string, body io.Reader) (*http.Response, error)

Send POST request

func ServeStatic added in v0.0.29

func ServeStatic(inb *Inbound, fs embed.FS, file string)

func ServeTempl added in v0.0.29

func ServeTempl(inb *Inbound, fs embed.FS, tmplName string, data any)

func SetDefProp

func SetDefProp(prop string, defVal any)

Set default value for the prop

func SetDefaultTimeout added in v0.0.6

func SetDefaultTimeout(ttl time.Duration)

Set default http client timeout

func SetEnv

func SetEnv(key string, val string)

Set environment variable

func SetLogLevel added in v0.0.8

func SetLogLevel(level string)

func SetMachineCode

func SetMachineCode(code int) error

Overwrite the randomly generated machine code, machine code must be between 0 and 999999, at most 6 digits.

func SetProp

func SetProp(prop string, val any)

Set value for the prop

func SetResultBodyBuilder added in v0.0.25

func SetResultBodyBuilder(rbb ResultBodyBuilder) error

Replace the default ResultBodyBuilder

func SetScheduleGroup

func SetScheduleGroup(groupName string)

Set the schedule group for current node, by default it's 'default'

func SetToSlice

func SetToSlice[T comparable](s Set[T]) []T

Copy keys of set

func ShuffleRunes

func ShuffleRunes(letters []rune, times int) []rune

func ShuffleStr

func ShuffleStr(letters string, times int) string

func Shutdown

func Shutdown()

Shutdown server

func SliceGetOne

func SliceGetOne[T any](items []*T) *T

Select random one from the slice

func Spaces added in v0.0.22

func Spaces(count int) string

func SprintMemStats added in v0.0.13

func SprintMemStats(ms runtime.MemStats) string

func SqliteBootstrap added in v0.0.8

func SqliteBootstrap(rail Rail) error

func SqliteBootstrapCondition added in v0.0.8

func SqliteBootstrapCondition(rail Rail) (bool, error)

func StartRabbitMqClient

func StartRabbitMqClient(rail Rail) error

Start RabbitMQ Client (synchronous for the first time, then auto-reconnect later in another goroutine)

This func will attempt to establish connection to broker, declare queues, exchanges and bindings.

Listeners are also created once the intial setup is done.

When connection is lost, it will attmpt to reconnect to recover, unless the given context is done.

To register listener, please use 'AddListener' func.

func StartSchedulerAsync

func StartSchedulerAsync()

Start scheduler asynchronously

func StartSchedulerBlocking

func StartSchedulerBlocking()

Start scheduler and block current routine

func StartTaskSchedulerAsync

func StartTaskSchedulerAsync(rail Rail) error

Start distributed scheduler asynchronously

func StartTaskSchedulerBlocking

func StartTaskSchedulerBlocking(rail Rail) error

Start distributed scheduler, current routine is blocked

func StopScheduler

func StopScheduler()

Stop scheduler

func StopTaskScheduler

func StopTaskScheduler()

Shutdown distributed job scheduling

func StrMap added in v0.0.3

func StrMap[T any, V any](l []T, keyMapper func(T) string, valueMapper func(T) V) map[string]V

Build a map with string type key and any type of value

func SubEventBus

func SubEventBus[T any](name string, concurrency int, listener func(rail Rail, t T) error)

Subscribe to event bus.

Internally, it calls NewEventBus(...) and registers a listener for the queue identified by the bus name.

func SubscribeServerChanges added in v0.0.19

func SubscribeServerChanges(rail Rail, name string, cbk func()) error

Subscribe to changes to service instances.

Callback is triggered asynchronously.

func TermOpenUrl added in v0.0.29

func TermOpenUrl(url string) error

func TimeOp

func TimeOp(r Rail, start time.Time, name string)

Run timer for named operation and print result in log

e.g.,

defer TimeOp(ec, time.Now(), "someOperation")

func ToStr added in v0.0.9

func ToStr(v any) string

func TraceLogger

func TraceLogger(ctx context.Context) *logrus.Entry

Return logger with tracing infomation

func TraceMiddleware

func TraceMiddleware() gin.HandlerFunc

Tracing Middleware

func TraceRequest

func TraceRequest(ctx context.Context, req *http.Request) *http.Request

Wraper request with tracing key/value pairs on http headers

func Tracef added in v0.0.12

func Tracef(format string, args ...interface{})

func TypeName added in v0.0.25

func TypeName(t reflect.Type) string

func UnmarshalFromProp

func UnmarshalFromProp(ptr any)

Unmarshal configuration.

func UnmarshalFromPropKey added in v0.0.22

func UnmarshalFromPropKey(key string, ptr any)

Unmarshal configuration from a speicific key.

func UnsafeByt2Str added in v0.0.26

func UnsafeByt2Str(b []byte) string

Convert []byte to string without alloc.

Both the []byte and the string share the same memory.

Any modification on the original []byte is reflected on the returned string.

byt = []byte("abc")
s = UnsafeByt2Str(byt) // "abc" using the same memory
byt[0] = 'd' // modified in place at 0, also reflected on s ("dbc")

Tricks from https://github.com/valyala/fasthttp.

func UnsafeStr2Byt added in v0.0.26

func UnsafeStr2Byt(s string) (b []byte)

Convert string to []byte without alloc.

Both the []byte and the string share the same memory.

The resulting []byte is not modifiable, program will panic if modified.

s := "abc"
byt := UnsafeStr2Byt(s) // "abc" but in []byte
byt[0] = 'd' // will panic

Tricks from https://github.com/valyala/fasthttp.

func UsePropagationKeys added in v0.0.25

func UsePropagationKeys(forEach func(key string))

func Validate

func Validate(target any) error

Validate target object based on the validation rules specified by tags 'valid:"[RULE]"'.

Available Rules:

  • maxLen
  • notEmpty
  • notNil
  • positive
  • positiveOrZero
  • negative
  • negativeOrZero
  • notZero
  • validated

func ValidateIntRule

func ValidateIntRule(ival int64, rule string, fname string, param string) error

func ValidateIssuer

func ValidateIssuer() jwt.ParserOption

func ValidateRule

func ValidateRule(field reflect.StructField, value reflect.Value, rule string, ruleParam string) error

func WalkTagShallow added in v0.0.26

func WalkTagShallow(ptr any, callbacks ...WalkTagCallback) error

Walk fields of *struct, won't go deeper even if the field is a struct.

func Warn added in v0.0.8

func Warn(args ...interface{})

func Warnf added in v0.0.8

func Warnf(format string, args ...interface{})

func WebServerBootstrap

func WebServerBootstrap(rail Rail) error

func WebServerBootstrapCondition added in v0.0.8

func WebServerBootstrapCondition(rail Rail) (bool, error)

func WriteJson added in v0.0.4

func WriteJson(body any) ([]byte, error)

Write JSON using jsoniter.

Types

type AsyncPool added in v0.0.14

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

A long live, bounded pool of goroutines.

Use miso.NewAsyncPool to create a new pool.

AsyncPool internally maintains a task queue with limited size and limited number of workers. If the task queue is full, the caller of *AsyncPool.Go is blocked indefinitively.

func NewAsyncPool added in v0.0.14

func NewAsyncPool(maxTasks int, maxWorkers int) *AsyncPool

Create a bounded pool of goroutines.

The maxTasks determines the capacity of the task queues. If the task queue is full, the caller of *AsyncPool.Go is blocked.

The maxWorkers determines the max number of workers.

func (*AsyncPool) Go added in v0.0.14

func (p *AsyncPool) Go(f func())

Submit task to the pool.

If the task queue is full, the caller is blocked.

If the pool is closed, return ErrAsyncPoolClosed.

type AwaitFutures added in v0.0.18

type AwaitFutures[T any] struct {
	// contains filtered or unexported fields
}

AwaitFutures represent multiple tasks that will be submitted to the pool asynchronously whose results will be awaited together.

AwaitFutures should only be used once everytime it's needed.

Use miso.NewAwaitFutures() to create one.

func NewAwaitFutures added in v0.0.18

func NewAwaitFutures[T any](pool *AsyncPool) *AwaitFutures[T]

func (*AwaitFutures[T]) Await added in v0.0.18

func (a *AwaitFutures[T]) Await() []Future[T]

func (*AwaitFutures[T]) SubmitAsync added in v0.0.18

func (a *AwaitFutures[T]) SubmitAsync(task func() (T, error))

type BindingRegistration

type BindingRegistration struct {
	Queue      string
	RoutingKey string
	Exchange   string
}

type CTFormatter

type CTFormatter struct {
}

func (*CTFormatter) Format

func (c *CTFormatter) Format(entry *logrus.Entry) ([]byte, error)

type ComponentBootstrap

type ComponentBootstrap struct {
	// name of the component.
	Name string
	// the actual bootstrap function.
	Bootstrap func(rail Rail) error
	// check whether component should be bootstraped
	Condition func(rail Rail) (bool, error)
	// order of which the components are bootstraped, natural order, it's by default 15.
	Order int
}

type ConsulApiImpl added in v0.0.6

type ConsulApiImpl struct{}

func (ConsulApiImpl) CatalogFetchServiceNames added in v0.0.6

func (c ConsulApiImpl) CatalogFetchServiceNames(rail Rail) (map[string][]string, error)

Fetch all registered services, this method always call Consul instead of reading from cache

func (ConsulApiImpl) CatalogFetchServiceNodes added in v0.0.6

func (c ConsulApiImpl) CatalogFetchServiceNodes(rail Rail, name string) ([]*api.CatalogService, error)

Fetch registered service by name, this method always call Consul instead of reading from cache

func (ConsulApiImpl) DeregisterService added in v0.0.6

func (c ConsulApiImpl) DeregisterService(serviceId string) error

func (ConsulApiImpl) RegisterService added in v0.0.12

func (c ConsulApiImpl) RegisterService(registration *api.AgentServiceRegistration) error

type ConsulServerList added in v0.0.28

type ConsulServerList struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

Holder of a list of ServiceHolder

func (*ConsulServerList) IsSubscribed added in v0.0.28

func (s *ConsulServerList) IsSubscribed(rail Rail, service string) bool

func (*ConsulServerList) ListServers added in v0.0.28

func (s *ConsulServerList) ListServers(rail Rail, name string) []Server

func (*ConsulServerList) PollInstance added in v0.0.28

func (s *ConsulServerList) PollInstance(rail Rail, name string) error

Fetch and cache services nodes.

func (*ConsulServerList) PollInstances added in v0.0.28

func (s *ConsulServerList) PollInstances(rail Rail) error

func (*ConsulServerList) Subscribe added in v0.0.28

func (s *ConsulServerList) Subscribe(rail Rail, service string) error

func (*ConsulServerList) Unsubscribe added in v0.0.28

func (s *ConsulServerList) Unsubscribe(rail Rail, service string) error

func (*ConsulServerList) UnsubscribeAll added in v0.0.28

func (s *ConsulServerList) UnsubscribeAll(rail Rail) error

type Consumer

type Consumer[T any] func(t T) error

Consume t

type Converter

type Converter[T any, V any] func(t T) (V, error)

Convert t to v

type ETime

type ETime time.Time

EpochTime, same as time.Time but will be serialized/deserialized as epoch milliseconds

This type can be safely used in GORM just like time.Time

func Now

func Now() ETime

func (ETime) FormatClassic

func (t ETime) FormatClassic() string

func (ETime) FormatClassicLocale added in v0.0.9

func (t ETime) FormatClassicLocale() string

func (ETime) MarshalJSON

func (t ETime) MarshalJSON() ([]byte, error)

func (*ETime) Scan

func (et *ETime) Scan(value interface{}) error

Implements sql.Scanner in database/sql.

func (ETime) String

func (t ETime) String() string

func (ETime) ToTime

func (t ETime) ToTime() time.Time

func (ETime) UnixMilli

func (t ETime) UnixMilli() int64

func (*ETime) UnmarshalJSON

func (t *ETime) UnmarshalJSON(b []byte) error

implements decorder.Unmarshaler in encoding/json.

func (ETime) Value

func (et ETime) Value() (driver.Value, error)

Implements driver.Valuer in database/sql.

type EventPipeline added in v0.0.26

type EventPipeline[T any] struct {
	// contains filtered or unexported fields
}

EventPipeline is a thin wrapper of NewEventBus, SubEventBus and PubEventBus. It's used to make things easier and more consistent.

Use NewEventPipeline to instantiate.

func NewEventPipeline added in v0.0.26

func NewEventPipeline[T any](name string) EventPipeline[T]

Create new EventPipeline. NewEventBus is internally called as well.

func (*EventPipeline[T]) Listen added in v0.0.26

func (ep *EventPipeline[T]) Listen(concurrency int, listener func(rail Rail, t T) error)

Call SubEventBus.

func (*EventPipeline[T]) Name added in v0.0.27

func (ep *EventPipeline[T]) Name() string

func (*EventPipeline[T]) Send added in v0.0.26

func (ep *EventPipeline[T]) Send(rail Rail, event T) error

Call PubEventBus.

type ExchangeRegistration

type ExchangeRegistration struct {
	Name       string
	Kind       string
	Durable    bool
	Properties map[string]any
}

type ForEachField

type ForEachField func(index int, field reflect.StructField) (breakIteration bool)

type Future

type Future[T any] interface {
	Get() (T, error)
	TimedGet(timeout int) (T, error)
}

func RunAsync

func RunAsync[T any](task func() (T, error)) Future[T]

Create Future, once the future is created, it starts running on a new goroutine.

func SubmitAsync added in v0.0.18

func SubmitAsync[T any](pool *AsyncPool, task func() (T, error)) Future[T]

Create Future, once the future is created, it starts running on a saperate goroutine from the pool.

type GinPreProcessor added in v0.0.16

type GinPreProcessor func(rail Rail, engine *gin.Engine)

Preprocessor of *gin.Engine.

type GnResp

type GnResp[T any] struct {
	ErrorCode string `json:"errorCode" desc:"error code"`
	Msg       string `json:"msg" desc:"message"`
	Error     bool   `json:"error" desc:"whether the request was successful"`
	Data      T      `json:"data" desc:"response data"`
}

Generic version of Resp

func OkGnResp added in v0.0.25

func OkGnResp[T any](data T) GnResp[T]

func WrapGnResp added in v0.0.25

func WrapGnResp[T any](data T, err error) (GnResp[T], error)

func (GnResp[T]) Err

func (r GnResp[T]) Err() error

func (GnResp[T]) MappedRes added in v0.0.15

func (r GnResp[T]) MappedRes(mapper map[string]error) (T, error)

func (GnResp[T]) Res added in v0.0.3

func (r GnResp[T]) Res() (T, error)

func (GnResp[T]) Unwrap added in v0.0.25

func (r GnResp[T]) Unwrap() Resp

type HardcodedServiceRegistry added in v0.0.14

type HardcodedServiceRegistry struct {
}

Service registry backed by loaded configuration.

func (HardcodedServiceRegistry) ListServers added in v0.0.14

func (r HardcodedServiceRegistry) ListServers(rail Rail, service string) ([]Server, error)

func (HardcodedServiceRegistry) ResolveUrl added in v0.0.14

func (r HardcodedServiceRegistry) ResolveUrl(rail Rail, service string, relativeUrl string) (string, error)

type HealthIndicator added in v0.0.6

type HealthIndicator struct {
	Name        string               // name of the indicator
	CheckHealth func(rail Rail) bool // Check health
}

Indicator of health status

type HealthStatus added in v0.0.6

type HealthStatus struct {
	Name    string
	Healthy bool
}

func CheckHealth added in v0.0.6

func CheckHealth(rail Rail) []HealthStatus

Check health status.

type HistTimer added in v0.0.13

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

Timer based on prometheus.Histogram.

Duration is measured in millisecond.

Use NewHistTimer to create a new one, and each timer can only be used for once.

func NewHistTimer added in v0.0.13

func NewHistTimer(hist prometheus.Histogram) *HistTimer

Create new timer that is backed by a prometheus.Histogram. Each timer can only be used for once.

func (*HistTimer) ObserveDuration added in v0.0.13

func (t *HistTimer) ObserveDuration() time.Duration

func (*HistTimer) Reset added in v0.0.25

func (t *HistTimer) Reset()

type HttpRoute

type HttpRoute struct {
	Url             string
	Method          string
	Extra           map[string][]any
	Desc            string     // description of the route (metadata).
	Scope           string     // the documented access scope of the route, it maybe "PUBLIC" or something else (metadata).
	Resource        string     // the documented resource that the route should be bound to (metadata).
	Headers         []ParamDoc // the documented header parameters that will be used by the endpoint (metadata).
	QueryParams     []ParamDoc // the documented query parameters that will used by the endpoint (metadata).
	JsonRequestVal  any        // the documented json request value that is expected by the endpoint (metadata).
	JsonResponseVal any        // the documented json response value that will be returned by the endpoint (metadata).
}

func GetHttpRoutes

func GetHttpRoutes() []HttpRoute

Get recorded http server routes

type HttpRouteDoc added in v0.0.23

type HttpRouteDoc struct {
	Url              string
	Method           string
	Extra            map[string][]any
	Desc             string     // description of the route (metadata).
	Scope            string     // the documented access scope of the route, it maybe "PUBLIC" or something else (metadata).
	Resource         string     // the documented resource that the route should be bound to (metadata).
	Headers          []ParamDoc // the documented header parameters that will be used by the endpoint (metadata).
	QueryParams      []ParamDoc // the documented query parameters that will used by the endpoint (metadata).
	JsonRequestDesc  []jsonDesc // the documented json request type that is expected by the endpoint (metadata).
	JsonResponseDesc []jsonDesc // the documented json response type that will be returned by the endpoint (metadata).
	Curl             string
}

type Inbound added in v0.0.26

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

Inbound request context.

Inbound hides the underlying engine (e.g., *gin.Context) using .Engine() method. In most cases, you should not attempt to cast the engine explictly, it's possible that miso will replace the engine in future release.

However, you should be able to satisfy most of your need by calling .Unwrap(), that returns the underlying http.ResponseWriter, *http.Request.

Use miso.Rail for tracing (not just logs), pass it around your application code and the code calling miso's methods course.

func (*Inbound) AddHeader added in v0.0.26

func (i *Inbound) AddHeader(k string, v string)

func (*Inbound) Engine added in v0.0.26

func (i *Inbound) Engine() any

func (*Inbound) HandleResult added in v0.0.26

func (i *Inbound) HandleResult(result any, err error)

Handle the result using universally configured handler.

The result or error is written back to the client. In most cases, caller must exit the handler after calling this method. Theoritically, this method is only useful for RawGet, RawPut, RawPost, RawDelete. Other methods, such as IGet, IPost, Post, Put or Delete, handle the results automatically in exactly the same way.

E.g.,

miso.RawGet("/dir/info", func(inb *miso.Inbound) {
	// ... do something

	if err != nil {
		inb.HandleResult(nil, err) // something goes wrong
		return
	}

	// return result back to the client
	inb.HandleResult(result, err)
})

func (*Inbound) Header added in v0.0.26

func (i *Inbound) Header(k string) string

func (*Inbound) Query added in v0.0.26

func (i *Inbound) Query(k string) string

func (*Inbound) Rail added in v0.0.26

func (i *Inbound) Rail() Rail

func (*Inbound) SetHeader added in v0.0.26

func (i *Inbound) SetHeader(k string, v string)

func (*Inbound) Status added in v0.0.26

func (i *Inbound) Status(status int)

func (*Inbound) Unwrap added in v0.0.26

func (i *Inbound) Unwrap() (http.ResponseWriter, *http.Request)

type Introspector

type Introspector struct {
	Type   reflect.Type
	Fields []reflect.StructField
	// contains filtered or unexported fields
}

func Introspect

func Introspect(ptr any) Introspector

Create new Introspector

func (*Introspector) Field

func (it *Introspector) Field(fieldName string) (field reflect.StructField, isFieldFound bool)

Get field by name

func (*Introspector) FieldAt

func (it *Introspector) FieldAt(idx int) (field reflect.StructField)

Get field at index

func (*Introspector) FieldIdx

func (it *Introspector) FieldIdx(fieldName string) (index int, isFieldFound bool)

Get field index

func (*Introspector) IterFields

func (it *Introspector) IterFields(forEach ForEachField)

Iterate fields

func (*Introspector) Tag

func (it *Introspector) Tag(fieldName string, tagName string) (tag string, isFieldFound bool)

Get tag by of field

func (*Introspector) TagRetriever

func (it *Introspector) TagRetriever(fieldName string) (t TagRetriever, isFieldFound bool)

Get tag retriever for a field

type Job added in v0.0.8

type Job struct {
	Name                   string           // name of the job.
	Cron                   string           // cron expr.
	CronWithSeconds        bool             // whether cron expr contains the second field.
	Run                    func(Rail) error // actual job execution logic.
	LogJobExec             bool             // whether job execution should be logged, error msg is always logged and is not affected by this option.
	TriggeredOnBoostrapped bool             // whether job should be triggered when server is fully bootstrapped
}

type JobExecStats added in v0.0.8

type JobExecStats struct {
	Time time.Duration
	Err  error
}

type JobInf added in v0.0.8

type JobInf struct {
	Name            string
	Cron            string
	CronWithSeconds bool
}

type JsonMsgListener

type JsonMsgListener[T any] struct {
	QueueName     string
	Handler       func(rail Rail, payload T) error
	NumOfRoutines int
}

Json Message Listener for Queue

func (JsonMsgListener[T]) Concurrency

func (m JsonMsgListener[T]) Concurrency() int

func (JsonMsgListener[T]) Handle

func (m JsonMsgListener[T]) Handle(rail Rail, payload string) error

func (JsonMsgListener[T]) Queue

func (m JsonMsgListener[T]) Queue() string

func (JsonMsgListener[T]) String

func (m JsonMsgListener[T]) String() string

type JsonSerializer added in v0.0.18

type JsonSerializer struct {
}

func (JsonSerializer) Deserialize added in v0.0.18

func (j JsonSerializer) Deserialize(ptr any, v string) error

func (JsonSerializer) Serialize added in v0.0.18

func (j JsonSerializer) Serialize(t any) (string, error)

type LRunnable

type LRunnable[T any] func() (T, error)

type LazyRouteDecl added in v0.0.23

type LazyRouteDecl struct {
	Url     string
	Method  string
	Handler func(c *gin.Context)

	RegisterFunc func(extra ...StrPair)
	Extras       []StrPair
}

Lazy route declaration

func Delete

func Delete[Res any](url string, handler TRouteHandler[Res]) *LazyRouteDecl

Register DELETE request.

The result and error are automatically wrapped to miso.Resp (see miso.SetResultBodyBuilder func) and serialized to json.

func Get

func Get[Res any](url string, handler TRouteHandler[Res]) *LazyRouteDecl

Register GET request.

The result and error are automatically wrapped to miso.Resp (see miso.SetResultBodyBuilder func) and serialized to json.

func IDelete

func IDelete[Req any, Res any](url string, handler MappedTRouteHandler[Req, Res]) *LazyRouteDecl

Register DELETE request.

Req type should be a struct, where all fields are automatically mapped from the request using 'json' tag or 'form' tag (for form-data, query param) or 'header' tag (only supports string/*string).

Res type should be a struct. By default both Res value and error (if not nil) will be wrapped inside miso.Resp and serialized to json. Wrapping to miso.Resp is customizable using miso.SetResultBodyBuilder func.

With both Req and Res type declared, miso will automatically parse these two types using reflect and generate an API documentation describing the endpoint.

func IGet

func IGet[Req any, Res any](url string, handler MappedTRouteHandler[Req, Res]) *LazyRouteDecl

Register GET request.

Req type should be a struct, where all fields are automatically mapped from the request using 'form' tag (for form-data, query param) or 'header' tag (only supports string/*string).

Res type should be a struct. By default both Res value and error (if not nil) will be wrapped inside miso.Resp and serialized to json. Wrapping to miso.Resp is customizable using miso.SetResultBodyBuilder func.

With both Req and Res type declared, miso will automatically parse these two types using reflect and generate an API documentation describing the endpoint.

func IPost

func IPost[Req any, Res any](url string, handler MappedTRouteHandler[Req, Res]) *LazyRouteDecl

Register POST request.

Req type should be a struct, where all fields are automatically mapped from the request using 'json' tag or 'form' tag (for form-data, query param) or 'header' tag (only supports string/*string).

Res type should be a struct. By default both Res value and error (if not nil) will be wrapped inside miso.Resp and serialized to json. Wrapping to miso.Resp is customizable using miso.SetResultBodyBuilder func.

With both Req and Res type declared, miso will automatically parse these two types using reflect and generate an API documentation describing the endpoint.

func IPut

func IPut[Req any, Res any](url string, handler MappedTRouteHandler[Req, Res]) *LazyRouteDecl

Register PUT request.

Req type should be a struct, where all fields are automatically mapped from the request using 'json' tag or 'form' tag (for form-data, query param) or 'header' tag (only supports string/*string).

Res type should be a struct. By default both Res value and error (if not nil) will be wrapped inside miso.Resp and serialized to json. Wrapping to miso.Resp is customizable using miso.SetResultBodyBuilder func.

With both Req and Res type declared, miso will automatically parse these two types using reflect and generate an API documentation describing the endpoint.

func NewLazyRouteDecl added in v0.0.23

func NewLazyRouteDecl(url string, method string, handler func(c *gin.Context)) *LazyRouteDecl

func Post

func Post[Res any](url string, handler TRouteHandler[Res]) *LazyRouteDecl

Register POST request.

The result and error are automatically wrapped to miso.Resp (see miso.SetResultBodyBuilder func) and serialized to json.

func Put

func Put[Res any](url string, handler TRouteHandler[Res]) *LazyRouteDecl

Register PUT request.

The result and error are automatically wrapped to miso.Resp (see miso.SetResultBodyBuilder func) and serialized to json.

func RawDelete

func RawDelete(url string, handler RawTRouteHandler) *LazyRouteDecl

Register DELETE request route (raw version)

func RawGet

func RawGet(url string, handler RawTRouteHandler) *LazyRouteDecl

Register GET request route (raw version)

func RawPost

func RawPost(url string, handler RawTRouteHandler) *LazyRouteDecl

Register POST request route (raw version)

func RawPut

func RawPut(url string, handler RawTRouteHandler) *LazyRouteDecl

Register PUT request route (raw version)

func (*LazyRouteDecl) Desc added in v0.0.23

func (g *LazyRouteDecl) Desc(desc string) *LazyRouteDecl

Add endpoint description (only serves as metadata that maybe used by some plugins).

func (*LazyRouteDecl) DocHeader added in v0.0.23

func (g *LazyRouteDecl) DocHeader(headerName string, desc string) *LazyRouteDecl

Document header parameter that the endpoint will use (only serves as metadata that maybe used by some plugins).

func (*LazyRouteDecl) DocHeaderReq added in v0.0.26

func (g *LazyRouteDecl) DocHeaderReq(v any) *LazyRouteDecl

Document header parameters that the endpoint expects (only serves as metadata that maybe used by some plugins).

func (*LazyRouteDecl) DocJsonReq added in v0.0.23

func (g *LazyRouteDecl) DocJsonReq(v any) *LazyRouteDecl

Document json request that the endpoint expects (only serves as metadata that maybe used by some plugins).

func (*LazyRouteDecl) DocJsonResp added in v0.0.23

func (g *LazyRouteDecl) DocJsonResp(v any) *LazyRouteDecl

Document json response that the endpoint returns (only serves as metadata that maybe used by some plugins).

func (*LazyRouteDecl) DocQueryParam added in v0.0.23

func (g *LazyRouteDecl) DocQueryParam(queryName string, desc string) *LazyRouteDecl

Document query parameter that the endpoint will use (only serves as metadata that maybe used by some plugins).

func (*LazyRouteDecl) DocQueryReq added in v0.0.25

func (g *LazyRouteDecl) DocQueryReq(v any) *LazyRouteDecl

Document query parameters that the endpoint expects (only serves as metadata that maybe used by some plugins).

func (*LazyRouteDecl) Extra added in v0.0.23

func (g *LazyRouteDecl) Extra(key string, value any) *LazyRouteDecl

Add extra info to endpoint's metadata.

func (*LazyRouteDecl) Prepend added in v0.0.23

func (g *LazyRouteDecl) Prepend(baseUrl string)

func (*LazyRouteDecl) Protected added in v0.0.23

func (g *LazyRouteDecl) Protected() *LazyRouteDecl

Documents that the endpoint requires protection (only serves as metadata that maybe used by some plugins).

func (*LazyRouteDecl) Public added in v0.0.23

func (g *LazyRouteDecl) Public() *LazyRouteDecl

Mark endpoint publicly accessible (only serves as metadata that maybe used by some plugins).

func (*LazyRouteDecl) Resource added in v0.0.23

func (g *LazyRouteDecl) Resource(resource string) *LazyRouteDecl

Record the resource that the endppoint should be bound to (only serves as metadata that maybe used by some plugins).

type LocalCache

type LocalCache[T any] map[string]T

Simple local map-based cache.

This should not be a long-live object.

func NewLocalCache

func NewLocalCache[T any]() LocalCache[T]

create new LocalCache with key of type string and value of type T.

func (LocalCache[T]) Get

func (lc LocalCache[T]) Get(key string, supplier func(string) (T, error)) (T, error)

get cached value identified by the key, if absent, call the supplier func instead, and cache and return the supplied value.

type MappedTRouteHandler

type MappedTRouteHandler[Req any, Res any] func(inb *Inbound, req Req) (Res, error)

Traced and parameters mapped route handler.

Req type should be a struct, where all fields are automatically mapped from the request using 'json' tag or 'form' tag (for form-data, query param) or 'header' tag (only supports string/*string).

Res type should be a struct. By default both Res value and error (if not nil) will be wrapped inside miso.Resp and serialized to json. Wrapping to miso.Resp is customizable using miso.SetResultBodyBuilder func.

With both Req and Res type declared, miso will automatically parse these two types using reflect and generate an API documentation describing the endpoint.

type MetricsCollector added in v0.0.13

type MetricsCollector struct {
	Desc      []metrics.Description
	Samples   []metrics.Sample
	SampleMap map[string]*metrics.Sample
	// contains filtered or unexported fields
}

Collector of runtime/metrics.

Use NewMetricsCollector() to create a new collector, the collector is thread-safe. Periodically call Read() to load metrics from runtime. Once the metrics are loaded, you can either use Value() or MemStats() func to access the values that you are interested in.

func NewMetricsCollector added in v0.0.13

func NewMetricsCollector(descs []metrics.Description) MetricsCollector

Create new MetricsCollector.

MetricsCollector only supports Uint64 metrics, those that are not Uint64 kind, are simply ignored.

func (*MetricsCollector) MemStats added in v0.0.13

func (m *MetricsCollector) MemStats() runtime.MemStats

func (*MetricsCollector) Read added in v0.0.13

func (m *MetricsCollector) Read()

func (*MetricsCollector) Value added in v0.0.13

func (m *MetricsCollector) Value(name string) uint64

type MisoErr added in v0.0.3

type MisoErr struct {
	Code        string // error code.
	Msg         string // error message returned to the client requested to the endpoint.
	InternalMsg string // internal message that is only logged on server.
}

Miso Error.

Use NewErrf(...) to instantiate.
var (
	// Error that represents None or Nil.
	//
	// Use miso.IsNoneErr(err) to check if an error represents None.
	NoneErr *MisoErr = NewErrf("none")
)

func NewErrf added in v0.0.22

func NewErrf(msg string, args ...any) *MisoErr

Create new MisoErr with message.

func (*MisoErr) Error added in v0.0.3

func (e *MisoErr) Error() string

func (*MisoErr) HasCode added in v0.0.6

func (e *MisoErr) HasCode() bool

func (*MisoErr) Is added in v0.0.25

func (e *MisoErr) Is(target error) bool

Implements *MisoErr Is check.

Returns true, if both are *MisoErr and the code matches.

WithInternalMsg always create new error, so we can basically reuse the same error created using 'miso.NewErrf(...).WithCode(...)'

var ErrIllegalArgument = miso.NewErrf(...).WithCode(...)

var e1 = ErrIllegalArgument.WithInternalMsg(...)
var e2 = ErrIllegalArgument.WithInternalMsg(...)

errors.Is(e1, ErrIllegalArgument)
errors.Is(e2, ErrIllegalArgument)

func (*MisoErr) WithCode added in v0.0.22

func (e *MisoErr) WithCode(code string) *MisoErr

func (*MisoErr) WithInternalMsg added in v0.0.22

func (e *MisoErr) WithInternalMsg(msg string, args ...any) *MisoErr

type MsgListener

type MsgListener struct {
	QueueName     string
	Handler       func(rail Rail, payload string) error
	NumOfRoutines int
}

Message Listener for Queue

func (MsgListener) Concurrency

func (m MsgListener) Concurrency() int

func (MsgListener) Handle

func (m MsgListener) Handle(rail Rail, payload string) error

func (MsgListener) Queue

func (m MsgListener) Queue() string

func (MsgListener) String

func (m MsgListener) String() string

type MySQLBootstrapCallback added in v0.0.28

type MySQLBootstrapCallback func(rail Rail, db *gorm.DB) error

type MySQLConnParam added in v0.0.14

type MySQLConnParam struct {
	User            string
	Password        string
	Schema          string
	Host            string
	Port            int
	ConnParam       string
	MaxConnLifetime time.Duration
	MaxOpenConns    int
	MaxIdleConns    int
}

type NewRollingLogFileParam

type NewRollingLogFileParam struct {
	Filename   string // filename
	MaxSize    int    // max file size in mb
	MaxAge     int    // max age in day
	MaxBackups int    // max number of files
}

type Opt added in v0.0.25

type Opt[T any] struct {
	Val       T
	IsPresent bool
}

Optional value, useful for passing zero value struct

func EmptyOpt

func EmptyOpt[T any]() Opt[T]

Empty Optional

func OptWith

func OptWith[T any](t T) Opt[T]

Optional with value present

func (*Opt[T]) Get added in v0.0.25

func (o *Opt[T]) Get() (T, bool)

func (*Opt[T]) IfPresent added in v0.0.25

func (o *Opt[T]) IfPresent(call func(t T))

type OrderedShutdownHook added in v0.0.23

type OrderedShutdownHook struct {
	Hook  func()
	Order int
}

type PageQueryBuilder added in v0.0.3

type PageQueryBuilder func(tx *gorm.DB) *gorm.DB

type PageRes

type PageRes[T any] struct {
	Page    Paging `json:"paging" desc:"pagination parameters"`
	Payload []T    `json:"payload" desc:"payload values in current page"`
}

func QueryPage

func QueryPage[Res any](rail Rail, tx *gorm.DB, p QueryPageParam[Res]) (PageRes[Res], error)

Execute paged query.

COUNT query is called first, if none is found (i.e., COUNT(...) == 0), this method will not call the actual SELECT query to avoid unnecessary performance lost.

type Paging

type Paging struct {
	Limit int `json:"limit" desc:"page limit"`
	Page  int `json:"page" desc:"page number, 1-based"`
	Total int `json:"total" desc:"total count"`
}

func RespPage

func RespPage(reqPage Paging, total int) Paging

Build Paging for response

func (Paging) GetLimit

func (p Paging) GetLimit() int

func (Paging) GetOffset

func (p Paging) GetOffset() int

func (Paging) GetPage

func (p Paging) GetPage() int

func (Paging) ToRespPage

func (p Paging) ToRespPage(total int) Paging

type Pair

type Pair struct {
	Left  any
	Right any
}

Pair data structure

type ParamDoc added in v0.0.22

type ParamDoc struct {
	Name string
	Desc string
}

type ParsedJwt

type ParsedJwt struct {
	Valid  bool
	Claims jwt.MapClaims
}

func JwtDecode

func JwtDecode(token string) (ParsedJwt, error)

type Peek

type Peek[T any] func(t T)

Peek t

type PostJobHook added in v0.0.8

type PostJobHook func(rail Rail, inf JobInf, stats JobExecStats) error

Hook triggered after job's execution.

type PreJobHook added in v0.0.8

type PreJobHook func(rail Rail, inf JobInf) error

Hook triggered before job's execution.

type Predicate

type Predicate[T any] func(t T) bool

Predicate based on t

type PropagationKeys

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

type QueryPageParam

type QueryPageParam[V any] struct {
	// contains filtered or unexported fields
}

Create param for page query.

func NewPageQuery added in v0.0.26

func NewPageQuery[Res any]() *QueryPageParam[Res]

func (*QueryPageParam[V]) Exec added in v0.0.26

func (q *QueryPageParam[V]) Exec(rail Rail, tx *gorm.DB) (PageRes[V], error)

Execute paging query

func (*QueryPageParam[V]) ForEach

func (q *QueryPageParam[V]) ForEach(t Transform[V]) *QueryPageParam[V]

func (*QueryPageParam[V]) WithBaseQuery added in v0.0.26

func (q *QueryPageParam[V]) WithBaseQuery(qry PageQueryBuilder) *QueryPageParam[V]

func (*QueryPageParam[V]) WithPage added in v0.0.26

func (q *QueryPageParam[V]) WithPage(p Paging) *QueryPageParam[V]

func (*QueryPageParam[V]) WithSelectQuery added in v0.0.26

func (q *QueryPageParam[V]) WithSelectQuery(qry PageQueryBuilder) *QueryPageParam[V]

type QueueRegistration

type QueueRegistration struct {
	Name    string
	Durable bool
}

type RCache

type RCache[T any] struct {
	ValueSerializer Serializer // serializer / deserializer
	// contains filtered or unexported fields
}

Redis Cache implementation.

RCache internal isn't backed by an actual redis HSet. Cache name is simply the prefix for each key, and each key is stored independently.

Use NewRCache(...) to instantiate.

func NewRCache

func NewRCache[T any](name string, conf RCacheConfig) RCache[T]

Create new RCache

func (*RCache[T]) Del

func (r *RCache[T]) Del(rail Rail, key string) error

func (*RCache[T]) DelAll added in v0.0.19

func (r *RCache[T]) DelAll(rail Rail) error

func (*RCache[T]) Exists added in v0.0.18

func (r *RCache[T]) Exists(rail Rail, key string) (bool, error)

func (*RCache[T]) Get

func (r *RCache[T]) Get(rail Rail, key string, supplier func() (T, error)) (T, error)

Get from cache else run supplier

Return miso.NoneErr if none is found

func (*RCache[T]) Put

func (r *RCache[T]) Put(rail Rail, key string, t T) error

type RCacheConfig added in v0.0.8

type RCacheConfig struct {
	//expire time for each entry
	Exp time.Duration

	// Disable use of distributed lock to synchronize access to the key in the cache.
	//
	// Most of the operations are atomic except Get(...) with supplier callback.
	// If your are loading the cache manually using Put(...), then you probably don't need synchronization at all.
	NoSync bool
}

Configuration of RCache.

type RLock added in v0.0.3

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

RLock

func NewCustomRLock added in v0.0.3

func NewCustomRLock(rail Rail, key string, config RLockConfig) *RLock

Create customized RLock.

func NewRLock added in v0.0.3

func NewRLock(rail Rail, key string) *RLock

Create new RLock with default backoff configuration (5ms backoff window, 1000 attempts, i.e., retry for 5s).

func NewRLockf added in v0.0.5

func NewRLockf(rail Rail, keyPattern string, args ...any) *RLock

Create new RLock with default backoff configuration (5ms backoff window, 1000 attempts, i.e., retry for 5s).

func (*RLock) Lock added in v0.0.3

func (r *RLock) Lock() error

Acquire lock.

func (*RLock) Unlock added in v0.0.3

func (r *RLock) Unlock() error

Attempt to Unlock.

If the lock is not obtained, method call will be ignored.

type RLockConfig added in v0.0.3

type RLockConfig struct {
	// Backoff duration.
	//
	// This is not an exact configuration. Linear back off strategy is used with a window size of 5ms, which means RLock will attempt to acquire the lock every 5ms.
	//
	// The number of times we may attempt to acquire the lock is called steps, which is by default 200 (that's 1s = 200 * 5ms).
	// When BackoffDuration is provided, this duration is divided by 5ms to convert to steps and then used by RLock.
	BackoffDuration time.Duration
}

RLock Configuration.

type RString

type RString []rune

func (RString) IfBlankThen

func (r RString) IfBlankThen(defStr string) string

if r is blank return defStr else return r

func (RString) IsBlank

func (r RString) IsBlank() bool

check if r is blank

dont't use it just because you need IsBlank

func (RString) RuneLen

func (r RString) RuneLen() int

count number of runes

func (RString) StrAt

func (r RString) StrAt(i int) string

get string at

func (RString) Substr

func (r RString) Substr(start int, end int) string

substring

func (RString) SubstrEnd

func (r RString) SubstrEnd(end int) string

substring before end

func (RString) SubstrStart

func (r RString) SubstrStart(start int) string

substring starting from start

type RWMap added in v0.0.6

type RWMap[V any] struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

Map with sync.RWMutex embeded.

func NewRWMap added in v0.0.6

func NewRWMap[V any](newFunc func(string) V) *RWMap[V]

Create new RWMap

func (*RWMap[V]) Get added in v0.0.6

func (r *RWMap[V]) Get(k string) V

Get V using k, if V exists return, else create a new one and store it.

type RabbitListener

type RabbitListener interface {
	Queue() string                          // return name of the queue
	Handle(rail Rail, payload string) error // handle message
	Concurrency() int
}

RabbitListener of Queue

type Rail

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

Rail, an object that carries trace infromation along with the execution.

func BuildRail

func BuildRail(c *gin.Context) Rail

Build Rail from gin.Context.

This func creates new Rail for the first time by setting up proper traceId and spanId.

It can also recognize that a traceId (and spanId) was previously created, and do attempt to reuse these tracing values, such that the Rail acts as if it's the previous one, this is especially useful when we are recovering from a panic. In most cases, we should only call BuildRail for once.

However, if the Rail has attempted to overwrite it's spanId (i.e., creating new span), this newly created spanId will not be reflected on the Rail created here. But this should be fine, because new span is usually created for async operation.

func EmptyRail

func EmptyRail() Rail

Create empty Rail.

func NewRail

func NewRail(ctx context.Context) Rail

Create new Rail from context.

func (Rail) Context added in v0.0.23

func (r Rail) Context() context.Context

func (Rail) CtxValInt

func (r Rail) CtxValInt(key string) int

func (Rail) CtxValStr

func (r Rail) CtxValStr(key string) string

func (Rail) CtxValue

func (r Rail) CtxValue(key string) any

func (Rail) Debug

func (r Rail) Debug(args ...interface{})

func (Rail) Debugf

func (r Rail) Debugf(format string, args ...interface{})

func (Rail) Debugln added in v0.0.28

func (r Rail) Debugln(args ...interface{})

func (Rail) Error

func (r Rail) Error(args ...interface{})

func (Rail) Errorf

func (r Rail) Errorf(format string, args ...interface{})

func (Rail) Errorln added in v0.0.28

func (r Rail) Errorln(args ...interface{})

func (Rail) Fatal

func (r Rail) Fatal(args ...interface{})

func (Rail) Fatalf

func (r Rail) Fatalf(format string, args ...interface{})

func (Rail) Fatalln added in v0.0.28

func (r Rail) Fatalln(args ...interface{})

func (Rail) Info

func (r Rail) Info(args ...interface{})

func (Rail) Infof

func (r Rail) Infof(format string, args ...interface{})

func (Rail) Infoln added in v0.0.28

func (r Rail) Infoln(args ...interface{})

func (Rail) NextSpan

func (r Rail) NextSpan() Rail

Create a new Rail with a new SpanId

func (Rail) Panic added in v0.0.28

func (r Rail) Panic(args ...interface{})

func (Rail) Panicf added in v0.0.28

func (r Rail) Panicf(format string, args ...interface{})

func (Rail) Panicln added in v0.0.28

func (r Rail) Panicln(args ...interface{})

func (Rail) Print added in v0.0.28

func (r Rail) Print(args ...interface{})

func (Rail) Printf added in v0.0.28

func (r Rail) Printf(format string, args ...interface{})

func (Rail) Println added in v0.0.28

func (r Rail) Println(args ...interface{})

func (Rail) SpanId

func (r Rail) SpanId() string

func (Rail) TraceId

func (r Rail) TraceId() string

func (Rail) Tracef added in v0.0.12

func (r Rail) Tracef(format string, args ...interface{})

func (Rail) Warn

func (r Rail) Warn(args ...interface{})

func (Rail) Warnf

func (r Rail) Warnf(format string, args ...interface{})

func (Rail) Warnln added in v0.0.28

func (r Rail) Warnln(args ...interface{})

func (Rail) WithCancel

func (r Rail) WithCancel() (Rail, context.CancelFunc)

Create new Rail with context's CancelFunc

func (Rail) WithCtxVal

func (r Rail) WithCtxVal(key string, val any) Rail

type RawTRouteHandler

type RawTRouteHandler func(inb *Inbound)

Raw version of traced route handler.

type RedisConnParam

type RedisConnParam struct {
	Address  string
	Port     string
	Username string
	Password string
	Db       int
}

type Resp

type Resp struct {
	ErrorCode string      `json:"errorCode" desc:"error code"`
	Msg       string      `json:"msg" desc:"message"`
	Error     bool        `json:"error" desc:"whether the request was successful"`
	Data      interface{} `json:"data" desc:"response data"`
}

Web Endpoint's Resp

func ErrorResp

func ErrorResp(msg string) Resp

Build error Resp

func ErrorRespWCode

func ErrorRespWCode(code string, msg string) Resp

Build error Resp

func OkResp

func OkResp() Resp

Build OK Resp

func OkRespWData

func OkRespWData(data interface{}) Resp

Build OK Resp with data

func WrapResp

func WrapResp(rail Rail, data interface{}, err error, url string) Resp

Wrap result (data and err) with a common Resp object.

If err is not nil, returns a Resp body containing the error code and message. If err is nil, the data is wrapped inside a Resp object and returned with http.StatusOK.

type RespUnwrapper added in v0.0.25

type RespUnwrapper interface {
	Unwrap() Resp
}

type ResultBodyBuilder added in v0.0.8

type ResultBodyBuilder struct {
	// wrap error in json, the returned object will be serialized to json.
	ErrJsonBuilder func(rail Rail, url string, err error) any

	// wrap payload object, the returned object will be serialized to json.
	PayloadJsonBuilder func(payload any) any

	// build empty ok response object, the returned object will be serialized to json.
	OkJsonBuilder func() any
}

type RoutingGroup added in v0.0.4

type RoutingGroup struct {
	Base  string
	Paths []TreePath
}

func BaseRoute added in v0.0.4

func BaseRoute(baseUrl string) *RoutingGroup

Group routes together to share the same base url.

func GroupRoute added in v0.0.23

func GroupRoute(baseUrl string, grouped ...TreePath) *RoutingGroup

Group routes together to share the same base url.

func (*RoutingGroup) Group added in v0.0.4

func (rg *RoutingGroup) Group(grouped ...TreePath) *RoutingGroup

Group routes, routes are immediately registered

func (*RoutingGroup) Prepend added in v0.0.23

func (rg *RoutingGroup) Prepend(baseUrl string)

type Runnable

type Runnable func() error

type SLPinter added in v0.0.30

type SLPinter struct {
	*strings.Builder
	LineSuffix string
	LinePrefix string
}

func (*SLPinter) Printlnf added in v0.0.30

func (s *SLPinter) Printlnf(st string, args ...any)

type Serializer added in v0.0.18

type Serializer interface {
	Serialize(t any) (string, error)
	Deserialize(ptr any, v string) error
}

Value serializer / deserializer.

type Server added in v0.0.14

type Server struct {
	Protocol string
	Address  string
	Port     int
	Meta     map[string]string
}

func SelectAnyServer added in v0.0.22

func SelectAnyServer(rail Rail, name string) (Server, error)

Select one Server randomly.

This func internally calls SelectServer with RandomServerSelector.

func SelectServer added in v0.0.14

func SelectServer(rail Rail, name string, selector func(servers []Server) int) (Server, error)

Select one Server based on the provided selector.

GetServerList() is internally called to obtain current ServerList implementation.

If none is found and the service is not subscribed yet in the ServerList, this func subscribes to the service and polls the service instances immediately.

If ServerList indeed doesn't find any available instance for the service, ErrServiceInstanceNotFound is returned.

func (*Server) BuildUrl added in v0.0.14

func (c *Server) BuildUrl(relUrl string) string

Build the complete request url.

func (*Server) ServerAddress added in v0.0.14

func (c *Server) ServerAddress() string

Build server address with host and port concatenated, e.g., 'localhost:8080'

type ServerChangeListenerMap added in v0.0.19

type ServerChangeListenerMap struct {
	Listeners map[string][]func()
	Pool      *AsyncPool
	sync.RWMutex
}

func (*ServerChangeListenerMap) SubscribeChange added in v0.0.28

func (s *ServerChangeListenerMap) SubscribeChange(name string, cbk func())

func (*ServerChangeListenerMap) TriggerListeners added in v0.0.28

func (s *ServerChangeListenerMap) TriggerListeners(name string)

type ServerList added in v0.0.14

type ServerList interface {
	PollInstances(rail Rail) error
	PollInstance(rail Rail, name string) error
	ListServers(rail Rail, name string) []Server
	IsSubscribed(rail Rail, service string) bool
	Subscribe(rail Rail, service string) error
	Unsubscribe(rail Rail, service string) error
	UnsubscribeAll(rail Rail) error
}

type ServerListServiceRegistry added in v0.0.28

type ServerListServiceRegistry struct {
	Rule ServerSelector
}

func (ServerListServiceRegistry) ListServers added in v0.0.28

func (c ServerListServiceRegistry) ListServers(rail Rail, service string) ([]Server, error)

func (ServerListServiceRegistry) ResolveUrl added in v0.0.28

func (c ServerListServiceRegistry) ResolveUrl(rail Rail, service string, relativeUrl string) (string, error)

type ServerSelector added in v0.0.14

type ServerSelector func(servers []Server) int

Server selector, returns index of the selected one.

type ServiceRegistry

type ServiceRegistry interface {
	ResolveUrl(rail Rail, service string, relativeUrl string) (string, error)
	ListServers(rail Rail, service string) ([]Server, error)
}

func GetServiceRegistry

func GetServiceRegistry() ServiceRegistry

Get service registry.

Service registry initialization is lazy, don't store the retunred value in global var.

type Set

type Set[T comparable] struct {
	// Keys in Set
	Keys map[T]Void
}

Set data structure

It's internally backed by a Map.

To create a new Set, use NewSet() func.

func NewSet

func NewSet[T comparable]() Set[T]

Create new Set

func (*Set[T]) Add

func (s *Set[T]) Add(key T) bool

Add key to set, return true if the key wasn't present previously

func (*Set[T]) AddAll

func (s *Set[T]) AddAll(keys []T)

Add keys to set

func (*Set[T]) AddThen

func (s *Set[T]) AddThen(key T) *Set[T]

Add key to set (same as Add, but used for method chaining)

func (*Set[T]) CopyKeys

func (s *Set[T]) CopyKeys() []T

Copy keys in set

func (*Set[T]) Has

func (s *Set[T]) Has(key T) bool

Test whether the key is in the set

func (*Set[T]) IsEmpty

func (s *Set[T]) IsEmpty() bool

Check if the Set is empty

func (*Set[T]) Size

func (s *Set[T]) Size() int

Get the size of the Set

func (*Set[T]) String

func (s *Set[T]) String() string

To string

type StrPair

type StrPair struct {
	Left  string
	Right any
}

String-based Pair data structure

type Supplier added in v0.0.3

type Supplier[T any] func() T

Supplier of T

type TBucket added in v0.0.22

type TBucket[T any] struct {
	// contains filtered or unexported fields
}

func NewTBucket added in v0.0.22

func NewTBucket[T any](val T) TBucket[T]

type TClient

type TClient struct {
	Url        string              // request url (absolute or relative)
	Headers    map[string][]string // request headers
	Ctx        context.Context     // context provided by caller
	QueryParam map[string][]string // query parameters
	Rail       Rail                // rail
	// contains filtered or unexported fields
}

Helper type for sending HTTP requests

Provides convenients methods to build requests, use http.Client and propagate tracing information

func NewDynTClient

func NewDynTClient(ec Rail, relUrl string, serviceName string) *TClient

Create new defualt TClient with EnableServiceDiscovery(), EnableTracing(), and Require2xx() turned on.

The provided relUrl should be a relative url starting with '/'.

func NewTClient

func NewTClient(rail Rail, url string) *TClient

Create new TClient.

func (*TClient) AddHeader

func (t *TClient) AddHeader(k string, v string) *TClient

Append header, subsequent method calls doesn't override previously appended headers

func (*TClient) AddHeaders

func (t *TClient) AddHeaders(headers map[string]string) *TClient

Append headers, subsequent method calls doesn't override previously appended headers

func (*TClient) AddQueryParams

func (t *TClient) AddQueryParams(k string, v ...string) *TClient

Append Query Parameters, subsequent method calls doesn't override previously appended parameters

func (*TClient) Delete

func (t *TClient) Delete() *TResponse

Send DELETE request

func (*TClient) EnableServiceDiscovery

func (t *TClient) EnableServiceDiscovery(serviceName string) *TClient

Enable service discovery

func (*TClient) EnableTracing

func (t *TClient) EnableTracing() *TClient

Enable tracing by putting propagation key/value pairs on http headers.

func (*TClient) Get

func (t *TClient) Get() *TResponse

Send GET request

func (*TClient) Head

func (t *TClient) Head() *TResponse

Send HEAD request

func (*TClient) Http added in v0.0.5

func (t *TClient) Http() *TClient

Append 'http://' protocol.

If service discovery is enabled, or the url contains http protocol already, this will be skipped.

func (*TClient) Https added in v0.0.5

func (t *TClient) Https() *TClient

Append 'https://' protocol.

If service discovery is enabled, or the url contains http protocol already, this will be skipped.

func (*TClient) Options

func (t *TClient) Options() *TResponse

Send OPTIONS request

func (*TClient) Post

func (t *TClient) Post(body io.Reader) *TResponse

Send POST request with reader to request body.

func (*TClient) PostBytes added in v0.0.22

func (t *TClient) PostBytes(body []byte) *TResponse

Send POST request with bytes.

func (*TClient) PostForm

func (t *TClient) PostForm(data url.Values) *TResponse

Send POST request with urlencoded form data

func (*TClient) PostJson

func (t *TClient) PostJson(body any) *TResponse

Send POST request with JSON.

Use simple types like struct instad of pointer for body.

func (*TClient) Put

func (t *TClient) Put(body io.Reader) *TResponse

Send PUT request

func (*TClient) PutBytes added in v0.0.22

func (t *TClient) PutBytes(body []byte) *TResponse

Send PUT request with bytes.

func (*TClient) PutJson

func (t *TClient) PutJson(body any) *TResponse

Send PUT request with JSON

func (*TClient) Require2xx added in v0.0.8

func (t *TClient) Require2xx() *TClient

Requires response to have 2xx status code, if not, the *TResponse will contain error built for this specific reason.

func (*TClient) SetContentType

func (t *TClient) SetContentType(ct string) *TClient

Set Content-Type

func (*TClient) SetHeaders

func (t *TClient) SetHeaders(k string, v ...string) *TClient

Overwrite header

func (*TClient) UseClient added in v0.0.8

func (t *TClient) UseClient(client *http.Client) *TClient

Change the underlying *http.Client

type TResponse

type TResponse struct {
	Rail       Rail
	Ctx        context.Context
	Resp       *http.Response
	RespHeader http.Header
	StatusCode int
	Err        error
}

Helper type for handling HTTP responses

func (*TResponse) Bytes added in v0.0.3

func (tr *TResponse) Bytes() ([]byte, error)

Read response as []bytes.

Response is always closed automatically.

If response body is somehow empty, *miso.NoneErr is returned.

func (*TResponse) Close

func (tr *TResponse) Close() error

Close Response

func (*TResponse) Is2xx

func (tr *TResponse) Is2xx() bool

Is status code 2xx

func (*TResponse) Json added in v0.0.3

func (tr *TResponse) Json(ptr any) error

Read response as JSON object.

Response is always closed automatically.

If response body is somehow empty, *miso.NoneErr is returned.

func (*TResponse) Require2xx

func (tr *TResponse) Require2xx() error

Check if it's 2xx, else return error

func (*TResponse) Str added in v0.0.3

func (tr *TResponse) Str() (string, error)

Read response as string.

Response is always closed automatically.

If response body is somehow empty, *miso.NoneErr is returned.

func (*TResponse) WriteTo added in v0.0.15

func (tr *TResponse) WriteTo(writer io.Writer) (int64, error)

Write the response data to the given writer.

Response is always closed automatically.

If response body is somehow empty, *miso.NoneErr is returned.

type TRouteHandler

type TRouteHandler[Res any] func(inb *Inbound) (Res, error)

Traced route handler.

Res type should be a struct. By default both Res value and error (if not nil) will be wrapped inside miso.Resp and serialized to json. Wrapping to miso.Resp is customizable using miso.SetResultBodyBuilder func.

With Res type declared, miso will automatically parse the Res type using reflect and generate an API documentation describing the endpoint.

type TTLCache added in v0.0.3

type TTLCache[T any] interface {
	TryGet(key string) (T, bool)
	Get(key string, elseGet func() (T, bool)) (T, bool)
	Put(key string, t T)
	Del(key string)
	Size() int
	Exists(key string) bool
	PutIfAbsent(key string, t T) bool
}

Time-based Cache.

func NewTTLCache added in v0.0.3

func NewTTLCache[T any](ttl time.Duration, maxSize int) TTLCache[T]

Create new TTLCache.

Each k/v is associated with a timestamp. Each time a key lookup occurs, it checks whether the k/v is still valid by comparing the timestamp with time.Now().

If the k/v is no longer 'alive', or the cache doesn't have the key, supplier func for the value is called, and the returned value is then cached. I.e., each k/v is evicted only at key lookup, there is no secret go-routine running to do the clean-up, the overhead for maintaining the cache is relatively small.

For the max size, TTLCache will try it's best to maintain it, but it's quite possible that all values in the cache are 'alive'. Whenever the max size is violated, the cache will simply drop the 'least recently put' item.

The returned TTLCache can be used concurrently.

type TagRetriever

type TagRetriever func(tagName string) string

type TickRunner added in v0.0.14

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

Runner that triggers run on every tick.

Create TickRunner using func NewTickRunner(...).

func NewTickRuner added in v0.0.14

func NewTickRuner(freq time.Duration, run func()) *TickRunner

func (*TickRunner) Start added in v0.0.14

func (t *TickRunner) Start()

func (*TickRunner) Stop added in v0.0.14

func (t *TickRunner) Stop()

type Transform added in v0.0.3

type Transform[T any] func(t T) T

Transform t to another t

type TreePath added in v0.0.23

type TreePath interface {
	Prepend(baseUrl string)
}

type ValidationError

type ValidationError struct {
	Field         string
	Rule          string
	ValidationMsg string
}

Validation Error

func (*ValidationError) Error

func (ve *ValidationError) Error() string

type VecTimer added in v0.0.13

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

Timer based on prometheus.HistogramVec.

Duration is measured in millisecond.

Use NewVecTimer to create a new one, and each timer can only be used for once.

func NewVecTimer added in v0.0.13

func NewVecTimer(vec *prometheus.HistogramVec) *VecTimer

Create new timer that is back by prometheus HistogramVec. Each timer can only be used for once.

func (*VecTimer) ObserveDuration added in v0.0.13

func (t *VecTimer) ObserveDuration(labels ...string) time.Duration

func (*VecTimer) Reset added in v0.0.25

func (t *VecTimer) Reset()

type Void

type Void struct{}

Empty Struct

type WalkTagCallback added in v0.0.26

type WalkTagCallback struct {
	Tag      string
	OnWalked func(tagVal string, fieldVal reflect.Value, fieldType reflect.StructField) error
}

Jump to

Keyboard shortcuts

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