Skip to content
This repository was archived by the owner on May 8, 2020. It is now read-only.

Commit 45faea6

Browse files
committed
fix discover
1 parent 0da8fa3 commit 45faea6

12 files changed

+713
-0
lines changed

README.md

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# fbxcli
2+
3+
WIP French ISP Free Freebox CLI implementation in golang.
4+
Use at your own risk, yadda, yadda yadda

cmd/add.go

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package cmd
16+
17+
import (
18+
"log"
19+
20+
"github.com/jsurloppe/fbxapi"
21+
"github.com/spf13/cobra"
22+
)
23+
24+
const defaultPort = 80
25+
const defaultPortSSL = 443
26+
27+
// addCmd represents the add command
28+
var addCmd = &cobra.Command{
29+
Use: "add",
30+
Short: "Add local or remote freebox with address and port",
31+
PersistentPreRun: func(cmd *cobra.Command, args []string) {
32+
flags := cmd.Flags()
33+
alias, err := flags.GetString("alias")
34+
checkErr(err)
35+
if len(alias) == 0 {
36+
log.Panic("alias flag required")
37+
}
38+
host, err := flags.GetString("host")
39+
checkErr(err)
40+
if len(host) == 0 {
41+
log.Panic("host flag required")
42+
}
43+
},
44+
Run: func(cmd *cobra.Command, args []string) {
45+
flags := cmd.Flags()
46+
port, err := flags.GetInt("port")
47+
checkErr(err)
48+
ssl, err := flags.GetBool("ssl")
49+
checkErr(err)
50+
if ssl && port == defaultPort {
51+
port = defaultPortSSL
52+
}
53+
alias, err := flags.GetString("alias")
54+
checkErr(err)
55+
host, err := flags.GetString("host")
56+
checkErr(err)
57+
freebox, err := fbxapi.HttpDiscover(host, port, ssl)
58+
checkErr(err)
59+
Register(alias, freebox, ssl)
60+
},
61+
}
62+
63+
func init() {
64+
RootCmd.AddCommand(addCmd)
65+
66+
// Here you will define your flags and configuration settings.
67+
68+
// Cobra supports Persistent Flags which will work for this command
69+
// and all subcommands, e.g.:
70+
// addCmd.PersistentFlags().String("foo", "", "A help for foo")
71+
72+
// Cobra supports local flags which will only run when this command
73+
// is called directly, e.g.:
74+
addCmd.Flags().String("alias", "", "Alias of the freebox")
75+
addCmd.Flags().String("host", "", "Host of the freebox")
76+
addCmd.Flags().Int("port", defaultPort, "Port of the freebox")
77+
addCmd.Flags().Bool("ssl", false, "Require https")
78+
79+
}

