Skip to content

Commit

Permalink
Fixed a bug with the status freezing when copying a button;
Browse files Browse the repository at this point in the history
Added a new type of proxy http(s), which works simultaneously with http and https;
Increased stability;
  • Loading branch information
gri-gus committed Sep 23, 2024
1 parent 2311f44 commit d99f234
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 34 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Stream Deck plugin for enabling and disabling proxies on MacOS.
## Features

* Supports `http`, `https` and `socks` proxies.
* There is `http(s)` proxy to manage `http` and `https` proxies at the same time.
* The color of the button changes depending on its state.

## Installation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class ProxyTypes(Enum):
HTTP = "http"
HTTPS = "https"
SOCKS = "socks"
HTTP_HTTPS = "http(s)"


def set_proxy(
Expand All @@ -16,7 +17,7 @@ def set_proxy(
port: str,
username: str = "",
password: str = "",
):
) -> None:
if proxy_type is ProxyTypes.HTTP:
res = setwebproxy(
networkservice=networkservice,
Expand All @@ -41,6 +42,22 @@ def set_proxy(
username=username,
password=password,
)
elif proxy_type is ProxyTypes.HTTP_HTTPS:
res1 = setwebproxy(
networkservice=networkservice,
domain=domain,
port=port,
username=username,
password=password,
)
res2 = setsecurewebproxy(
networkservice=networkservice,
domain=domain,
port=port,
username=username,
password=password,
)
res = "\n".join([res1, res2]) if res1 or res2 else ""
else:
raise ValueError("Bad proxy_type")
if res:
Expand All @@ -67,6 +84,16 @@ def set_proxy_state(
networkservice=networkservice,
enabled=enabled,
)
elif proxy_type is ProxyTypes.HTTP_HTTPS:
res1 = setwebproxystate(
networkservice=networkservice,
enabled=enabled,
)
res2 = setsecurewebproxystate(
networkservice=networkservice,
enabled=enabled,
)
res = "\n".join([res1, res2]) if res1 or res2 else ""
else:
raise ValueError("Bad proxy_type")
if res:
Expand All @@ -89,6 +116,17 @@ def get_proxy(
res = getsocksfirewallproxy(
networkservice=networkservice,
)
elif proxy_type is ProxyTypes.HTTP_HTTPS:
res1 = getwebproxy(
networkservice=networkservice,
)
res2 = getsecurewebproxy(
networkservice=networkservice,
)
if res1.enabled and res2.enabled and res1.server == res2.server and res1.port == res2.port:
res = res1
else:
res = ProxyInfo(enabled=False, server="Unknown", port="Unknown")
else:
raise ValueError("Bad proxy_type")
return res
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@ def test_set_proxy(self):
)
print(res)

def test_set_proxy_http_https(self):
res = set_proxy(
proxy_type=ProxyTypes.HTTP_HTTPS,
networkservice="Wi-Fi",
domain="192.168.158.9",
port="1080",
)
print(res)

def test_set_proxy_state_enable(self):
res = set_proxy_state(
proxy_type=ProxyTypes.SOCKS,
Expand All @@ -34,9 +43,30 @@ def test_set_proxy_state_disable(self):
)
print(res)

def test_get_proxy(self):
def test_get_proxy_socks(self):
res = get_proxy(
proxy_type=ProxyTypes.SOCKS,
networkservice="Wi-Fi"
)
print(res)

def test_get_proxy_http(self):
res = get_proxy(
proxy_type=ProxyTypes.HTTP,
networkservice="Wi-Fi"
)
print(res)

def test_get_proxy_https(self):
res = get_proxy(
proxy_type=ProxyTypes.HTTPS,
networkservice="Wi-Fi"
)
print(res)

def test_get_proxy_http_https(self):
res = get_proxy(
proxy_type=ProxyTypes.HTTP_HTTPS,
networkservice="Wi-Fi"
)
print(res)
99 changes: 69 additions & 30 deletions com.ggusev.proxymanager.sdPlugin/code/main.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import time
from dataclasses import dataclass
from enum import IntEnum
from typing import Dict
from typing import Dict, Union

from streamdeck_sdk import (
StreamDeck,
Expand All @@ -27,7 +27,7 @@ class ConnectStates(IntEnum):


@dataclass
class ProxySettings:
class MonitoringParams:
networkservice: str
proxy_type: ProxyTypes
domain: str
Expand All @@ -36,18 +36,20 @@ class ProxySettings:

MONITORING_INTERVAL: float = 2
DELAY_BETWEEN_KEY_DOWN: float = 2.4
CONTEXT_TO_PROXY_SETTINGS: Dict[str, ProxySettings] = {}
CONTEXT_TO_MONITORING_PARAMS: Dict[str, MonitoringParams] = {}
PROXY_TYPES = ["http", "https", "http(s)", "socks", ]


class ConnectDisconnectAction(Action):
UUID = "com.ggusev.proxymanager.connectdisconnect"
LAST_KEY_DOWN_TIME = 0

def on_key_down(self, obj: events_received_objs.KeyDown) -> None:
if time.time() - self.LAST_KEY_DOWN_TIME < DELAY_BETWEEN_KEY_DOWN:
now = time.time()
if now - self.LAST_KEY_DOWN_TIME < DELAY_BETWEEN_KEY_DOWN:
self.show_alert(context=obj.context)
return
self.LAST_KEY_DOWN_TIME = time.time()
self.LAST_KEY_DOWN_TIME = now

networkservice = obj.payload.settings["networkservice"]
proxy_types, proxy_type_selected = obj.payload.settings["proxy_type"]
Expand All @@ -62,27 +64,31 @@ def on_key_down(self, obj: events_received_objs.KeyDown) -> None:
proxy_type = ProxyTypes(proxy_type_selected)

if obj.payload.state == ConnectStates.ENABLED:
set_proxy_state_error = set_proxy_state(
proxy_type=proxy_type,
networkservice=networkservice,
enabled=False,
)
if set_proxy_state_error:
try:
set_proxy_state(
proxy_type=proxy_type,
networkservice=networkservice,
enabled=False,
)
except Exception as err:
logger.warning(err, exc_info=True)
self.show_alert(context=obj.context)
return
self.set_state(context=obj.context, state=ConnectStates.DISABLED)
self.show_ok(context=obj.context)
return
elif obj.payload.state == ConnectStates.DISABLED:
set_proxy_error = set_proxy(
proxy_type=proxy_type,
networkservice=networkservice,
domain=domain,
port=port,
username=username,
password=password
)
if set_proxy_error:
try:
set_proxy(
proxy_type=proxy_type,
networkservice=networkservice,
domain=domain,
port=port,
username=username,
password=password
)
except Exception as err:
logger.warning(err, exc_info=True)
self.show_alert(context=obj.context)
return
self.set_state(context=obj.context, state=ConnectStates.ENABLED)
Expand All @@ -91,25 +97,54 @@ def on_key_down(self, obj: events_received_objs.KeyDown) -> None:
self.show_alert(context=obj.context)

def on_will_appear(self, obj: events_received_objs.WillAppear):
self.LAST_KEY_DOWN_TIME = time.time()
self._update_or_create_proxy_in_monitoring(obj=obj)

def on_will_disappear(self, obj: events_received_objs.WillDisappear) -> None:
CONTEXT_TO_MONITORING_PARAMS.pop(obj.context, None)

def on_did_receive_settings(self, obj: events_received_objs.DidReceiveSettings) -> None:
self._update_proxy_types_in_pi(obj=obj)
self._update_or_create_proxy_in_monitoring(obj=obj)

def on_property_inspector_did_appear(self, obj: events_received_objs.PropertyInspectorDidAppear) -> None:
self.get_settings(context=obj.context)

def _update_proxy_types_in_pi(self, obj: events_received_objs.DidReceiveSettings):
"""
Update proxy_types when updating the plugin if they have been changed.
"""
proxy_types, proxy_type_selected = obj.payload.settings["proxy_type"]
if proxy_types == PROXY_TYPES:
return
_settings = obj.payload.settings.copy()
_settings["proxy_type"] = [PROXY_TYPES, proxy_type_selected]
self.set_settings(context=obj.context, payload=_settings)

def _update_or_create_proxy_in_monitoring(
self,
obj: Union[
events_received_objs.DidReceiveSettings,
events_received_objs.WillAppear,
],
):
networkservice = obj.payload.settings["networkservice"]
proxy_types, proxy_type_selected = obj.payload.settings["proxy_type"]
domain = obj.payload.settings["domain"]
port = obj.payload.settings["port"]

if not (networkservice and proxy_type_selected and domain and port):
self.set_state(context=obj.context, state=ConnectStates.DISABLED)
if obj.payload.state == ConnectStates.ENABLED:
self.set_state(context=obj.context, state=ConnectStates.DISABLED)
return
proxy_type = ProxyTypes(proxy_type_selected)
proxy_settings = ProxySettings(
monitoring_params = MonitoringParams(
networkservice=networkservice,
proxy_type=proxy_type,
domain=domain,
port=port
)
CONTEXT_TO_PROXY_SETTINGS[obj.context] = proxy_settings

def on_will_disappear(self, obj: events_received_objs.WillDisappear) -> None:
CONTEXT_TO_PROXY_SETTINGS.pop(obj.context, None)
CONTEXT_TO_MONITORING_PARAMS[obj.context] = monitoring_params

@in_separate_thread(daemon=True)
@log_errors
Expand All @@ -122,10 +157,14 @@ def run_monitoring(self):
logger.exception(err)

def monitoring_iteration(self):
for context, proxy_settings in CONTEXT_TO_PROXY_SETTINGS.items():
proxy_info = get_proxy(proxy_type=proxy_settings.proxy_type, networkservice=proxy_settings.networkservice)
if (proxy_info.enabled and proxy_info.server == proxy_settings.domain
and proxy_info.port == proxy_settings.port):
context_to_monitoring_params = CONTEXT_TO_MONITORING_PARAMS.copy()
for context, monitoring_params in context_to_monitoring_params.items():
proxy_info = get_proxy(
proxy_type=monitoring_params.proxy_type,
networkservice=monitoring_params.networkservice,
)
if (proxy_info.enabled and proxy_info.server == monitoring_params.domain
and proxy_info.port == monitoring_params.port):
self.set_state(context=context, state=ConnectStates.ENABLED)
continue
self.set_state(context=context, state=ConnectStates.DISABLED)
Expand Down
2 changes: 1 addition & 1 deletion com.ggusev.proxymanager.sdPlugin/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"Description": "Control proxy on MacOS",
"Icon": "assets/plugin_icon",
"Name": "Proxy manager",
"Version": "1.0.3",
"Version": "1.1.0",
"SDKVersion": 2,
"OS": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<option selected value="null"></option>
<option value="http">http</option>
<option value="https">https</option>
<option value="http(s)">http(s)</option>
<option value="socks">socks</option>
</select>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def main():
Select(
uid="proxy_type",
label="Proxy type",
values=["http", "https", "socks", ],
values=["http", "https", "http(s)", "socks", ],
default_value=None,
),
Textfield(
Expand Down

0 comments on commit d99f234

Please sign in to comment.