[add] websocket command

This commit is contained in:
Max 2022-07-17 09:08:57 +08:00
parent d2cc885e3e
commit ae4529009e
9 changed files with 290 additions and 3 deletions

View file

@ -95,6 +95,7 @@ func init() {
dumpCmd,
restoreCmd,
socketCmd,
websocketCmd,
)
// rootCmd.SetHelpCommand(helpCmd)
rootCmd.PersistentFlags().StringVarP(&appPath, "app", "a", "", L("Application directory"))

View file

@ -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()

View file

@ -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
View 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
}
},
}

View file

@ -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
}

View file

@ -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");
}

View 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
View 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
}

View 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))
}