cycls 0.0.2.12__tar.gz → 0.0.2.20__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,68 @@
1
+ Metadata-Version: 2.1
2
+ Name: cycls
3
+ Version: 0.0.2.20
4
+ Summary: Cycls SDK
5
+ Author: Mohammed Jamal
6
+ Author-email: mj@cycls.com
7
+ Requires-Python: >=3.8,<4.0
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.8
10
+ Classifier: Programming Language :: Python :: 3.9
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Requires-Dist: asyncssh (>=2.14.2,<3.0.0)
15
+ Requires-Dist: fastapi (>=0.111.0,<0.112.0)
16
+ Requires-Dist: httpx (>=0.27.0,<0.28.0)
17
+ Description-Content-Type: text/markdown
18
+
19
+ </br></br><p align="center"><img src="https://cycls.com/static/assets/favicon.svg" alt="Cycls"></p></br>
20
+
21
+ <div align="center">
22
+ <a href="https://pypi.org/project/cycls/" target="_blank" rel="noopener noreferrer">
23
+ <img loading="lazy" src="https://img.shields.io/pypi/v/cycls.svg" alt="PyPI" class="img_ev3q" style="display: inline;">
24
+ </a>
25
+ <a href="https://discord.gg/BMnaMatDC7" target="_blank" rel="noopener noreferrer">
26
+ <img loading="lazy" src="https://img.shields.io/discord/1175782747164389466" alt="Discord" class="img_ev3q" style="display: inline;">
27
+ </a>
28
+ </div>
29
+
30
+ </br>
31
+
32
+ ```sh
33
+ pip install cycls
34
+ ```
35
+
36
+ ```py
37
+ from cycls import Cycls
38
+
39
+ cycls = Cycls()
40
+
41
+ # sync app on https://cycls.com/@spark
42
+ @cycls("@spark")
43
+ def spark_app(message):
44
+ print("history", message.history)
45
+ print("session id", message.id)
46
+ return message.content + "from spark"
47
+
48
+ # async app on https://cycls.com/@cake
49
+ @cycls("@cake")
50
+ async def cake_app(message):
51
+ print("history", message.history)
52
+ print("session id", message.id)
53
+ return message.content + "from cake"
54
+
55
+ # publish to https://cycls.com
56
+ cycls.push()
57
+ ```
58
+
59
+ Return a string. Supports markdown. Supports generators for streaming responses.
60
+
61
+ try it live
62
+ - https://cycls.com/@groq
63
+ - https://cycls.com/@openai
64
+
65
+ code examples
66
+ - https://github.com/Cycls/examples/blob/main/groq.py
67
+ - https://github.com/Cycls/examples/blob/main/openai.py
68
+
@@ -0,0 +1,49 @@
1
+ </br></br><p align="center"><img src="https://cycls.com/static/assets/favicon.svg" alt="Cycls"></p></br>
2
+
3
+ <div align="center">
4
+ <a href="https://pypi.org/project/cycls/" target="_blank" rel="noopener noreferrer">
5
+ <img loading="lazy" src="https://img.shields.io/pypi/v/cycls.svg" alt="PyPI" class="img_ev3q" style="display: inline;">
6
+ </a>
7
+ <a href="https://discord.gg/BMnaMatDC7" target="_blank" rel="noopener noreferrer">
8
+ <img loading="lazy" src="https://img.shields.io/discord/1175782747164389466" alt="Discord" class="img_ev3q" style="display: inline;">
9
+ </a>
10
+ </div>
11
+
12
+ </br>
13
+
14
+ ```sh
15
+ pip install cycls
16
+ ```
17
+
18
+ ```py
19
+ from cycls import Cycls
20
+
21
+ cycls = Cycls()
22
+
23
+ # sync app on https://cycls.com/@spark
24
+ @cycls("@spark")
25
+ def spark_app(message):
26
+ print("history", message.history)
27
+ print("session id", message.id)
28
+ return message.content + "from spark"
29
+
30
+ # async app on https://cycls.com/@cake
31
+ @cycls("@cake")
32
+ async def cake_app(message):
33
+ print("history", message.history)
34
+ print("session id", message.id)
35
+ return message.content + "from cake"
36
+
37
+ # publish to https://cycls.com
38
+ cycls.push()
39
+ ```
40
+
41
+ Return a string. Supports markdown. Supports generators for streaming responses.
42
+
43
+ try it live
44
+ - https://cycls.com/@groq
45
+ - https://cycls.com/@openai
46
+
47
+ code examples
48
+ - https://github.com/Cycls/examples/blob/main/groq.py
49
+ - https://github.com/Cycls/examples/blob/main/openai.py
@@ -0,0 +1 @@
1
+ from .cycls import Cycls
@@ -0,0 +1,129 @@
1
+ from fastapi import FastAPI, Request
2
+ from fastapi.responses import StreamingResponse
3
+ from pydantic import BaseModel
4
+ from typing import List, Dict, Optional
5
+
6
+ from functools import wraps
7
+ import uvicorn, socket, httpx
8
+ import inspect
9
+
10
+ import logging
11
+ logging.basicConfig(level=logging.ERROR)
12
+
13
+ O = lambda x,y: print(f"✦/✧ {str(x).ljust(7)} | {y}")
14
+
15
+ import os
16
+ current_dir = os.path.dirname(os.path.abspath(__file__))
17
+ key_path = os.path.join(current_dir, 'tuns')
18
+
19
+ class Message(BaseModel):
20
+ handle: str
21
+ content: str
22
+ id: str
23
+ history: Optional[List[Dict[str, str]]] = None
24
+
25
+ #!
26
+ def find_available_port(start_port):
27
+ port = start_port
28
+ while True:
29
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
30
+ if s.connect_ex(('localhost', port)) != 0:
31
+ return port
32
+ port += 1
33
+
34
+ import asyncssh, asyncio
35
+ async def create_ssh_tunnel(x,y,z='tuns.sh'):
36
+ try:
37
+ async with asyncssh.connect(z,client_keys=[key_path],known_hosts=None) as conn:
38
+ listener = await conn.forward_remote_port(x, 80, 'localhost', y)
39
+ O("tunnel","open");print(" ")
40
+ await listener.wait_closed()
41
+ except (OSError, asyncssh.Error) as e:
42
+ O("tunnel",f"disconnected ({e})")
43
+
44
+ def register(handles, graph, url, mode):
45
+ try:
46
+ with httpx.Client() as client:
47
+ response = client.post(f"{graph}/register", json={"handles":handles, "url":url, "mode":mode})
48
+ if response.status_code==200:
49
+ data = (response.json()).get("content")
50
+ for i in data:
51
+ O(i[0],f"{graph}/{i[1]}")
52
+ else:
53
+ print("✦/✧ failed to register ⚠️")
54
+ except Exception as e:
55
+ print(f"An error occurred: {e}")
56
+
57
+ class Cycls:
58
+ def __init__(self, url="", graph="https://cycls.com", port=find_available_port(8001)):
59
+ import uuid
60
+ self.subdomain = str(uuid.uuid4())[:8]
61
+ self.server = FastAPI()
62
+ self.graph = graph
63
+ self.port = port
64
+ self.url = url
65
+ self.apps = {}
66
+
67
+ def __call__(self, handle):
68
+ def decorator(func):
69
+ @wraps(func)
70
+ async def async_wrapper(*args, **kwargs):
71
+ return StreamingResponse(await func(*args, **kwargs))
72
+ @wraps(func)
73
+ def sync_wrapper(*args, **kwargs):
74
+ return StreamingResponse(func(*args, **kwargs))
75
+ wrapper = async_wrapper if inspect.iscoroutinefunction(func) else sync_wrapper
76
+ self.apps[handle] = wrapper
77
+ return wrapper
78
+ return decorator
79
+
80
+ async def gateway(self, request: Request):
81
+ data = await request.json()
82
+ handle = data.get('handle')
83
+ if handle in self.apps:
84
+ func = self.apps[handle]
85
+ message = Message(**data)
86
+ return await func(message) if inspect.iscoroutinefunction(func) else func(message)
87
+ return {"error": "Handle not found"}
88
+
89
+ def push(self):
90
+ self.server.post("/gateway")(self.gateway)
91
+ @self.server.on_event("startup")
92
+ def startup_event():
93
+ asyncio.create_task(create_ssh_tunnel(f"{self.subdomain}-cycls", self.port))
94
+
95
+ self.publish()
96
+
97
+ try:
98
+ uvicorn.run(self.server, host="127.0.0.1", port=self.port, log_level="error")
99
+ except KeyboardInterrupt:
100
+ print(" ");O("exit","done")
101
+
102
+ def publish(self):
103
+ #!
104
+ prod=False
105
+ if self.url != "":
106
+ prod=True
107
+
108
+ O("port",self.port)
109
+ if prod:
110
+ O("mode",f"production (url:{self.url})")
111
+ register(list(self.apps.keys()), self.graph, self.url+"/gateway", "prod")
112
+ else:
113
+ self.url = f"http://{self.subdomain}-cycls.tuns.sh"
114
+ O("mode","development")
115
+ register(list(self.apps.keys()), self.graph, self.url+"/gateway", "dev")
116
+
117
+ async def call(self, handle, content):
118
+ data = {"handle":handle, "content":content, "session":{}, "agent":"yes"}
119
+ try:
120
+ url = f"{self.graph}/stream/"
121
+ async with httpx.AsyncClient(timeout=20) as client, client.stream("POST", url, json=data) as response:
122
+ if response.status_code != 200:
123
+ print("http error")
124
+ async for token in response.aiter_text():
125
+ yield token
126
+ except Exception as e:
127
+ print("Exception", e)
128
+
129
+ # poetry publish --build
@@ -0,0 +1,27 @@
1
+ -----BEGIN OPENSSH PRIVATE KEY-----
2
+ b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
3
+ NhAAAAAwEAAQAAAQEAxq9z8nrMUnCRBSDhOcUeAZ//dolIg7RQoXM+Yo6aPACuqRMjo70b
4
+ wzXotyIqFRHe5eLntoa5FLj4n/3/uKVjy+f0xwPxquzTRESJehmUNN7WXaXQt2TX7BmMeo
5
+ vxWiQ69qzcQMQx7FNJNKSsA4Ynw9fIg/NDvEAtnYotmcF37finCJzj3OOxAaAB53bAzfY2
6
+ GD0JL+W8bzuMXpyZaqD+33selRNLqWVbcgNrJW6IDtZXvT1gBRsVsycbNrBrwFuhafnLW1
7
+ KAP/ZLLRP4w+BUgJVJVu9PqTfTrAcnDwspduNJqAtYPMbvuoToip1kYwws3wl8hHpsal67
8
+ U5xZeOn+5QAAA9i3Fmc8txZnPAAAAAdzc2gtcnNhAAABAQDGr3PyesxScJEFIOE5xR4Bn/
9
+ 92iUiDtFChcz5ijpo8AK6pEyOjvRvDNei3IioVEd7l4ue2hrkUuPif/f+4pWPL5/THA/Gq
10
+ 7NNERIl6GZQ03tZdpdC3ZNfsGYx6i/FaJDr2rNxAxDHsU0k0pKwDhifD18iD80O8QC2dii
11
+ 2ZwXft+KcInOPc47EBoAHndsDN9jYYPQkv5bxvO4xenJlqoP7fex6VE0upZVtyA2slbogO
12
+ 1le9PWAFGxWzJxs2sGvAW6Fp+ctbUoA/9kstE/jD4FSAlUlW70+pN9OsBycPCyl240moC1
13
+ g8xu+6hOiKnWRjDCzfCXyEemxqXrtTnFl46f7lAAAAAwEAAQAAAQBFcWl7JMRpRALL4hQW
14
+ VvkH5F4rlgwMTGeqJld1pxXtRufFHHVmc2BSuHLgH0bKGnbnrokCWNAzl/r+II7SgKwCxs
15
+ 3dCVncPe4RfEr4rBwK5p/SF3R9xPdbBAr/gg4XTXZ2ZTCOSoSQbwO1LKEakjcv0im5RLs1
16
+ /tBysasChIZgW9x4gGj7Kv4kz6Ojak/enlylwoz4q/dxaX9wV0op8YbnBubI3PS4gosYyz
17
+ fR9QAQbLrugo79xM9MpH1XjpQmk4UkuJX+OWqtZHq4Q2ZLuCoN4dv/mDcijAa/+lVtzerj
18
+ Ku6XtUREHRfdbKi88j+E7N4CfLW26UmV5xQhRjC8m+b5AAAAgQDoBpIUKoLEVVsWjc6n/e
19
+ TGip/qTlzcakODPELOzFK13GCAb/gj/sPxT6tUa382X9jcotgFSYBnO2TFA8gbBSXovWZv
20
+ zrXsNwfQBnvKih1Wngsq/bk7MYUvNPC0zomX0/dPi+riNb/5jLSEy5uICY4swMnsYb2Eyw
21
+ 5CO+eHC9yiWAAAAIEA6Rx6TvBlMvqt5YbmdOX6LdNi9KNbh4ZmimFJu95IuvYUDol0aDa+
22
+ qc85GPBXt/vU6+mD3A1somE2WI2P0sswdYn+g7pbBdItA3NcCuqBFl735bOU6CQ5mygY2P
23
+ B/AE43+jeQUFfjBM+lDJNB8adffyBOQBhgmGAqGCq/p6GtgvMAAACBANoxpAHC8Q4cm4No
24
+ vsCefODzNUqgsOtgrJXfp3aDVx2pL9Ua71EAh2e5eWvr8YdvmhgU7ophAeEezQqt0nrQYW
25
+ xheJQQd1hgm50DY9ssKNcFHd8BkLwGVRbgDfwhPLDektZZqRlbrVsqIBkDurVI764h2v8M
26
+ G/fyU3Xv57Ed1vzHAAAAHm1vaGFtbWVkYWxydWpheWlATW9oYW1tZWRzLUFpcgECAwQ=
27
+ -----END OPENSSH PRIVATE KEY-----
@@ -1,9 +1,6 @@
1
1
  [tool.poetry]
