Dernière activité 1 month ago

shell.command.sh Brut
1#!/usr/bin/env bash
2
3# ============================================
4# Private helpers
5# ============================================
6
7function cmd::shell::_prompt() {
8 local user host dir
9 user=$(whoami)
10 host=$(hostname -s)
11 dir=$(basename "$PWD")
12 printf "\033[1;32m%s@%s\033[0m:\033[0;36m%s\033[0m \033[1;34mwgctl\033[0m> " \
13 "$user" "$host" "$dir"
14}
15
16function cmd::shell::_is_wgctl_command() {
17 local cmd="$1"
18 # Check against known wgctl commands
19 local known=(
20 list add remove rm inspect block unblock
21 rule group audit logs watch fw config qr
22 rename keys ip service shell help
23 )
24 local c
25 for c in "${known[@]}"; do
26 [[ "$c" == "$cmd" ]] && return 0
27 done
28 return 1
29}
30
31function cmd::shell::_handle_builtin() {
32 local input="$1"
33 local first="${input%% *}"
34
35 case "$first" in
36 cd)
37 local dir="${input#cd }"
38 [[ "$dir" == "$input" ]] && dir="$HOME"
39 cd "$dir" 2>/dev/null || log::error "cd: $dir: No such file or directory"
40 return 0
41 ;;
42 cd*) eval "$input" ;; # eval preserves shell state for cd
43 export|unset|source|.)
44 eval "$input"
45 return 0
46 ;;
47 esac
48 return 1 # not a builtin
49}
50
51function cmd::shell::_execute() {
52 local input="$1"
53 local first="${input%% *}"
54 local rest="${input#"$first"}"
55 rest="${rest# }"
56
57 # Handle shell builtins first
58 cmd::shell::_handle_builtin "$input" && return 0
59
60 # Try as wgctl command via dispatcher
61 if cmd::shell::_is_wgctl_command "$first"; then
62 if [[ -n "$rest" ]]; then
63 wgctl::dispatch "$first" $rest || true # never exit REPL on failure
64 else
65 wgctl::dispatch "$first" || true
66 fi
67 return 0 # Always 0 to keep REPL running
68 fi
69
70 # Fall back to bash
71 bash -c "$input" || true # same for bash commands
72}
73
74function cmd::shell::_setup_history() {
75 HISTFILE="${HOME}/.wgctl_history"
76 HISTSIZE=1000
77 HISTFILESIZE=2000
78 history -r 2>/dev/null || true
79}
80
81function cmd::shell::_save_history() {
82 history -w 2>/dev/null || true
83}
84
85function cmd::shell::_banner() {
86 ui::section "wgctl shell"
87 printf "\n"
88 printf " Type wgctl commands directly, or any bash command.\n"
89 printf " Type \033[1mexit\033[0m or \033[1mquit\033[0m to leave.\n"
90 printf " Type \033[1mhelp\033[0m for wgctl commands.\n"
91 printf "\n"
92}
93
94# ============================================
95# Run
96# ============================================
97
98function cmd::shell::on_load() {
99 : # no flags needed
100}
101
102function cmd::shell::help() {
103 cat <<EOF
104Usage: wgctl shell
105
106Start an interactive wgctl shell. Supports all wgctl commands
107directly (no 'wgctl' prefix needed), plus any bash command.
108
109Builtins handled: cd, export, unset, source
110Everything else: passed to bash
111
112Examples:
113 wgctl shell
114 wgctl> list
115 wgctl> inspect --name phone-nuno
116 wgctl> ls /etc/wireguard
117 wgctl> exit
118EOF
119}
120
121function cmd::shell::run() {
122 cmd::shell::_banner
123 cmd::shell::_setup_history
124
125 while true; do
126 local input
127 # Read with readline support (-e) and custom prompt
128 IFS= read -r -e -p "$(cmd::shell::_prompt)" input || break
129
130 # Handle empty input
131 [[ -z "${input// }" ]] && continue
132
133 # Add to history
134 history -s "$input"
135
136 # Handle exit
137 case "${input%% *}" in
138 exit|quit) break ;;
139 esac
140
141 # Execute
142 cmd::shell::_execute "$input"
143 done
144
145 cmd::shell::_save_history
146 printf "\n Goodbye!\n\n"
147}
148
149# ============================================
150# Tab completion (loaded when shell starts)
151# ============================================
152
153function cmd::shell::_setup_completion() {
154 local commands="list add remove inspect block unblock rule group audit logs watch fw config qr rename shell help"
155
156 function _wgctl_shell_complete() {
157 local cur="${COMP_WORDS[COMP_CWORD]}"
158 COMPREPLY=( $(compgen -W "$commands" -- "$cur") )
159 }
160
161 # Bind completion to the read prompt
162 bind 'set show-all-if-ambiguous on' 2>/dev/null || true
163 bind 'set completion-ignore-case on' 2>/dev/null || true
164}