Initial commit

This commit is contained in:
Daniel Prows 2023-08-24 21:52:28 -06:00
parent 104a042e5e
commit ff229676d7
19 changed files with 227 additions and 159 deletions

View File

@ -1,6 +1,2 @@
# Stream Deck Go Plugin
# Mac HTTP Proxy Control
find everywhere with {{{NAME}}} and replace it with appropriate values
do the manifest
write code

View File

@ -1,7 +1,7 @@
INSTALLDIR = ~/Library/Application\ Support/com.elgato.StreamDeck/Plugins/com.dlprows.{{{NAME}}}.sdPlugin
INSTALLDIR = ~/Library/Application\ Support/com.elgato.StreamDeck/Plugins/com.dlprows.httpproxy.sdPlugin
#BUILDDIR = build
#RELEASEDIR = release
#SDPLUGINDIR = "./com.dlprows.{{{NAME}}}.sdPlugin"
#SDPLUGINDIR = "./com.dlprows.httpproxycontrol.sdPlugin"
update:
killall Stream\ Deck || true
@ -9,9 +9,9 @@ update:
open -a Elgato\ Stream\ Deck
build:
go build -o com.dlprows.{{{NAME}}}.sdPlugin
rm com.dlprows.{{{NAME}}}.streamDeckPlugin
./DistributionTool -b -i com.dlprows.{{{NAME}}}.sdPlugin -o .
go build -o com.dlprows.httpproxy.sdPlugin
rm com.dlprows.httpproxy.streamDeckPlugin || true
./DistributionTool -b -i com.dlprows.httpproxy.sdPlugin -o .
#.PHONY: test install build logs

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -0,0 +1,53 @@
{
"Actions": [
{
"UUID": "com.dlprows.httpproxy.action",
"Name": "System Proxy",
"Tooltip": "Turn on/off system proxy",
"Icon": "Images/icon",
"States": [
{
"Image": "Images/pluginAction",
"TitleAlignment": "middle",
"FontSize": "12"
},
{
"Image": "Images/pluginAction",
"TitleAlignment": "middle",
"FontSize": "12"
},
{
"Image": "Images/pluginAction",
"TitleAlignment": "middle",
"FontSize": "12"
},
{
"Image": "Images/pluginAction",
"TitleAlignment": "middle",
"FontSize": "12"
}
],
"Controllers": [ "Keypad" ],
"SupportedInMultiActions": false
}
],
"Author": "dlprows",
"Name": "Http Proxy Control",
"Description": "Turn on and off HTTP(S) proxy settings in mac os",
"URL": "https://encyclopediaofdaniel.com",
"Version": "1.0",
"CodePath": "httpproxycontrol",
"Category": "Networking [dlprows]",
"Icon": "Images/pluginIcon",
"CategoryIcon": "Images/categoryIcon",
"OS": [
{
"Platform": "mac",
"MinimumVersion": "13.0"
}
],
"SDKVersion": 2,
"Software": {
"MinimumVersion": "6.0"
}
}

View File

@ -1,49 +0,0 @@
{
"Actions": [
{
"UUID": "com.dlprows.{{{NAME}}}.dialaction",
"Name": "Volume",
"Tooltip": "Control system volume",
"Icon": "Images/icon",
"States": [
{
"Image": "Images/pluginAction",
"TitleAlignment": "middle",
"FontSize": "12"
}
],
"Controllers": [ "Encoder" ],
"Encoder": {
"background": "backgroundImage",
"Icon": "Images/actionIcon",
"layout": "$B1",
"StackColor": "#AABBCC",
"TriggerDescription": {
"Rotate": "System Volume",
"Push": "Mute",
"Touch": "Mute"
}
},
"SupportedInMultiActions": false
}
],
"Author": "dlprows",
"Name": "{{{NAME}}}",
"Description": "Control volume on mac",
"URL": "https://encyclopediaofdaniel.com",
"Version": "1.0",
"CodePath": "{{{NAME}}}",
"Category": "Volume Control [dlprows]",
"Icon": "Images/pluginIcon",
"CategoryIcon": "Images/categoryIcon",
"OS": [
{
"Platform": "mac",
"MinimumVersion": "13.0"
}
],
"SDKVersion": 2,
"Software": {
"MinimumVersion": "6.0"
}
}

View File

@ -1,7 +1,9 @@
module macvolumecontrol
module httpproxycontrol
go 1.20
require code.encyclopediaofdaniel.com/dlprows/streamdeck-sdk v1.0.1
require github.com/gorilla/websocket v1.5.0 // indirect
require (
code.encyclopediaofdaniel.com/dlprows/streamdeck-sdk v1.0.1 // indirect
github.com/b4b4r07/go-pipe v0.0.0-20191010045404-84b446f57366 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
)

