assets: optimize static files archetucture

This commit is contained in:
fatedier 2016-08-10 20:18:36 +08:00
parent 3ab9850871
commit 4300169041
20 changed files with 151 additions and 104 deletions

View File

@ -15,6 +15,7 @@ fmt:
frps: frps:
go build -o bin/frps ./src/frp/cmd/frps go build -o bin/frps ./src/frp/cmd/frps
cp -rf ./assets ./bin
frpc: frpc:
go build -o bin/frpc ./src/frp/cmd/frpc go build -o bin/frpc ./src/frp/cmd/frpc

View File

@ -1,10 +1,4 @@
/*! /*!
* bootswatch v3.3.6
* Homepage: http://bootswatch.com
* Copyright 2012-2015 Thomas Park
* Licensed under MIT
* Based on Bootstrap
*//*!
* Bootstrap v3.3.6 (http://getbootstrap.com) * Bootstrap v3.3.6 (http://getbootstrap.com)
* Copyright 2011-2015 Twitter, Inc. * Copyright 2011-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)

18
assets/css/iconfont.css Normal file
View File

@ -0,0 +1,18 @@
@font-face {font-family: "iconfont";
src: url('/static/font/iconfont.eot'); /* IE9*/
src: url('/static/font/iconfont.eot#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('/static/font/iconfont.woff') format('woff'), /* chrome, firefox */
url('/static/font/iconfont.ttf') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
url('/static/font/iconfont.svg#iconfont') format('svg'); /* iOS 4.1- */
}
.iconfont {
font-family:"iconfont" !important;
font-size:16px;
font-style:normal;
-webkit-font-smoothing: antialiased;
-webkit-text-stroke-width: 0.2px;
-moz-osx-font-smoothing: grayscale;
}
.icon-sort:before { content: "\e66d"; }

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -3,19 +3,14 @@
<head> <head>
<title>frp</title> <title>frp</title>
<link href="static/bootstrap.min.css" rel="stylesheet"> <link href="static/css/bootstrap.min.css" rel="stylesheet">
<script src="static/jquery.min.js"></script> <link href="static/css/iconfont.css" rel="stylesheet">
<script src="static/bootstrap.min.js"></script> <script src="static/js/jquery.min.js"></script>
<link href="static/iconfont.css" rel="stylesheet"> <script src="static/js/bootstrap.min.js"></script>
</head> </head>
<body> <body>
<div class="container-fluid"> <div class="container-fluid" style="margin-top: 80px">
<!--div class="row">
<div class="col-sm-12 text-center">
<h1 class="logo">frp</h1>
</div>
</div-->
<div class="row"> <div class="row">
<div class="col-md-5 col-sm-offset-1"> <div class="col-md-5 col-sm-offset-1">
<div class="panel panel-default"> <div class="panel panel-default">
@ -57,23 +52,23 @@
</div> </div>
</div> </div>
</div> </div>
<script src="static/angular.min.js"></script> <script src="static/js/angular.min.js"></script>
<script type="text/javascript" src="static/echarts.min.js"></script> <script type="text/javascript" src="static/js/echarts.min.js"></script>
<script> <script>
var alldata = new Array(); var alldata = new Array();
var index = null; var index = null;
<<< range .proxies >>> <<< range .>>>
alldata["<<< .name >>>"] = { alldata["<<< .Name >>>"] = {
name: "<<< .name >>>", name: "<<< .Name >>>",
type: "<<< .type >>>", type: "<<< .Type >>>",
bind_addr: "<<< .bind_addr >>>", bind_addr: "<<< .BindAddr >>>",
listen_port: "<<< .listen_port >>>", listen_port: "<<< .ListenPort >>>",
current_conns: <<< .current_conns >>> , current_conns: <<< .CurrentConns >>> ,
domains: [ <<< range.custom_domains >>> "<<< . >>>", <<< end >>> ], domains: [ <<< range.CustomDomains >>> "<<< . >>>", <<< end >>> ],
stat: "<<< .status >>>", stat: "<<< .Status >>>",
use_encryption: "<<< .use_encryption >>>", use_encryption: "<<< .UseEncryption >>>",
use_gzip: "<<< .use_gzip >>>", use_gzip: "<<< .UseGzip >>>",
privilege_mode: "<<< .privilege_mode >>>", privilege_mode: "<<< .PrivilegeMode >>>",
times: [], times: [],
ins: [], ins: [],
outs: [], outs: [],
@ -93,7 +88,6 @@
var step = 1; var step = 1;
function reloadview() { function reloadview() {
console.log("in reloadview index:", index);
window.maxval = 0; window.maxval = 0;
window.dw = " B"; window.dw = " B";
window.step = 1; window.step = 1;
@ -154,12 +148,12 @@
}, },
series: [{ series: [{
name: 'flow_in', name: 'flow_in',
type: 'line', type: 'bar',
stack: '总量', stack: '总量',
data: alldata[index].ins data: alldata[index].ins
}, { }, {
name: 'flow_out', name: 'flow_out',
type: 'line', type: 'bar',
stack: '总量', stack: '总量',
data: alldata[index].outs data: alldata[index].outs
}] }]
@ -196,7 +190,7 @@
}, },
series: [{ series: [{
name: 'total_accept_conns', name: 'total_accept_conns',
type: 'line', type: 'bar',
stack: '总量', stack: '总量',
data: alldata[index].conns data: alldata[index].conns
}] }]
@ -244,34 +238,33 @@
{ {
var ttdy = new Date(); var ttdy = new Date();
var today = ttdy.getFullYear() * 10000 + (1 + ttdy.getMonth()) * 100 + ttdy.getDate(); var today = ttdy.getFullYear() * 10000 + (1 + ttdy.getMonth()) * 100 + ttdy.getDate();
for (var inx in newproxies.proxies) { for (var inx in newproxies) {
console.log("now inx is ", inx); if (newproxies[inx].current_conns == undefined) {
if (newproxies.proxies[inx].current_conns == undefined) { newproxies[inx].current_conns = 0;
newproxies.proxies[inx].current_conns = 0; alldata[newproxies[inx].name].current_conns = 0;
alldata[newproxies.proxies[inx].name].current_conns = 0;
} }
if (newproxies.proxies[inx].daily == undefined ) { if (newproxies[inx].daily == undefined ) {
newproxies.proxies[inx].daily = []; newproxies[inx].daily = [];
} }
newproxies.proxies[inx].daily.sort(function (a, b) { newproxies[inx].daily.sort(function (a, b) {
return a.time > b.time; return a.time > b.time;
}); });
for (var iinnx in newproxies.proxies[inx].daily) { for (var iinnx in newproxies[inx].daily) {
alldata[newproxies.proxies[inx].name].times.push(newproxies.proxies[inx].daily[iinnx].time); alldata[newproxies[inx].name].times.push(newproxies[inx].daily[iinnx].time);
alldata[newproxies.proxies[inx].name].ins.push(newproxies.proxies[inx].daily[iinnx].flow_in); alldata[newproxies[inx].name].ins.push(newproxies[inx].daily[iinnx].flow_in);
alldata[newproxies.proxies[inx].name].outs.push(newproxies.proxies[inx].daily[iinnx].flow_out); alldata[newproxies[inx].name].outs.push(newproxies[inx].daily[iinnx].flow_out);
alldata[newproxies.proxies[inx].name].conns.push(newproxies.proxies[inx].daily[iinnx].total_accept_conns); alldata[newproxies[inx].name].conns.push(newproxies[inx].daily[iinnx].total_accept_conns);
} }
if (newproxies.proxies[inx].daily.length == 0 || newproxies.proxies[inx].daily[0].time != today) { if (newproxies[inx].daily.length == 0 || newproxies[inx].daily[0].time != today) {
alldata[newproxies.proxies[inx].name].times.push(today); alldata[newproxies[inx].name].times.push(today);
alldata[newproxies.proxies[inx].name].ins.push(0); alldata[newproxies[inx].name].ins.push(0);
alldata[newproxies.proxies[inx].name].outs.push(0); alldata[newproxies[inx].name].outs.push(0);
alldata[newproxies.proxies[inx].name].conns.push(0); alldata[newproxies[inx].name].conns.push(0);
newproxies.proxies[inx].daily.push({ newproxies[inx].daily.push({
time: today, time: today,
flow_in: 0, flow_in: 0,
flow_out: 0, flow_out: 0,
@ -286,7 +279,7 @@
app.controller('myCtrl', function($scope) { app.controller('myCtrl', function($scope) {
$scope.col = 'name'; $scope.col = 'name';
$scope.desc = 0; $scope.desc = 0;
$scope.proxies = newproxies.proxies; $scope.proxies = newproxies;
}); });
$(".tab_info").hover( $(".tab_info").hover(

View File

@ -315,4 +315,3 @@ y(e)||e.test(b)}}}}},Kc=function(){return{restrict:"A",require:"?ngModel",link:f
C.console&&console.log("WARNING: Tried to load angular more than once."):(je(),le(ca),ca.module("ngLocale",[],["$provide",function(a){function b(a){a+="";var b=a.indexOf(".");return-1==b?0:a.length-b-1}a.value("$locale",{DATETIME_FORMATS:{AMPMS:["AM","PM"],DAY:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),ERANAMES:["Before Christ","Anno Domini"],ERAS:["BC","AD"],FIRSTDAYOFWEEK:6,MONTH:"January February March April May June July August September October November December".split(" "), C.console&&console.log("WARNING: Tried to load angular more than once."):(je(),le(ca),ca.module("ngLocale",[],["$provide",function(a){function b(a){a+="";var b=a.indexOf(".");return-1==b?0:a.length-b-1}a.value("$locale",{DATETIME_FORMATS:{AMPMS:["AM","PM"],DAY:"Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split(" "),ERANAMES:["Before Christ","Anno Domini"],ERAS:["BC","AD"],FIRSTDAYOFWEEK:6,MONTH:"January February March April May June July August September October November December".split(" "),
SHORTDAY:"Sun Mon Tue Wed Thu Fri Sat".split(" "),SHORTMONTH:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),STANDALONEMONTH:"January February March April May June July August September October November December".split(" "),WEEKENDRANGE:[5,6],fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",medium:"MMM d, y h:mm:ss a",mediumDate:"MMM d, y",mediumTime:"h:mm:ss a","short":"M/d/yy h:mm a",shortDate:"M/d/yy",shortTime:"h:mm a"},NUMBER_FORMATS:{CURRENCY_SYM:"$",DECIMAL_SEP:".",GROUP_SEP:",", SHORTDAY:"Sun Mon Tue Wed Thu Fri Sat".split(" "),SHORTMONTH:"Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),STANDALONEMONTH:"January February March April May June July August September October November December".split(" "),WEEKENDRANGE:[5,6],fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",medium:"MMM d, y h:mm:ss a",mediumDate:"MMM d, y",mediumTime:"h:mm:ss a","short":"M/d/yy h:mm a",shortDate:"M/d/yy",shortTime:"h:mm a"},NUMBER_FORMATS:{CURRENCY_SYM:"$",DECIMAL_SEP:".",GROUP_SEP:",",
PATTERNS:[{gSize:3,lgSize:3,maxFrac:3,minFrac:0,minInt:1,negPre:"-",negSuf:"",posPre:"",posSuf:""},{gSize:3,lgSize:3,maxFrac:2,minFrac:2,minInt:1,negPre:"-\u00a4",negSuf:"",posPre:"\u00a4",posSuf:""}]},id:"en-us",localeID:"en_US",pluralCat:function(a,c){var e=a|0,f=c;void 0===f&&(f=Math.min(b(a),3));Math.pow(10,f);return 1==e&&0==f?"one":"other"}})}]),F(C.document).ready(function(){fe(C.document,Bc)}))})(window);!window.angular.$$csp().noInlineStyle&&window.angular.element(document.head).prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}.ng-animate-shim{visibility:hidden;}.ng-anchor{position:absolute;}</style>'); PATTERNS:[{gSize:3,lgSize:3,maxFrac:3,minFrac:0,minInt:1,negPre:"-",negSuf:"",posPre:"",posSuf:""},{gSize:3,lgSize:3,maxFrac:2,minFrac:2,minInt:1,negPre:"-\u00a4",negSuf:"",posPre:"\u00a4",posSuf:""}]},id:"en-us",localeID:"en_US",pluralCat:function(a,c){var e=a|0,f=c;void 0===f&&(f=Math.min(b(a),3));Math.pow(10,f);return 1==e&&0==f?"one":"other"}})}]),F(C.document).ready(function(){fe(C.document,Bc)}))})(window);!window.angular.$$csp().noInlineStyle&&window.angular.element(document.head).prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}.ng-animate-shim{visibility:hidden;}.ng-anchor{position:absolute;}</style>');
//# sourceMappingURL=angular.min.js.map

View File

@ -7,6 +7,8 @@ vhost_http_port = 80
vhost_https_port = 443 vhost_https_port = 443
# if you want to configure or reload frps by dashboard, dashboard_port must be set # if you want to configure or reload frps by dashboard, dashboard_port must be set
dashboard_port = 7500 dashboard_port = 7500
# dashboard assets directory(only for debug mode)
assets_dir = ./assets
# console or real logFile path like ./frps.log # console or real logFile path like ./frps.log
log_file = ./frps.log log_file = ./frps.log
# debug, info, warn, error # debug, info, warn, error

View File

@ -36,6 +36,7 @@ var (
VhostHttpPort int64 = 0 // if VhostHttpPort equals 0, don't listen a public port for http protocol VhostHttpPort int64 = 0 // if VhostHttpPort equals 0, don't listen a public port for http protocol
VhostHttpsPort int64 = 0 // if VhostHttpsPort equals 0, don't listen a public port for https protocol VhostHttpsPort int64 = 0 // if VhostHttpsPort equals 0, don't listen a public port for https protocol
DashboardPort int64 = 0 // if DashboardPort equals 0, dashboard is not available DashboardPort int64 = 0 // if DashboardPort equals 0, dashboard is not available
AssetsDir string = ""
LogFile string = "console" LogFile string = "console"
LogWay string = "console" // console or file LogWay string = "console" // console or file
LogLevel string = "info" LogLevel string = "info"
@ -118,6 +119,11 @@ func loadCommonConf(confFile string) error {
DashboardPort = 0 DashboardPort = 0
} }
tmpStr, ok = conf.Get("common", "assets_dir")
if ok {
AssetsDir = tmpStr
}
tmpStr, ok = conf.Get("common", "log_file") tmpStr, ok = conf.Get("common", "log_file")
if ok { if ok {
LogFile = tmpStr LogFile = tmpStr
@ -252,6 +258,8 @@ func loadProxyConf(confFile string) (proxyServers map[string]*ProxyServer, err e
} }
} else if proxyServer.Type == "http" { } else if proxyServer.Type == "http" {
// for http // for http
proxyServer.ListenPort = VhostHttpPort
domainStr, ok := section["custom_domains"] domainStr, ok := section["custom_domains"]
if ok { if ok {
proxyServer.CustomDomains = strings.Split(domainStr, ",") proxyServer.CustomDomains = strings.Split(domainStr, ",")
@ -266,6 +274,8 @@ func loadProxyConf(confFile string) (proxyServers map[string]*ProxyServer, err e
} }
} else if proxyServer.Type == "https" { } else if proxyServer.Type == "https" {
// for https // for https
proxyServer.ListenPort = VhostHttpsPort
domainStr, ok := section["custom_domains"] domainStr, ok := section["custom_domains"]
if ok { if ok {
proxyServer.CustomDomains = strings.Split(domainStr, ",") proxyServer.CustomDomains = strings.Split(domainStr, ",")

View File

@ -16,55 +16,42 @@ package server
import ( import (
"fmt" "fmt"
"frp/models/metric" "net"
"html/template"
"net/http" "net/http"
"time"
"github.com/gin-gonic/gin"
) )
func index(w http.ResponseWriter, r *http.Request) { var (
serinfo := metric.GetAllProxyMetrics() httpServerReadTimeout = 10 * time.Second
t := template.Must(template.New("index.html").Delims("<<<", ">>>").ParseFiles("index.html")) httpServerWriteTimeout = 10 * time.Second
)
err := t.Execute(w, serinfo)
if err != nil {
fmt.Println(err.Error())
}
}
func RunDashboardServer(addr string, port int64) (err error) { func RunDashboardServer(addr string, port int64) (err error) {
defer func() { // url router
if r := recover(); r != nil { mux := http.NewServeMux()
err = fmt.Errorf("%v", r) // api, see dashboard_api.go
mux.HandleFunc("/api/reload", apiReload)
mux.HandleFunc("/api/proxies", apiProxies)
// view see dashboard_view.go
mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./assets"))))
mux.HandleFunc("/", viewDashboard)
address := fmt.Sprintf("%s:%d", addr, port)
server := &http.Server{
Addr: address,
Handler: mux,
ReadTimeout: httpServerReadTimeout,
WriteTimeout: httpServerWriteTimeout,
} }
}() if address == "" {
gin.SetMode(gin.ReleaseMode) address = ":http"
router := gin.New()
//router.LoadHTMLGlob("assets/*")
router.GET("/api/reload", apiReload)
router.GET("/api/proxies", apiProxies)
go router.Run(fmt.Sprintf("%s:%d", addr, port))
return
} }
ln, err := net.Listen("tcp", address)
func RunDashboardServer2(addr string, port int64) (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("%v", r)
}
}()
http.HandleFunc("/", index)
fs := http.FileServer(http.Dir("static"))
http.Handle("/static/", http.StripPrefix("/static/", fs))
newPort := fmt.Sprintf(":%d", port)
err = http.ListenAndServe(newPort, nil)
if err != nil { if err != nil {
return err return err
} }
return nil go server.Serve(ln)
return
} }

View File

@ -17,8 +17,7 @@ package server
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http"
"github.com/gin-gonic/gin"
"frp/models/metric" "frp/models/metric"
"frp/utils/log" "frp/utils/log"
@ -29,10 +28,10 @@ type GeneralResponse struct {
Msg string `json:"msg"` Msg string `json:"msg"`
} }
func apiReload(c *gin.Context) { func apiReload(w http.ResponseWriter, r *http.Request) {
var buf []byte
res := &GeneralResponse{} res := &GeneralResponse{}
defer func() { defer func() {
buf, _ := json.Marshal(res)
log.Info("Http response [/api/reload]: %s", string(buf)) log.Info("Http response [/api/reload]: %s", string(buf))
}() }()
@ -43,7 +42,9 @@ func apiReload(c *gin.Context) {
res.Msg = fmt.Sprintf("%v", err) res.Msg = fmt.Sprintf("%v", err)
log.Error("frps reload error: %v", err) log.Error("frps reload error: %v", err)
} }
c.JSON(200, res)
buf, _ = json.Marshal(res)
w.Write(buf)
} }
type ProxiesResponse struct { type ProxiesResponse struct {
@ -52,7 +53,8 @@ type ProxiesResponse struct {
Proxies []*metric.ServerMetric `json:"proxies"` Proxies []*metric.ServerMetric `json:"proxies"`
} }
func apiProxies(c *gin.Context) { func apiProxies(w http.ResponseWriter, r *http.Request) {
var buf []byte
res := &ProxiesResponse{} res := &ProxiesResponse{}
defer func() { defer func() {
log.Info("Http response [/api/proxies]: code [%d]", res.Code) log.Info("Http response [/api/proxies]: code [%d]", res.Code)
@ -60,5 +62,6 @@ func apiProxies(c *gin.Context) {
log.Info("Http request: [/api/proxies]") log.Info("Http request: [/api/proxies]")
res.Proxies = metric.GetAllProxyMetrics() res.Proxies = metric.GetAllProxyMetrics()
c.JSON(200, res) buf, _ = json.Marshal(res)
w.Write(buf)
} }

View File

@ -0,0 +1,35 @@
// Copyright 2016 fatedier, fatedier@gmail.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package server
import (
"html/template"
"net/http"
"path"
"frp/models/metric"
"frp/utils/log"
)
func viewDashboard(w http.ResponseWriter, r *http.Request) {
metrics := metric.GetAllProxyMetrics()
t := template.Must(template.New("index.html").Delims("<<<", ">>>").ParseFiles(path.Join(AssetsDir, "index.html")))
err := t.Execute(w, metrics)
if err != nil {
log.Warn("parse template file [index.html] error: %v", err)
http.Error(w, "parse template file error", http.StatusInternalServerError)
}
}

View File

@ -63,7 +63,13 @@ func NewProxyServerFromCtlMsg(req *msg.ControlReq) (p *ProxyServer) {
p.PrivilegeMode = req.PrivilegeMode p.PrivilegeMode = req.PrivilegeMode
p.PrivilegeToken = PrivilegeToken p.PrivilegeToken = PrivilegeToken
p.BindAddr = BindAddr p.BindAddr = BindAddr
if p.Type == "tcp" {
p.ListenPort = req.RemotePort p.ListenPort = req.RemotePort
} else if p.Type == "http" {
p.ListenPort = VhostHttpPort
} else if p.Type == "https" {
p.ListenPort = VhostHttpsPort
}
p.CustomDomains = req.CustomDomains p.CustomDomains = req.CustomDomains
p.HostHeaderRewrite = req.HostHeaderRewrite p.HostHeaderRewrite = req.HostHeaderRewrite
return return

View File

@ -131,7 +131,6 @@ func (l *Listener) Accept() (*conn.Conn, error) {
// if rewriteFunc is exist and rewriteHost is set // if rewriteFunc is exist and rewriteHost is set
// rewrite http requests with a modified host header // rewrite http requests with a modified host header
if l.mux.rewriteFunc != nil && l.rewriteHost != "" { if l.mux.rewriteFunc != nil && l.rewriteHost != "" {
fmt.Printf("host rewrite: %s\n", l.rewriteHost)
sConn, err := l.mux.rewriteFunc(conn, l.rewriteHost) sConn, err := l.mux.rewriteFunc(conn, l.rewriteHost)
if err != nil { if err != nil {
return nil, fmt.Errorf("http host header rewrite failed") return nil, fmt.Errorf("http host header rewrite failed")