I need to get property value:
telegram_token: "telegramtoken"
other_token: "othertoken"
But if I do Init() of import api and initialize function in func main() I don't get property value.
Why?
Thanks!
This is works:
package main
import (
"fmt"
"github.com/go-yaml/yaml"
)
var (
cfg Config
configData = []byte(`api:
telegram_token: "telegramtoken"
other_token: "othertoken"`)
)
type Config struct {
API ConfigAPI `yaml:"api"`
}
type ConfigAPI struct {
TelegramToken string `yaml:"telegram_token"`
OtherToken string `yaml:"other_token"`
}
func (c *Config) parse() {
err := yaml.Unmarshal(configData, c)
if err != nil {
fmt.Println(err.Error())
}
}
func Init() {
cfg.parse()
fmt.Printf("%+v\n", cfg)
}
func main() {
Init()
}
Console:
{API:{TelegramToken:telegramtoken OtherToken:othertoken}}
Doesn't work:
package api
import (
"fmt"
"github.com/go-yaml/yaml"
)
var (
cfg Config
configData = []byte(`api:
telegram_token: "telegramtoken"
waves_token: "wavestoken"`)
)
type Config struct {
API ConfigAPI `yaml:"api"`
}
type ConfigAPI struct {
TelegramToken string `yaml:"telegram_token"`
WavesToken string `yaml:"waves_token"`
}
func (c *Config) parse() {
err := yaml.Unmarshal(configData, c)
if err != nil {
fmt.Println(err.Error())
}
}
func Init() {
cfg.parse()
fmt.Printf("%+v\n", cfg)
}
package main, see on api.Init()
// The daemon that starts the API in background process.
package main
import (
"fmt"
"log"
"net/http"
"time"
"github.com/julienschmidt/httprouter"
api "github.com/krypton-code/waves-bot/pkg/api"
)
var (
host = "https://api.telegram.org/bot"
method = "/getMe"
)
// Index - home page.
func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
fmt.Fprint(w, "<h1>Server of TelegaBot for Waves Platform is running!</h1>\n")
}
func main() {
api.Init()
router := httprouter.New()
router.GET("/", Index)
s := &http.Server{
Addr: ":8089",
Handler: router,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
log.Printf("\nApp listening on port%s. Go to http://localhost:8089/", s.Addr)
log.Fatal(s.ListenAndServe())
}
Console:
{API:{TelegramToken: WavesToken:}}
Modify the YAML to match the expected structure by indenting the token fields:
configData = []byte(`api:
telegram_token: "telegramtoken"
waves_token: "wavestoken"`)
)
Related
In rocket.rs, we've this simple route code:
#[get("/hello/<name>/<age>")]
fn hello(name: &str, age: u8) -> String {
format!("Hello, {} year old named {}!", age, name)
}
where if you were to visit http://localhost:8000/hello/John/58 in the browser, you’d see:
Hello, 58 year old named John!
I read this, but the accepted answer is about a way to do Go url parameters mapping for single route, that could read http://localhost:8080/blob/123/test as /blob/{id}/test and display the required route.
I know there are some great routers/frameworks there, but looking to build simple code myself to understand http route handlers in a better way.
Let's say I've:
type Tender struct {
tenderReference string
venderCode int
}
func (t Tender) readWrite() {
fmt.Printf("Tender %s is ready for vendor %d to review and submit\n", t.tenderReference, t.venderCode)
}
func (t Tender) readOnly(w http.ResponseWriter, r *http.Request) {
fmt.Printf("Tender %s already submitted by vender %d\n", t.tenderReference, t.venderCode)
}
And want my routes to be something like:
/api/tender/readWrite/{tenderReference}/vendor/{venderCode} that is calling func (t Tender) readWrite(){}
/api/tender/readOnly/{tenderReference}/vendor/{venderCode} that is calling func (t Tender) readOnly(){}
How many route handler do I have to build?
I solved it as below, other thoughts are welcomed:
404.go
package main
import (
"fmt"
"net/http"
)
func handle404(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "mmm, it looks you are playing around, page is not available :)\n")
}
getField.go
package main
import "net/http"
type ctxKey struct{}
func getField(r *http.Request, index int) string {
fields := r.Context().Value(ctxKey{}).([]string)
return fields[index]
}
routes.go
package main
import (
"net/http"
"regexp"
)
type route struct {
method string
regex *regexp.Regexp
handler http.HandlerFunc
}
var routes = []route{
newRoute("GET", "/api/tender/(rw|r)/([^/]+)/vendor/([0-9]+)", apiTenders),
}
func newRoute(method, pattern string, handler http.HandlerFunc) route {
return route{method, regexp.MustCompile("^" + pattern + "$"), handler}
}
tendor.go
package main
import (
"fmt"
"net/http"
"strconv"
)
type Tender struct {
tenderReference string
venderCode int
}
// Handles GET /api/tender/(rw|r)/([^/]+)/vendor/([0-9]+)
func apiTenders(w http.ResponseWriter, r *http.Request) {
action := getField(r, 0)
tenderReference := getField(r, 1)
venderCode, _ := strconv.Atoi(getField(r, 2))
tender := Tender{tenderReference, venderCode}
switch action {
case "rw":
tender.readWrite(w, r) // Display tender and allow vendor to submit feedback
case "r":
tender.readOnly(w, r) // Display readOnly copy of the tender
default:
fmt.Fprintf(w, "Tendert ERROR\n")
}
}
func (t Tender) readWrite(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Tender %s is ready for vendor %d to review and submit\n", t.tenderReference, t.venderCode)
}
func (t Tender) readOnly(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Tender %s already submitted by vender %d\n", t.tenderReference, t.venderCode)
}
server.go
package main
import (
"context"
"fmt"
"net/http"
"strings"
)
type apiHandler struct{}
func main() {
http.Handle("/api/", apiHandler{})
http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
// The "/" pattern matches everything, so we need to check
// that we're at the root here.
if req.URL.Path != "/" {
http.NotFound(w, req)
return
}
fmt.Fprintf(w, "Welcome to the home page!")
})
http.ListenAndServe(":8000", nil)
}
func (apiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var allow []string
for _, route := range routes {
matches := route.regex.FindStringSubmatch(r.URL.Path)
if len(matches) > 0 {
if r.Method != route.method {
allow = append(allow, route.method)
continue
}
ctx := context.WithValue(r.Context(), ctxKey{}, matches[1:])
route.handler(w, r.WithContext(ctx))
return
}
}
if len(allow) > 0 {
w.Header().Set("Allow", strings.Join(allow, ", "))
http.Error(w, "405 method not allowed", http.StatusMethodNotAllowed)
return
}
handle404(w, r)
//http.NotFound(w, r)
}
Here is the example of my code.Now I want add histogram in my code.
but I can't find a way to add histogram like this.
Is anybody could help me?
I am able to write histogram sample but I can't add it in my below code
package main
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/prometheus/common/log"
"net/http"
)
type fooCollector struct {
fooMetric *prometheus.Desc
}
func newFooCollector(label1 string) *fooCollector {
return &fooCollector{
fooMetric: prometheus.NewDesc("fff_metric",
"Shows whether a foo has occurred in our cluster",
nil, prometheus.Labels{"env":label1},
),
}
}
func (collector *fooCollector) Describe(ch chan<- *prometheus.Desc) {
//Update this section with the each metric you create for a given collector
ch <- collector.fooMetric
}
func (collector *fooCollector) Collect(ch chan<- prometheus.Metric) {
ch <- prometheus.MustNewConstMetric(collector.fooMetric, prometheus.GaugeValue, 111111)
}
func main() {
prometheus.MustRegister(newFooCollector("dev"))
http.Handle("/metrics", promhttp.Handler())
http.ListenAndServe(":80", nil)
}
finally I learned how histogram works.here is my code
package main
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"net/http"
)
type fooCollector struct {
fooMetric *prometheus.Desc
}
//First,we define the variable of histogram
var (
hbrms_histovec = prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "hbrms_histogram",
Help: "hbrms_histogram",
ConstLabels: prometheus.Labels{"constname": "constvalue"},
Buckets: prometheus.ExponentialBuckets(50, 1.3, 15),//50*1.3,15times
},
[]string{"env"},
)
)
func newFooCollector() *fooCollector {
return &fooCollector{
fooMetric: prometheus.NewDesc("fff_metric",
"Shows whether a foo has occurred in our cluster",
nil, nil,
),
}
}
func (collector *fooCollector) Describe(ch chan<- *prometheus.Desc) {
ch <- collector.fooMetric
}
func (collector *fooCollector) Collect(ch chan<- prometheus.Metric) {
ch <- prometheus.MustNewConstMetric(collector.fooMetric, prometheus.CounterValue, float64(1))
// 2nd,we set metrics in this way instead of write to channel,we just find a way of calling the code below when we visit the url.
hbrms_histovec.WithLabelValues("val1").Observe(float64(10))
}
func main() {
reg := prometheus.NewPedanticRegistry()
reg.MustRegister(newFooCollector())
// finally,we register the metrics "hbrms_histovec" in this way
reg.MustRegister(hbrms_histovec)
gatherers := prometheus.Gatherers{reg}
h := promhttp.HandlerFor(gatherers,
promhttp.HandlerOpts{
ErrorHandling: promhttp.ContinueOnError,
})
http.HandleFunc("/metrics", func(w http.ResponseWriter, r *http.Request) {
h.ServeHTTP(w, r)
})
http.ListenAndServe(":80", nil)
}
You can just simply call .Collect(ch) method for each metric(thats both includes description and values). Also you don't need to extend default prometheus route handler - just be careful you don't have collision with default metric names
package main
import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promhttp"
"net/http"
)
type fooCollector struct {
fooMetric *prometheus.GaugeVec
hmdrsHistogram *prometheus.HistogramVec
}
func newFooCollector() *fooCollector {
return &fooCollector{
fooMetric: prometheus.NewGaugeVec(prometheus.GaugeOpts{
Name: "fff_metric",
Help: "Shows whether a foo has occurred in our cluster",
}, []string{"country"}),
hmdrsHistogram: prometheus.NewHistogramVec(
prometheus.HistogramOpts{
Name: "hbrms_histogram",
Help: "hbrms_histogram",
ConstLabels: prometheus.Labels{"constname": "constvalue"},
Buckets: prometheus.ExponentialBuckets(50, 1.3, 15), //50*1.3,15times
},
[]string{"env"},
),
}
}
func (collector *fooCollector) Describe(ch chan<- *prometheus.Desc) {
// don't need to manually call .Describe() here,
// because description was defined with prometheus.MustRegister method
//collector.fooMetric.Describe(ch)
//collector.hmdrsHistogram.Describe(ch)
}
func (collector *fooCollector) Collect(ch chan<- prometheus.Metric) {
v := 14 // get value from DB/External service/etc
collector.fooMetric.WithLabelValues("qwe").Set(float64(v))
collector.fooMetric.WithLabelValues("qwe").Set(v)
collector.fooMetric.Collect(ch)
collector.hmdrsHistogram.WithLabelValues("val1").Observe(float64(10))
collector.hmdrsHistogram.Collect(ch)
}
func RegisterFooCollector() {
fc := newFooCollector()
prometheus.MustRegister(fc)
}
func main() {
RegisterFooCollector()
// also includes default metrics
http.Handle("/metrics", promhttp.Handler())
err := http.ListenAndServe(":80", nil)
if err != nil {
return
}
}
Just as Gin describe here
r.Use(static.Serve("/", static.LocalFile("/src", false)))
r.NoRoute(func(c *gin.Context){
c.File("/src/index.html")
})
But I don't know how to inline the src folder into the binary file.
How should I proceed, or is there a case project I can refer to.
The case is in github.com/gin-contrib/static/_example/bindata.
package main
import (
assetfs "github.com/elazarl/go-bindata-assetfs"
"github.com/fidelyiu/yiu-note/core/asset"
"github.com/gin-contrib/static"
"github.com/gin-gonic/gin"
"net/http"
"strings"
)
type binaryFileSystem struct {
fs http.FileSystem
}
func (b *binaryFileSystem) Open(name string) (http.File, error) {
return b.fs.Open(name)
}
func (b *binaryFileSystem) Exists(prefix string, filepath string) bool {
if p := strings.TrimPrefix(filepath, prefix); len(p) < len(filepath) {
if _, err := b.fs.Open(p); err != nil {
return false
}
return true
}
return false
}
func BinaryFileSystem(root string) *binaryFileSystem {
fs := &assetfs.AssetFS{
Asset: asset.Asset,
AssetDir: asset.AssetDir,
AssetInfo: asset.AssetInfo,
Prefix: root,
}
return &binaryFileSystem{
fs,
}
}
func main() {
r := gin.Default()
// go-bindata -o=core/asset/asset.go -pkg=asset dist/...
r.Use(static.Serve("/", BinaryFileSystem("dist")))
r.NoRoute(func(c *gin.Context) {
c.File("./dist/index.html")
})
_ = r.Run(":8080")
}
I have a project consisting of 4 parts:
A gateway (gateway/gateway.go) it's a package that knows how to talk with an application server and open this connection channel.
A runner (runner/runner.go) it's the main (go build -o runner/runner runner/runner.go) It loads and execute Modules (using reflect I run functions from the module)!
A framework (framework/framework.go) Implements many functionalities calling the gateway.
Modules (aka Plugins in Go) (modules/sample.go) (go build -buildmode plugin -o modules/sample.so ./modules/sample.go) Using the framework, does customer logic! When init I export the reflect.Value of struct, then runner can run methods of this struct.
I want the runner instantiate the gateway and the framework obtain this instance without create a dependency between runner/framework.
Why? To avoid Go error 'plugin was built with a different version of package' when runner loads the module!
If I update the runner (with the framework changed), I will invalidate old modules.
I already do that using 2 ways I don't like:
Using context, but all functions from module and framework need receive a parameter context, then framework extract the gateway.
Just let the framework instantiate gateway, but then the runner cannot use gateway.
There have been a lot of headaches with Go plugins, especially the plugin compiler version must exactly match the program's compiler version. But the example works.
runner/runner.go
package main
import (
"context"
"fmt"
"os"
"plugin"
"reflect"
"../gateway"
"../dep"
)
var a *gateway.Gateway
func main() {
myModule := os.Args[1]
if _, err := plugin.Open(myModule); err != nil {
os.Exit(1)
}
mod, err := dep.NewModule()
if err != nil {
os.Exit(1)
}
a = gateway.NewGW()
ctx := context.WithValue(context.Background(), "gateway", a)
modreflect, err := mod.Init(ctx, dep.Config{})
if err != nil {
os.Exit(1)
}
if !modreflect.IsValid() {
os.Exit(1)
}
modnode, err := mod.Start(ctx)
if err != nil {
os.Exit(1002)
}
for {
if len(modnode) <= 0 {
break
}
modnoderefl := modreflect.MethodByName(modnode)
if !modnoderefl.IsValid() {
break
}
result := modnoderefl.Call([]reflect.Value{reflect.ValueOf(ctx)})
if len(result) != 2 {
break
}
modnode = result[0].String()
}
mod.End(ctx)
}
gateway/gateway.go
package gateway
type Gateway struct {}
fun NewGW() *Gateway {
a := Gateway{}
return &a
}
dep/dep.go
package dep
import (
"errors"
"context"
"reflect"
)
// Config is a configuration provider.
type Config map[string]interface{}
// Module is the interface implementated by types that
// register themselves as modular plug-ins.
type Module interface {
Init(ctx context.Context, config Config) (reflect.Value,error)
Start(ctx context.Context) (string,error)
End(ctx context.Context) error
}
var themod = []func() Module{}
func RegisterModule(ctor func() Module) {
themod = append(themod, ctor)
}
func NewModule() (Module, error) {
if len(themod) == 0 {
return nil, errors.New("Module not registered")
}
return themod[0](), nil
}
framework/framework.go
package framework
import (
"fmt"
"context"
"../gateway"
)
type PlayFileInput struct {
Path string
}
func Play(ctx context.Context, p PlayFileInput) error {
if a := ctx.Value("gateway"); a != nil {
if a.(*gateway.Gateway) != nil {
_, err := a.(*gateway.Gateway).Exec("Playback", p.Path)
return err
}
}
return nil
}
modules/sample.go
package main
import "C"
import (
"context"
"fmt"
"os"
"reflect"
"../dep"
"../framework"
)
type MyModuleImpl struct {}
func init() {
dep.RegisterModule(func() dep.Module {
return &MyModuleImpl{}
})
}
func (m *MyModuleImpl) Init(ctx context.Context, config dep.Config) (reflect.Value, error) {
return reflect.ValueOf(m), nil
}
func (m *MyModuleImpl) Start(ctx context.Context) (string,error) {
return "Menu_1",nil
}
func (n *MyModuleImpl)Menu_1(ctx context.Context) (string, error) {
framework.Play(ctx, framework.PlayFileInput{Path: "welcome.wav"})
return "Menu_2",nil
}
func (n *MyModuleImpl)Menu_2(ctx context.Context) (string, error) {
return "Menu_3", nil
}
// ....
// ....
func (m *MyModuleImpl) End(ctx context.Context) error {
return nil
}
I wrote a functions that save data into redis database server. The challenge is that I want to test these functions and do not know how to test it.
I just start somehow with
Functions
package sessrage
/*
* Save data into redis database. In the common case,
* the data will be only valid during a request. Use
* hash datatype in redis.
*/
import (
"../context"
"github.com/garyburd/redigo/redis"
"net/http"
)
const (
protocol string = "tcp"
port string = ":6379"
)
func connectAndCloseRedis(connectCall func(con redis.Conn)) {
c, err := redis.Dial("tcp", ":6379")
defer c.Close()
if err != nil {
panic(err.Error())
}
connectCall(c)
}
func PostSessionData(r *http.Request, key, value string) {
go connectAndCloseRedis(func(con redis.Conn) {
sessionId := context.Get(r, context.JwtId).(string)
con.Do("HMSET", sessionId, key, value)
})
}
func GetSessionData(r *http.Request, key string) interface{} {
var result interface{}
sessionId := context.Get(r, context.JwtId).(string)
reply, _ := redis.Values(c.Do("HMGET", sessionId, key))
redis.Scan(reply, &result)
return result
}
and the test file
package sessrage
import (
//"fmt"
"../context"
. "github.com/smartystreets/goconvey/convey"
"github.com/stretchr/testify/assert"
"net/http"
"net/http/httptest"
"testing"
"time"
)
var server *httptest.Server
var glrw http.ResponseWriter
var glr *http.Request
func init() {
server = httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
glrw = rw
glr = r
context.Set(glr, context.JwtId, "TestId")
}))
}
func TestPostAndGetSession(t *testing.T) {
Convey("POST and GET data on redis.", t, func() {
PostSessionData(glr, "key1", "value1")
time.Sleep(time.Second * 10)
v := GetSessionData(glr, "key1")
assert.Equal(t, "value1", v)
})
}
when I try to run the test I've got
an't load package: ......./sessrage.go:10:2: local import "../context" in non-local package
and the context package looks like
package context
import (
"github.com/gorilla/context"
"net/http"
)
type contextKey int
const (
LanguageId contextKey = iota
JwtId
)
func Get(r *http.Request, key interface{}) interface{} {
return context.Get(r, key)
}
func Set(r *http.Request, key, val interface{}) {
context.Set(r, key, val)
}
What do I wrong?
That is the first time, I am testing code in conjunction with http. It seems to be very hard to test.
There are a few issues:
Don't use relative import paths.
Use a pool instead of dialing redis on every action.
The call to sessionId := context.Get(r, context.JwtId).(string) in the PostSessionData anonymous function can fail if the mux or something higher in the call chain clears the Gorilla context before the goroutine runs. Do this instead:
func PostSessionData(r *http.Request, key, value string) {
c := pool.Get()
defer c.Close()
sessionId := context.Get(r, context.JwtId).(string)
if err := c.Do("HMSET", sessionId, key, value); err != nil {
// handle error
}
}