cmd/config.go

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package cmd
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"os"
7+
"strconv"
8+
"sync"
9+
10+
"github.com/jsurloppe/fbxapi"
11+
)
12+
13+
const APPID = "com.github.jsurloppe.fbxcli"
14+
const APPNAME = "fbxcli"
15+
const APPVERSION = "0"
16+
17+
var DEBUGMACRO = false
18+
19+
type CliConfig struct {
20+
Session string `json:"session,omitempty"`
21+
Default bool `json:"default,omitempty"`
22+
UseSSL bool `json:"use_ssl"`
23+
}
24+
25+
// ConfigEntry An entry representing a registered freebox
26+
type ConfigEntry struct {
27+
fbxapi.Freebox
28+
fbxapi.RespAuthorize
29+
CliConfig
30+
}
31+
32+
var ENV struct {
33+
CfgFile string
34+
Freeboxs map[string]ConfigEntry
35+
CurrentAlias string
36+
CurrentClient *fbxapi.Client
37+
KeepSession bool
38+
Cwd string
39+
}
40+
41+
var clientPool struct {
42+
pool map[string]*fbxapi.Client
43+
mutex sync.Mutex
44+
}
45+
46+
func PoolLogout() {
47+
for _, client := range clientPool.pool {
48+
client.Logout()
49+
}
50+
}
51+
52+
func init() {
53+
debugStr := os.Getenv("FBXCLI_DEBUG")
54+
if len(debugStr) > 0 {
55+
debugBool, err := strconv.ParseBool(debugStr)
56+
if err == nil {
57+
DEBUGMACRO = debugBool
58+
}
59+
}
60+
clientPool.pool = make(map[string]*fbxapi.Client)
61+
ENV.Cwd = "/"
62+
}
63+
64+
func NewClientFromPool(alias string) (client *fbxapi.Client, err error) {
65+
clientPool.mutex.Lock()
66+
defer clientPool.mutex.Unlock()
67+
client, ok := clientPool.pool[alias]
68+
if !ok {
69+
freebox, ok := ENV.Freeboxs[alias]
70+
if !ok {
71+
return nil, errors.New("Unregistered alias")
72+
}
73+
client, err = fbxapi.NewClientFromFreebox(freebox.Freebox, freebox.UseSSL)
74+
checkErr(err)
75+
client.SessionToken = freebox.Session
76+
clientPool.pool[alias] = client
77+
}
78+
return client, err
79+
}
80+
81+
func Register(alias string, freebox *fbxapi.Freebox, ssl bool) (client *fbxapi.Client, track_id int, err error) {
82+
hostname, err := os.Hostname()
83+
checkErr(err)
84+
85+
reqAuth := fbxapi.TokenRequest{
86+
AppId: APPID,
87+
AppName: APPNAME,
88+
AppVersion: APPVERSION,
89+
DeviceName: hostname,
90+
}
91+
92+
client, err = fbxapi.NewClientFromFreebox(*freebox, ssl)
93+
checkErr(err)
94+
resp, err := client.Authorize(reqAuth)
95+
checkErr(err)
96+
configEntry := ConfigEntry{Freebox: *freebox, RespAuthorize: *resp}
97+
// if registered:
98+
ENV.Freeboxs[alias] = configEntry
99+
updateConfig()
100+
track_id = resp.TrackID
101+
return
102+
}
103+
104+
func updateConfig() {
105+
writer, err := os.Create(ENV.CfgFile)
106+
checkErr(err)
107+
108+
encoder := json.NewEncoder(writer)
109+
encoder.SetIndent("", " ")
110+
encoder.Encode(ENV.Freeboxs)
111+
112+
writer.Close()
113+
}

cmd/connect.go

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package cmd
16+
17+
import (
18+
shellwords "github.com/mattn/go-shellwords"
19+
"github.com/spf13/cobra"
20+
)
21+
22+
func printErr(err error) {
23+
rlshell.writeString(err.Error())
24+
}
25+
26+
// connectCmd represents the connect command
27+
var connectCmd = &cobra.Command{
28+
Use: "connect",
29+
Short: "An interactive shell",
30+
PersistentPreRun: func(cmd *cobra.Command, args []string) {
31+
panicHandler = recoverOnPanic
32+
RootCmd.PersistentPreRun(cmd, args)
33+
},
34+
Run: func(cmd *cobra.Command, args []string) {
35+
defer panicHandler()
36+
37+
for {
38+
line, err := rlshell.Readline()
39+
if err != nil { // io.EOF
40+
break
41+
}
42+
43+
args, err := shellwords.Parse(line)
44+
checkErr(err)
45+
46+
replCmd, replCmdArgs, err := RootCmd.Find(args)
47+
if err != nil {
48+
printErr(err)
49+
continue
50+
}
51+
replCmd.SetArgs(replCmdArgs)
52+
53+
if cmd == replCmd {
54+
falias := replCmd.Flag("freebox")
55+
alias := falias.Value.String()
56+
if len(alias) > 0 {
57+
connect(alias)
58+
} else if len(replCmdArgs) > 0 {
59+
connect(replCmdArgs[0])
60+
}
61+
62+
continue
63+
}
64+
// cause weird nesting in interactive mode
65+
if replCmd.PreRun != nil {
66+
replCmd.PreRun(replCmd, replCmdArgs)
67+
}
68+
replCmd.Run(replCmd, replCmdArgs)
69+
if replCmd.PostRun != nil {
70+
replCmd.PostRun(replCmd, replCmdArgs)
71+
}
72+
}
73+
},
74+
}
75+
76+
func init() {
77+
RootCmd.AddCommand(connectCmd)
78+
79+
// Here you will define your flags and configuration settings.
80+
81+
// Cobra supports Persistent Flags which will work for this command
82+
// and all subcommands, e.g.:
83+
// connectCmd.PersistentFlags().String("foo", "", "A help for foo")
84+
85+
// Cobra supports local flags which will only run when this command
86+
// is called directly, e.g.:
87+
// connectCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
88+
89+
}

