added some clarifying comments

This commit is contained in:
Rasmus Moorats 2018-08-29 18:15:33 +03:00
parent 8a561cf920
commit ed86579646
9 changed files with 55 additions and 14 deletions

View file

@ -34,6 +34,7 @@ var auth = cmd.Command{
}
func authRun(param []string) {
// Authenticating is just another call
setting.Vars.Conn.Call("session", "login", map[string]interface{}{"username": param[0],
"password": param[1]})
}

View file

@ -24,8 +24,10 @@ import (
"strings"
)
// CommandList will map all of the command structs to their names
var CommandList = make(map[string]Command)
// Command is the actual struct for commands
type Command struct {
Name string
UsageText string
@ -35,14 +37,18 @@ type Command struct {
MaxArg int // Same as above
}
// Register adds command to CommandList. Should be called on init()
func (cmd *Command) Register() {
CommandList[cmd.Name] = *cmd
}
// Usage prints the command's usage
func (cmd *Command) Usage() {
fmt.Println("Usage:", cmd.UsageText)
}
// Execute runs the command's specified "Action" function,
// if MinArg and MaxArg are within acceptable bounds
func (cmd *Command) Execute(line string) {
arg := strings.Split(line, " ")
switch {

View file

@ -34,13 +34,15 @@ var dialer = websocket.Dialer{
HandshakeTimeout: 15 * time.Second,
}
// Connection houses the current connection's details
type Connection struct {
Ws *websocket.Conn
Key string
User string
Id int
ID int
}
// Connect to the specified host
func (c *Connection) Connect(addr string) {
u := url.URL{Scheme: "ws", Host: addr, Path: "/"}
@ -55,6 +57,7 @@ func (c *Connection) Connect(addr string) {
}
}
// Disconnect from the host
func (c *Connection) Disconnect() {
if c.Ws != nil {
c.Ws.Close()
@ -62,18 +65,20 @@ func (c *Connection) Disconnect() {
}
}
// Send the specified interface{} as json
func (c *Connection) Send(request interface{}) {
if c.Ws != nil {
c.Ws.WriteJSON(request)
c.Id++
c.ID++
}
}
func (c *Connection) Recv() response {
// Recv reads a json response into a response struct
func (c *Connection) Recv() Response {
if c.Ws != nil {
var r response
var r Response
c.Ws.ReadJSON(&r)
return r
}
return response{}
return Response{}
}

View file

@ -19,16 +19,18 @@
package connection
type response struct {
Id int
// Response from server is stored in this struct
type Response struct {
ID int
Result []interface{}
Jsonrpc string
}
// Generate a request interface{} which can be sent to ubus
func (c *Connection) genUbusRequest(method, path, pmethod string, message map[string]interface{}) interface{} {
request := map[string]interface{}{
"jsonrpc": "2.0",
"id": c.Id,
"id": c.ID,
"method": method,
"params": []interface{}{
c.Key,
@ -41,6 +43,7 @@ func (c *Connection) genUbusRequest(method, path, pmethod string, message map[st
return request
}
// Call a method on the target device
func (c *Connection) Call(path, method string, message map[string]interface{}) {
request := c.genUbusRequest("call", path, method, message)
c.Send(request)
@ -72,9 +75,10 @@ func resultToStr(r int) string {
return "Unknown error"
}
func ParseResponse(r *response) (int, string, map[string]interface{}) {
var result string
var data map[string]interface{}
// ParseResponse reads a response and returns data, which is more comfortable to use
func ParseResponse(r *Response) (int, string, map[string]interface{}) {
var result string // the "error code" should be human-readable
var data map[string]interface{} // if the call returned data, map it
rLen := len(r.Result)
if rLen > 0 {
result = resultToStr(int(r.Result[0].(float64)))

View file

@ -28,29 +28,38 @@ import (
)
var (
// Cmd is a makeshift "API" to avoid imports
Cmd = make(chan []string)
In = make(chan interface{})
// In receives incoming messages
In = make(chan interface{})
// Out houses outgoing messages
Out = make(chan interface{})
)
var (
// Host IP. In reality, this should be read from a file (if it exists)
Host = "192.168.1.1"
)
// ShellVars house some important structs, so they can be accessed elsewhere
type ShellVars struct {
Conn *connection.Connection
Completer readline.PrefixCompleter
Instance *readline.Instance
}
// UpdatePrompt refreshes the prompt and sets it according to current status
func (s *ShellVars) UpdatePrompt() {
var prompt string
if s.Conn.Ws == nil {
// Not connected
prompt = "\033[91miop\033[0;1m$\033[0m "
} else {
if s.Conn.User == "" {
// Connected but not authenticated
prompt = "\033[32miop\033[0;1m$\033[0m "
} else {
// Connected and authenticated
prompt = fmt.Sprintf("\033[32miop\033[0m %s\033[0;1m$\033[0m ", s.Conn.User)
}
}
@ -58,6 +67,7 @@ func (s *ShellVars) UpdatePrompt() {
s.Instance.Refresh()
}
// UpdateCompleter adds commands registered with .Register() to the autocompleter
func (s *ShellVars) UpdateCompleter(cmdlist map[string]cmd.Command) {
s.Completer = *readline.NewPrefixCompleter()
s.Completer.SetChildren(*new([]readline.PrefixCompleterInterface))
@ -73,4 +83,5 @@ func (s *ShellVars) UpdateCompleter(cmdlist map[string]cmd.Command) {
}
}
// Vars is an instance of ShellVars
var Vars ShellVars

View file

@ -39,6 +39,7 @@ func filterInput(r rune) (rune, bool) {
return r, true
}
// Sv is just Vars for easy access
var Sv = &setting.Vars
func connectionHandler() {
@ -68,14 +69,16 @@ func msgListener() {
response := Sv.Conn.Recv()
if response.Jsonrpc != "" {
rLen, err, rData := connection.ParseResponse(&response)
fmt.Printf("\n%d: %s\n", response.Id, err)
fmt.Printf("\n%d: %s\n", response.ID, err)
if rLen > 1 {
fmt.Println(textmutate.Pprint(rData))
if key, ok := rData["ubus_rpc_session"]; ok {
// See if we have a session key
Sv.Conn.Key = key.(string)
}
if data, ok := rData["data"]; ok {
if user, ok := data.(map[string]interface{})["username"]; ok {
// If we just logged in, we get our username
Sv.Conn.User = user.(string)
}
}
@ -88,6 +91,7 @@ func msgListener() {
return
}
// Shell provides the CLI interface
func Shell() {
l, err := readline.NewEx(&readline.Config{
HistoryFile: "/tmp/iop.tmp",

View file

@ -23,6 +23,8 @@ import (
"encoding/json"
)
// Pprint pretty-prints a json input (interface{})
// In the future, this should be replaced with a custom function
func Pprint(input interface{}) string {
out, err := json.MarshalIndent(input, "", " ")
if err == nil {

View file

@ -29,6 +29,8 @@ type parser struct {
Cursor int
}
// Simply returns whether the current char (or char + offset) is
// a special char (one specified in SChars)
func (p *parser) specialChar(offset ...int) bool {
cursor := p.Cursor
if len(offset) > 0 {
@ -42,6 +44,7 @@ func (p *parser) specialChar(offset ...int) bool {
return false
}
// Consume a word until a special char and return it
func (p *parser) word() string {
var word strings.Builder
@ -56,6 +59,7 @@ func (p *parser) word() string {
return word.String()
}
// Return what the next special char is
func (p *parser) peekChar() rune {
for i, char := range p.Input[p.Cursor:] {
if p.specialChar(i) {
@ -65,6 +69,10 @@ func (p *parser) peekChar() rune {
return 0
}
// StrToMap takes an input string and creates a map out of it, for use
// in json requests. For example,
// "key1:key1-1:value1-1,key1-2:value1-2;key2:value2" returns
// {"key1": {"key1-1": "value1-1", "key1-2": "value1-2"}, "key2": "value2"}
func StrToMap(input string) (map[string]interface{}, int) {
out := make(map[string]interface{})
p := parser{Input: input,

View file

@ -20,7 +20,7 @@
package main
import (
_ "gitlab.com/neonsea/iopshell/commands"
_ "gitlab.com/neonsea/iopshell/commands" // runs .Register() for each command
"gitlab.com/neonsea/iopshell/internal/shell"
)