View File

@ -1,6 +1,6 @@
code.encyclopediaofdaniel.com/dlprows/streamdeck-sdk v1.0.1 h1:2IoDJrWt6Bp5IcXTtqjdygDo3Ruh5VHsS9R5MjI2WWQ=
code.encyclopediaofdaniel.com/dlprows/streamdeck-sdk v1.0.1/go.mod h1:SaMt3PIkPtNwkgrcLpD89GK/7tLaUkcEvOZaHUC66+4=
github.com/b4b4r07/go-pipe v0.0.0-20191010045404-84b446f57366 h1:FVAkDbBxovi2ID0vaxY7vCGvdKASt9r0TGPM1u4YQyg=
github.com/b4b4r07/go-pipe v0.0.0-20191010045404-84b446f57366/go.mod h1:1ymsiQNa3qebVEEVtuIdhtAXRfjO4qFCFq1bBUOT2HE=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/samwho/streamdeck v0.0.0-20190725183037-2b866fdcb4a6 h1:ocHB+wIjLCdideequ8l8dUem6DxHf/A4Mmo0TRxBf1U=
github.com/samwho/streamdeck v0.0.0-20190725183037-2b866fdcb4a6/go.mod h1:OjeKL1Q8xRGm1zHGmtu9JeQUFNOXXXIcSZvCNzRP3GM=

View File

