web application base layout
This commit is contained in:
parent
e3bfd27b0a
commit
0f0213c326
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
/vendor
|
||||
/bin
|
||||
/.env
|
||||
/.env
|
||||
/.vscode
|
2
Makefile
2
Makefile
@ -14,7 +14,7 @@ test: tidy
|
||||
go test -mod=vendor -v ./...
|
||||
|
||||
lint:
|
||||
@GO111MODULE=off golangci-lint run -e '.*/pkg/mod' -e ".*/go/src" --enable-all --disable lll $(LINT_ARGS)
|
||||
@GO111MODULE=off golangci-lint run --tests=false --skip-dirs 'example' -e '.*/pkg/mod' -e ".*/go/src" --enable-all --disable lll $(LINT_ARGS)
|
||||
|
||||
tidy:
|
||||
go mod tidy
|
||||
|
0
cmd/server/assets/test.txt
Normal file
0
cmd/server/assets/test.txt
Normal file
21
cmd/server/assets/vendor/bulma-0.7.2/LICENSE
vendored
Normal file
21
cmd/server/assets/vendor/bulma-0.7.2/LICENSE
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2018 Jeremy Thomas
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
1
cmd/server/assets/vendor/bulma-0.7.2/css/bulma.css.map
vendored
Normal file
1
cmd/server/assets/vendor/bulma-0.7.2/css/bulma.css.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1
cmd/server/assets/vendor/bulma-0.7.2/css/bulma.min.css
vendored
Normal file
1
cmd/server/assets/vendor/bulma-0.7.2/css/bulma.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -5,8 +5,10 @@ import (
|
||||
)
|
||||
|
||||
type config struct {
|
||||
HTTPHost string `env:"ORION_HTTP_HOST"`
|
||||
HTTPPort string `env:"ORION_HTTP_PORT"`
|
||||
HTTPHost string `env:"ORION_HTTP_HOST"`
|
||||
HTTPPort string `env:"ORION_HTTP_PORT"`
|
||||
TemplateDir string `env:"ORION_TEMPLATE_DIR"`
|
||||
AssetDir string `env:"ORION_ASSET_DIR"`
|
||||
}
|
||||
|
||||
func overwriteFromEnv(conf *config) error {
|
||||
@ -18,7 +20,9 @@ func overwriteFromEnv(conf *config) error {
|
||||
|
||||
func newDefaultConfig() *config {
|
||||
return &config{
|
||||
HTTPHost: "0.0.0.0",
|
||||
HTTPPort: "8888",
|
||||
HTTPHost: "0.0.0.0",
|
||||
HTTPPort: "8888",
|
||||
TemplateDir: "./templates",
|
||||
AssetDir: "./assets",
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package rpc
|
||||
package jsonrpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -7,10 +7,10 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"forge.cadoles.com/Cadoles/owrt"
|
||||
"forge.cadoles.com/Pyxis/orion/emlid"
|
||||
"forge.cadoles.com/Pyxis/orion/emlid/reachview"
|
||||
"forge.cadoles.com/Pyxis/orion/emlid/updater"
|
||||
"forge.cadoles.com/Pyxis/orion/openwrt"
|
||||
"github.com/gorilla/rpc"
|
||||
"github.com/gorilla/rpc/json"
|
||||
"github.com/pkg/errors"
|
||||
@ -18,12 +18,12 @@ import (
|
||||
|
||||
// OrionService is the JSON-RPC API
|
||||
type OrionService struct {
|
||||
UCI *openwrt.UCI
|
||||
UCI *owrt.UCI
|
||||
}
|
||||
|
||||
// NewOrionService create a new OrionService !
|
||||
func NewOrionService() *OrionService {
|
||||
uci := openwrt.NewUCI()
|
||||
uci := owrt.NewUCI()
|
||||
return &OrionService{
|
||||
UCI: uci,
|
||||
}
|
||||
@ -50,7 +50,7 @@ type ListIfaceArgs struct{}
|
||||
|
||||
// ListIfaceResponse is the response structure for exposed method OwrtListWifiDevices
|
||||
type ListIfaceResponse struct {
|
||||
Interfaces []*openwrt.UCIWirelessInterface
|
||||
Interfaces map[int]*owrt.UCIWirelessInterface
|
||||
}
|
||||
|
||||
// OwrtListWifiInterfaces offers an RPC Method to list wifi interfaces in a OpenWRT device.
|
||||
@ -63,13 +63,13 @@ func (o *OrionService) OwrtListWifiInterfaces(r *http.Request, args *ListIfaceAr
|
||||
// CreateIfaceArgs argument structure for exported method OwrtCreateWifiInterface
|
||||
type CreateIfaceArgs struct {
|
||||
Cleanup bool
|
||||
Iface *openwrt.UCIWirelessInterface
|
||||
Iface *owrt.UCIWirelessInterface
|
||||
}
|
||||
|
||||
// CreateIfaceResponse argument structure for exported method OwrtCreateWifiInterface
|
||||
type CreateIfaceResponse struct {
|
||||
Errors []*openwrt.Action
|
||||
Iface *openwrt.UCIWirelessInterface
|
||||
Errors []*owrt.Action
|
||||
Iface *owrt.UCIWirelessInterface
|
||||
}
|
||||
|
||||
// OwrtCreateWifiInterface Create a WifiInterface in openwrt
|
||||
@ -124,7 +124,7 @@ func (o *OrionService) OwrtCreateWifiInterface(r *http.Request,
|
||||
|
||||
// ConnectIfaceArgs argument structure for exported method OwrtCreateWifiInterface
|
||||
type ConnectIfaceArgs struct {
|
||||
Iface *openwrt.UCIWirelessInterface
|
||||
Iface *owrt.UCIWirelessInterface
|
||||
SSID string
|
||||
Key string
|
||||
}
|
||||
@ -175,7 +175,7 @@ type OrionServer struct {
|
||||
SSID string
|
||||
Security string
|
||||
WifiKey string
|
||||
ClientIface *openwrt.UCIWirelessInterface
|
||||
ClientIface *owrt.UCIWirelessInterface
|
||||
}
|
||||
|
||||
// UpdateOrionBoxArgs argument structure for exported method OwrtCreateWifiInterface
|
||||
@ -212,7 +212,7 @@ func (o *OrionService) connectBox(box *OrionBox, server *OrionServer) error {
|
||||
if cn.ReturnCode != 0 {
|
||||
return fmt.Errorf("%s\n%s", cn.Stdout, cn.Stderr)
|
||||
}
|
||||
dhcli := openwrt.NewDhcpClient(iface.SysDevName)
|
||||
dhcli := owrt.NewDhcpClient(iface.SysDevName)
|
||||
dhres := dhcli.AskForIP()
|
||||
if dhres.CmdRes.ReturnCode != 0 {
|
||||
return fmt.Errorf("%s\n%s", cn.Stdout, cn.Stderr)
|
34
cmd/server/jsonrpc/service.go
Normal file
34
cmd/server/jsonrpc/service.go
Normal file
@ -0,0 +1,34 @@
|
||||
package jsonrpc
|
||||
|
||||
import (
|
||||
"forge.cadoles.com/wpetit/goweb/service"
|
||||
"github.com/gorilla/rpc"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
const ServiceName service.Name = "jsonrpc"
|
||||
|
||||
// From retrieves the JSONRPC service in the given container or panic
|
||||
func From(container *service.Container) (*rpc.Server, error) {
|
||||
|
||||
service, err := container.Service(ServiceName)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error while retrieving '%s' service", ServiceName)
|
||||
}
|
||||
|
||||
jsonRPCService, ok := service.(*rpc.Server)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("retrieved service is not a valid '%s' service", ServiceName)
|
||||
}
|
||||
|
||||
return jsonRPCService, nil
|
||||
}
|
||||
|
||||
// Must retrieves the json-rpc service in the given container or panic otherwise
|
||||
func Must(container *service.Container) *rpc.Server {
|
||||
service, err := From(container)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return service
|
||||
}
|
@ -4,15 +4,28 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/rpc"
|
||||
|
||||
"github.com/gorilla/sessions"
|
||||
|
||||
"forge.cadoles.com/wpetit/goweb/static"
|
||||
|
||||
"forge.cadoles.com/wpetit/goweb/session/gorilla"
|
||||
"forge.cadoles.com/wpetit/goweb/template/html"
|
||||
|
||||
"forge.cadoles.com/Pyxis/orion/cmd/server/rpc"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/chi/middleware"
|
||||
|
||||
goweb "forge.cadoles.com/wpetit/goweb/middleware"
|
||||
"forge.cadoles.com/wpetit/goweb/service/session"
|
||||
"forge.cadoles.com/wpetit/goweb/service/template"
|
||||
|
||||
"forge.cadoles.com/Pyxis/orion/cmd/server/jsonrpc"
|
||||
"forge.cadoles.com/wpetit/goweb/service"
|
||||
"github.com/go-chi/chi"
|
||||
)
|
||||
|
||||
var (
|
||||
conf = newDefaultConfig()
|
||||
jsonrpc = rpc.NewServer()
|
||||
conf = newDefaultConfig()
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -21,24 +34,80 @@ func main() {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
r := chi.NewRouter()
|
||||
// Create service container
|
||||
container := service.NewContainer()
|
||||
container.Provide(jsonrpc.ServiceName, getJSONRPCServiceProvider())
|
||||
container.Provide(template.ServiceName, getTemplateServiceProvider(conf.TemplateDir))
|
||||
container.Provide(session.ServiceName, getSessionServiceProvider())
|
||||
|
||||
r.Use(middleware.Recoverer)
|
||||
r.Use(middleware.RequestID)
|
||||
r.Use(middleware.RealIP)
|
||||
r.Use(middleware.Logger)
|
||||
router := chi.NewRouter()
|
||||
|
||||
r.Post("/rpc", handleRPC)
|
||||
router.Use(middleware.Recoverer)
|
||||
router.Use(middleware.RequestID)
|
||||
router.Use(middleware.Logger)
|
||||
router.Use(goweb.ServiceContainer(container))
|
||||
|
||||
// Define routes
|
||||
router.Get("/", serveHomepage)
|
||||
router.Post("/rpc", handleJSONRPC)
|
||||
router.Get("/**", static.Dir(conf.AssetDir, "", router.NotFoundHandler()))
|
||||
|
||||
hostStr := fmt.Sprintf("%s:%s", conf.HTTPHost, conf.HTTPPort)
|
||||
log.Printf("listening on http://%s", hostStr)
|
||||
|
||||
if err := http.ListenAndServe(hostStr, r); err != nil {
|
||||
log.Printf("listening on http://%s", hostStr)
|
||||
if err := http.ListenAndServe(hostStr, router); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func handleRPC(w http.ResponseWriter, r *http.Request) {
|
||||
jsonrpc.ServeHTTP(w, r)
|
||||
func getJSONRPCServiceProvider() service.Provider {
|
||||
jsonrpc := rpc.NewServer()
|
||||
return func(c *service.Container) (interface{}, error) {
|
||||
return jsonrpc, nil
|
||||
}
|
||||
}
|
||||
|
||||
func getTemplateServiceProvider(templateDir string) service.Provider {
|
||||
|
||||
// Create templateService at application startup
|
||||
templateService := html.NewTemplateService()
|
||||
|
||||
// Load templates and keep error in cache
|
||||
err := templateService.LoadTemplates(templateDir)
|
||||
|
||||
return func(c *service.Container) (interface{}, error) {
|
||||
|
||||
// If an error occured during the templates loading
|
||||
// return the error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return templateService, nil
|
||||
}
|
||||
}
|
||||
|
||||
func getSessionServiceProvider() service.Provider {
|
||||
|
||||
// Create a new encrypted/authenticated cookie store for the session
|
||||
cookieStore, err := gorilla.CreateCookieSessionStore(32, 64)
|
||||
|
||||
var sessionService session.Service
|
||||
if err == nil {
|
||||
sessionService = gorilla.NewSessionService(
|
||||
"orion",
|
||||
cookieStore,
|
||||
&sessions.Options{
|
||||
HttpOnly: true,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return func(c *service.Container) (interface{}, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sessionService, nil
|
||||
}
|
||||
|
||||
}
|
||||
|
33
cmd/server/route.go
Normal file
33
cmd/server/route.go
Normal file
@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"forge.cadoles.com/wpetit/goweb/middleware"
|
||||
"forge.cadoles.com/wpetit/goweb/service"
|
||||
"forge.cadoles.com/wpetit/goweb/service/template"
|
||||
|
||||
"forge.cadoles.com/Pyxis/orion/cmd/server/jsonrpc"
|
||||
)
|
||||
|
||||
func serveHomepage(w http.ResponseWriter, r *http.Request) {
|
||||
container := getServiceContainer(r)
|
||||
templateService := template.Must(container)
|
||||
if err := templateService.RenderPage(w, "home.html.tmpl", nil); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func handleJSONRPC(w http.ResponseWriter, r *http.Request) {
|
||||
container := getServiceContainer(r)
|
||||
rpcServer := jsonrpc.Must(container)
|
||||
rpcServer.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func getServiceContainer(r *http.Request) *service.Container {
|
||||
container, err := middleware.GetServiceContainer(r.Context())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return container
|
||||
}
|
23
cmd/server/templates/blocks/base.html.tmpl
Normal file
23
cmd/server/templates/blocks/base.html.tmpl
Normal file
@ -0,0 +1,23 @@
|
||||
{{define "base"}}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Orion</title>
|
||||
<link rel="stylesheet" href="/vendor/bulma-0.7.2/css/bulma.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<h1 class="title">
|
||||
Hello World
|
||||
</h1>
|
||||
<p class="subtitle">
|
||||
My first website with <strong>Bulma</strong>!
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
1
cmd/server/templates/layouts/home.html.tmpl
Normal file
1
cmd/server/templates/layouts/home.html.tmpl
Normal file
@ -0,0 +1 @@
|
||||
{{template "base" .}}
|
4
go.mod
4
go.mod
@ -1,16 +1,20 @@
|
||||
module forge.cadoles.com/Pyxis/orion
|
||||
|
||||
require (
|
||||
forge.cadoles.com/Cadoles/owrt v0.0.0-20181112081730-972e21754f2d
|
||||
forge.cadoles.com/Pyxis/golang-socketio v0.0.0-20180919100209-bb857ced6b95
|
||||
forge.cadoles.com/wpetit/goweb v0.0.0-20181206210705-100cf8391731
|
||||
github.com/caarlos0/env v3.4.0+incompatible
|
||||
github.com/cenkalti/backoff v2.0.0+incompatible // indirect
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/go-chi/chi v3.3.3+incompatible
|
||||
github.com/gorilla/rpc v1.1.0
|
||||
github.com/gorilla/sessions v1.1.3
|
||||
github.com/gorilla/websocket v1.4.0 // indirect
|
||||
github.com/grandcat/zeroconf v0.0.0-20180329153754-df75bb3ccae1
|
||||
github.com/miekg/dns v1.0.12 // indirect
|
||||
github.com/mitchellh/mapstructure v1.1.2
|
||||
github.com/oxtoacart/bpool v0.0.0-20150712133111-4e1c5567d7c2 // indirect
|
||||
github.com/pkg/errors v0.8.0
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/stretchr/testify v1.2.2 // indirect
|
||||
|
12
go.sum
12
go.sum
@ -1,5 +1,9 @@
|
||||
forge.cadoles.com/Cadoles/owrt v0.0.0-20181112081730-972e21754f2d h1:JrHRNqeepC+rk7/06UYd9a/+WA/CppGswZdmRNyzSgU=
|
||||
forge.cadoles.com/Cadoles/owrt v0.0.0-20181112081730-972e21754f2d/go.mod h1:VLonz5tZXLI6NIndv6vr3741fCLntobz4gIG37b96xo=
|
||||
forge.cadoles.com/Pyxis/golang-socketio v0.0.0-20180919100209-bb857ced6b95 h1:o3G5+9RjczCK1xAYFaRMknk1kY9Ule6PNfiW6N6hEpg=
|
||||
forge.cadoles.com/Pyxis/golang-socketio v0.0.0-20180919100209-bb857ced6b95/go.mod h1:I6kYOFWNkFlNeQLI7ZqfTRz4NdPHZxX0Bzizmzgchs0=
|
||||
forge.cadoles.com/wpetit/goweb v0.0.0-20181206210705-100cf8391731 h1:PRbNjsIKEV42r/gRKs6RDQgEkNGcftTsirC8JsXGLH0=
|
||||
forge.cadoles.com/wpetit/goweb v0.0.0-20181206210705-100cf8391731/go.mod h1:0zrl4O5z1OWAlQYtFF8/O/iGpCMsiDmbXx3ZO+PNG3o=
|
||||
github.com/caarlos0/env v3.4.0+incompatible h1:FRwBdvENjLHZoUbFnULnFss9wKtcapdaM35DfxiTjeM=
|
||||
github.com/caarlos0/env v3.4.0+incompatible/go.mod h1:tdCsowwCzMLdkqRYDlHpZCp2UooDD3MspDBjZ2AD02Y=
|
||||
github.com/cenkalti/backoff v2.0.0+incompatible h1:5IIPUHhlnUZbcHQsQou5k1Tn58nJkeJL9U+ig5CHJbY=
|
||||
@ -8,8 +12,14 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-chi/chi v3.3.3+incompatible h1:KHkmBEMNkwKuK4FdQL7N2wOeB9jnIx7jR5wsuSBEFI8=
|
||||
github.com/go-chi/chi v3.3.3+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||
github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/rpc v1.1.0 h1:marKfvVP0Gpd/jHlVBKCQ8RAoUPdX7K1Nuh6l1BNh7A=
|
||||
github.com/gorilla/rpc v1.1.0/go.mod h1:V4h9r+4sF5HnzqbwIez0fKSpANP0zlYd3qR7p36jkTQ=
|
||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.1.3 h1:uXoZdcdA5XdXF3QzuSlheVRUvjl+1rKY7zBXL68L9RU=
|
||||
github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w=
|
||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/grandcat/zeroconf v0.0.0-20180329153754-df75bb3ccae1 h1:VSELJSxQlpi1bz4ZwT+93hPpzNLRcgytLr77iVRJpcE=
|
||||
@ -18,6 +28,8 @@ github.com/miekg/dns v1.0.12 h1:814rTNaw7Q7pGncpSEDT06YS8rdGmpUEnKgpQzctJsk=
|
||||
github.com/miekg/dns v1.0.12/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/oxtoacart/bpool v0.0.0-20150712133111-4e1c5567d7c2 h1:CXwSGu/LYmbjEab5aMCs5usQRVBGThelUKBNnoSOuso=
|
||||
github.com/oxtoacart/bpool v0.0.0-20150712133111-4e1c5567d7c2/go.mod h1:L3UMQOThbttwfYRNFOWLLVXMhk5Lkio4GGOtw5UrxS0=
|
||||
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
|
Reference in New Issue
Block a user