feat:KCP协议
This commit is contained in:
86
cmd/kcppeer/interactive.go
Normal file
86
cmd/kcppeer/interactive.go
Normal file
@@ -0,0 +1,86 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
kcpInteractiveCommandHelp = "help"
|
||||
kcpInteractiveCommandQuit = "quit"
|
||||
kcpInteractiveCommandText = "text"
|
||||
kcpInteractiveCommandFile = "file"
|
||||
)
|
||||
|
||||
var errKCPEmptyInteractiveCommand = errors.New("interactive command is empty")
|
||||
|
||||
type kcpInteractiveCommand struct {
|
||||
name string
|
||||
to string
|
||||
value string
|
||||
}
|
||||
|
||||
func parseKCPInteractiveCommand(line string) (kcpInteractiveCommand, error) {
|
||||
commandName, rest, ok := cutKCPInteractiveField(strings.TrimSpace(line))
|
||||
if !ok {
|
||||
return kcpInteractiveCommand{}, errKCPEmptyInteractiveCommand
|
||||
}
|
||||
|
||||
switch strings.ToLower(commandName) {
|
||||
case "help", "h", "?":
|
||||
return kcpInteractiveCommand{name: kcpInteractiveCommandHelp}, nil
|
||||
case "quit", "exit":
|
||||
return kcpInteractiveCommand{name: kcpInteractiveCommandQuit}, nil
|
||||
case kcpInteractiveCommandText:
|
||||
to, body, err := parseKCPInteractiveTargetValue(rest, kcpInteractiveCommandText)
|
||||
if err != nil {
|
||||
return kcpInteractiveCommand{}, err
|
||||
}
|
||||
return kcpInteractiveCommand{name: kcpInteractiveCommandText, to: to, value: body}, nil
|
||||
case kcpInteractiveCommandFile:
|
||||
to, path, err := parseKCPInteractiveTargetValue(rest, kcpInteractiveCommandFile)
|
||||
if err != nil {
|
||||
return kcpInteractiveCommand{}, err
|
||||
}
|
||||
return kcpInteractiveCommand{name: kcpInteractiveCommandFile, to: to, value: path}, nil
|
||||
default:
|
||||
return kcpInteractiveCommand{}, fmt.Errorf("unknown command %q; type help for usage", commandName)
|
||||
}
|
||||
}
|
||||
|
||||
func parseKCPInteractiveTargetValue(rest, commandName string) (string, string, error) {
|
||||
to, value, ok := cutKCPInteractiveField(strings.TrimSpace(rest))
|
||||
if !ok {
|
||||
return "", "", fmt.Errorf("%s command requires a target peer and payload", commandName)
|
||||
}
|
||||
if strings.TrimSpace(value) == "" {
|
||||
return "", "", fmt.Errorf("%s command requires a non-empty payload", commandName)
|
||||
}
|
||||
|
||||
return to, strings.TrimSpace(value), nil
|
||||
}
|
||||
|
||||
func cutKCPInteractiveField(input string) (string, string, bool) {
|
||||
trimmed := strings.TrimSpace(input)
|
||||
if trimmed == "" {
|
||||
return "", "", false
|
||||
}
|
||||
|
||||
for i, r := range trimmed {
|
||||
if r == ' ' || r == '\t' {
|
||||
return trimmed[:i], strings.TrimSpace(trimmed[i+1:]), true
|
||||
}
|
||||
}
|
||||
|
||||
return trimmed, "", true
|
||||
}
|
||||
|
||||
func printKCPInteractiveHelp(w io.Writer) {
|
||||
_, _ = fmt.Fprintln(w, "interactive mode commands (KCP):")
|
||||
_, _ = fmt.Fprintln(w, " help show this help")
|
||||
_, _ = fmt.Fprintln(w, " text <peer> <message> send one text message over the existing KCP session")
|
||||
_, _ = fmt.Fprintln(w, " file <peer> <path> send one file over the existing KCP session")
|
||||
_, _ = fmt.Fprintln(w, " quit exit this peer process")
|
||||
}
|
||||
Reference in New Issue
Block a user