xmux

package module
v0.0.0-...-3726c4b Latest Latest
Warning

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

Go to latest
Published: Jul 12, 2022 License: GPL-3.0 Imports: 40 Imported by: 4

README

xmux

Based on native net HTTP is extremely simple and flexible, focusing on the routing of front and back-end separation projects

Function is up to you

video tutorial

English | English | 简体中文

Navigation

Install

go get github.com/hyahm/xmux

Quick Start

package main

import (
	"net/http"

	"github.com/hyahm/xmux"
)

func main() {
	router := xmux.NewRouter()
	router.Get("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("<h1>hello world!<h1>"))
	})
	router.Run()
}

open http://localhost:8080 in brower you can see hello world!

Multiple request method

package main

import (
	"net/http"

	"github.com/hyahm/xmux"
)

func main() {
	router := xmux.NewRouter()
	//Just for example, the following writing method is not recommended, but route.Reqeust("/",nil, "POST", "GET")
	router.Get("/", nil) // get request
	router.Post("/", nil) // post request
	router.Request("/getpost", nil, "POST", "GET") // both get and post requests are supported
	router.Any("/any", nil) // supports all requests except options
	router.Run()
}

Route Group

aritclegroup.go

func hello(w http.ResponseWriter, r *http.Request) {
	fmt.Println(xmux.Var(r)["id"])
	w.Write([]byte("hello world!!!!"))
	return
}

var Article *xmux.RouteGroup

func init() {
	Article = xmux.NewRouteGroup()
	Article.Get("/{int:id}", hello)

}

main.go

func main() {
	router := xmux.NewRouter()
	router.AddGroup(aritclegroup.Article)
}
prefix

// notice: DelPrefix and Prefix are valid only by routegroup


func main() {
	router := xmux.NewRouter().Prefix("test")
	router.Get("/bbb", c)   // /test/bbb
	router.Get("/ccc", c).DelPrefix("test")   // /test/bbb
	g := xmux.NewRouteGroup()
	g.Get("/aaa", noCache).DelModule(setKey) // /test/bbb
	g.Get("/no/cache1", noCache1).DelModule(setKey).DelPrefix("test") // /no/cache1
	router.AddGroup(g)
	router.Run()
}

Automatically detect duplicates

Write a lot of routes. I don't know if there are duplicates
An error will be reported when running the above, as follows

func main() {
	router := xmux.NewRouter()
	router.Get("/get",show) // 
	router.Get("/get",nil) // 
	router.Run()
}


2019/11/29 21:51:11 GET pattern duplicate for /get  

ignore url path slash

Remove any unnecessary slashes, for example
/asdf/sadf//asdfsadf/asdfsdaf////as/// -> /asdf/sadf/asdfsadf/asdfsdaf/as

func main() {
	router := xmux.NewRouter()
	router.IgnoreSlash = true
	router.Get("/get",show) 
	router.Get("/get/",show)
	router.Run()
}



if router.IgnoreSlash = false
Then an error will be reported when running the above, and / get / will be changed to / get as follows

2019/11/29 21:51:11 pattern duplicate for /get

Three Global handle

// This is the global options request processing. The front-end pre request is exempted. You have to write a pre request processing every time. By default, it will return OK, which can also be customized
HandleOptions:        handleoptions(),  
//404 is returned by default. You can also customize it
HandleNotFound: 	  handleNotFound(),  
// /favicon
HanleFavicon:        methodNotAllowed(),   

// The default method called is as follows. No route was found
func handleNotFound(w http.ResponseWriter, r *http.Request)  {
	w.Header().Add("Access-Control-Allow-Origin", "*")
	// Note: which is to pass the status code to exit and print the status code
	GetInstance(r).StatusCode = http.StatusNotFound
	w.WriteHeader(http.StatusNotFound)
}

Module which replaces the middleware functions of other frameworks and is more flexible and simple

  • Priority module

Global routing > group routing > private routing
if there is a high priority, execute first.

If you don't want to use it, you can delete it separately at the route point or route group you don't want to use delmodule

Note: Meaning of module return value: true: directly return to the client without subsequent processing. False means continue to execute downward

func home(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("hello world home"))
	return
}


func hf(w http.ResponseWriter, r *http.Request)  bool {
	fmt.Println("44444444444444444444444444")
	return true
}

func hf1(w http.ResponseWriter, r *http.Request)  bool {
	fmt.Println("66666")
	return false
}

func main() {
	router := xmux.NewRouter().AddModule(hf).SetHeader("name", "cander")
	router.Get("/home/{test}",home).AddModule(hf1)  // Module sequence hf -> hf1 -> home
	router.Get("/test/{test}",home).DelModule(hf)  //  home
	router.Run()
}

Context value transfer

  • Custom values can only be assigned from the module
// set key value
xmux.GetInstance(r).Set("key", "value")

// get value
xmux.GetInstance(r).Get("key")

Hook

  • NotFoundRequiredField : Processing tick for failed verification of required fields
  • UnmarshalError : Built in Unmarshal error hook
  • Exit (start time.Time, w http.ResponseWriter, r *http.Request) : handle exit
  • Enter( w http.ResponseWriter, r *http.Request) bool : handle enter
func exit(start time.Time, w http.ResponseWriter, r *http.Request) {
	// Any valid request will end up here
	fmt.Println(time.Since(start).Seconds(), r.URL.Path)
}



func enter( w http.ResponseWriter, r *http.Request) bool {
	// Any request will coming,You can filter IP domain names and other security or debugging operations
	
	fmt.Println(time.Since(start).Seconds(), r.URL.Path)
}

router := xmux.NewRouter()
router.Enter = enter
router.Exit = exit

Set Header

Cross origin is mainly about adding request headers. Other frameworks are generally set up with the help of middleware

However, this route greatly simplifies the cross origin configuration with the help of the above request header settings

Priority

