mirror of
https://github.com/fatedier/frp.git
synced 2024-11-23 18:49:24 +08:00
assets: optimize static files archetucture
This commit is contained in:
parent
3ab9850871
commit
4300169041
1
Makefile
1
Makefile
@ -15,6 +15,7 @@ fmt:
|
||||
|
||||
frps:
|
||||
go build -o bin/frps ./src/frp/cmd/frps
|
||||
cp -rf ./assets ./bin
|
||||
|
||||
frpc:
|
||||
go build -o bin/frpc ./src/frp/cmd/frpc
|
||||
|
@ -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)
|
||||
* Copyright 2011-2015 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
18
assets/css/iconfont.css
Normal file
18
assets/css/iconfont.css
Normal 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"; }
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
@ -3,19 +3,14 @@
|
||||
|
||||
<head>
|
||||
<title>frp</title>
|
||||
<link href="static/bootstrap.min.css" rel="stylesheet">
|
||||
<script src="static/jquery.min.js"></script>
|
||||
<script src="static/bootstrap.min.js"></script>
|
||||
<link href="static/iconfont.css" rel="stylesheet">
|
||||
<link href="static/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="static/css/iconfont.css" rel="stylesheet">
|
||||
<script src="static/js/jquery.min.js"></script>
|
||||
<script src="static/js/bootstrap.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<!--div class="row">
|
||||
<div class="col-sm-12 text-center">
|
||||
<h1 class="logo">frp</h1>
|
||||
</div>
|
||||
</div-->
|
||||
<div class="container-fluid" style="margin-top: 80px">
|
||||
<div class="row">
|
||||
<div class="col-md-5 col-sm-offset-1">
|
||||
<div class="panel panel-default">
|
||||
@ -57,23 +52,23 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="static/angular.min.js"></script>
|
||||
<script type="text/javascript" src="static/echarts.min.js"></script>
|
||||
<script src="static/js/angular.min.js"></script>
|
||||
<script type="text/javascript" src="static/js/echarts.min.js"></script>
|
||||
<script>
|
||||
var alldata = new Array();
|
||||
var index = null;
|
||||
<<< range .proxies >>>
|
||||
alldata["<<< .name >>>"] = {
|
||||
name: "<<< .name >>>",
|
||||
type: "<<< .type >>>",
|
||||
bind_addr: "<<< .bind_addr >>>",
|
||||
listen_port: "<<< .listen_port >>>",
|
||||
current_conns: <<< .current_conns >>> ,
|
||||
domains: [ <<< range.custom_domains >>> "<<< . >>>", <<< end >>> ],
|
||||
stat: "<<< .status >>>",
|
||||
use_encryption: "<<< .use_encryption >>>",
|
||||
use_gzip: "<<< .use_gzip >>>",
|
||||
privilege_mode: "<<< .privilege_mode >>>",
|
||||
<<< range .>>>
|
||||
alldata["<<< .Name >>>"] = {
|
||||
name: "<<< .Name >>>",
|
||||
type: "<<< .Type >>>",
|
||||
bind_addr: "<<< .BindAddr >>>",
|
||||
listen_port: "<<< .ListenPort >>>",
|
||||
current_conns: <<< .CurrentConns >>> ,
|
||||
domains: [ <<< range.CustomDomains >>> "<<< . >>>", <<< end >>> ],
|
||||
stat: "<<< .Status >>>",
|
||||
use_encryption: "<<< .UseEncryption >>>",
|
||||
use_gzip: "<<< .UseGzip >>>",
|
||||
privilege_mode: "<<< .PrivilegeMode >>>",
|
||||
times: [],
|
||||
ins: [],
|
||||
outs: [],
|
||||
@ -93,7 +88,6 @@
|
||||
var step = 1;
|
||||
|
||||
function reloadview() {
|
||||
console.log("in reloadview index:", index);
|
||||
window.maxval = 0;
|
||||
window.dw = " B";
|
||||
window.step = 1;
|
||||
@ -154,12 +148,12 @@
|
||||
},
|
||||
series: [{
|
||||
name: 'flow_in',
|
||||
type: 'line',
|
||||
type: 'bar',
|
||||
stack: '总量',
|
||||
data: alldata[index].ins
|
||||
}, {
|
||||
name: 'flow_out',
|
||||
type: 'line',
|
||||
type: 'bar',
|
||||
stack: '总量',
|
||||
data: alldata[index].outs
|
||||
}]
|
||||
@ -196,7 +190,7 @@
|
||||
},
|
||||
series: [{
|
||||
name: 'total_accept_conns',
|
||||
type: 'line',
|
||||
type: 'bar',
|
||||
stack: '总量',
|
||||
data: alldata[index].conns
|
||||
}]
|
||||
@ -244,34 +238,33 @@
|
||||
{
|
||||
var ttdy = new Date();
|
||||
var today = ttdy.getFullYear() * 10000 + (1 + ttdy.getMonth()) * 100 + ttdy.getDate();
|
||||
for (var inx in newproxies.proxies) {
|
||||
console.log("now inx is ", inx);
|
||||
if (newproxies.proxies[inx].current_conns == undefined) {
|
||||
newproxies.proxies[inx].current_conns = 0;
|
||||
alldata[newproxies.proxies[inx].name].current_conns = 0;
|
||||
for (var inx in newproxies) {
|
||||
if (newproxies[inx].current_conns == undefined) {
|
||||
newproxies[inx].current_conns = 0;
|
||||
alldata[newproxies[inx].name].current_conns = 0;
|
||||
}
|
||||
|
||||
if (newproxies.proxies[inx].daily == undefined ) {
|
||||
newproxies.proxies[inx].daily = [];
|
||||
if (newproxies[inx].daily == undefined ) {
|
||||
newproxies[inx].daily = [];
|
||||
}
|
||||
|
||||
newproxies.proxies[inx].daily.sort(function (a, b) {
|
||||
newproxies[inx].daily.sort(function (a, b) {
|
||||
return a.time > b.time;
|
||||
});
|
||||
|
||||
for (var iinnx in newproxies.proxies[inx].daily) {
|
||||
alldata[newproxies.proxies[inx].name].times.push(newproxies.proxies[inx].daily[iinnx].time);
|
||||
alldata[newproxies.proxies[inx].name].ins.push(newproxies.proxies[inx].daily[iinnx].flow_in);
|
||||
alldata[newproxies.proxies[inx].name].outs.push(newproxies.proxies[inx].daily[iinnx].flow_out);
|
||||
alldata[newproxies.proxies[inx].name].conns.push(newproxies.proxies[inx].daily[iinnx].total_accept_conns);
|
||||
for (var iinnx in newproxies[inx].daily) {
|
||||
alldata[newproxies[inx].name].times.push(newproxies[inx].daily[iinnx].time);
|
||||
alldata[newproxies[inx].name].ins.push(newproxies[inx].daily[iinnx].flow_in);
|
||||
alldata[newproxies[inx].name].outs.push(newproxies[inx].daily[iinnx].flow_out);
|
||||
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) {
|
||||
alldata[newproxies.proxies[inx].name].times.push(today);
|
||||
alldata[newproxies.proxies[inx].name].ins.push(0);
|
||||
alldata[newproxies.proxies[inx].name].outs.push(0);
|
||||
alldata[newproxies.proxies[inx].name].conns.push(0);
|
||||
newproxies.proxies[inx].daily.push({
|
||||
if (newproxies[inx].daily.length == 0 || newproxies[inx].daily[0].time != today) {
|
||||
alldata[newproxies[inx].name].times.push(today);
|
||||
alldata[newproxies[inx].name].ins.push(0);
|
||||
alldata[newproxies[inx].name].outs.push(0);
|
||||
alldata[newproxies[inx].name].conns.push(0);
|
||||
newproxies[inx].daily.push({
|
||||
time: today,
|
||||
flow_in: 0,
|
||||
flow_out: 0,
|
||||
@ -286,7 +279,7 @@
|
||||
app.controller('myCtrl', function($scope) {
|
||||
$scope.col = 'name';
|
||||
$scope.desc = 0;
|
||||
$scope.proxies = newproxies.proxies;
|
||||
$scope.proxies = newproxies;
|
||||
});
|
||||
|
||||
$(".tab_info").hover(
|
||||
|
@ -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(" "),
|
||||
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>');
|
||||
//# sourceMappingURL=angular.min.js.map
|
@ -7,6 +7,8 @@ vhost_http_port = 80
|
||||
vhost_https_port = 443
|
||||
# if you want to configure or reload frps by dashboard, dashboard_port must be set
|
||||
dashboard_port = 7500
|
||||
# dashboard assets directory(only for debug mode)
|
||||
assets_dir = ./assets
|
||||
# console or real logFile path like ./frps.log
|
||||
log_file = ./frps.log
|
||||
# debug, info, warn, error
|
||||
|
@ -36,6 +36,7 @@ var (
|
||||
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
|
||||
DashboardPort int64 = 0 // if DashboardPort equals 0, dashboard is not available
|
||||
AssetsDir string = ""
|
||||
LogFile string = "console"
|
||||
LogWay string = "console" // console or file
|
||||
LogLevel string = "info"
|
||||
@ -118,6 +119,11 @@ func loadCommonConf(confFile string) error {
|
||||
DashboardPort = 0
|
||||
}
|
||||
|
||||
tmpStr, ok = conf.Get("common", "assets_dir")
|
||||
if ok {
|
||||
AssetsDir = tmpStr
|
||||
}
|
||||
|
||||
tmpStr, ok = conf.Get("common", "log_file")
|
||||
if ok {
|
||||
LogFile = tmpStr
|
||||
@ -252,6 +258,8 @@ func loadProxyConf(confFile string) (proxyServers map[string]*ProxyServer, err e
|
||||
}
|
||||
} else if proxyServer.Type == "http" {
|
||||
// for http
|
||||
proxyServer.ListenPort = VhostHttpPort
|
||||
|
||||
domainStr, ok := section["custom_domains"]
|
||||
if ok {
|
||||
proxyServer.CustomDomains = strings.Split(domainStr, ",")
|
||||
@ -266,6 +274,8 @@ func loadProxyConf(confFile string) (proxyServers map[string]*ProxyServer, err e
|
||||
}
|
||||
} else if proxyServer.Type == "https" {
|
||||
// for https
|
||||
proxyServer.ListenPort = VhostHttpsPort
|
||||
|
||||
domainStr, ok := section["custom_domains"]
|
||||
if ok {
|
||||
proxyServer.CustomDomains = strings.Split(domainStr, ",")
|
||||
|
@ -16,55 +16,42 @@ package server
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"frp/models/metric"
|
||||
"html/template"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"time"
|
||||
)
|
||||
|
||||
func index(w http.ResponseWriter, r *http.Request) {
|
||||
serinfo := metric.GetAllProxyMetrics()
|
||||
t := template.Must(template.New("index.html").Delims("<<<", ">>>").ParseFiles("index.html"))
|
||||
|
||||
err := t.Execute(w, serinfo)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
}
|
||||
var (
|
||||
httpServerReadTimeout = 10 * time.Second
|
||||
httpServerWriteTimeout = 10 * time.Second
|
||||
)
|
||||
|
||||
func RunDashboardServer(addr string, port int64) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("%v", r)
|
||||
}
|
||||
}()
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
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
|
||||
}
|
||||
// url router
|
||||
mux := http.NewServeMux()
|
||||
// api, see dashboard_api.go
|
||||
mux.HandleFunc("/api/reload", apiReload)
|
||||
mux.HandleFunc("/api/proxies", apiProxies)
|
||||
|
||||
func RunDashboardServer2(addr string, port int64) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("%v", r)
|
||||
}
|
||||
}()
|
||||
// view see dashboard_view.go
|
||||
mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./assets"))))
|
||||
mux.HandleFunc("/", viewDashboard)
|
||||
|
||||
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)
|
||||
address := fmt.Sprintf("%s:%d", addr, port)
|
||||
server := &http.Server{
|
||||
Addr: address,
|
||||
Handler: mux,
|
||||
ReadTimeout: httpServerReadTimeout,
|
||||
WriteTimeout: httpServerWriteTimeout,
|
||||
}
|
||||
if address == "" {
|
||||
address = ":http"
|
||||
}
|
||||
ln, err := net.Listen("tcp", address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
go server.Serve(ln)
|
||||
return
|
||||
}
|
||||
|
@ -17,8 +17,7 @@ package server
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
|
||||
"frp/models/metric"
|
||||
"frp/utils/log"
|
||||
@ -29,10 +28,10 @@ type GeneralResponse struct {
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
|
||||
func apiReload(c *gin.Context) {
|
||||
func apiReload(w http.ResponseWriter, r *http.Request) {
|
||||
var buf []byte
|
||||
res := &GeneralResponse{}
|
||||
defer func() {
|
||||
buf, _ := json.Marshal(res)
|
||||
log.Info("Http response [/api/reload]: %s", string(buf))
|
||||
}()
|
||||
|
||||
@ -43,7 +42,9 @@ func apiReload(c *gin.Context) {
|
||||
res.Msg = fmt.Sprintf("%v", err)
|
||||
log.Error("frps reload error: %v", err)
|
||||
}
|
||||
c.JSON(200, res)
|
||||
|
||||
buf, _ = json.Marshal(res)
|
||||
w.Write(buf)
|
||||
}
|
||||
|
||||
type ProxiesResponse struct {
|
||||
@ -52,7 +53,8 @@ type ProxiesResponse struct {
|
||||
Proxies []*metric.ServerMetric `json:"proxies"`
|
||||
}
|
||||
|
||||
func apiProxies(c *gin.Context) {
|
||||
func apiProxies(w http.ResponseWriter, r *http.Request) {
|
||||
var buf []byte
|
||||
res := &ProxiesResponse{}
|
||||
defer func() {
|
||||
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]")
|
||||
res.Proxies = metric.GetAllProxyMetrics()
|
||||
c.JSON(200, res)
|
||||
buf, _ = json.Marshal(res)
|
||||
w.Write(buf)
|
||||
}
|
||||
|
35
src/frp/models/server/dashboard_view.go
Normal file
35
src/frp/models/server/dashboard_view.go
Normal 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)
|
||||
}
|
||||
}
|
@ -63,7 +63,13 @@ func NewProxyServerFromCtlMsg(req *msg.ControlReq) (p *ProxyServer) {
|
||||
p.PrivilegeMode = req.PrivilegeMode
|
||||
p.PrivilegeToken = PrivilegeToken
|
||||
p.BindAddr = BindAddr
|
||||
p.ListenPort = req.RemotePort
|
||||
if p.Type == "tcp" {
|
||||
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.HostHeaderRewrite = req.HostHeaderRewrite
|
||||
return
|
||||
|
@ -131,7 +131,6 @@ func (l *Listener) Accept() (*conn.Conn, error) {
|
||||
// if rewriteFunc is exist and rewriteHost is set
|
||||
// rewrite http requests with a modified host header
|
||||
if l.mux.rewriteFunc != nil && l.rewriteHost != "" {
|
||||
fmt.Printf("host rewrite: %s\n", l.rewriteHost)
|
||||
sConn, err := l.mux.rewriteFunc(conn, l.rewriteHost)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("http host header rewrite failed")
|
||||
|
Loading…
Reference in New Issue
Block a user