cmd/discover.go

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"github.com/jsurloppe/fbxapi"
8+
"github.com/spf13/cobra"
9+
)
10+
11+
func isKnownFreebox(host string) bool {
12+
for _, knHost := range getKnownHosts() {
13+
if host == knHost {
14+
return true
15+
}
16+
}
17+
return false
18+
}
19+
20+
// discoverCmd represents the discover command
21+
var discoverCmd = &cobra.Command{
22+
Use: "discover",
23+
Short: "Discover freebox(s) on the lan",
24+
Run: func(cmd *cobra.Command, args []string) {
25+
defer panicHandler()
26+
27+
boxs := fbxapi.MdnsDiscover()
28+
nboxs := len(boxs)
29+
30+
for _, freebox := range boxs {
31+
if isKnownFreebox(freebox.Host) {
32+
nboxs--
33+
continue
34+
}
35+
line := fmt.Sprintf("Found %s at %s:%d\nEnter a name for saving it or leave blank for ignore:\n",
36+
freebox.DeviceName, freebox.Host, freebox.Port)
37+
_, err := rlshell.Write([]byte(line))
38+
checkErr(err)
39+
alias, err := rlshell.Readline()
40+
checkErr(err)
41+
alias = strings.TrimSpace(alias)
42+
if len(alias) > 0 {
43+
client, track_id, err := Register(alias, freebox, false)
44+
checkErr(err)
45+
line = fmt.Sprintf("Added %s as %s\n(touch the right arrow on the freebox, then press enter)\n", freebox.DeviceName, alias)
46+
_, err = rlshell.Write([]byte(line))
47+
rlshell.Readline()
48+
resp, err := client.TrackLogin(track_id)
49+
rlshell.writeString(resp.Status)
50+
checkErr(err)
51+
}
52+
}
53+
54+
if nboxs == 0 {
55+
rlshell.Write([]byte("No new freebox found\n"))
56+
}
57+
},
58+
}
59+
60+
func init() {
61+
// logrus.SetOutput(os.Stdout)
62+
RootCmd.AddCommand(discoverCmd)
63+
64+
// Here you will define your flags and configuration settings.
65+
66+
// Cobra supports Persistent Flags which will work for this command
67+
// and all subcommands, e.g.:
68+
// discoverCmd.PersistentFlags().String("foo", "", "A help for foo")
69+
70+
// Cobra supports local flags which will only run when this command
71+
// is called directly, e.g.:
72+
// discoverCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
73+
74+
}

cmd/lan.go

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/spf13/cobra"
7+
)
8+
9+
var lanCmd = &cobra.Command{
10+
Use: "lan",
11+
Short: "List currently connected devices",
12+
Run: func(cmd *cobra.Command, args []string) {
13+
defer panicHandler()
14+
15+
iface, err := cmd.Flags().GetString("iface")
16+
checkErr(err)
17+
18+
devices, err := ENV.CurrentClient.Interface(iface)
19+
checkErr(err)
20+
21+
for _, device := range devices {
22+
if device.Active {
23+
line := fmt.Sprintf("[%s] %s %s %s\n", device.HostType, device.PrimaryName, device.L2Ident.Type, device.GetIPv4s())
24+
_, err := rlshell.Write([]byte(line))
25+
checkErr(err)
26+
}
27+
}
28+
},
29+
}
30+
31+
func init() {
32+
RootCmd.AddCommand(lanCmd)
33+
lanCmd.Flags().String("iface", "pub", "The freebox interface to scan (default: pub)")
34+
}

0 commit comments

Comments
 (0)