Explorar el Código

initial web server with websocket support.

master
sp hace 4 años
commit
20f31d3d9e
Se han modificado 16 ficheros con 427 adiciones y 0 borrados
  1. +25
    -0
      .gcloudignore
  2. +8
    -0
      .idea/.gitignore
  3. +9
    -0
      .idea/goweb.iml
  4. +8
    -0
      .idea/modules.xml
  5. +6
    -0
      .idea/vcs.xml
  6. +11
    -0
      api1.go
  7. +67
    -0
      api1ws.go
  8. +1
    -0
      app.yaml
  9. +48
    -0
      config.go
  10. +31
    -0
      config.json
  11. +24
    -0
      html/css/index.css
  12. +69
    -0
      html/index.html
  13. +22
    -0
      html/test/css/test.css
  14. +30
    -0
      html/test/index.html
  15. +24
    -0
      http_handler.go
  16. +44
    -0
      main.go

+ 25
- 0
.gcloudignore Ver fichero

@@ -0,0 +1,25 @@
# 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

+ 8
- 0
.idea/.gitignore Ver fichero

@@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

+ 9
- 0
.idea/goweb.iml Ver fichero

@@ -0,0 +1,9 @@
<?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>

+ 8
- 0
.idea/modules.xml Ver fichero

@@ -0,0 +1,8 @@
<?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>

+ 6
- 0
.idea/vcs.xml Ver fichero

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

+ 11
- 0
api1.go Ver fichero

@@ -0,0 +1,11 @@
package main

import (
"net/http"
)

const apiV1Prefix = "/api1/"

func apiV1Main(http.ResponseWriter, *http.Request) {

}

+ 67
- 0
api1ws.go Ver fichero

@@ -0,0 +1,67 @@
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
}
}

+ 1
- 0
app.yaml Ver fichero

@@ -0,0 +1 @@
runtime: go115

+ 48
- 0
config.go Ver fichero

@@ -0,0 +1,48 @@
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
}

+ 31
- 0
config.json Ver fichero

@@ -0,0 +1,31 @@
{
"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
}
}

+ 24
- 0
html/css/index.css Ver fichero

@@ -0,0 +1,24 @@
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;
}

+ 69
- 0
html/index.html Ver fichero

@@ -0,0 +1,69 @@
<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> &#x2192; "./html/test/"
</li>
<li>
static url <a href="spa2/">/spa2 </a> &#x2192; "./html/test/"
</li>
<li>
static url <a href="test/">/test </a> &#x2192; "./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>


+ 22
- 0
html/test/css/test.css Ver fichero

@@ -0,0 +1,22 @@
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;
}

+ 30
- 0
html/test/index.html Ver fichero

@@ -0,0 +1,30 @@
<head>
<title>Demo static "Test" </title>
<link rel="stylesheet" type="text/css" href="css/test.css">
</head>
<h1> Test </h1>
<h1> &#8595; </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> &#8595; </h1>
<ul>
<li>
<a href="/"> back to "/" &#x2192; "./html/" </a>
</li>
</ul>
</div>




+ 24
- 0
http_handler.go Ver fichero

@@ -0,0 +1,24 @@
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))
}

+ 44
- 0
main.go Ver fichero

@@ -0,0 +1,44 @@
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))
}
}

Cargando…
Cancelar
Guardar