Private route > group route > global route (if there is one with high priority, the one with low priority will be overwritten)

// For the example of cross origin processing, after setting the following request header, all routes will be attached to the request header,

// If some routes have separate request headers, they can be set separately
func main() {
	router := xmux.NewRouter()
	router.IgnoreSlash = true
	// The main solution is cross origin. Because it is a global request header, all the routes added later support cross origin
	router.SetHeader("Access-Control-Allow-Origin", "*")  
	// Allowed request headers
	router.SetHeader("Access-Control-Allow-Headers", "Content-Type,Access-Token,X-Token,Origin,smail,authorization") 
	router.Get("/", index)
	router.Run()
}

Data binding (the data after binding analysis takes effect before the module)

-Bindjason: bound is a JSON
-Bindxml: binding is an XML
-Bindform: a form is bound, can not bind file , you need get file from from r.FormFile() -Bind: custom processing binding (processed by module)

Validation field must required

type User struct {
	Username string "json:"username,required"
}
  • router.PrintRequestStr: Print the content of the acceptance request body

  • xmux.MaxPrintLength: If the size of the printed form exceeds the specified size, it will not be printed (default 2K)

func JsonToStruct(w http.ResponseWriter, r *http.Request) bool {
	// If any error message is reported, return true directly, which means that the handle has been executed directly and does not continue to go back
	if goconfig.ReadBool("debug", false) {
		b, err := ioutil.ReadAll(r.Body)
		if err != nil {
			return true
		}
		err = json.Unmarshal(b, xmux.GetInstance(r).Data)
		if err != nil {
			return true
		}
	} else {
		err := json.NewDecoder(r.Body).Decode(xmux.GetInstance(r).Data)
		if err != nil {
			return true
		}

	}
	return false
}

type DataName struct{}
type DataStd struct{}
type DataFoo struct{}

func AddName(w http.ResponseWriter, r *http.Request) {
	df := xmux.GetInstance(r).Data.(*DataName)
	fmt.Printf("%#v", df)
}

func AddStd(w http.ResponseWriter, r *http.Request) {
	df := xmux.GetInstance(r).Data.(*DataStd)
	fmt.Printf("%#v", df)
}

func AddFoo(w http.ResponseWriter, r *http.Request) {
	df := xmux.GetInstance(r).Data.(*DataFoo)
	fmt.Printf("%#v", df)
}

func main() {
	router := xmux.NewRouter()
	router.Post("/important/name", AddName).Bind(&DataName{}).AddModule(JsonToStruct)
	router.Post("/important/std", AddStd).Bind(&DataStd{}).AddModule(JsonToStruct)
	router.Post("/important/foo", AddFoo).Bind(&DataFoo{}).AddModule(JsonToStruct)
	// You can also directly use the built-in
	// If it is in JSON format, you can directly bind JSON. The effect is similar to that above
	router.Post("/important/foo/by/json", AddFoo).BindJson(&DataFoo{}) 
	router.Run()
}

  • Binding return value
    data := &Response{
		Code: 200,
	}
	router := xmux.NewRouter().BindResponse(data)

Pass Bind response (nil) to set and cancel a route using global binding

Matching route

The following five types are supported

Word matches only numbers and letter underscores (default)

  • string matches all characters without /

  • int match integer

  • all: match all, including/

  • re: Custom regular

example:

  • /aaa/{name} is the same as the following one, omitting the type, and the default is word
  • /aaa/{string: name} This is the same as above. The string type
  • /aaa/{int: name} matches the int type
  • /aaa/adf{re:([a-z]{1,4})sf([0-9]{0,10})sd: name, age} This is a paragraph that matches two parameters name, age,

Curly braces indicate a matching rule, in which two colons are divided into three parts

The first one: re indicates the use of custom rules. Only re has two colon divisions,

The second: regular expression, which cannot appear: the parameters to be extracted are enclosed by (),

Third: parameter name. The number of pairs () in the front and the number of parameters to be matched in the back are separated by commas

For example: /aaa/adfaasf16sd

This is a match. Name: aa age: 16

xmux.Var(r)["name"] 

websocket

Here is a complete example

package main

import (
	"fmt"
	"log"
	"net/http"
	"sync"
	"time"

	"github.com/hyahm/xmux"
)

type client struct {
	msg string
	c   *xmux.BaseWs
}

var msgchan chan client
var wsmu sync.RWMutex
var ps map[*xmux.BaseWs]byte

func sendMsg() {
	for {
		c := <-msgchan
		for p := range ps {
			if c.c == p {
				// Don't send it to yourself
				continue
			}
			fmt.Println(c.msg)
			
			//The length of the sent MSG cannot exceed 1 < < 31, otherwise the content will be lost and subcontracting is recommended
			p.SendMessage([]byte(c.msg), ps[p])
		}
	}
}

func ws(w http.ResponseWriter, r *http.Request) {
	p, err := xmux.UpgradeWebSocket(w, r)
	if err != nil {
		w.Write([]byte(err.Error()))
		return
	}
	p.SendMessage([]byte("hello"), xmux.TypeMsg)
	wsmu.Lock()
	ps[p] = xmux.TypeMsg
	wsmu.Unlock()
	tt := time.NewTicker(time.Second * 2)
	go func() {
		for {
			<-tt.C
			if err := p.SendMessage([]byte(time.Now().String()), xmux.TypeMsg); err != nil {
				break
			}
		}
	}()
	for {
		if p.Conn == nil {
			return
		}
		// Package
		msgType, msg, err := p.ReadMessage()
		if err != nil {
			fmt.Println(err.Error())
			// Disconnected
			wsmu.Lock()
			delete(ps, p)
			wsmu.Unlock()
			break
		}
		ps[p] = msgType
		c := client{
			msg: msg,
			c:   p,
		}
		msgchan <- c
	}
}

