| # This file specifies files that are *not* uploaded to Google Cloud Platform | |||||
| # using gcloud. It follows the same syntax as .gitignore, with the addition of | |||||
| # "#!include" directives (which insert the entries of the given .gitignore-style | |||||
| # file at that point). | |||||
| # | |||||
| # For more information, run: | |||||
| # $ gcloud topic gcloudignore | |||||
| # | |||||
| .gcloudignore | |||||
| # If you would like to upload your .git directory, .gitignore file or files | |||||
| # from your .gitignore file, remove the corresponding line | |||||
| # below: | |||||
| .git | |||||
| .gitignore | |||||
| # Binaries for programs and plugins | |||||
| *.exe | |||||
| *.exe~ | |||||
| *.dll | |||||
| *.so | |||||
| *.dylib | |||||
| # Test binary, build with `go test -c` | |||||
| *.test | |||||
| # Output of the go coverage tool, specifically when used with LiteIDE | |||||
| *.out |
| # Default ignored files | |||||
| /shelf/ | |||||
| /workspace.xml | |||||
| # Datasource local storage ignored files | |||||
| /dataSources/ | |||||
| /dataSources.local.xml | |||||
| # Editor-based HTTP Client requests | |||||
| /httpRequests/ |
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <module type="WEB_MODULE" version="4"> | |||||
| <component name="Go" enabled="true" /> | |||||
| <component name="NewModuleRootManager"> | |||||
| <content url="file://$MODULE_DIR$" /> | |||||
| <orderEntry type="inheritedJdk" /> | |||||
| <orderEntry type="sourceFolder" forTests="false" /> | |||||
| </component> | |||||
| </module> |
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <project version="4"> | |||||
| <component name="ProjectModuleManager"> | |||||
| <modules> | |||||
| <module fileurl="file://$PROJECT_DIR$/.idea/goweb.iml" filepath="$PROJECT_DIR$/.idea/goweb.iml" /> | |||||
| </modules> | |||||
| </component> | |||||
| </project> |
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <project version="4"> | |||||
| <component name="VcsDirectoryMappings"> | |||||
| <mapping directory="$PROJECT_DIR$" vcs="Git" /> | |||||
| </component> | |||||
| </project> |
| package main | |||||
| import ( | |||||
| "net/http" | |||||
| ) | |||||
| const apiV1Prefix = "/api1/" | |||||
| func apiV1Main(http.ResponseWriter, *http.Request) { | |||||
| } |
| package main | |||||
| import ( | |||||
| "fmt" | |||||
| "github.com/gorilla/websocket" | |||||
| "log" | |||||
| "net/http" | |||||
| ) | |||||
| const apiV1WebSocket = apiV1Prefix + "ws" | |||||
| // We'll need to define an upgradeToWs | |||||
| // this will require a Read and Write buffer size | |||||
| var upgradeToWs = websocket.Upgrader{ | |||||
| ReadBufferSize: 1024, | |||||
| WriteBufferSize: 1024, | |||||
| } | |||||
| func apiV1WebSocketHandler(w http.ResponseWriter, r *http.Request) { | |||||
| upgradeToWs.CheckOrigin = func(r *http.Request) bool { return true } | |||||
| ws, err := upgradeToWs.Upgrade(w, r, nil) | |||||
| if err != nil { | |||||
| log.Println("cannot upgrade websocket", err) | |||||
| return | |||||
| } | |||||
| // helpful log statement to show connections | |||||
| log.Println("Websocket Api/V1: Client Connected", r.RemoteAddr) | |||||
| wsReader(ws) | |||||
| } | |||||
| func wsReader(conn *websocket.Conn) { | |||||
| for { | |||||
| // read in a message | |||||
| messageType, p, err := conn.ReadMessage() | |||||
| if err != nil { | |||||
| log.Println(err) | |||||
| return | |||||
| } | |||||
| WsEchoIncomingMessage(conn, string(p), messageType) | |||||
| //switch messageType { | |||||
| //case websocket.TextMessage: | |||||
| // WsProcessingTxtMessage(conn, string(p)) | |||||
| // break | |||||
| //case websocket.BinaryMessage: | |||||
| // WsProcessingBinaryMessage(conn, p) | |||||
| // break | |||||
| //case websocket.PingMessage: | |||||
| // break | |||||
| //case websocket.PongMessage: | |||||
| // break | |||||
| //} | |||||
| } | |||||
| } | |||||
| func WsEchoIncomingMessage(conn *websocket.Conn, msg string, messageType int) { | |||||
| // print out that message for clarity | |||||
| fmt.Println(msg) | |||||
| // this is echo | |||||
| if err := conn.WriteMessage(messageType, []byte(msg)); err != nil { | |||||
| log.Println(err) | |||||
| return | |||||
| } | |||||
| } |
| runtime: go115 |
| package main | |||||
| import ( | |||||
| "encoding/json" | |||||
| "io/ioutil" | |||||
| "log" | |||||
| ) | |||||
| type configStaticHtml struct { | |||||
| Dir string | |||||
| StaticUrl string | |||||
| StripPrefix string | |||||
| } | |||||
| type configuration struct { | |||||
| Host string | |||||
| Port string | |||||
| DSN string | |||||
| TlsCert string | |||||
| TlsKey string | |||||
| Static []configStaticHtml | |||||
| Debug bool | |||||
| TempDir string | |||||
| Session struct { //TODO: figure what is this intended for | |||||
| Guest bool | |||||
| Year int //how many years | |||||
| Month int //how many years | |||||
| Day int //how many years | |||||
| } | |||||
| } | |||||
| var configFile = "config.json" | |||||
| var config = configuration{} | |||||
| func (m *configuration) readConfig() (e error) { | |||||
| log.Printf("read Path config from %s", configFile) | |||||
| body, e := ioutil.ReadFile(configFile) | |||||
| if e != nil { | |||||
| log.Fatal("Cannot read config from " + configFile) | |||||
| return | |||||
| } | |||||
| e = json.Unmarshal(body, m) | |||||
| if config.Debug { | |||||
| log.Println(config) | |||||
| } | |||||
| return | |||||
| } |
| { | |||||
| "Host":"0.0.0.0", | |||||
| "Port":"8080", | |||||
| "DSN": "sp:sp@tcp(192.168.1.70:3306)/syd_credit?parseTime=true&loc=Australia%2FSydney&collation=utf8mb4_0900_ai_ci", | |||||
| "TlsCert": "fullchain.pem", | |||||
| "TlsKey": "privkey.pem", | |||||
| "Debug": true, | |||||
| "Static": [ | |||||
| { | |||||
| "Dir": "./html/", | |||||
| "StaticUrl": "/", | |||||
| "StripPrefix" : "/" | |||||
| }, | |||||
| { | |||||
| "Dir": "./html/test/", | |||||
| "StaticUrl": "/spa1/", | |||||
| "StripPrefix" : "/spa1/" | |||||
| }, | |||||
| { | |||||
| "Dir": "./html/test/", | |||||
| "StaticUrl": "/spa2/", | |||||
| "StripPrefix" : "/spa2/" | |||||
| } | |||||
| ], | |||||
| "Session" : { | |||||
| "Guest": true, | |||||
| "Year": 10, | |||||
| "Month": 1, | |||||
| "Day": 1 | |||||
| } | |||||
| } |
| p { | |||||
| background-color:yellow; | |||||
| } | |||||
| h1 { | |||||
| text-align: center; | |||||
| text-decoration: #1ABC9C; | |||||
| } | |||||
| div { | |||||
| width: 300px; | |||||
| margin: auto; | |||||
| text-align: left; | |||||
| } | |||||
| hr { | |||||
| width: 100px; | |||||
| border: 10px solid green; | |||||
| border-radius: 5px; | |||||
| } | |||||
| li{ | |||||
| padding-bottom:15px; | |||||
| } |
| <head> | |||||
| <title>Demo static index</title> | |||||
| <link rel="stylesheet" type="text/css" href="css/index.css"> | |||||
| </head> | |||||
| <body> | |||||
| <h1> Static Html Site </h1> | |||||
| <hr> | |||||
| <div class="center"> | |||||
| <p > | |||||
| This is a static website located on / | |||||
| </p> | |||||
| <ol> | |||||
| <li> | |||||
| <a href="css/index.css"> css/index.css </a> | |||||
| </li> | |||||
| <li> | |||||
| static url <a href="spa1/"> /spa1 </a> → "./html/test/" | |||||
| </li> | |||||
| <li> | |||||
| static url <a href="spa2/">/spa2 </a> → "./html/test/" | |||||
| </li> | |||||
| <li> | |||||
| static url <a href="test/">/test </a> → "./html/test/" | |||||
| </li> | |||||
| <script> | |||||
| let socket = new WebSocket("wss://svr2021.lawipac.com:8080/api/v1/ws"); | |||||
| console.log("Attempting Connection..."); | |||||
| socket.onopen = () => { | |||||
| console.log("Successfully Connected"); | |||||
| socket.send("Hi From the Client!"); | |||||
| socket.send("send dummy string for 500 times"); //this is a special command server will respond; | |||||
| }; | |||||
| socket.onclose = event => { | |||||
| console.log("Socket Closed Connection: ", event); | |||||
| socket.send("Client Closed!") | |||||
| }; | |||||
| socket.onerror = error => { | |||||
| console.log("Socket Error: ", error); | |||||
| }; | |||||
| socket.onmessage = e => { | |||||
| if(typeof e.data != "string" ) { | |||||
| console.log("invalid data received ", e) | |||||
| }else{ | |||||
| let server_message = e.data; | |||||
| console.log("server said: ", server_message) | |||||
| document.getElementById("socketOutPut").innerHTML= server_message; | |||||
| } | |||||
| } | |||||
| </script> | |||||
| </ol> | |||||
| <p id="socketOutPut"></p> | |||||
| </div> | |||||
| <!--<script type="text/javascript">--> | |||||
| <!-- setTimeout(function(){--> | |||||
| <!-- location.reload();--> | |||||
| <!-- },1000)--> | |||||
| <!--</script>--> | |||||
| </body> | |||||
| p { | |||||
| background-color:lightblue; | |||||
| padding: 20px 5px; | |||||
| } | |||||
| h1 { | |||||
| text-align: center; | |||||
| text-decoration: overline; | |||||
| } | |||||
| div { | |||||
| width: 300px; | |||||
| margin: auto; | |||||
| text-align: left; | |||||
| background-color: yellow; | |||||
| } | |||||
| hr { | |||||
| width: 100px; | |||||
| border: 6px solid lightcoral; | |||||
| border-radius: 5px; | |||||
| } |
| <head> | |||||
| <title>Demo static "Test" </title> | |||||
| <link rel="stylesheet" type="text/css" href="css/test.css"> | |||||
| </head> | |||||
| <h1> Test </h1> | |||||
| <h1> ↓ </h1> | |||||
| <hr> | |||||
| <div class="center"> | |||||
| <p > | |||||
| This is a static website located on /test but virtually accessed by /spa1 and /spa2 | |||||
| </p> | |||||
| <hr> | |||||
| <ul> | |||||
| <li> | |||||
| <a href="css/test.css"> css/test.css </a> | |||||
| </li> | |||||
| </ul> | |||||
| <h1> ↓ </h1> | |||||
| <ul> | |||||
| <li> | |||||
| <a href="/"> back to "/" → "./html/" </a> | |||||
| </li> | |||||
| </ul> | |||||
| </div> | |||||
| package main | |||||
| import ( | |||||
| "log" | |||||
| "net/http" | |||||
| ) | |||||
| type httpEntry func(http.ResponseWriter, *http.Request) | |||||
| var httpEntryMap = map[string]httpEntry{ | |||||
| apiV1Prefix: apiV1Main, | |||||
| apiV1WebSocket: apiV1WebSocketHandler, | |||||
| } | |||||
| func setupHTTPHandler() { | |||||
| for key, val := range httpEntryMap { | |||||
| http.HandleFunc(key, val) | |||||
| } | |||||
| log.Printf("Server started at %s:%s\n", config.Host, config.Port) | |||||
| log.Fatal(http.ListenAndServe(config.Host+":"+config.Port, nil)) | |||||
| // log.Fatal(http.ListenAndServeTLS(config.Host+":"+config.Port, config.TlsCert, config.TlsKey, nil)) | |||||
| } |
| package main | |||||
| // [START import] | |||||
| import ( | |||||
| "log" | |||||
| "net/http" | |||||
| ) | |||||
| // [END import] | |||||
| // [START main_func] | |||||
| func main() { | |||||
| err := config.readConfig() // | |||||
| if err != nil { | |||||
| log.Println(err) | |||||
| log.Fatalf("unable to read %s, program quit\n", configFile) | |||||
| return | |||||
| } | |||||
| // [START setting_port] | |||||
| port := config.Port | |||||
| if port == "" { | |||||
| port = "8081" | |||||
| log.Printf("Defaulting to port %s", port) | |||||
| } | |||||
| // [END setting_port] | |||||
| setupRootFileServer() | |||||
| //always last | |||||
| setupHTTPHandler() | |||||
| } | |||||
| // [END main_func] | |||||
| func setupRootFileServer() { | |||||
| //root of doc | |||||
| for idx, node := range config.Static { | |||||
| log.Printf("setting up static %d with %+v\n", idx, node) | |||||
| fs := http.FileServer(http.Dir(node.Dir)) | |||||
| http.Handle(node.StaticUrl, http.StripPrefix(node.StripPrefix, fs)) | |||||
| } | |||||
| } |