@ -2,21 +2,17 @@ package main
import (
"context"
"encoding/json"
"fmt"
"log"
"os"
"time"
"macvolumecontrol/logging"
"macvolumecontrol/volume"
"httpproxycontrol/logging"
"httpproxycontrol/networking"
"code.encyclopediaofdaniel.com/dlprows/streamdeck-sdk"
sdcontext "code.encyclopediaofdaniel.com/dlprows/streamdeck-sdk/context"
)
var _currentSettings *volume.VolumeSettings = &volume.VolumeSettings{}
func main() {
logging.Enable()
log.Println("Starting plugin")
@ -38,64 +34,26 @@ func main() {
func setup(client *streamdeck.Client) {
log.Println("Registering actions")
action := client.Action("com.dlprows.macvolumecontrol.dialaction")
action := client.Action("com.dlprows.httpproxy.action")
contexts := make(map[string]struct{})
action.RegisterHandler(streamdeck.DialRotate, func(ctx context.Context, client *streamdeck.Client, event streamdeck.Event) error {
log.Println("dial rotate")
action.RegisterHandler(streamdeck.KeyDown, func(ctx context.Context, client *streamdeck.Client, event streamdeck.Event) error {
log.Println("Key Down")
p := streamdeck.DialRotatePayload[any]{}
toggleVpn()
if err := json.Unmarshal(event.Payload, &p); err != nil {
return err
}
client.SetState(ctx, getState())
//volume.ChangeVolumeWithKeyboard(p.Ticks)
newSettings, err := volume.ChangeVolume(p.Ticks)
if err != nil {
return err
}
return setFeedbackIfNeeded(ctx, client, newSettings)
})
action.RegisterHandler(streamdeck.DialDown, func(ctx context.Context, client *streamdeck.Client, event streamdeck.Event) error {
log.Println("dial down")
newSettings, err := volume.ToggleMute()
if err != nil {
return err
}
return setFeedbackIfNeeded(ctx, client, newSettings)
})
action.RegisterHandler(streamdeck.TouchTap, func(ctx context.Context, client *streamdeck.Client, event streamdeck.Event) error {
log.Println("touch tap")
newSettings, err := volume.ToggleMute()
if err != nil {
return err
}
return setFeedbackIfNeeded(ctx, client, newSettings)
return nil
})
action.RegisterHandler(streamdeck.WillAppear, func(ctx context.Context, client *streamdeck.Client, event streamdeck.Event) error {
log.Println("Will Appear")
contexts[event.Context] = struct{}{}
newSettings, err := volume.GetVolumeSettings()
if err != nil {
return err
}
return setFeedback(ctx, client, newSettings)
client.SetState(ctx, getState())
return nil
})
action.RegisterHandler(streamdeck.WillDisappear, func(ctx context.Context, client *streamdeck.Client, event streamdeck.Event) error {
@ -106,12 +64,7 @@ func setup(client *streamdeck.Client) {
//start background thread to keep the display up to date if changed outside the stream deck
go func() {
for range time.Tick(time.Second * 1) {
newSettings, err := volume.GetVolumeSettings()
if err != nil {
log.Fatal(err)
}
for range time.Tick(time.Second * 10) {
for ctxStr := range contexts {
//for each context
@ -119,55 +72,60 @@ func setup(client *streamdeck.Client) {
ctx := context.Background()
ctx = sdcontext.WithContext(ctx, ctxStr)
setFeedback(ctx, client, newSettings)
client.SetState(ctx, getState())
}
_currentSettings = newSettings
}
}()
}
func setFeedback(ctx context.Context, client *streamdeck.Client, newSettings *volume.VolumeSettings) error {
func toggleVpn() error {
/*
if on, turn off
if off, turn on
if broken, turn off
*/
activeDevice, err := networking.GetActiveDevice()
payload := FeedbackPayload{}
opacity := 1.0
if newSettings.OutputMuted {
opacity = 0.5
if err != nil {
return err
}
payload.Value = ValueWithOpacity[string]{
fmt.Sprintf("%d%%", newSettings.OutputVolume),
opacity,
enabled, err := networking.IsProxyEnabled(activeDevice)
if err != nil {
return err
}
payload.Indicator = ValueWithOpacity[int]{
newSettings.OutputVolume,
opacity,
}
networking.SetProxyServer(activeDevice, "192.168.41.101", "8888")
networking.SetProxyState(activeDevice, !enabled)
payload.Icon = ValueWithOpacity[any]{nil, opacity}
return client.SetFeedback(ctx, payload)
}
func setFeedbackIfNeeded(ctx context.Context, client *streamdeck.Client, newSettings *volume.VolumeSettings) error {
if _currentSettings.OutputVolume == newSettings.OutputVolume && _currentSettings.OutputMuted == newSettings.OutputMuted {
return nil
}
func getState() int {
/*
0 for no network
1 for proxy off
2 for proxy on
3 for busted
*/
activeDevice, err := networking.GetActiveDevice()
if err != nil {
return 3
}
_currentSettings = newSettings
return setFeedback(ctx, client, newSettings)
}
if activeDevice == "" {
return 0
}
type FeedbackPayload struct {
Value ValueWithOpacity[string] `json:"value"`
Indicator ValueWithOpacity[int] `json:"indicator"`
Icon ValueWithOpacity[any] `json:"icon"`
}
proxyEnabled, err := networking.IsProxyEnabled(activeDevice)
type ValueWithOpacity[T any] struct {
Value T `json:"value,omitempty"`
Opacity float64 `json:"opacity"`
if err != nil {
return 3
}
if proxyEnabled {
return 2
}
return 1
}

View File

@ -0,0 +1,108 @@
package networking
import (
"os/exec"
"strings"
)
func GetActiveDevice() (string, error) {
output, err := exec.Command("networksetup", "-listnetworkserviceorder").Output()
if err != nil {
return "", err
}
for _, line := range strings.Split(strings.TrimSuffix(string(output), "\n"), "\n") {
if !strings.Contains(line, "Device:") {
continue
}
//(Hardware Port: Thunderbolt Ethernet Slot 2, Device: en8)
split := strings.Split(line, ",")
name := strings.Split(split[0], ":")[1]
name = strings.TrimPrefix(name, " ")
device := strings.Split(split[1], ":")[1]
device = device[1 : len(device)-1]
active := isDeviceActive(device)
if active {
return name, nil
}
}
return "", nil
}
func isDeviceActive(device string) bool {
output, _ := exec.Command("ifconfig", device).Output()
for _, line := range strings.Split(strings.TrimSuffix(string(output), "\n"), "\n") {
if strings.Contains(line, "status: active") {
return true
}
}
return false
}
func IsProxyEnabled(deviceName string) (bool, error) {
output, err := exec.Command("networksetup", "-getwebproxy", deviceName).Output()
if err != nil {
return false, err
}
webEnabled := strings.Contains(string(output), "Enabled: Yes\n")
output, err = exec.Command("networksetup", "-getsecurewebproxy", deviceName).Output()
if err != nil {
return false, err
}
secureEnabled := strings.Contains(string(output), "Enabled: Yes\n")
//todo: if they're not equal, its some sort of error case
return webEnabled && secureEnabled, nil
}
func SetProxyState(deviceName string, on bool) error {
onOff := "on"
if !on {
onOff = "off"
}
err := exec.Command("networksetup", "-setwebproxystate", deviceName, onOff).Run()
if err != nil {
return err
}
err = exec.Command("networksetup", "-setsecurewebproxystate", deviceName, onOff).Run()
if err != nil {
return err
}
return nil
}
func SetProxyServer(deviceName string, host string, port string) error {
err := exec.Command("networksetup", "-setwebproxy", deviceName, host, port).Run()
if err != nil {
return err
}
err = exec.Command("networksetup", "-setsecurewebproxy", deviceName, host, port).Run()
if err != nil {
return err
}
return nil
}