func main() {
	router := xmux.NewRouter()
	wsmu = sync.RWMutex{}
	msgchan = make(chan client, 100)
	ps = make(map[*xmux.BaseWs]byte)
	router.SetHeader("Access-Control-Allow-Origin", "*")
	router.Get("/{int:uid}", ws)

	go sendMsg()
	if err := http.ListenAndServe(":8080", router); err != nil {
		log.Fatal(err)
	}

}

<!DOCTYPE html>
<html>

<head>
    <title>go websocket</title>
    <meta charset="utf-8" />
</head>

<body>
    <script type="text/javascript">
        var wsUri = "ws://localhost:8080/3";
        var output;
        var connect = false;
   
        function init() {
            output = document.getElementById("output");
            testWebSocket();
        }

        function testWebSocket() {
            websocket = new WebSocket(wsUri, WebSocket.binaryType);
            websocket.onopen = function(evt) {
                onOpen(evt)
            };
            websocket.onclose = function(evt) {
                onClose(evt)
            };
            websocket.onmessage = function(evt) {
                onMessage(evt)
            };
            websocket.onerror = function(evt) {
                onError(evt)
            };
        }

        function onOpen(evt) {
            writeToScreen("CONNECTED");
            connect = true
                // doSend("WebSocket rocks");
        }

        function onClose(evt) {
            connect = false
            writeToScreen("DISCONNECTED");
        }

        function onMessage(evt) {

            msg = String.fromCharCode(evt.data)
            console.log(msg)
            writeToScreen('<span style="color: blue;">RESPONSE: ' + evt.data + '</span>');
            // websocket.close();
        }

        function onError(evt) {
            writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
        }

        function doSend(message) {
            if (!connect) {
                console.log("connect error")
                return
            }
            writeToScreen("SENT: " + message);
            websocket.send(message);
        }

        function writeToScreen(message) {
            var pre = document.createElement("p");
            pre.style.wordWrap = "break-word";

            pre.innerHTML = message;
            output.appendChild(pre);
        }

        window.addEventListener("load", init, false);

        function sendBtnClick() {
            var msg = document.getElementById("input").value;
            doSend(msg);
            document.getElementById("input").value = '';
        }

        function closeBtnClick() {
            websocket.close();
        }
    </script>
    <h2>WebSocket Test</h2>
    <input type="text" id="input"></input>
    <button onclick="sendBtnClick()">send</button>
    <button onclick="closeBtnClick()">close</button>
    <div id="output"></div>

</body>

</html>

swagger

