[add] websocket command
This commit is contained in:
parent
d2cc885e3e
commit
ae4529009e
9 changed files with 290 additions and 3 deletions
|
|
@ -95,6 +95,7 @@ func init() {
|
|||
dumpCmd,
|
||||
restoreCmd,
|
||||
socketCmd,
|
||||
websocketCmd,
|
||||
)
|
||||
// rootCmd.SetHelpCommand(helpCmd)
|
||||
rootCmd.PersistentFlags().StringVarP(&appPath, "app", "a", "", L("Application directory"))
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ import (
|
|||
|
||||
var socketCmd = &cobra.Command{
|
||||
Use: "socket",
|
||||
Short: L("Open socket"),
|
||||
Long: L("Open socket"),
|
||||
Short: L("Open a socket connection"),
|
||||
Long: L("Open a socket connection"),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
defer share.SessionStop()
|
||||
defer gou.KillPlugins()
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ var startCmd = &cobra.Command{
|
|||
host = "127.0.0.1"
|
||||
}
|
||||
|
||||
if mode == "development" {
|
||||
if mode == "development" || mode == "production" {
|
||||
fmt.Println(color.WhiteString("\n---------------------------------"))
|
||||
fmt.Println(color.WhiteString(L("API List")))
|
||||
fmt.Println(color.WhiteString("---------------------------------"))
|
||||
|
|
|
|||
71
cmd/websocket.go
Normal file
71
cmd/websocket.go
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/kun/exception"
|
||||
"github.com/yaoapp/yao/config"
|
||||
"github.com/yaoapp/yao/engine"
|
||||
"github.com/yaoapp/yao/share"
|
||||
)
|
||||
|
||||
var websocketCmd = &cobra.Command{
|
||||
Use: "websocket",
|
||||
Short: L("Open a websocket connection"),
|
||||
Long: L("Open a websocket connection"),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
defer share.SessionStop()
|
||||
defer gou.KillPlugins()
|
||||
defer func() {
|
||||
err := exception.Catch(recover())
|
||||
if err != nil {
|
||||
fmt.Println(color.RedString(L("Fatal: %s"), err.Error()))
|
||||
}
|
||||
}()
|
||||
|
||||
Boot()
|
||||
cfg := config.Conf
|
||||
cfg.Session.IsCLI = true
|
||||
engine.Load(cfg)
|
||||
if len(args) < 1 {
|
||||
fmt.Println(color.RedString(L("Not enough arguments")))
|
||||
fmt.Println(color.WhiteString(share.BUILDNAME + " help"))
|
||||
return
|
||||
}
|
||||
|
||||
name := args[0]
|
||||
websocket, has := gou.WebSockets[name]
|
||||
if !has {
|
||||
fmt.Println(color.RedString(L("%s not exists!"), name))
|
||||
return
|
||||
}
|
||||
|
||||
url := websocket.URL
|
||||
protocols := websocket.Protocols
|
||||
argsLen := len(args)
|
||||
if argsLen > 1 {
|
||||
url = args[1]
|
||||
}
|
||||
|
||||
if argsLen > 2 {
|
||||
protocols = args[2:]
|
||||
}
|
||||
|
||||
fmt.Println(color.WhiteString("\n---------------------------------"))
|
||||
fmt.Println(color.WhiteString(websocket.Name))
|
||||
fmt.Println(color.WhiteString("---------------------------------"))
|
||||
fmt.Println(color.GreenString(" URL: %s", url))
|
||||
fmt.Println(color.GreenString("Protocols: %s", strings.Join(protocols, ",")))
|
||||
fmt.Println(color.WhiteString("--------------------------------------"))
|
||||
pargs := append([]string{url}, protocols...)
|
||||
err := websocket.Open(pargs...)
|
||||
if err != nil {
|
||||
fmt.Println(color.RedString(L("%s"), err.Error()))
|
||||
return
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ import (
|
|||
"github.com/yaoapp/yao/socket"
|
||||
"github.com/yaoapp/yao/store"
|
||||
"github.com/yaoapp/yao/table"
|
||||
"github.com/yaoapp/yao/websocket"
|
||||
)
|
||||
|
||||
// Load 根据配置加载 API, FLow, Model, Plugin
|
||||
|
|
@ -115,6 +116,11 @@ func Load(cfg config.Config) (err error) {
|
|||
log.Debug(err.Error())
|
||||
}
|
||||
|
||||
err = websocket.Load(cfg) // Load websockets (client)
|
||||
if err != nil {
|
||||
log.Debug(err.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,3 +3,89 @@ function Hello() {
|
|||
var response = ws.push("Hello World");
|
||||
return response;
|
||||
}
|
||||
|
||||
const host = "127.0.0.1:5099";
|
||||
|
||||
/**
|
||||
* WebSocket Client EventMode(daemon)
|
||||
*/
|
||||
function Event() {
|
||||
var url = `ws://${host}/websocket/chat`;
|
||||
var ws = new WebSocket(url, "yao-chat-01");
|
||||
|
||||
// Connection opened
|
||||
ws.on("open", function (event) {
|
||||
ws.send("Hello Server!", event.data);
|
||||
});
|
||||
|
||||
// Listen for messages
|
||||
ws.on("message", function (event) {
|
||||
console.log("Message from server ", event.data);
|
||||
ws.close(200, "Bye");
|
||||
});
|
||||
|
||||
// Listen for error
|
||||
ws.on("error", (event) => {
|
||||
console.log("Message from server ", event);
|
||||
});
|
||||
|
||||
// Listen for close
|
||||
ws.on("close", (event) => {
|
||||
console.log("The connection has been closed successfully");
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* WebSocket Client PushMode
|
||||
*/
|
||||
function Push() {
|
||||
var url = `ws://${host}/websocket/chat`;
|
||||
var ws = new WebSocket(url, "yao-chat-01");
|
||||
var message = ws.push("Hello Server!");
|
||||
console.log(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* WebSocket Client JWT Auth
|
||||
*/
|
||||
function Token() {
|
||||
var token = "xxx";
|
||||
var url = `ws://${host}/websocket/chat?token=${token}`;
|
||||
var ws = new WebSocket(url, "yao-chat-01");
|
||||
var message = ws.push("Hello Server!");
|
||||
console.log(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* WebSocket Client Basic Auth
|
||||
*/
|
||||
function Basic() {
|
||||
// Basic Auth username:password
|
||||
var user = "test";
|
||||
var password = "WsTest123**";
|
||||
var url = `ws://${user}:${password}@${host}/websocket/chat?token=${token}`;
|
||||
var ws = new WebSocket(url, "yao-chat-01");
|
||||
var message = ws.push("Hello Server!");
|
||||
console.log(message);
|
||||
}
|
||||
|
||||
function onData(data, recvLen) {
|
||||
console.log(`Data: ${data} ${recvLen}`);
|
||||
log.Trace("onData: %v %v", data, recvLen);
|
||||
if (data[0] == "1") {
|
||||
Process("websocket.Close", "message");
|
||||
}
|
||||
}
|
||||
|
||||
function onError(err) {
|
||||
console.log(`Error: ${err} `);
|
||||
}
|
||||
|
||||
function onClosed(data, err) {
|
||||
console.log(`Closed: ${data} ${err} `);
|
||||
}
|
||||
|
||||
function onConnected(option) {
|
||||
console.log("onConnected", option);
|
||||
Process("websocket.Write", "message", "1|Hello World");
|
||||
}
|
||||
|
|
|
|||
18
tests/websockets/message.ws.json
Normal file
18
tests/websockets/message.ws.json
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "A WebSocket client",
|
||||
"description": "A Chat WebSocket client",
|
||||
"version": "0.10.0",
|
||||
"url": "ws://127.0.0.1:5011/websocket/message",
|
||||
"protocols": ["yao-message-01"],
|
||||
"buffer": { "read": 1024, "write": 1024 },
|
||||
"limit": { "read-wait": 10, "pong-wait": 20, "max-message": 1024 },
|
||||
"timeout": 5,
|
||||
"attempt_after": 200,
|
||||
"attempts": 9,
|
||||
"event": {
|
||||
"data": "scripts.websocket.onData",
|
||||
"closed": "scripts.websocket.onClosed",
|
||||
"connected": "scripts.websocket.onConnected",
|
||||
"error": "scripts.websocket.onError"
|
||||
}
|
||||
}
|
||||
36
websocket/websocket.go
Normal file
36
websocket/websocket.go
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
package websocket
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/kun/log"
|
||||
"github.com/yaoapp/yao/config"
|
||||
"github.com/yaoapp/yao/share"
|
||||
)
|
||||
|
||||
// Load 加载API
|
||||
func Load(cfg config.Config) error {
|
||||
var root = filepath.Join(cfg.Root, "websockets")
|
||||
return LoadFrom(root, "")
|
||||
}
|
||||
|
||||
// LoadFrom 从特定目录加载
|
||||
func LoadFrom(dir string, prefix string) error {
|
||||
|
||||
if share.DirNotExists(dir) {
|
||||
return fmt.Errorf("%s does not exists", dir)
|
||||
}
|
||||
|
||||
err := share.Walk(dir, ".ws.json", func(root, filename string) {
|
||||
name := prefix + share.SpecName(root, filename)
|
||||
content := share.ReadFile(filename)
|
||||
_, err := gou.LoadWebSocket(string(content), name)
|
||||
if err != nil {
|
||||
log.With(log.F{"root": root, "file": filename}).Error(err.Error())
|
||||
}
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
69
websocket/websocket_test.go
Normal file
69
websocket/websocket_test.go
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
package websocket
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/yaoapp/gou"
|
||||
"github.com/yaoapp/gou/websocket"
|
||||
"github.com/yaoapp/yao/config"
|
||||
"github.com/yaoapp/yao/script"
|
||||
)
|
||||
|
||||
func TestLoad(t *testing.T) {
|
||||
Load(config.Conf)
|
||||
LoadFrom("not a path", "404.")
|
||||
check(t)
|
||||
}
|
||||
|
||||
func TestWebSocketOpen(t *testing.T) {
|
||||
Load(config.Conf)
|
||||
script.Load(config.Conf)
|
||||
srv, url := serve(t)
|
||||
defer srv.Stop()
|
||||
|
||||
ws := gou.SelectWebSocket("message")
|
||||
err := ws.Open(url, "messageV2", "chatV3")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func serve(t *testing.T) (*websocket.Upgrader, string) {
|
||||
|
||||
ws, err := websocket.NewUpgrader("test")
|
||||
if err != nil {
|
||||
t.Fatalf("%s", err)
|
||||
}
|
||||
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
router := gin.Default()
|
||||
ws.SetHandler(func(message []byte) ([]byte, error) { return message, nil })
|
||||
ws.SetRouter(router)
|
||||
|
||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
go ws.Start()
|
||||
go func() {
|
||||
http.Serve(listener, router)
|
||||
}()
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
|
||||
return ws, fmt.Sprintf("ws://127.0.0.1:%d/websocket/test", listener.Addr().(*net.TCPAddr).Port)
|
||||
}
|
||||
|
||||
func check(t *testing.T) {
|
||||
keys := []string{}
|
||||
for key := range gou.WebSockets {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
assert.Equal(t, 1, len(keys))
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue