web application base layout

This commit is contained in:
wpetit 2018-12-06 22:12:32 +01:00
parent e3bfd27b0a
commit 0f0213c326
17 changed files with 240 additions and 32 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
/vendor
/bin
/.env
/.vscode

View File

@ -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

View File

View 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.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -7,6 +7,8 @@ import (
type config struct {
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 {
@ -20,5 +22,7 @@ func newDefaultConfig() *config {
return &config{
HTTPHost: "0.0.0.0",
HTTPPort: "8888",
TemplateDir: "./templates",
AssetDir: "./assets",
}
}

View File

@ -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)

View 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
}

View File

@ -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()
)
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
View 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
}

View 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}}

View File

@ -0,0 +1 @@
{{template "base" .}}

4
go.mod
View File

@ -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
View File

@ -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=

View File

@ -2,9 +2,13 @@
!**/*_test.go
modd.conf
.env
cmd/server/templates/**
Makefile {
prep: make build
daemon: [ -e .env ] && . .env; ./bin/server
daemon: [ -e .env ] && . .env; \
ORION_TEMPLATE_DIR="cmd/server/templates" \
ORION_ASSET_DIR="cmd/server/assets" \
./bin/server
}