gluerpy 0.0.0__py3-none-any.whl

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.
gluerpy/__init__.py ADDED
File without changes
gluerpy/client.py ADDED
@@ -0,0 +1,305 @@
1
+ import asyncio
2
+ import traceback
3
+ import time
4
+ import json
5
+ import uuid
6
+ import sys
7
+ import os
8
+ import importlib
9
+ import random
10
+ import websockets
11
+ # from websockets.sync.client import connect
12
+
13
+ # from mako.lookup import TemplateLookup
14
+ # from mako.template import Template
15
+
16
+ project = "sm"
17
+ websocket_url = "wss://ws.gluer.io/server"
18
+ session_id = f'ws-{str(uuid.uuid4())}'
19
+ heartbeat_interval = 5
20
+ retry_delay = 5
21
+ ws = None
22
+
23
+ imported_files = {}
24
+ methods_map = {}
25
+
26
+
27
+ def set_project(p):
28
+ global project
29
+ project = p
30
+
31
+
32
+ def set_websocket_url(url):
33
+ global websocket_url
34
+ websocket_url = url
35
+
36
+
37
+ # async def start():
38
+ # print("Start")
39
+ # sub_server()
40
+ # await asyncio.get_event_loop().run_until_complete(start_ws())
41
+ # await asyncio.to_thread(queue())
42
+
43
+ def build_header_from_message(job):
44
+ smh = job["smh"].split(":")
45
+ return {"d": smh[0], "session_id": smh[1].split('>'), "project": smh[2], "plugin": smh[3] or "", "action": smh[4] or ""}
46
+
47
+
48
+ def build_message_from_header(header):
49
+ return f'{header["d"]}:{">".join(header["session_id"])}>{session_id}:{header["project"]}:{header["plugin"] or ""}:{header["action"] or ""}'
50
+
51
+
52
+ async def on_message(wsapp, message):
53
+ global methods_map
54
+ print("MethodsMap",methods_map)
55
+
56
+ job = json.loads(message)
57
+ header = build_header_from_message(job)
58
+ job["smh"] = build_message_from_header(header)
59
+ print("header")
60
+ print(header)
61
+ try:
62
+ mtd = None
63
+ print(header["plugin"])
64
+ print(methods_map)
65
+ print(methods_map[header["plugin"]])
66
+ if header["plugin"] in methods_map and header["action"] in methods_map[header["plugin"]]:
67
+ mtd = methods_map[header["plugin"]][header["action"]]
68
+ elif header["plugin"] in imported_files:
69
+ if hasattr(imported_files[header["plugin"]], header["action"]):
70
+ mtd = getattr(
71
+ imported_files[header["plugin"]], header["action"])
72
+ if mtd:
73
+ ret = None
74
+ if "data" in job:
75
+ ret = mtd(job["data"])
76
+ else:
77
+ ret = mtd(job)
78
+ # print("Pre Process")
79
+ process_dict(ret)
80
+ # print(ret)
81
+ # print("Post Process")
82
+ job["data"] = ret
83
+ # if "htmx" in job:
84
+ # # print("HTMX found")
85
+ # try:
86
+ # act_template = lookup.get_template(
87
+ # f'{header["plugin"]}/{header["action"]}.mako')
88
+ # # print("act_template")
89
+ # # print(act_template)
90
+ # if act_template:
91
+ # # print("Template Found")
92
+ # # print(ret)
93
+ # # print(job["data"])
94
+ # job["data"] = act_template.render(data=ret)
95
+ # # print(job["data"])
96
+ # except Exception as error:
97
+ # print(error)
98
+ else:
99
+ job["data"] = {
100
+ "error": f"no server actions found for {header['plugin']}:{header['action']}"
101
+ }
102
+ except Exception as error:
103
+ print("ERROR")
104
+ print(traceback.format_exc())
105
+ # print(error)
106
+ error_handler(job, error)
107
+ # if "ws" in job:
108
+
109
+ job["smh"] = "<" + job["smh"][1:]
110
+ # print("Sending job back")
111
+ # print(job["data"])
112
+ # job["d"] = "<"
113
+ await wsapp.send(json.dumps(job))
114
+
115
+
116
+ def on_open(ws):
117
+ print("Opened")
118
+ job = f'{{"smh":"+:{session_id}:{project}","channel":"{session_id},{project}"}}'
119
+ ws.send(job)
120
+
121
+
122
+ def on_error(ws, error):
123
+ print("Error")
124
+ print(ws)
125
+ print(error)
126
+ # job = f'{{"smh":"+:{session_id}:{project}","channel":"{session_id},{project}"}}'
127
+ # ws.send(job)
128
+
129
+
130
+ async def connect():
131
+ global ws
132
+ while True:
133
+ try:
134
+ print(f"Connecting to {websocket_url}...")
135
+ async with websockets.connect(f'{websocket_url}/{project}/{session_id}') as websocket:
136
+ print(f"Connected to {websocket_url}")
137
+
138
+ # job = f'{{"smh":"+:{session_id}:{project}","channel":"{session_id},{project}"}}'
139
+ # await websocket.send(job)
140
+ # print(f"Sent custom message: {custom_message}")
141
+
142
+ # Send a greeting message after successful connection
143
+ # await websocket.send("Hello, WebSocket server!")
144
+
145
+ while True:
146
+ try:
147
+ message = await websocket.recv()
148
+ if message is None:
149
+ print("Received None, connection may be closed. Reconnecting...")
150
+ break # Break the inner loop to reconnect
151
+ print(f"Received: {message}")
152
+ await on_message(websocket, message)
153
+ # You can add your message handling logic here.
154
+ # For example, you might want to check for specific messages
155
+ # and respond accordingly. Or, process the data.
156
+ except websockets.ConnectionClosedError:
157
+ print("Connection closed unexpectedly. Reconnecting...")
158
+ break # Break the inner loop to reconnect
159
+ except websockets.ConnectionClosedOK:
160
+ print("Connection closed normally. Reconnecting...")
161
+ break
162
+ except Exception as e:
163
+ print(f"Error receiving message: {e}. Reconnecting...")
164
+ break # Exit inner loop, try to reconnect
165
+ except ConnectionRefusedError:
166
+ print("Connection refused. Server may not be running or is busy.")
167
+ break # Don't reconnect, since the server refused. Exit the outer loop
168
+ except OSError as e:
169
+ if e.errno in (54, 61, 64): # Connection reset, connection refused, host down
170
+ print(f"Network error: {e}. Attempting to reconnect...")
171
+ else:
172
+ print(f"OS error: {e}. Reconnecting...")
173
+ except Exception as e:
174
+ print(f"Error: {e}")
175
+ print("An unexpected error occurred. Check network, server, and code.")
176
+ # Consider different strategies here. For example, you might
177
+ # want to exit after a few unknown errors, or perhaps
178
+ # log the error to a file. For this example, we'll just
179
+ # keep trying to reconnect.
180
+ # Use exponential backoff to avoid overwhelming the server with rapid reconnect attempts.
181
+ delay = random.uniform(1, 5) # Introduce some random jitter
182
+ print(f"Reconnecting in {delay:.2f} seconds...")
183
+ await asyncio.sleep(delay)
184
+ # with connect(websocket_url) as websocket:
185
+ # ws = websocket
186
+ # websocket.send("Hello world!")
187
+ # message = websocket.recv()
188
+ # print(f"Received: {message}")
189
+ # with connect(websocket_url) as websocket:
190
+ # ws = websocket
191
+ # message = websocket.recv()
192
+ # print(f"Received: {message}")
193
+ # websocket.enableTrace(false)
194
+ # ws = websocket.WebSocketApp(
195
+ # websocket_url, on_message=on_message, on_open=on_open, on_error=on_error)
196
+ # ws.run_forever(dispatcher=rel, ping_interval=60, ping_timeout=10, reconnect=5,
197
+ # ping_payload="This is an optional ping payload")
198
+
199
+ # rel.dispatch()
200
+
201
+
202
+ lookup = None
203
+
204
+
205
+ def import_directories(path):
206
+ global lookup
207
+ files = os.listdir(path)
208
+ # print(files)
209
+ sys.path.append(path)
210
+ for file in files:
211
+ if file.endswith(".py"):
212
+ try:
213
+ file = file[:-3]
214
+ imported_files.setdefault(file, importlib.import_module(file))
215
+ print(f"Imported {file}")
216
+ except ImportError as err:
217
+ print('Error:', err)
218
+ # lookup = TemplateLookup(directories=[f'{path}/templates'])
219
+
220
+
221
+ def add_method(plugin, action, fn):
222
+ global methods_map
223
+ print("Adding method", plugin, action)
224
+ methods_map.setdefault(plugin, {})
225
+ methods_map[plugin].setdefault(action, fn)
226
+
227
+ def register_plugin(plugin_name: str, fn_name: str, fn: callable):
228
+ global methods_map
229
+ """
230
+ Registers a function under a given plugin name.
231
+
232
+ Args:
233
+ plugin_name: The name of the plugin.
234
+ fn_name: The name of the function to register.
235
+ fn: The function object.
236
+ """
237
+ fn_map = {fn_name: fn}
238
+ if plugin_name not in methods_map:
239
+ methods_map[plugin_name] = {}
240
+ methods_map[plugin_name].update(fn_map)
241
+
242
+ def register_object(plugin_name: str, obj: object):
243
+ """
244
+ Registers all methods of an object under a given plugin name.
245
+
246
+ Args:
247
+ plugin_name: The name of the plugin.
248
+ obj: The object whose methods will be registered.
249
+ """
250
+ methods = [
251
+ method_name for method_name in dir(obj)
252
+ if callable(getattr(obj, method_name)) and not method_name.startswith("__")
253
+ ]
254
+ print("methods",methods)
255
+ for method_name in methods:
256
+ method = getattr(obj, method_name)
257
+ register_plugin(plugin_name, method_name, method)
258
+ # print('Methods', methods)
259
+
260
+ def error_handler(job, error):
261
+ job["data"] = {"error": {
262
+ "message": error.content[0]['message'], "code": error.content[0]['errorCode']}}
263
+
264
+
265
+ def set_error_handler(fn):
266
+ global error_handler
267
+ error_handler = fn
268
+
269
+
270
+ def process_dict(data):
271
+ for key, value in data.items():
272
+ # Check if the value has a 'model_dump' method
273
+ if hasattr(value, "model_dump") and callable(getattr(value, "model_dump")):
274
+ # Call model_dump() if it's available and callable
275
+ data[key] = value.model_dump()
276
+ elif isinstance(value, dict):
277
+ # If the value is a nested dictionary, recursively process it
278
+ process_dict(value)
279
+ elif isinstance(value, list):
280
+ # If the value is a list, process each item
281
+ for i, item in enumerate(value):
282
+ if hasattr(item, "model_dump") and callable(getattr(item, "model_dump")):
283
+ value[i] = item.model_dump()
284
+ elif isinstance(item, dict):
285
+ process_dict(item)
286
+
287
+ def start():
288
+ asyncio.run(connect())
289
+ # """
290
+ # Main function to start the WebSocket client. Allows user to specify the URI.
291
+ # """
292
+ # await start()
293
+
294
+ # if __name__ == '__main__':
295
+ # asyncio.run(main())
296
+ # print('start')
297
+ # redis.set_user("Teste")
298
+ # try:
299
+ # # loop = asyncio.get_event_loop()
300
+ # # loop.run_until_complete(start())
301
+ # asyncio.run(start())
302
+ # except Exception as error:
303
+ # print(error)
304
+ # traceback.print_exc()
305
+ # # asyncio.run(start())
@@ -0,0 +1,269 @@
1
+ import datetime
2
+ import asyncio
3
+ import threading
4
+ import traceback
5
+ import time
6
+ import json
7
+ import uuid
8
+ import sys
9
+ import os
10
+ import importlib
11
+ import redis
12
+
13
+ import gluer.lib.redis_lib as redis_lib
14
+ import gluer.lib.acl as acl
15
+
16
+ project = "sm"
17
+ session_id = str(uuid.uuid4())
18
+ heartbeat_interval = 5
19
+ retry_delay = 5
20
+
21
+ imported_files = {}
22
+ methods_map = {}
23
+
24
+ # ssh -R 80:localhost:9001 serveo.net
25
+ # autossh -M 0 -R gluer.serveo.net:80:localhost:9001 serveo.net
26
+ # autossh -M 0 -R gluer:80:localhost:9001 serveo.net
27
+ # ssh -R gluer.serveo.net:443:localhost:9001 serveo.net
28
+ # ssh -R 443:localhost:9001 serveo.net
29
+
30
+ # def import_directories():
31
+ # files = os.listdir('./plugins')
32
+ # # print(files)
33
+ # sys.path.append('./plugins')
34
+ # for file in files:
35
+ # if file.endswith(".py"):
36
+ # try:
37
+ # file = file[:-3]
38
+ # imported_files.setdefault(file, importlib.import_module(file))
39
+ # except ImportError as err:
40
+ # print('Error:', err)
41
+ # # print(imported_files)
42
+
43
+
44
+ def set_project(p):
45
+ global project
46
+ project = p
47
+
48
+
49
+ def set_user(u):
50
+ redis_lib.set_redis_user(u)
51
+
52
+
53
+ def set_password(p):
54
+ redis_lib.set_redis_password(p)
55
+
56
+
57
+ def set_redis_url(url):
58
+ redis_lib.set_redis_url(url)
59
+
60
+
61
+ def set_redis_api_key(key):
62
+ acl.set_api_key(key)
63
+
64
+
65
+ def set_redis_api_secret(secret):
66
+ acl.set_api_secret(secret)
67
+
68
+
69
+ async def start():
70
+ # print("Start")
71
+ sub_server()
72
+ await asyncio.to_thread(queue())
73
+
74
+
75
+ def import_directories(path):
76
+ files = os.listdir(path)
77
+ # print(files)
78
+ sys.path.append(path)
79
+ for file in files:
80
+ if file.endswith(".py"):
81
+ try:
82
+ file = file[:-3]
83
+ imported_files.setdefault(file, importlib.import_module(file))
84
+ print(f"Imported {file}")
85
+ except ImportError as err:
86
+ print('Error:', err)
87
+
88
+
89
+ def sub_server():
90
+ print("Sub Server")
91
+ # r = await redis.from_url("redis://admin:V!6xU8Kf*sQqJS@redis-10264.c277.us-east-1-3.ec2.redns.redis-cloud.com:10264")
92
+
93
+ # acl.create_acl("test2", "test123")
94
+ ev = {
95
+ "channel": f'{project}:bl',
96
+ "action": "server_up",
97
+ "created": time.time_ns()
98
+ }
99
+ # get_redis_connection().hset(
100
+ # f'pp1:servers:{session_id}', mapping=session_data)
101
+ # get_redis_connection().expire(
102
+ # f'pp1:servers:{session_id}', heartbeat_interval)
103
+ # ev = {
104
+ # "channel": f'{project}:bl',
105
+ # "action": "server_up",
106
+ # "created": time.time_ns()
107
+ # }
108
+ redis_lib.get_redis_connection().publish(f'{project}:bl', json.dumps(ev))
109
+ pubsub = redis_lib.get_redis_connection().pubsub()
110
+ subscribe_channel(pubsub, f'{project}:br')
111
+
112
+ # update_redis_hash()
113
+ # Run the update_redis_hash function in a separate thread
114
+ interval_thread = threading.Thread(target=update_redis_hash)
115
+ interval_thread.daemon = True # Daemon thread will exit when the main program exits
116
+ interval_thread.start()
117
+
118
+ # while True:
119
+ # try:
120
+ # # Listen for messages
121
+ # for message in pubsub.listen():
122
+ # if message['type'] == 'message':
123
+ # print(f"Message received: {message['data']}")
124
+
125
+ # except Exception as e:
126
+ # time.sleep(5)
127
+ # pubsub = get_redis_connection().pubsub()
128
+ # subscribe_channel(pubsub, f'{project}:br')
129
+
130
+
131
+ def update_redis_hash():
132
+ while True:
133
+ session_data = {
134
+ "type": "plugin",
135
+ "sessionId": session_id,
136
+ "project": project
137
+ }
138
+ try:
139
+ redis_lib.get_redis_connection().hset(
140
+ f'pp1:servers:{session_id}', mapping=session_data)
141
+ redis_lib.get_redis_connection().expire(
142
+ f'pp1:servers:{session_id}', heartbeat_interval)
143
+ # print("Ping Redis", session_id)
144
+ time.sleep(heartbeat_interval-1)
145
+ except (redis.exceptions.ConnectionError, redis.exceptions.TimeoutError) as e:
146
+ print(e)
147
+ except Exception as e:
148
+ print(e)
149
+
150
+
151
+ def message_handler(message):
152
+ print("message_handler")
153
+ print(message.get("data"))
154
+ job = json.loads(message.get("data"))
155
+ job["connected"] = True
156
+ if "action" in job and job["action"] == "ping":
157
+ print("PING")
158
+ if "ws" in job:
159
+ redis_lib.get_redis_connection().rpush(
160
+ job["ws"], json.dumps(job))
161
+ redis_lib.get_redis_connection().expire(
162
+ job["ws"], 60)
163
+ # redis_lib.get_redis_connection().publish(f'{project}:bl', json.dumps(job))
164
+
165
+ elif "plugin" in job and job["plugin"] in imported_files:
166
+ if hasattr(imported_files[job["plugin"]], job["action"]):
167
+ mtd = getattr(
168
+ imported_files[job["plugin"]], job["action"])
169
+ ret = mtd(job["data"])
170
+ job["data"] = ret
171
+ print('job with data')
172
+ print(job)
173
+ if "ws" in job:
174
+ redis_lib.get_redis_connection().rpush(
175
+ job["ws"], json.dumps(job))
176
+ redis_lib.get_redis_connection().expire(
177
+ job["ws"], 60)
178
+
179
+
180
+ def subscribe_channel(pubsub, channel):
181
+ print("Subscribe", channel)
182
+ # pubsub.subscribe(channel)
183
+ pubsub.subscribe(**{channel: message_handler})
184
+ pubsub.run_in_thread(sleep_time=0.001)
185
+
186
+
187
+ def add_method(plugin, action, fn):
188
+ print("Adding method", plugin, action)
189
+ methods_map.setdefault(plugin, {})
190
+ methods_map[plugin].setdefault(action, fn)
191
+
192
+
193
+ def error_handler(job, error):
194
+ job["data"] = {"error": {
195
+ "message": error.content[0]['message'], "code": error.content[0]['errorCode']}}
196
+
197
+
198
+ def set_error_handler(fn):
199
+ global error_handler
200
+ error_handler = fn
201
+
202
+
203
+ def queue():
204
+ # print('Queue')
205
+ # r = await redis.from_url("redis://admin:V!6xU8Kf*sQqJS@redis-10264.c277.us-east-1-3.ec2.redns.redis-cloud.com:10264")
206
+ while True:
207
+ # print(f'{project}:r')
208
+ try:
209
+ val = redis_lib.get_redis_connection().blpop(f'{project}:r', 5)
210
+ if val:
211
+ job = json.loads(val[1])
212
+ try:
213
+ mtd = None
214
+ if job["plugin"] in methods_map and job["action"] in methods_map[job["plugin"]]:
215
+ mtd = methods_map[job["plugin"]][job["action"]]
216
+ elif job["plugin"] in imported_files:
217
+ if hasattr(imported_files[job["plugin"]], job["action"]):
218
+ mtd = getattr(
219
+ imported_files[job["plugin"]], job["action"])
220
+ if mtd:
221
+ ret = None
222
+ if "data" in job:
223
+ ret = mtd(job["data"])
224
+ else:
225
+ ret = mtd(job)
226
+ job["data"] = ret
227
+ else:
228
+ job["data"] = {
229
+ "error": f"no server actions found for {job['plugin']}:{job['action']}"
230
+ }
231
+ except Exception as error:
232
+ print("ERROR")
233
+ print(traceback.format_exc())
234
+ # print(error)
235
+ error_handler(job, error)
236
+ if "ws" in job:
237
+ redis_lib.get_redis_connection().rpush(
238
+ job["ws"], json.dumps(job))
239
+ redis_lib.get_redis_connection().expire(
240
+ job["ws"], 60)
241
+ except (redis.exceptions.ConnectionError, redis.exceptions.TimeoutError) as e:
242
+ print("Redis connection lost. Reconnecting...")
243
+ print(e)
244
+ time.sleep(retry_delay)
245
+
246
+ except redis.exceptions.RedisError as e:
247
+ # Catch other general Redis-related exceptions
248
+ print("General Redis error")
249
+ print(e)
250
+ # traceback.print_exc()
251
+
252
+ except Exception as error:
253
+ print("Unexpected error on brpop queue")
254
+ print(error)
255
+
256
+ def queue_ws():
257
+ print("Queue WS")
258
+
259
+ if __name__ == '__main__':
260
+ print('start')
261
+ # redis.set_user("Teste")
262
+ # try:
263
+ # # loop = asyncio.get_event_loop()
264
+ # # loop.run_until_complete(start())
265
+ # asyncio.run(start())
266
+ # except Exception as error:
267
+ # print(error)
268
+ # traceback.print_exc()
269
+ # # asyncio.run(start())
File without changes
gluerpy/lib/acl.py ADDED
@@ -0,0 +1,148 @@
1
+ import requests
2
+ import time
3
+ import os
4
+
5
+ API_KEY = os.getenv('REDIS_API_KEY',None)
6
+ API_SECRET_KEY = os.getenv('REDIS_API_SECRET',None)
7
+
8
+ headers = {
9
+ "x-api-key": "Ay9adtha5prx8za3413t4v9y5vptrvst1aulowgz6r30uz2oa7",
10
+ "x-api-secret-key": "S3ctl9u1zjg5cbcyma38bgnbrq6q2ia6pud7lwvaonramcpanq9",
11
+ "Content-Type": "application/json"
12
+ }
13
+
14
+
15
+ def set_api_key(key):
16
+ API_KEY = key
17
+
18
+
19
+ def set_api_secret(secret):
20
+ API_SECRET_KEY = secret
21
+
22
+
23
+ def check_task_status(task_url):
24
+ while True:
25
+ response = requests.get(task_url, headers=headers)
26
+ if response.status_code == 200:
27
+ task_status = response.json()
28
+ status = task_status.get('status')
29
+
30
+ if status == 'processing-completed':
31
+ return task_status
32
+ elif status in ['received', 'processing', 'processing-in-progress']:
33
+ print(f"Task is still processing: {status}")
34
+ time.sleep(5) # Non-blocking sleep
35
+ elif status == 'processing-error':
36
+ raise Exception(
37
+ f"Task failed with status: {status}. Error details: {task_status.get('response', {}).get('error', {}).get('description', 'No details provided')}")
38
+ else:
39
+ raise Exception(f"Unexpected task status: {status}")
40
+ else:
41
+ response.raise_for_status()
42
+
43
+
44
+ def create_acl(name, password):
45
+ rule = create_rule(name)
46
+ role = create_role(name)
47
+ user = create_user(name, password)
48
+ print("ACL Created")
49
+ print(rule)
50
+ print(role)
51
+ print(user)
52
+ return {"rule": rule, "role": role, "user": user}
53
+
54
+
55
+ def delete_acl(name):
56
+ delete_user(name)
57
+ # create_rule(name)
58
+ # create_role(name)
59
+
60
+
61
+ def create_rule(name):
62
+ print('Create Rule')
63
+ print(name)
64
+ data = {
65
+ "name": name,
66
+ "redisRule": f'+hset +unlink +pubsub +subscribe +brpop +blpop +rpush +lpush ~{name}* +pubsub ~pp1:* ~ws:*'
67
+ }
68
+ print(data)
69
+ response = requests.post(
70
+ 'https://api.redislabs.com/v1/acl/redisRules', json=data, headers=headers)
71
+ response.raise_for_status()
72
+ data = response.json()
73
+ print(data)
74
+ if "links" in data and len(data["links"]) > 0:
75
+ status = check_task_status(data["links"][0]["href"])
76
+ print(status)
77
+ return status.get('response').get('resourceId')
78
+
79
+
80
+ def create_role(name):
81
+ data = {
82
+ "name": name,
83
+ "redisRules": [
84
+ {
85
+ "ruleName": name,
86
+ "databases": [
87
+ {
88
+ "subscriptionId": 2350147,
89
+ "databaseId": 12364997
90
+ }
91
+ ]
92
+ }
93
+ ]
94
+ }
95
+ response = requests.post(
96
+ 'https://api.redislabs.com/v1/acl/roles', json=data, headers=headers)
97
+ response.raise_for_status()
98
+ data = response.json()
99
+ print(data)
100
+ if "links" in data and len(data["links"]) > 0:
101
+ status = check_task_status(data["links"][0]["href"])
102
+ print(status)
103
+ return status.get('response').get('resourceId')
104
+
105
+
106
+ def create_user(name, password):
107
+ if not password:
108
+ passowrd = generate_random_password()
109
+ data = {
110
+ "name": name,
111
+ "role": name,
112
+ "password": password
113
+ }
114
+ response = requests.post(
115
+ 'https://api.redislabs.com/v1/acl/users', json=data, headers=headers)
116
+ response.raise_for_status()
117
+ data = response.json()
118
+ print(data)
119
+ if "links" in data and len(data["links"]) > 0:
120
+ status = check_task_status(data["links"][0]["href"])
121
+ print(status)
122
+ return status.get('response').get('resourceId')
123
+ # return data
124
+
125
+
126
+ def delete_user(name):
127
+ data = {
128
+ "name": name,
129
+ "role": name,
130
+ "password": password
131
+ }
132
+ response = requests.post(
133
+ 'https://api.redislabs.com/v1/acl/users', json=data, headers=headers)
134
+ response.raise_for_status()
135
+ data = response.json()
136
+ print(data)
137
+ if "links" in data and len(data["links"]) > 0:
138
+ status = check_task_status(data["links"][0]["href"])
139
+ print(status)
140
+ return data
141
+
142
+
143
+ def generate_random_password(length=12):
144
+ # Define the character sets to use
145
+ characters = string.ascii_letters + string.digits + '!@$'
146
+ # Generate a random password
147
+ password = ''.join(random.choice(characters) for _ in range(length))
148
+ return password
@@ -0,0 +1,69 @@
1
+ # redis_connection.py
2
+ import redis
3
+ import os
4
+
5
+ redis_client = None
6
+ redis_pubsub = None
7
+
8
+ redis_url = os.getenv('REDIS_URL', None)
9
+ redis_user = os.getenv('REDIS_USER', None)
10
+ redis_password = os.getenv('REDIS_PASSWORD', None)
11
+ redis_host = os.getenv(
12
+ 'REDIS_HOST', "redis-10264.c277.us-east-1-3.ec2.redns.redis-cloud.com")
13
+ redis_port = os.getenv('REDIS_PORT', "10264")
14
+
15
+
16
+ def set_redis_url(u):
17
+ global redis_url
18
+ redis_url = u
19
+
20
+
21
+ def set_redis_user(u):
22
+ global redis_user
23
+ redis_user = u
24
+
25
+
26
+ def set_redis_password(p):
27
+ global redis_password
28
+ redis_password = p
29
+
30
+
31
+ events = {}
32
+
33
+ # pool = None
34
+ # r = redis.Redis(connection_pool=pool)
35
+
36
+
37
+ def get_url():
38
+ global redis_url, redis_user, redis_password
39
+ if redis_url:
40
+ return redis_url
41
+ elif redis_user and redis_password:
42
+ return f"redis://{redis_user}:{redis_password}@{redis_host}:{redis_port}"
43
+
44
+
45
+ def get_redis_connection():
46
+ global redis_client, redis_url
47
+ if redis_client is None:
48
+ redis_client = redis.from_url(redis_url,
49
+ decode_responses=True)
50
+ return redis_client
51
+ # if pool is None:
52
+ # pool = redis.ConnectionPool.from_url(get_url())
53
+ # return redis.Redis(connection_pool=pool, decode_responses=True)
54
+
55
+ # if redis_client is None:
56
+ # if redis_user and redis_password:
57
+ # redis_url = f"redis://{redis_user}:{redis_password}@redis-10264.c277.us-east-1-3.ec2.redns.redis-cloud.com:10264"
58
+ # redis_client = redis.from_url(redis_url,
59
+ # decode_responses=True)
60
+ # # redis_client = redis.Redis(
61
+ # # host='localhost', port=6379, decode_responses=True)
62
+
63
+
64
+ def get_redis_pubsub():
65
+ global redis_pubsub
66
+ if redis_pubsub is None:
67
+ redis_pubsub = get_redis_connection().pubsub()
68
+ redis_pubsub.run_in_thread(sleep_time=0.001)
69
+ return redis_pubsub
@@ -0,0 +1,24 @@
1
+ Metadata-Version: 2.4
2
+ Name: gluerpy
3
+ Version: 0.0.0
4
+ Summary: Python library to connect to gluer services
5
+ Home-page: https://www.gluer.io
6
+ Author: Thiago Magro
7
+ Author-email: thiago.magro@gmail.com
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.6
12
+ Description-Content-Type: text/markdown
13
+ Requires-Dist: redis
14
+ Dynamic: author
15
+ Dynamic: author-email
16
+ Dynamic: classifier
17
+ Dynamic: description
18
+ Dynamic: description-content-type
19
+ Dynamic: home-page
20
+ Dynamic: requires-dist
21
+ Dynamic: requires-python
22
+ Dynamic: summary
23
+
24
+ Gluer Library for Python
@@ -0,0 +1,10 @@
1
+ gluerpy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ gluerpy/client.py,sha256=YYmMnbVs_yPUD8-ekR4A3_BOF5JxPAcfYHNkwjlfS-w,10874
3
+ gluerpy/client_redis.py,sha256=P1x24i9it9p7H0mNAp-8ZfiuohDvCItneSJiQeoLwSU,8355
4
+ gluerpy/lib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
+ gluerpy/lib/acl.py,sha256=7laiX-NqpzqTb3LXlZkk6LBGQPBPir_6vxnmupyx_D4,4342
6
+ gluerpy/lib/redis_lib.py,sha256=hjPGkacuiJLHYrEj-5rg3rMcAm83lp63BPetvrlY964,1891
7
+ gluerpy-0.0.0.dist-info/METADATA,sha256=qa0nCzymQVu-HVpWrJV6oI4x4siHtGV-XizQrvIONrs,647
8
+ gluerpy-0.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
9
+ gluerpy-0.0.0.dist-info/top_level.txt,sha256=CDQjbVgZAl4XVoo2vzvPCKwq1t6aRSD3GEyJ4G_iroE,8
10
+ gluerpy-0.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ gluerpy