2
- #name = "cycls-dev"
3
- #version = "0.0.1.3"
4
-
5
2
  name = "cycls"
6
- version = "0.0.2.12"
3
+ version = "0.0.2.20"
7
4
 
8
5
  packages = [{ include = "cycls" }]
9
6
  description = "Cycls SDK"
@@ -14,6 +11,7 @@ readme = "README.md"
14
11
  python = "^3.8"
15
12
  fastapi = "^0.111.0"
16
13
  httpx = "^0.27.0"
14
+ asyncssh = "^2.14.2"
17
15
 
18
16
 
19
17
  [build-system]
cycls-0.0.2.12/PKG-INFO DELETED
@@ -1,132 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: cycls
3
- Version: 0.0.2.12
4
- Summary: Cycls SDK
5
- Author: Mohammed Jamal
6
- Author-email: mj@cycls.com
7
- Requires-Python: >=3.8,<4.0
8
- Classifier: Programming Language :: Python :: 3
9
- Classifier: Programming Language :: Python :: 3.8
10
- Classifier: Programming Language :: Python :: 3.9
11
- Classifier: Programming Language :: Python :: 3.10
12
- Classifier: Programming Language :: Python :: 3.11
13
- Classifier: Programming Language :: Python :: 3.12
14
- Requires-Dist: fastapi (>=0.111.0,<0.112.0)
15
- Requires-Dist: httpx (>=0.27.0,<0.28.0)
16
- Description-Content-Type: text/markdown
17
-
18
- </br></br><p align="center"><img src="https://cycls.com/static/assets/favicon.svg" alt="Cycls"></p></br>
19
-
20
- # cycls.py
21
-
22
- ```sh
23
- pip install cycls
24
- ```
25
-
26
- ## sync app
27
- ```py
28
- from cycls import Cycls, Message, Text
29
-
30
- push = Cycls()
31
-
32
- @push("cake")
33
- def app(m: Message):
34
- return Text(m.content)
35
- ```
36
- `https://cycls.com/@cake`
37
-
38
- ## async app
39
- ```py
40
- from cycls import Cycls, Message, Text
41
-
42
- push = Cycls()
43
-
44
- @push("her")
45
- async def app(m: Message):
46
- return Text(m.content)
47
- ```
48
- `https://cycls.com/@her`
49
-
50
- ## debug
51
- ```py
52
- push = Cycls(debug=True)
53
- ```
54
-
55
- ## groq app
56
- ```py
57
- from cycls import Cycls, Message, Text
58
- from groq import AsyncGroq
59
-
60
- push = Cycls()
61
-
62
- groq = AsyncGroq(api_key="YOUR_KEY")
63
-
64
- async def llm(content):
65
- stream = await groq.chat.completions.create(
66
- messages=[
67
- {"role": "system", "content": "you are a helpful assistant."},
68
- {"role": "user", "content": content}
69
- ],
70
- model="llama3-70b-8192",
71
- temperature=0.5, max_tokens=1024, top_p=1, stop=None,
72
- stream=True,
73
- )
74
-
75
- async def event_stream():
76
- async for chunk in stream:
77
- yield f"{chunk.choices[0].delta.content}"
78
-
79
- return event_stream()
80
-
81
- @push("groq-app")
82
- async def app(x:Message):
83
- stream = await llm(x.content)
84
- return Text(stream)
85
- ```
86
- `https://cycls.com/@groq-app`
87
-
88
- ## history
89
- ```py
90
- @push("cake")
91
- def app(m:Message):
92
- print(m.history)
93
- return Text(m.content)
94
- ```
95
- `https://cycls.com/@cake`
96
-
97
- ## groq app with history
98
- ```py
99
- from cycls import Cycls, Message, Text
100
- from groq import AsyncGroq
101
-
102
- push = Cycls()
103
-
104
- groq = AsyncGroq(api_key="YOUR_KEY")
105
-
106
- async def llm(messages):
107
- stream = await groq.chat.completions.create(
108
- messages=messages,
109
- model="llama3-70b-8192",
110
- temperature=0.5, max_tokens=1024, top_p=1, stop=None,
111
- stream=True,
112
- )
113
-
114
- async def event_stream():
115
- async for chunk in stream:
116
- yield f"{chunk.choices[0].delta.content}"
117
-
118
- return event_stream()
119
-
120
- @push("groq-app")
121
- async def app(m:Message):
122
- x = [{"role": "system", "content": "you are a helpful assistant."}]
123
- x += m.history
124
- x += [{"role": "user", "content": m.content}]
125
- stream = await llm(x)
126
- return Text(stream)
127
- ```
128
- `https://cycls.com/@groq-app`
129
-
130
- # Known issues
131
- - Dev mode doesn't work on Windows machines
132
-
cycls-0.0.2.12/README.md DELETED
@@ -1,114 +0,0 @@
1
- </br></br><p align="center"><img src="https://cycls.com/static/assets/favicon.svg" alt="Cycls"></p></br>
2
-
3
- # cycls.py
4
-
5
- ```sh
6
- pip install cycls
7
- ```
8
-
9
- ## sync app
10
- ```py
11
- from cycls import Cycls, Message, Text
12
-
13
- push = Cycls()
14
-
15
- @push("cake")
16
- def app(m: Message):
17
- return Text(m.content)
18
- ```
19
- `https://cycls.com/@cake`
20
-
21
- ## async app
22
- ```py
23
- from cycls import Cycls, Message, Text
24
-
25
- push = Cycls()
26
-
27
- @push("her")
28
- async def app(m: Message):
29
- return Text(m.content)
30
- ```
31
- `https://cycls.com/@her`
32
-
33
- ## debug
34
- ```py
35
- push = Cycls(debug=True)
36
- ```
37
-
38
- ## groq app
39
- ```py
40
- from cycls import Cycls, Message, Text
41
- from groq import AsyncGroq
42
-
43
- push = Cycls()
44
-
45
- groq = AsyncGroq(api_key="YOUR_KEY")
46
-
47
- async def llm(content):
48
- stream = await groq.chat.completions.create(
49
- messages=[
50
- {"role": "system", "content": "you are a helpful assistant."},
51
- {"role": "user", "content": content}
52
- ],
53
- model="llama3-70b-8192",
54
- temperature=0.5, max_tokens=1024, top_p=1, stop=None,
55
- stream=True,
56
- )
57
-
58
- async def event_stream():
59
- async for chunk in stream:
60
- yield f"{chunk.choices[0].delta.content}"
61
-
62
- return event_stream()
63
-
64
- @push("groq-app")
65
- async def app(x:Message):
66
- stream = await llm(x.content)
67
- return Text(stream)
68
- ```
69
- `https://cycls.com/@groq-app`
70
-
71
- ## history
72
- ```py
73
- @push("cake")
74
- def app(m:Message):
75
- print(m.history)
76
- return Text(m.content)
77
- ```
78
- `https://cycls.com/@cake`
79
-
80
- ## groq app with history
81
- ```py
82
- from cycls import Cycls, Message, Text
83
- from groq import AsyncGroq
84
-
85
- push = Cycls()
86
-
87
- groq = AsyncGroq(api_key="YOUR_KEY")
88
-
89
- async def llm(messages):
90
- stream = await groq.chat.completions.create(
91
- messages=messages,
92
- model="llama3-70b-8192",
93
- temperature=0.5, max_tokens=1024, top_p=1, stop=None,
94
- stream=True,
95
- )
96
-
97
- async def event_stream():
98
- async for chunk in stream:
99
- yield f"{chunk.choices[0].delta.content}"
100
-
101
- return event_stream()
102
-
103
- @push("groq-app")
104
- async def app(m:Message):
105
- x = [{"role": "system", "content": "you are a helpful assistant."}]
106
- x += m.history
107
- x += [{"role": "user", "content": m.content}]
108
- stream = await llm(x)
109
- return Text(stream)
110
- ```
111
- `https://cycls.com/@groq-app`
112
-
113
- # Known issues
114
- - Dev mode doesn't work on Windows machines
@@ -1 +0,0 @@
1
- from .cycls import Cycls, Text, Message
@@ -1,116 +0,0 @@
1
- from fastapi import FastAPI, Request
2
- from fastapi.responses import StreamingResponse, PlainTextResponse
3
- from pydantic import BaseModel
4
-
5
- from functools import wraps
6
- import uvicorn, socket, httpx
7
- import inspect
8
-
9
- from concurrent.futures import ThreadPoolExecutor
10
- import time, subprocess
11
-
12
- import os
13
- current_dir = os.path.dirname(os.path.abspath(__file__))
14
- key_path = os.path.join(current_dir, 'key.pub')
15
- # print(key_path)
16
-
17
- from typing import List, Dict, Optional
18
- class Message(BaseModel):
19
- handle: str
20
- content: str
21
- # history: List[Dict[str, str]] = []
22
- history: Optional[List[Dict[str, str]]] = None
23
-
24
-
25
- def find_available_port(start_port):
26
- port = start_port
27
- while True:
28
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
29
- if s.connect_ex(('localhost', port)) != 0:
30
- return port
31
- port += 1
32
-
33
- class Cycls:
34
- def __init__(self,network="https://cycls.com", port=find_available_port(8001),url="",debug=False):
35
- self.handle = None
36
- self.server = FastAPI()
37
- self.network = network
38
- self.port = port
39
- self.url = url
40
- self.debug = debug
41
-
42
- def __call__(self, handle):
43
- self.handle = handle
44
- def decorator(func):
45
- if inspect.iscoroutinefunction(func):
46
- @wraps(func)
47
- async def async_wrapper(*args, **kwargs):
48
- return await func(*args, **kwargs)
49
- self.server.post('/main')(async_wrapper)
50
- self.publish()
51
- return async_wrapper
52
- else:
53
- @wraps(func)
54
- def sync_wrapper(*args, **kwargs):
55
- return func(*args, **kwargs)
56
- self.server.post('/main')(sync_wrapper)
57
- self.publish()
58
- return sync_wrapper
59
- return decorator
60
-
61
- def publish(self):
62
- prod=False
63
- if self.url != "":
64
- prod=True
65
-
66
- if self.debug: print("✦/✧ debug = True")
67
- if prod:
68
- print("✦/✧","production mode",f"(url: {self.url}, port: {self.port})")
69
- else:
70
- print("✦/✧","development mode",f"(port: {self.port})")
71
- # self.url = f"https://{self.handle}-cycls.tuns.sh"
72
- self.url = f"https://{self.handle}-cycls.serveo.net"
73
-
74
- print("")
75
- print("✦/✧",f"https://cycls.com/@{self.handle}")
76
- print("")
77
-
78
- with ThreadPoolExecutor() as executor:
79
- if not prod:
80
- self.register('dev')
81
- executor.submit(self.tunnel)
82
- else:
83
- self.register('prod')
84
-
85
- if self.debug:
86
- executor.submit(uvicorn.run(self.server, host="127.0.0.1", port=self.port)) # perhaps keep traces?
87
- else:
88
- executor.submit(uvicorn.run(self.server, host="127.0.0.1", port=self.port, log_level="critical")) # perhaps keep traces?
89
-
90
- def register(self, mode):
91
- try:
92
- with httpx.Client() as client:
93
- response = client.post(f"{self.network}/register", json={"handle": f"@{self.handle}", "url": self.url, "mode": mode})
94
- if response.status_code==200:
95
- print(f"✦/✧ published 🎉")
96
- print("")
97
- else:
98
- print("✦/✧ failed to register ⚠️") # exit app
99
- except Exception as e:
100
- print(f"An error occurred: {e}")
101
-
102
- def tunnel(self):
103
- # ssh_command = ['ssh', '-q', '-i', 'tuns', '-o', 'StrictHostKeyChecking=no', '-R', f'{self.handle}-cycls:80:localhost:{self.port}', 'tuns.sh']
104
- # ssh_command = ['ssh', '-q', '-i', 'key.pub', '-o', 'StrictHostKeyChecking=no', '-R', f'{self.handle}-cycls:80:localhost:{self.port}', 'serveo.net']
105
- ssh_command = ['ssh', '-q', '-i', key_path, '-o', 'StrictHostKeyChecking=no', '-R', f'{self.handle}-cycls:80:localhost:{self.port}', 'serveo.net']
106
- try:
107
- if self.debug:
108
- process = subprocess.run(ssh_command,stdin=subprocess.DEVNULL) # very tricky! STDIN is what was messing with me
109
- else:
110
- process = subprocess.run(ssh_command, stdin=subprocess.DEVNULL, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
111
- except Exception as e:
112
- print(f"An error occurred: {e}") # exit app
113
-
114
- Text = StreamingResponse
115
-
116
- # ç
@@ -1 +0,0 @@
1
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC022DIsZ11836rKBvsXcd1H7AMbirWyFSZczn3KkwaheLE90DigO/WkYhPMP5XJ9L5MIGM9nemiQhciZdN9f7z9o0xJh72ZI2+tl5Fa77a9r+IsuWbhn8fNGIkzvyYx8zwSTZV/f2nMYr4I7sjTVFVlH2Een6R8RCZpJPe9Q4ph+k2BCp4DeKzCuOrH6t//flm4vZnP8EXXXpSxic0TpbSL+Is7jeRsZdA4/7LrASCxzxnz4e0RCyy61B/TCkOHbSk06SPjoykA9amMMQ3T0OaO72bimiiCbRqEudgX0gNSVTxcRpmPARNJJDk72gAuOwAD3cpvIiW1nPu6Zhgb2VozQhsN+Rmh3ZjlYRvBVsHbwAkGb0iTBrtLA9ghiPLD2oXWdRI6P5XnNvSRyRXcrt59e1w9Z6XmKOmRl94NYciaMqH1qEEVnNCWUZyYKpMWRseL7v95FSNEoIL47+I4OPTF657sxZHlE85Oxei858kS6/b8GUT4yJgCq/PnhjN7UtGYCVRSv6UHGgXGvLMZAtHmbs3RlhEeLsluPvzgsDhmO6XzdKgh/MZIHKMIP/BEU11FT2lh/kB4EP48dqQPJMFNefB1ybEC509RCSdzaDATYIGRi7+FV4B1O15nC3EQTudFJl7io3chsLbkayAbGRInYVUJ0WDA5Et7ekIKRPdfw== m@m