All applicable functions start with swagger, and the data structure is the same as [swagger]( https://swagger.io/docs/specification/2-0/basic-structure/ )The same as that of the document, please refer to the swagger data structure

package main

import "github.com/hyahm/xmux"

func main() {
	router := xmux.NewRouter()
	router.Get("/", nil)
	router.AddGroup(router.ShowSwagger("/docs", "localhost:8080"))
	router.Run()
}

Gets the current number of connections

xmux.GetConnents()

Graceful stop

xmux.StopService()

Built in routing cache


xmux.NewRouter(cache ...uint64) // Cache is a built-in LRU path cache. The default cache 10000 is not written. Please modify it yourself according to the situation

Permission control < a id = "permission" >

  • Page permissions

The idea comes from the roles of the front-end framework routing component meta Judging by a given array

Take the Vue backend project with the largest number of front-end stars in GitHub as an example https://github.com/PanJiaChen/vue-element-admin

src/router/index.js Page permission routing inside


{
    path: '/permission',
    component: Layout,
    redirect: '/permission/page',
    alwaysShow: true, // will always show the root menu
    name: 'Permission',
    meta: {
      title: 'Permission',
      icon: 'lock',
      roles: ['admin', 'editor'] // you can set roles in root nav
    },
    children: [
      {
        path: 'page',
        component: () => import('@/views/permission/page'),
        name: 'PagePermission',
        meta: {
          title: 'Page Permission',
          roles: ['admin'] // or you can only set roles in sub nav
        }
      },
      {
        path: 'directive',
        component: () => import('@/views/permission/directive'),
        name: 'DirectivePermission',
        meta: {
          title: 'Directive Permission'
          // if do not set roles, means: this page does not required permission
        }
      },
      {
        path: 'role',
        component: () => import('@/views/permission/role'),
        name: 'RolePermission',
        meta: {
          title: 'Role Permission',
          roles: ['admin']
        }
      }
    ]
  },

xmux Corresponding writing


func AddName(w http.ResponseWriter, r *http.Request) {
	fmt.Printf("%v", "AddName")
}

func AddStd(w http.ResponseWriter, r *http.Request) {
	fmt.Printf("%v", "AddStd")
}

func AddFoo(w http.ResponseWriter, r *http.Request) {
	fmt.Printf("%v", "AddFoo")
}

func role(w http.ResponseWriter, r *http.Request) {
	fmt.Printf("%v", "role")
}

func DefaultPermissionTemplate(w http.ResponseWriter, r *http.Request) (post bool) {

	// Get the permission of the corresponding URI, which is set by addpagekeys and delpagekeys
	pages := xmux.GetInstance(r).GetPageKeys()
	// If the length is 0, it means that anyone can access it
	if len(pages) == 0 {
		return false
	}

	// Get the corresponding role of the user and judge that it is all in
	roles := []string{"admin"} //Obtain the user's permission from the database or redis
	for _, role := range roles {
		if _, ok := pages[role]; ok {
			//What matches here is the existence of this permission. Continue to follow for so long
			return false
		}
	}
	// no permission
	w.Write([]byte("no permission"))
	return true
}

func 

func main() {
	router := xmux.NewRouter()
	router.AddModule(DefaultPermissionTemplate).AddPageKeys("admin", "editor")
	router.Post("/permission", AddName)
	router.Post("/permission/page", AddStd).DelPageKeys("editor")
	router.Post("/permission/directive", AddFoo)
	// You can also directly use the built-in
	router.Post("/permission/role", role).DelPageKeys("editor")
	router.Run()
}

  • More detailed addition, deletion, modification and query authority, but not limited to addition, deletion, modification and query

I think the simplest thing is to judge according to the function name of handle,

You can refer to the permission template of xmux.DefaultPermissionTemplate

Cache

  • Initialize cache cache.InitResponseCache(Cacher) Cacher is a interface

    type Cacher interface {
    	Add(string, []byte) (string, bool)
    	Get(string) ([]byte, bool)
    }
    

    if you want use lru or lfu or alfu cache. you can use github.com/hyahm/gocache

  • The module that needs to set the cached key (the core module does not need to be cached if it is not set)

  • To set the value of cachekey cache.GetInstance(r).Set(xmux.CacheKey, fmt.Sprintf("%s_%v", r.URL.Path, uid))

  • The cache module needs to be mounted

example of not bind return data

package main

import (
	"fmt"
	"net/http"
	"time"

	"github.com/hyahm/gocache"
	"github.com/hyahm/xmux"
)

func c(w http.ResponseWriter, r *http.Request) {
	fmt.Println("comming c")
	now := time.Now().String()
	xmux.GetInstance(r).Response.(*Response).Data = now
}

func noCache(w http.ResponseWriter, r *http.Request) {
	fmt.Println("update c")
	xmux.NeedUpdate("/aaa")
}

func noCache1(w http.ResponseWriter, r *http.Request) {
	fmt.Println("comming noCache1")
	now := time.Now().String()
	xmux.GetInstance(r).Response.(*Response).Data = now
}

func setKey(w http.ResponseWriter, r *http.Request) bool {
	xmux.GetInstance(r).Set(xmux.CacheKey, r.URL.Path)
	fmt.Print(r.URL.Path + " is cached")
	return false
}

type Response struct {
	Code int         `json:"code"`
	Data interface{} `json:"data"`
}

func main() {
	r := &Response{
		Code: 0,
	}
	cth := gocache.NewCache[string, []byte](100, gocache.LFU)
	xmux.InitResponseCache(cth)
	// If not bind response use xmux.DefaultCacheTemplateCacheWithoutResponse instead of xmux.DefaultCacheTemplateCacheWithResponse
	router := xmux.NewRouter().AddModule(setKey, xmux.DefaultCacheTemplateCacheWithResponse)
	router.BindResponse(r)
	router.Get("/aaa", c)
	router.Get("/update/aaa", noCache).DelModule(setKey)
	router.Get("/no/cache1", noCache1).DelModule(setKey)
	router.Run()
}


Client file download (official built-in method MP4 file as an example)

func PlayVideo(w http.ResponseWriter, r *http.Request) {
	filename := xmux.Var(r)["filename"]
	f, err := os.Open(<mp4file>)
	if err != nil {
		w.WriteHeader(404)
		return
	}
	defer f.Close()
	w.Header().Set("Content-Type", "video/mp4")
	w.Header().Set("X-Download-Options", "noopen")
	http.ServeContent(w, r, filename, time.Now(), f)

Client file upload (official built-in method)

func UploadFile(w http.ResponseWriter, r *http.Request) {
	// The maximum size of the official default uploaded file is 32m. You can set a new size through this method
	r.ParseMultipartForm(100 << 20)   // 100M
	// read file
	file, header, err := r.FormFile("file")
	if err != nil {
		return
	}
	f, err := os.OpenFile(<storefilepath>, os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		return
	}
	defer f.Close()
	_, err := io.Copy(f, file)
	if err != nil {
		return
	}
}

performance analysis Pprof

func main() {
	router := xmux.NewRouter()
	router.Post("/", nil)
	router.AddGroup(xmux.Pprof())
	router.Run()
}

open http://localhost:8080/debug/pprof can see pprof page

View the detailed middleware module and other information of a Handel

//View the details of a specified route
router. DebugAssignRoute("/user/info")
//Check the fixed URI of a regular fire matching route to obtain the details of a route
router. DebugIncludeTpl("")
//Show all, not recommended,
router. DebugRoute()
router. DebugTpl()

out

2022/01/22 17:16:11 url: /user/info, method: GET, header: map[], module: xmux.funcOrder{"github.com/hyahm/xmux.DefaultPermissionTemplate"}, midware: "" , pages: map[string]struct {}{}

Connection Instance

xmux.GetInstance(r).Body // Bind request data,  This data is only available when the binding value is
xmux.GetInstance(r).CacheKey  // cache key
xmux.GetInstance(r).Data   // Value parsed by data binding
xmux.GetInstance(r).Response  // Response data
xmux.GetInstance(r).StatusCode   // status_code
xmux.GetInstance(r).Get()  // Get context value
xmux.GetInstance(r).Set()  // Set context value
xmux.GetInstance(r).GetConnectId()  // Get current connect id
xmux.GetInstance(r).GetFuncName()  // It is related to the authority of adding, deleting, modifying and querying
xmux.GetInstance(r).GetPageKeys()  // Related to page permissions

Life cycle flow chart

cycle

Documentation

Index

Constants

View Source
const (
	MIMEJSON              = "application/json"
	MIMEXML               = "application/xml"
	MIMEXML2              = "text/xml"
	MIMEPlain             = "text/plain"
	MIMEPOSTForm          = "application/x-www-form-urlencoded"
	MIMEMultipartPOSTForm = "multipart/form-data"
	MIMEPROTOBUF          = "application/x-protobuf"
	MIMEMSGPACK           = "application/x-msgpack"
	MIMEMSGPACK2          = "application/msgpack"
	MIMEYAML              = "application/x-yaml"
)
View Source
const (
	TypeMsg    = byte(129)
	TypeBinary = byte(130)
	TypeClose  = byte(136)
	TypePing   = byte(137)
	TypePong   = byte(138)
)
View Source
const PAGES = "PAGES"

Variables

View Source
var (
	ErrConnectClosed    = errors.New("connect closed")
	ErrorType           = errors.New("type error")
	ErrorProtocol       = errors.New("protocol undefined")
	ErrorGetLenth       = errors.New("get length error")
	ErrorGetMsg         = errors.New("read data error")
	ErrorMsgNotEnough   = errors.New("data length not enough")
	ErrorNotFoundHandle = errors.New("please write a Handle")
	ErrorRespose        = errors.New("websocket: response does not implement http.Hijacker")
	ErrorHandshake      = errors.New("websocket: client sent data before handshake is complete")
	ErrorNoWebsocketKey = errors.New("not found Sec-WebSocket-Key")
)
View Source
var ErrBadStringFormat = errors.New("bad string format")

ErrBadStringFormat represents a error of input string's format is illegal .

View Source
var ErrEmptyString = errors.New("empty string")

ErrEmptyString represents a error of empty input string.

View Source
var ErrTypeUnsupport = errors.New("data type is unsupported")

Functions

func BinaryStringToBytes

func BinaryStringToBytes(s string) (bs []byte)

BinaryStringToBytes get the binary bytes according to the input string which is in binary format.

func ByteToBinaryString

func ByteToBinaryString(b byte) string

ByteToBinaryString get the string in binary format of a byte or uint8.

func BytesToBinaryString

func BytesToBinaryString(bs []byte) string

BytesToBinaryString get the string in binary format of a []byte or []int8.

func Clone

func Clone(src interface{}) interface{}

func DefaultCacheTemplateCacheWithResponse

func DefaultCacheTemplateCacheWithResponse(w http.ResponseWriter, r *http.Request) bool

func DefaultCacheTemplateCacheWithoutResponse

func DefaultCacheTemplateCacheWithoutResponse(w http.ResponseWriter, r *http.Request) bool

func DefaultModuleTemplate

func DefaultModuleTemplate(w http.ResponseWriter, r *http.Request) bool

func DefaultPermissionTemplate

func DefaultPermissionTemplate(w http.ResponseWriter, r *http.Request) (post bool)

func ExsitsCache

func ExsitsCache(key string) bool

是否存在缓存

func GenRsa

func GenRsa(prikey, pubkey, crtkey string) error

func GetCache

func GetCache(key string) []byte

获取缓存值, 如果不存在返回nil

func GetConnents

func GetConnents() int32

func GetLimit

func GetLimit(count, page, limit int) (int, int, int)

分页用到的计算sql limit的数值

func GetPerm

func GetPerm(permList []string, flag uint8) []bool

给定一个权限组, 顺序对应2进制的值必须是 1 << index, 最后返回对应位置 是不是 1 的 bool类型的切片 如果传入的切片大于8,只获取8个

func InitResponseCache

func InitResponseCache(cache Cacher)

func IsUpdate

func IsUpdate(key string) bool

是否在更新缓存

func JsonFile

func JsonFile(jsonPath, url, host string, router *Router, schemes ...string) http.HandlerFunc

func NeedUpdate

func NeedUpdate(key string)

need update cache

func PrettySlash

func PrettySlash(p string) string

func RSA_Encrypt

func RSA_Encrypt(plainText []byte, path string) ([]byte, error)

RSA加密

func ReadBinaryString

func ReadBinaryString(s string, data interface{}) (err error)

ReadBinaryString read the string in binary format into input data.

func RsaDecryptFromBase64

func RsaDecryptFromBase64(s string, priviteKeyPath string) ([]byte, error)

RSA解密

func RsaDecryptFromString

func RsaDecryptFromString(s string, priviteKeyPath string) ([]byte, error)

RSA解密

func SetCache

func SetCache(key string, value []byte)

设置缓存值

func SetKey

func SetKey(name string) string

func SetPem

func SetPem(name string) string

func SetUpdate

func SetUpdate(key string)

func ShutDown

func ShutDown()

平滑停止http

func StartService

func StartService()

func StopService

func StopService()

func Subtract

func Subtract[T comparable](a, b []T) []T

a 减去b的差集

func SubtractSliceMap

func SubtractSliceMap[T comparable](a []T, b map[T]struct{}) []T

func ToBinaryString

func ToBinaryString(v interface{}) (s string)

ToBinaryString get string in binary format according to input data. The input data can be diffrent kinds of basic data type.

func Uint16ToBinaryString

func Uint16ToBinaryString(i uint16) string

Uint16ToBinaryString get the string of a uint16 number in binary format.

func Uint32ToBinaryString

func Uint32ToBinaryString(i uint32) string

Uint32ToBinaryString get the string of a uint32 number in binary format.

func Uint64ToBinaryString

func Uint64ToBinaryString(i uint64) string

Uint64ToBinaryString get the string of a uint64 number in binary format.

func UnescapeUnicode

func UnescapeUnicode(raw []byte) (string, error)

将前端传进来的部分中文被编译成unicode编码进行还原

func Var

func Var(r *http.Request) params

Types

type BaseWs

type BaseWs struct {
	Conn       net.Conn
	RemoteAddr string
	IsExtras   bool
}

func UpgradeWebSocket

func UpgradeWebSocket(w http.ResponseWriter, r *http.Request) (*BaseWs, error)

func (*BaseWs) Close

func (bw *BaseWs) Close() error

func (*BaseWs) Ping

func (xws *BaseWs) Ping(ping []byte) error

func (*BaseWs) ReadBytes

func (xws *BaseWs) ReadBytes() (byte, []byte, error)

TODO: 没有处理附加数据

func (*BaseWs) ReadMessage

func (xws *BaseWs) ReadMessage() (byte, string, error)

func (*BaseWs) SendMessage

func (xws *BaseWs) SendMessage(msg []byte, typ byte) error

type CacheStatus

type CacheStatus string
const (
	NotFoundCache    CacheStatus = "Not found cache"
	CacheIsUpdateing CacheStatus = "Cache is Updating"
	CacheNeedUpdate  CacheStatus = "Cache need Updating"
	CacheHit         CacheStatus = "cache hit"
)

func GetCacheIfUpdating

func GetCacheIfUpdating(key string) ([]byte, CacheStatus)

获取缓存,如果正在更新 如果返回 NotFoundCache 说明不存在这个缓存 如果返回 CacheIsUpdateing 说明当前还在更新中, 还不是最新的缓存 如果返回 CacheNeedUpdate 说明缓存需要更新 如果返回 CacheHit 说明是最新的,可以直接返回

type Cacher

type Cacher interface {
	Add(string, []byte) (string, bool)
	Get(string) ([]byte, bool)
}

type ContentType

type ContentType string
const (
	URLENCODED ContentType = "application/x-www-form-urlencoded"
	JSON       ContentType = "application/json"
	FORM       ContentType = "multipart/form-data"
	XML        ContentType = "application/xml"
)

func (ContentType) String

func (ct ContentType) String() string

type Definition

type Definition struct {
	Properties map[string]Type `json:"properties" yaml:"properties"`
	Required   []string        `json:"required" yaml:"required"`
}

type FlowData

type FlowData struct {
	Data interface{} // 处理后的数据

	Response interface{} // 返回的数据结构

	StatusCode int
	Body       []byte
	CacheKey   string
	// contains filtered or unexported fields
}

func GetInstance

func GetInstance(r *http.Request) *FlowData

func (*FlowData) Del

func (data *FlowData) Del(k string)

func (*FlowData) Get

func (data *FlowData) Get(k string) interface{}

func (*FlowData) GetConnectId

func (data *FlowData) GetConnectId() int64

func (*FlowData) GetFuncName

func (data *FlowData) GetFuncName() string

func (*FlowData) GetPageKeys

func (data *FlowData) GetPageKeys() map[string]struct{}

func (*FlowData) Set

func (data *FlowData) Set(k string, v interface{})

type Info

type Info struct {
	Title       string `json:"title" yaml:"title"`
	Description string `json:"description" yaml:"description"`
	Version     string `json:"version" yaml:"version"`
}

type JsonStr

type JsonStr string

type MethodStrcut

type MethodStrcut struct {
	Summary    string              `json:"summary,omitempty" yaml:"summary"`
	Parameters []Parameter         `json:"parameters,omitempty" yaml:"parameters"`
	Responses  map[string]Response `json:"responses,omitempty" yaml:"responses"`
	Produces   []string            `json:"produces,omitempty" yaml:"produces" required:""`
	Consumes   []string            `json:"consumes,omitempty" yaml:"consumes"`
}

type MethodsRoute

type MethodsRoute map[string]*Route

string 对应的是method

func (MethodsRoute) AddModule

func (mr MethodsRoute) AddModule(handles ...func(http.ResponseWriter, *http.Request) bool) MethodsRoute

func (MethodsRoute) AddPageKeys

func (mr MethodsRoute) AddPageKeys(pagekeys ...string) MethodsRoute

func (MethodsRoute) Bind

func (mr MethodsRoute) Bind(dest interface{}) MethodsRoute

func (MethodsRoute) BindByContentType

func (mr MethodsRoute) BindByContentType(dest interface{}) MethodsRoute

func (MethodsRoute) BindForm

func (mr MethodsRoute) BindForm(dest interface{}) MethodsRoute

func (MethodsRoute) BindJson

func (mr MethodsRoute) BindJson(dest interface{}) MethodsRoute

func (MethodsRoute) BindResponse

func (mr MethodsRoute) BindResponse(dest interface{}) MethodsRoute

func (MethodsRoute) BindXml

func (mr MethodsRoute) BindXml(dest interface{}) MethodsRoute

func (MethodsRoute) BindYaml

func (mr MethodsRoute) BindYaml(dest interface{}) MethodsRoute

func (MethodsRoute) DelHeader

func (mr MethodsRoute) DelHeader(key string) MethodsRoute

func (MethodsRoute) DelModule

func (mr MethodsRoute) DelModule(handles ...func(http.ResponseWriter, *http.Request) bool) MethodsRoute

func (MethodsRoute) DelPageKeys

func (mr MethodsRoute) DelPageKeys(pagekeys ...string) MethodsRoute

func (MethodsRoute) GetRoute

func (mr MethodsRoute) GetRoute(method string) *Route

get route by method. if not found will return nil

func (MethodsRoute) SetHeader

func (mr MethodsRoute) SetHeader(key, value string) MethodsRoute

type Opt

type Opt interface {
	SetKey() string
	SetPem() string
	SetAddr() string
}

type Parameter

type Parameter struct {
	In          ParameterType     `json:"in,omitempty" yaml:"in"`
	Name        string            `json:"name,omitempty" yaml:"name"`
	Required    bool              `required:"in,omitempty" yaml:"required"`
	Type        string            `json:"type,omitempty" yaml:"type"`
	Schema      map[string]string `json:"schema,omitempty" yaml:"schema"`
	Minimum     int64             `json:"minimum,omitempty" yaml:"minimum"`
	Enum        []string          `json:"enum,omitempty" yaml:"enum"`
	Default     any               `json:"default,omitempty" yaml:"default"`
	Description string            `json:"description,omitempty" yaml:"description"`
}

type ParameterType

type ParameterType string
const (
	Query  ParameterType = "query"
	Path   ParameterType = "path"
	Header ParameterType = "header"
	Form   ParameterType = "formData"
)

type Response

type Response struct {
	Description string            `json:"type,omitempty" yaml:"type"`
	Schema      map[string]string `json:"schema,omitempty" yaml:"schema"`
}

type Route

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

初始化临时使用, 最后会合并到 router

func (*Route) AddModule

func (rt *Route) AddModule(handles ...func(http.ResponseWriter, *http.Request) bool) *Route

func (*Route) AddPageKeys

func (rt *Route) AddPageKeys(pagekeys ...string) *Route

func (*Route) Bind

func (rt *Route) Bind(s interface{}) *Route

数据绑定

func (*Route) BindByContentType

func (rt *Route) BindByContentType(s interface{}) *Route

func (*Route) BindForm

func (rt *Route) BindForm(s interface{}) *Route

func (*Route) BindJson

func (rt *Route) BindJson(s interface{}) *Route

json数据绑定

func (*Route) BindResponse

func (rt *Route) BindResponse(response interface{}) *Route

func (*Route) BindXml

func (rt *Route) BindXml(s interface{}) *Route

xml数据绑定

func (*Route) BindYaml

func (rt *Route) BindYaml(s interface{}) *Route

yaml数据绑定

func (*Route) DelHeader

func (rt *Route) DelHeader(dh ...string) *Route

func (*Route) DelModule

func (rt *Route) DelModule(handles ...func(http.ResponseWriter, *http.Request) bool) *Route

func (*Route) DelPageKeys

func (rt *Route) DelPageKeys(pagekeys ...string) *Route

func (*Route) DelPrefix

func (rt *Route) DelPrefix(prefixs ...string) *Route

func (*Route) GetHeader

func (rt *Route) GetHeader() map[string]string

func (*Route) Prefix

func (rt *Route) Prefix(prefix string) *Route

func (*Route) SetHeader

func (rt *Route) SetHeader(k, v string) *Route

func (*Route) SwaggerAddParameter

func (rt *Route) SwaggerAddParameter(pt Parameter) *Route

func (*Route) SwaggerSummary

func (rt *Route) SwaggerSummary(summary string) *Route

这个路由的注释, 使用swagger加上这个字段才能显示执行的窗口

type RouteGroup

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

服务启动前的操作, 所以里面的map 都是单线程不需要加锁的

func NewRouteGroup

func NewRouteGroup() *RouteGroup

func Pprof

func Pprof() *RouteGroup

func (*RouteGroup) AddGroup

func (g *RouteGroup) AddGroup(group *RouteGroup) *RouteGroup

组路由添加到组路由

func (*RouteGroup) AddModule

func (g *RouteGroup) AddModule(handles ...func(http.ResponseWriter, *http.Request) bool) *RouteGroup

func (*RouteGroup) AddPageKeys

func (g *RouteGroup) AddPageKeys(pagekeys ...string) *RouteGroup

func (*RouteGroup) Any

func (gr *RouteGroup) Any(pattern string, handler func(http.ResponseWriter, *http.Request)) MethodsRoute

func (*RouteGroup) BindResponse

func (g *RouteGroup) BindResponse(response interface{}) *RouteGroup

func (*RouteGroup) Connect

func (gr *RouteGroup) Connect(pattern string, handler func(http.ResponseWriter, *http.Request)) *Route

func (*RouteGroup) DebugAssignRoute

func (g *RouteGroup) DebugAssignRoute(thisurl string)

func (*RouteGroup) DebugIncludeTpl

func (g *RouteGroup) DebugIncludeTpl(pattern string)

func (*RouteGroup) DelHeader

func (g *RouteGroup) DelHeader(headers ...string) *RouteGroup

func (*RouteGroup) DelModule

func (g *RouteGroup) DelModule(handles ...func(http.ResponseWriter, *http.Request) bool) *RouteGroup

func (*RouteGroup) DelPageKeys

func (g *RouteGroup) DelPageKeys(pagekeys ...string) *RouteGroup

func (*RouteGroup) DelPrefix

func (g *RouteGroup) DelPrefix(prefixs ...string) *RouteGroup

func (*RouteGroup) Delete

func (gr *RouteGroup) Delete(pattern string, handler func(http.ResponseWriter, *http.Request)) *Route

func (*RouteGroup) Get

func (gr *RouteGroup) Get(pattern string, handler func(http.ResponseWriter, *http.Request)) *Route

func (*RouteGroup) Head

func (gr *RouteGroup) Head(pattern string, handler func(http.ResponseWriter, *http.Request)) *Route

func (*RouteGroup) Options

func (gr *RouteGroup) Options(pattern string, handler func(http.ResponseWriter, *http.Request)) *Route

func (*RouteGroup) Patch

func (gr *RouteGroup) Patch(pattern string, handler func(http.ResponseWriter, *http.Request)) *Route

func (*RouteGroup) Post

func (gr *RouteGroup) Post(pattern string, handler func(http.ResponseWriter, *http.Request)) *Route

func (*RouteGroup) Prefix

func (g *RouteGroup) Prefix(prefixs ...string) *RouteGroup

func (*RouteGroup) Put

func (gr *RouteGroup) Put(pattern string, handler func(http.ResponseWriter, *http.Request)) *Route

func (*RouteGroup) Request

func (gr *RouteGroup) Request(pattern string, handler func(http.ResponseWriter, *http.Request), methods ...string) *Route

func (*RouteGroup) Requests

func (gr *RouteGroup) Requests(pattern string, handler func(http.ResponseWriter, *http.Request), methods ...string) MethodsRoute

func (*RouteGroup) SetHeader

func (g *RouteGroup) SetHeader(k, v string) *RouteGroup

func (*RouteGroup) Trace

func (gr *RouteGroup) Trace(pattern string, handler func(http.ResponseWriter, *http.Request)) *Route

type Router

type Router struct {
	MaxPrintLength int
	Exit           func(time.Time, http.ResponseWriter, *http.Request)

	Enter                func(http.ResponseWriter, *http.Request) bool // 当有请求进入时候的执行
	ReadTimeout          time.Duration
	HanleFavicon         func(http.ResponseWriter, *http.Request)
	DisableOption        bool                                     // 禁止全局option
	HandleOptions        func(http.ResponseWriter, *http.Request) // 预请求 处理函数, 如果存在, 优先处理, 前后端分离后, 前段可能会先发送一个预请求
	HandleNotFound       func(http.ResponseWriter, *http.Request)
	NotFoundRequireField func(string, http.ResponseWriter, *http.Request) bool
	UnmarshalError       func(error, http.ResponseWriter, *http.Request) bool
	IgnoreSlash          bool // 忽略地址多个斜杠, 默认不忽略

	SwaggerTitle       string
	SwaggerDescription string
	SwaggerVersion     string
	// contains filtered or unexported fields
}

func NewRouter

func NewRouter(cacheSize ...int) *Router

func (*Router) AddGroup

func (r *Router) AddGroup(group *RouteGroup) *Router

组路由添加到router里面, 挂载到group之前, 全局的变量已经挂载到route 里面了, 所以不用再管组变量了

func (*Router) AddModule

func (r *Router) AddModule(handles ...func(http.ResponseWriter, *http.Request) bool) *Router

func (*Router) AddPageKeys

func (r *Router) AddPageKeys(pagekeys ...string) *Router

func (*Router) Any

func (r *Router) Any(pattern string, handler func(http.ResponseWriter, *http.Request)) MethodsRoute

func (*Router) BindResponse

func (r *Router) BindResponse(response interface{}) *Router

func (*Router) Connect

func (r *Router) Connect(pattern string, handler func(http.ResponseWriter, *http.Request)) *Route

func (*Router) Debug

func (r *Router) Debug(ctx context.Context, opt ...string)

func (*Router) DebugAssignRoute

func (r *Router) DebugAssignRoute(thisurl string)

func (*Router) DebugIncludeTpl

func (r *Router) DebugIncludeTpl(pattern string)

func (*Router) DebugRoute

func (r *Router) DebugRoute()

func (*Router) DebugTpl

func (r *Router) DebugTpl()

func (*Router) Delete

func (r *Router) Delete(pattern string, handler func(http.ResponseWriter, *http.Request)) *Route

func (*Router) Get

func (r *Router) Get(pattern string, handler func(http.ResponseWriter, *http.Request)) *Route

func (*Router) Head

func (r *Router) Head(pattern string, handler func(http.ResponseWriter, *http.Request)) *Route

func (*Router) Options

func (r *Router) Options(pattern string, handler func(http.ResponseWriter, *http.Request)) *Route

func (*Router) Patch

func (r *Router) Patch(pattern string, handler func(http.ResponseWriter, *http.Request)) *Route

func (*Router) Post

func (r *Router) Post(pattern string, handler func(http.ResponseWriter, *http.Request)) *Route

func (*Router) Prefix

func (r *Router) Prefix(prefixs ...string) *Router

func (*Router) Put

func (r *Router) Put(pattern string, handler func(http.ResponseWriter, *http.Request)) *Route

func (*Router) Request

func (r *Router) Request(pattern string, handler func(http.ResponseWriter, *http.Request), methods ...string) MethodsRoute

func (*Router) Run

func (r *Router) Run(opt ...string) error

func (*Router) RunTLS

func (r *Router) RunTLS(keyfile, pemfile string, opt ...string) error

func (*Router) RunUnsafeTLS

func (r *Router) RunUnsafeTLS(opt ...string) error

func (*Router) ServeHTTP

func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request)

func (*Router) SetHeader

func (r *Router) SetHeader(k, v string) *Router

func (*Router) ShowSwagger

func (r *Router) ShowSwagger(url, host string, schemes ...string) *RouteGroup

func (*Router) Trace

func (r *Router) Trace(pattern string, handler func(http.ResponseWriter, *http.Request)) *Route

type Schema

type Schema struct {
	Type       string          `json:"type" yaml:"type"`
	Properties map[string]Type `json:"properties" yaml:"properties"` // key是字段名
	Ref        string          `json:"$ref" yaml:"$ref"`             // $ref: '#/definitions/User'
}

type Swagger

type Swagger struct {
	Swagger             string                             `json:"swagger" yaml:"swagger"`
	Info                Info                               `json:"info" yaml:"info"`
	Host                string                             `json:"host" yaml:"host"`
	BasePath            string                             `json:"basePath,omitempty" yaml:"basePath"`
	Schemes             []string                           `json:"schemes,omitempty" yaml:"schemes"`
	Paths               map[string]map[string]MethodStrcut `json:"paths,omitempty" yaml:"paths"`
	Definitions         map[string]Definition              `json:"definitions,omitempty" yaml:"definitions"`
	Security            []map[string][]string              `json:"security,omitempty" yaml:"security"`
	SecurityDefinitions map[string]Type                    `json:"securityDefinitions,omitempty" yaml:"securityDefinitions"`
}

type SwaggerUIOpts

type SwaggerUIOpts struct {
	// BasePath for the UI path, defaults to: /
	SpecURL string

	// The three components needed to embed swagger-ui
	SwaggerURL       string
	SwaggerPresetURL string
	SwaggerStylesURL string

	Favicon32 string
	Favicon16 string

	// Title for the documentation site, default to: API documentation
	Title string
}

func DefaultEnsure

func DefaultEnsure(jsonPath string) *SwaggerUIOpts

type Type

type Type struct {
	Type        string `json:"type" yaml:"type"`
	Description string `json:"description" yaml:"description"`
}

type UMR

type UMR map[string]MethodsRoute

type WebSocket

type WebSocket interface {
	WS(*BaseWs)
	SendMessage(msg []byte)

	ReadMessage() (string, error)
	// contains filtered or unexported methods
}

type WsHandler

type WsHandler interface {
	Websocket(w http.ResponseWriter, r *http.Request)
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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