Wrote proxy
This commit is contained in:
parent
987fd909a9
commit
944b787432
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -10,3 +10,4 @@ localcert.key
|
|||
dev.json
|
||||
.bin
|
||||
client/dist
|
||||
config_dev.json
|
|
@ -5,3 +5,4 @@ env("GOPATH", run("go", ["env", "GOROOT"]) + ":" + pwd() + "/go_modules" + ":" +
|
|||
env("MONGODB", readJsonFile("dev.json").MONGODB)
|
||||
env("HTTP_PORT", 8080)
|
||||
env("HTTPS_PORT", 8443)
|
||||
env("CONFIG_FILE", "./config_dev.json")
|
|
@ -20,6 +20,8 @@
|
|||
"go://gopkg.in/ffmt.v1": "v1.5.6",
|
||||
"npm://@esbuild/linux-x64": "0.16.17",
|
||||
"npm://@vitejs/plugin-react": "3.1.0",
|
||||
"npm://express": "4.18.2",
|
||||
"npm://express-ws": "5.0.2",
|
||||
"npm://react": "18.2.0",
|
||||
"npm://react-dom": "18.2.0",
|
||||
"npm://typescript": "4.9.5",
|
||||
|
|
82
src/config.go
Normal file
82
src/config.go
Normal file
|
@ -0,0 +1,82 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"regexp"
|
||||
"./proxy"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
HTTPConfig HTTPConfig
|
||||
}
|
||||
|
||||
var defaultConfig = Config{
|
||||
HTTPConfig: HTTPConfig{
|
||||
TLSCert: "localcert.crt",
|
||||
TLSKey: "localcert.key",
|
||||
GenerateMissingTLSCert: true,
|
||||
HTTPPort: "80",
|
||||
HTTPSPort: "443",
|
||||
ProxyConfig: proxy.Config{
|
||||
Routes: []proxy.RouteConfig{},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func GetConfig() Config {
|
||||
configFile := os.Getenv("CONFIG_FILE")
|
||||
|
||||
if configFile == "" {
|
||||
configFile = "/cosmos.config.json"
|
||||
}
|
||||
|
||||
log.Println("Using config file: " + configFile)
|
||||
|
||||
// if file does not exist, create it
|
||||
if _, err := os.Stat(configFile); os.IsNotExist(err) {
|
||||
log.Println("Config file does not exist. Creating default config file.")
|
||||
file, err := os.Create(configFile)
|
||||
if err != nil {
|
||||
log.Fatal("[ERROR] Creating Default Config File: " + err.Error())
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
encoder := json.NewEncoder(file)
|
||||
encoder.SetIndent("", " ")
|
||||
err = encoder.Encode(defaultConfig)
|
||||
if err != nil {
|
||||
log.Fatal("[ERROR] Writing Default Config File: " + err.Error())
|
||||
}
|
||||
|
||||
return defaultConfig
|
||||
}
|
||||
|
||||
file, err := os.Open(configFile)
|
||||
if err != nil {
|
||||
log.Fatal("[ERROR] Opening Config File: " + err.Error())
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
decoder := json.NewDecoder(file)
|
||||
config := Config{}
|
||||
err = decoder.Decode(&config)
|
||||
// check file is not empty
|
||||
if err != nil {
|
||||
// check error is not empty
|
||||
if err.Error() == "EOF" {
|
||||
log.Fatal("[ERROR] Reading Config File: File is empty.")
|
||||
}
|
||||
|
||||
// get error string
|
||||
errString := err.Error()
|
||||
|
||||
// replace string in error
|
||||
m1 := regexp.MustCompile(`json: cannot unmarshal ([A-Za-z\.]+) into Go struct field ([A-Za-z\.]+) of type ([A-Za-z\.]+)`)
|
||||
errString = m1.ReplaceAllString(errString, "Invalid JSON in config file.\n > Field $2 is wrong.\n > Type is $1 Should be $3")
|
||||
log.Fatal("[ERROR] Reading Config File: " + errString)
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
93
src/httpServer.go
Normal file
93
src/httpServer.go
Normal file
|
@ -0,0 +1,93 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"./utils"
|
||||
// "./file"
|
||||
// "./user"
|
||||
"./proxy"
|
||||
"github.com/gorilla/mux"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type HTTPConfig struct {
|
||||
TLSCert string
|
||||
TLSKey string
|
||||
GenerateMissingTLSCert bool
|
||||
HTTPPort string
|
||||
HTTPSPort string
|
||||
ProxyConfig proxy.Config
|
||||
}
|
||||
|
||||
var serverPortHTTP = os.Getenv("HTTP_PORT")
|
||||
var serverPortHTTPS = os.Getenv("HTTPS_PORT")
|
||||
|
||||
func startHTTPServer(router *mux.Router) {
|
||||
log.Println("Listening to HTTP on :" + serverPortHTTP)
|
||||
|
||||
err := http.ListenAndServe("0.0.0.0:" + serverPortHTTP, router)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func startHTTPSServer(router *mux.Router, tlsCert string, tlsKey string) {
|
||||
// redirect http to https
|
||||
go (func () {
|
||||
err := http.ListenAndServe("0.0.0.0:" + serverPortHTTP, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// change port in host
|
||||
if strings.HasSuffix(r.Host, ":" + serverPortHTTP) {
|
||||
if serverPortHTTPS != "443" {
|
||||
r.Host = r.Host[:len(r.Host)-len(":" + serverPortHTTP)] + ":" + serverPortHTTPS
|
||||
} else {
|
||||
r.Host = r.Host[:len(r.Host)-len(":" + serverPortHTTP)]
|
||||
}
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "https://"+r.Host+r.URL.String(), http.StatusMovedPermanently)
|
||||
}))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
})()
|
||||
|
||||
log.Println("Listening to HTTP on :" + serverPortHTTP)
|
||||
log.Println("Listening to HTTPS on :" + serverPortHTTPS)
|
||||
|
||||
// start https server
|
||||
err := http.ListenAndServeTLS("0.0.0.0:" + serverPortHTTPS, tlsCert, tlsKey, router)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func StartServer(config HTTPConfig) {
|
||||
var tlsCert = config.TLSCert
|
||||
var tlsKey= config.TLSKey
|
||||
|
||||
if serverPortHTTP == "" {
|
||||
serverPortHTTP = config.HTTPPort
|
||||
}
|
||||
|
||||
if serverPortHTTPS == "" {
|
||||
serverPortHTTPS = config.HTTPSPort
|
||||
}
|
||||
|
||||
router := proxy.BuildFromConfig(config.ProxyConfig)
|
||||
|
||||
if utils.FileExists(tlsCert) && utils.FileExists(tlsKey) {
|
||||
log.Println("TLS certificate found, starting HTTPS servers and redirecting HTTP to HTTPS")
|
||||
startHTTPSServer(router, tlsCert, tlsKey)
|
||||
} else {
|
||||
log.Println("No TLS certificate found, starting HTTP server only")
|
||||
startHTTPServer(router)
|
||||
}
|
||||
}
|
||||
|
||||
func StopServer() {
|
||||
}
|
100
src/index.go
100
src/index.go
|
@ -1,106 +1,14 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"./utils"
|
||||
"./file"
|
||||
"./user"
|
||||
"github.com/gorilla/mux"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"log"
|
||||
)
|
||||
|
||||
var tlsCert = "localcert.crt"
|
||||
var tlsKey= "localcert.key"
|
||||
var serverPortHTTP = os.Getenv("HTTP_PORT")
|
||||
var serverPortHTTPS = os.Getenv("HTTPS_PORT")
|
||||
|
||||
func startHTTPServer(router *mux.Router) {
|
||||
log.Println("Listening to HTTP on :" + serverPortHTTP)
|
||||
|
||||
err := http.ListenAndServe("0.0.0.0:" + serverPortHTTP, router)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func startHTTPSServer(router *mux.Router) {
|
||||
// redirect http to https
|
||||
go (func () {
|
||||
err := http.ListenAndServe("0.0.0.0:" + serverPortHTTP, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// change port in host
|
||||
if strings.HasSuffix(r.Host, ":" + serverPortHTTP) {
|
||||
if serverPortHTTPS != "443" {
|
||||
r.Host = r.Host[:len(r.Host)-len(":" + serverPortHTTP)] + ":" + serverPortHTTPS
|
||||
} else {
|
||||
r.Host = r.Host[:len(r.Host)-len(":" + serverPortHTTP)]
|
||||
}
|
||||
}
|
||||
|
||||
http.Redirect(w, r, "https://"+r.Host+r.URL.String(), http.StatusMovedPermanently)
|
||||
}))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
})()
|
||||
|
||||
log.Println("Listening to HTTP on :" + serverPortHTTP)
|
||||
log.Println("Listening to HTTPS on :" + serverPortHTTPS)
|
||||
|
||||
// start https server
|
||||
err := http.ListenAndServeTLS("0.0.0.0:" + serverPortHTTPS, tlsCert, tlsKey, router)
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
log.Println("Starting...")
|
||||
|
||||
if serverPortHTTP == "" {
|
||||
serverPortHTTP = "80"
|
||||
}
|
||||
config := GetConfig()
|
||||
|
||||
if serverPortHTTPS == "" {
|
||||
serverPortHTTPS = "443"
|
||||
}
|
||||
|
||||
router := mux.NewRouter().StrictSlash(true)
|
||||
|
||||
utils.DB()
|
||||
defer utils.Disconnect()
|
||||
|
||||
router.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("OK"))
|
||||
})
|
||||
|
||||
router.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
|
||||
|
||||
router.HandleFunc("/file/list", file.FileList)
|
||||
router.HandleFunc("/file/get", file.FileGet)
|
||||
router.HandleFunc("/file/delete", file.FileDelete)
|
||||
router.HandleFunc("/file/copy", file.FileCopy)
|
||||
router.HandleFunc("/file/move", file.FileMove)
|
||||
|
||||
router.HandleFunc("/user/login", user.UserLogin)
|
||||
// router.HandleFunc("/user/register", user.UserRegister)
|
||||
// router.HandleFunc("/user/edit", )
|
||||
// router.HandleFunc("/user/delete", )
|
||||
|
||||
// router.HandleFunc("/config/get", )
|
||||
// router.HandleFunc("/config/set", )
|
||||
|
||||
// router.HandleFunc("/db", )
|
||||
|
||||
if utils.FileExists(tlsCert) && utils.FileExists(tlsKey) {
|
||||
log.Println("TLS certificate found, starting HTTPS servers and redirecting HTTP to HTTPS")
|
||||
startHTTPSServer(router)
|
||||
} else {
|
||||
log.Println("No TLS certificate found, starting HTTP server only")
|
||||
startHTTPServer(router)
|
||||
}
|
||||
defer StopServer()
|
||||
StartServer(config.HTTPConfig)
|
||||
}
|
33
src/proxy/buildFromConfig.go
Normal file
33
src/proxy/buildFromConfig.go
Normal file
|
@ -0,0 +1,33 @@
|
|||
package proxy
|
||||
|
||||
import (
|
||||
"github.com/gorilla/mux"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type RouteConfig struct {
|
||||
Routing Route
|
||||
Target string
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Routes []RouteConfig
|
||||
}
|
||||
|
||||
func BuildFromConfig(config Config) *mux.Router {
|
||||
router := mux.NewRouter().StrictSlash(true)
|
||||
|
||||
router.HandleFunc("/_health", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("OK"))
|
||||
})
|
||||
|
||||
router.PathPrefix("/_static").Handler(http.StripPrefix("/_static", http.FileServer(http.Dir("static"))))
|
||||
|
||||
for i := len(config.Routes)-1; i >= 0; i-- {
|
||||
routeConfig := config.Routes[i]
|
||||
RouterGen(routeConfig.Routing, router, RouteTo(routeConfig.Target))
|
||||
}
|
||||
|
||||
return router
|
||||
}
|
51
src/proxy/routeTo.go
Normal file
51
src/proxy/routeTo.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package proxy
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"log"
|
||||
// "io/ioutil"
|
||||
// "io"
|
||||
// "os"
|
||||
// "golang.org/x/crypto/bcrypt"
|
||||
|
||||
// "../utils"
|
||||
)
|
||||
|
||||
// NewProxy takes target host and creates a reverse proxy
|
||||
func NewProxy(targetHost string) (*httputil.ReverseProxy, error) {
|
||||
url, err := url.Parse(targetHost)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
proxy := httputil.NewSingleHostReverseProxy(url)
|
||||
|
||||
// upgrade the request to websocket
|
||||
proxy.ModifyResponse = func(resp *http.Response) error {
|
||||
log.Println("[INFO] Response from backend: ", resp.Status)
|
||||
log.Println("[INFO] URL was ", resp.Request.URL)
|
||||
return nil
|
||||
}
|
||||
|
||||
return proxy, nil
|
||||
}
|
||||
|
||||
// ProxyRequestHandler handles the http request using proxy
|
||||
func ProxyRequestHandler(proxy *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
proxy.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func RouteTo(destination string) *httputil.ReverseProxy /*func(http.ResponseWriter, *http.Request)*/ {
|
||||
// initialize a reverse proxy and pass the actual backend server url here
|
||||
proxy, err := NewProxy(destination)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// create a handler function which uses the reverse proxy
|
||||
return proxy //ProxyRequestHandler(proxy)
|
||||
}
|
41
src/proxy/routerGen.go
Normal file
41
src/proxy/routerGen.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
package proxy
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"github.com/gorilla/mux"
|
||||
// "log"
|
||||
// "io/ioutil"
|
||||
// "io"
|
||||
// "os"
|
||||
// "golang.org/x/crypto/bcrypt"
|
||||
|
||||
// "../utils"
|
||||
)
|
||||
|
||||
type Route struct {
|
||||
UseHost bool
|
||||
Host string
|
||||
UsePathPrefix bool
|
||||
PathPrefix string
|
||||
}
|
||||
|
||||
func RouterGen(route Route, router *mux.Router, destination *httputil.ReverseProxy) *mux.Route {
|
||||
var realDestination http.Handler
|
||||
realDestination = destination
|
||||
|
||||
origin := router.Methods("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD")
|
||||
|
||||
if(route.UseHost) {
|
||||
origin = origin.Host(route.Host)
|
||||
}
|
||||
|
||||
if(route.UsePathPrefix) {
|
||||
origin = origin.PathPrefix(route.PathPrefix)
|
||||
realDestination = http.StripPrefix(route.PathPrefix, destination)
|
||||
}
|
||||
|
||||
origin.Handler(realDestination)
|
||||
|
||||
return origin
|
||||
}
|
38
test-server.js
Normal file
38
test-server.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
|
||||
const express = require('express')
|
||||
const app = express()
|
||||
const port = 3000
|
||||
var expressWs = require('express-ws')(app);
|
||||
|
||||
// console log every request sent
|
||||
app.use((req, res, next) => {
|
||||
console.log(`[REQ] - ${req.method} ${req.url}`)
|
||||
next()
|
||||
});
|
||||
|
||||
app.get('/return/:status/:time', async (req, res) => {
|
||||
const statusCode = parseInt(req.params.status);
|
||||
const returnString =`Hello status ${statusCode} after ${req.params.time}ms !`
|
||||
|
||||
console.log(`[RES] - ${statusCode} ${returnString}`)
|
||||
|
||||
await new Promise(resolve => setTimeout(resolve, req.params.time));
|
||||
|
||||
return res.status(statusCode).send(returnString)
|
||||
});
|
||||
|
||||
app.get('/', (req, res) => {
|
||||
console.log("[RES] - Hello World!")
|
||||
res.send('Hello World!')
|
||||
})
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Example app listening on port ${port}`)
|
||||
})
|
||||
|
||||
app.ws('/ws', function(ws, req) {
|
||||
ws.on('message', function(msg) {
|
||||
console.log(msg);
|
||||
ws.send(msg);
|
||||
});
|
||||
});
|
16
test-websocket.js
Normal file
16
test-websocket.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
const WebSocket = require('ws');
|
||||
|
||||
// send
|
||||
|
||||
const ws = new WebSocket('ws://localhost:8080/proxy/ws', {
|
||||
rejectUnauthorized: false,
|
||||
followRedirects : true,
|
||||
});
|
||||
|
||||
ws.on('open', function open() {
|
||||
ws.send('something');
|
||||
});
|
||||
|
||||
ws.on('message', function incoming(data) {
|
||||
console.log(data);
|
||||
});
|
Loading…
Reference in a new issue