update
Browse files- feishu_service.py +0 -26
- main.py +0 -2
- redis_service.py +3 -11
feishu_service.py
CHANGED
|
@@ -14,26 +14,20 @@ from store import token_store
|
|
| 14 |
# Ensure SUPABASE_URL and SUPABASE_KEY are set in your .env file
|
| 15 |
SUPABASE_URL = os.getenv("SUPABASE_URL")
|
| 16 |
SUPABASE_KEY = os.getenv("SUPABASE_KEY")
|
| 17 |
-
print('\n\n\n\nSUPABASE_URL', SUPABASE_URL)
|
| 18 |
-
print('SUPABASE_KEY', SUPABASE_KEY)
|
| 19 |
-
|
| 20 |
if not SUPABASE_URL or not SUPABASE_KEY:
|
| 21 |
print("Error: SUPABASE_URL or SUPABASE_KEY not found in environment variables.")
|
| 22 |
# Depending on your application's needs, you might want to exit or handle this differently
|
| 23 |
# For now, we'll just print an error and the client will be None
|
| 24 |
supabase: Client | None = None
|
| 25 |
else:
|
| 26 |
-
print("\n\n\n\n\n\nConnecting to Supabase...")
|
| 27 |
supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
|
| 28 |
print("Supabase client initialized.")
|
| 29 |
|
| 30 |
-
|
| 31 |
async def get_app_secret_from_db(app_id: str) -> str | None:
|
| 32 |
"""
|
| 33 |
Reads the app_secret from the Supabase database based on app_id.
|
| 34 |
Assumes a table named 'feishu_apps' with columns 'app_id' and 'app_secret'.
|
| 35 |
"""
|
| 36 |
-
print('\n\n\n\n************************\nget_app_secret_from_db() app_id:', app_id)
|
| 37 |
if not supabase:
|
| 38 |
print("Supabase client not initialized, cannot fetch app_secret.")
|
| 39 |
return None # Correctly return None if supabase client is not initialized
|
|
@@ -42,14 +36,10 @@ async def get_app_secret_from_db(app_id: str) -> str | None:
|
|
| 42 |
# Query the 'feishu_bot_config' table for the platform_specific column matching the bot_id
|
| 43 |
# Use maybe_single() as we expect at most one row, and execute() to get the result
|
| 44 |
response = supabase.table('feishu_bot_config').select('platform_specific').eq('bot_id', app_id).single().execute()
|
| 45 |
-
# print(f"\n\n\n\nResponse from Supabase (maybe_single().execute()): ",response)
|
| 46 |
-
print('\nresponse.data', response.data)
|
| 47 |
-
|
| 48 |
# Check if a row was returned and extract the app_secret from platform_specific
|
| 49 |
# The result of maybe_single().execute() will have a 'data' attribute
|
| 50 |
if response.data and 'platform_specific' in response.data and 'app_secret' in response.data['platform_specific']:
|
| 51 |
app_secret = response.data['platform_specific']['app_secret']
|
| 52 |
-
print(f"Successfully retrieved app_secret for app_id: {app_id} from Supabase. app_secret: ", app_secret)
|
| 53 |
return app_secret
|
| 54 |
else:
|
| 55 |
print(f"No app_secret found in Supabase for app_id: {app_id}.")
|
|
@@ -58,7 +48,6 @@ async def get_app_secret_from_db(app_id: str) -> str | None:
|
|
| 58 |
print(f"Error fetching app_secret from Supabase for app_id {app_id}: {e}")
|
| 59 |
return None
|
| 60 |
|
| 61 |
-
|
| 62 |
async def get_valid_tenant_access_token(app_id: str) -> str | None:
|
| 63 |
"""
|
| 64 |
Retrieves a valid tenant access token for the given app_id.
|
|
@@ -71,13 +60,8 @@ async def get_valid_tenant_access_token(app_id: str) -> str | None:
|
|
| 71 |
Returns:
|
| 72 |
A valid tenant access token or None if unable to obtain one.
|
| 73 |
"""
|
| 74 |
-
print('\n\n\n\n\n\n\n*******************************\n')
|
| 75 |
-
print('get_valid_tenant_access_token, appid:', app_id)
|
| 76 |
# 1. Prioritize fetching from the global store
|
| 77 |
stored_token_info = token_store.get(app_id)
|
| 78 |
-
print('\n\n\n\n\n\n\n\n$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\nstored_token_info',stored_token_info)
|
| 79 |
-
print('\ntoken_store:', token_store)
|
| 80 |
-
|
| 81 |
if stored_token_info:
|
| 82 |
token = stored_token_info.get('token')
|
| 83 |
created_time = stored_token_info.get('created_time')
|
|
@@ -119,24 +103,16 @@ async def get_valid_tenant_access_token(app_id: str) -> str | None:
|
|
| 119 |
response = await client.post(url, headers=headers, json=payload)
|
| 120 |
response.raise_for_status() # Raise an exception for bad status codes
|
| 121 |
data = response.json()
|
| 122 |
-
print('\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n^^^^^data',data)
|
| 123 |
if data.get("code") == 0:
|
| 124 |
new_token = data.get("tenant_access_token")
|
| 125 |
expire = data.get("expire") # Note: Feishu API returns 'expire_in'
|
| 126 |
-
print('\nnew_token',new_token)
|
| 127 |
-
print('\nexpires',expire)
|
| 128 |
-
|
| 129 |
-
|
| 130 |
if new_token and expire is not None:
|
| 131 |
-
print("\n\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%New token received")
|
| 132 |
# 4. Store the new token and its expiry information
|
| 133 |
token_store[app_id] = {
|
| 134 |
'token': new_token,
|
| 135 |
'created_time': time.time(),
|
| 136 |
'expire': expire
|
| 137 |
}
|
| 138 |
-
print(f"Successfully generated and stored new tenant access token for app_id: {app_id}")
|
| 139 |
-
print('\ntoken_store',token_store)
|
| 140 |
return new_token
|
| 141 |
else:
|
| 142 |
print(f"Error generating new tenant access token: Missing token or expiry info in response.")
|
|
@@ -179,8 +155,6 @@ async def send_feishu_reply(msg_id: str, tenant_access_token: str, content: dict
|
|
| 179 |
try:
|
| 180 |
response = await client.post(url, headers=headers, json=body)
|
| 181 |
response.raise_for_status() # Raise an exception for bad status codes
|
| 182 |
-
print(f"Successfully sent reply: Status Code {response.status_code}")
|
| 183 |
-
print(f"Reply Response: {response.text}")
|
| 184 |
except httpx.HTTPStatusError as e:
|
| 185 |
print(f"HTTP error sending reply: {e}")
|
| 186 |
except httpx.RequestError as e:
|
|
|
|
| 14 |
# Ensure SUPABASE_URL and SUPABASE_KEY are set in your .env file
|
| 15 |
SUPABASE_URL = os.getenv("SUPABASE_URL")
|
| 16 |
SUPABASE_KEY = os.getenv("SUPABASE_KEY")
|
|
|
|
|
|
|
|
|
|
| 17 |
if not SUPABASE_URL or not SUPABASE_KEY:
|
| 18 |
print("Error: SUPABASE_URL or SUPABASE_KEY not found in environment variables.")
|
| 19 |
# Depending on your application's needs, you might want to exit or handle this differently
|
| 20 |
# For now, we'll just print an error and the client will be None
|
| 21 |
supabase: Client | None = None
|
| 22 |
else:
|
|
|
|
| 23 |
supabase: Client = create_client(SUPABASE_URL, SUPABASE_KEY)
|
| 24 |
print("Supabase client initialized.")
|
| 25 |
|
|
|
|
| 26 |
async def get_app_secret_from_db(app_id: str) -> str | None:
|
| 27 |
"""
|
| 28 |
Reads the app_secret from the Supabase database based on app_id.
|
| 29 |
Assumes a table named 'feishu_apps' with columns 'app_id' and 'app_secret'.
|
| 30 |
"""
|
|
|
|
| 31 |
if not supabase:
|
| 32 |
print("Supabase client not initialized, cannot fetch app_secret.")
|
| 33 |
return None # Correctly return None if supabase client is not initialized
|
|
|
|
| 36 |
# Query the 'feishu_bot_config' table for the platform_specific column matching the bot_id
|
| 37 |
# Use maybe_single() as we expect at most one row, and execute() to get the result
|
| 38 |
response = supabase.table('feishu_bot_config').select('platform_specific').eq('bot_id', app_id).single().execute()
|
|
|
|
|
|
|
|
|
|
| 39 |
# Check if a row was returned and extract the app_secret from platform_specific
|
| 40 |
# The result of maybe_single().execute() will have a 'data' attribute
|
| 41 |
if response.data and 'platform_specific' in response.data and 'app_secret' in response.data['platform_specific']:
|
| 42 |
app_secret = response.data['platform_specific']['app_secret']
|
|
|
|
| 43 |
return app_secret
|
| 44 |
else:
|
| 45 |
print(f"No app_secret found in Supabase for app_id: {app_id}.")
|
|
|
|
| 48 |
print(f"Error fetching app_secret from Supabase for app_id {app_id}: {e}")
|
| 49 |
return None
|
| 50 |
|
|
|
|
| 51 |
async def get_valid_tenant_access_token(app_id: str) -> str | None:
|
| 52 |
"""
|
| 53 |
Retrieves a valid tenant access token for the given app_id.
|
|
|
|
| 60 |
Returns:
|
| 61 |
A valid tenant access token or None if unable to obtain one.
|
| 62 |
"""
|
|
|
|
|
|
|
| 63 |
# 1. Prioritize fetching from the global store
|
| 64 |
stored_token_info = token_store.get(app_id)
|
|
|
|
|
|
|
|
|
|
| 65 |
if stored_token_info:
|
| 66 |
token = stored_token_info.get('token')
|
| 67 |
created_time = stored_token_info.get('created_time')
|
|
|
|
| 103 |
response = await client.post(url, headers=headers, json=payload)
|
| 104 |
response.raise_for_status() # Raise an exception for bad status codes
|
| 105 |
data = response.json()
|
|
|
|
| 106 |
if data.get("code") == 0:
|
| 107 |
new_token = data.get("tenant_access_token")
|
| 108 |
expire = data.get("expire") # Note: Feishu API returns 'expire_in'
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
if new_token and expire is not None:
|
|
|
|
| 110 |
# 4. Store the new token and its expiry information
|
| 111 |
token_store[app_id] = {
|
| 112 |
'token': new_token,
|
| 113 |
'created_time': time.time(),
|
| 114 |
'expire': expire
|
| 115 |
}
|
|
|
|
|
|
|
| 116 |
return new_token
|
| 117 |
else:
|
| 118 |
print(f"Error generating new tenant access token: Missing token or expiry info in response.")
|
|
|
|
| 155 |
try:
|
| 156 |
response = await client.post(url, headers=headers, json=body)
|
| 157 |
response.raise_for_status() # Raise an exception for bad status codes
|
|
|
|
|
|
|
| 158 |
except httpx.HTTPStatusError as e:
|
| 159 |
print(f"HTTP error sending reply: {e}")
|
| 160 |
except httpx.RequestError as e:
|
main.py
CHANGED
|
@@ -85,8 +85,6 @@ async def handle_webhook(request: Request):
|
|
| 85 |
|
| 86 |
# Publish the processed message data to Redis
|
| 87 |
await publish_to_redis(REDIS_CHANNEL_NAME, json.dumps(ret_data))
|
| 88 |
-
|
| 89 |
-
print('\n\n\nret_data: ', json.dumps(ret_data, indent=2)) # Use indent for readability
|
| 90 |
return {'status': 'OK'}
|
| 91 |
|
| 92 |
# The /publish endpoint is now handled by the publish_message function in redis_service.py
|
|
|
|
| 85 |
|
| 86 |
# Publish the processed message data to Redis
|
| 87 |
await publish_to_redis(REDIS_CHANNEL_NAME, json.dumps(ret_data))
|
|
|
|
|
|
|
| 88 |
return {'status': 'OK'}
|
| 89 |
|
| 90 |
# The /publish endpoint is now handled by the publish_message function in redis_service.py
|
redis_service.py
CHANGED
|
@@ -31,9 +31,7 @@ async def connect_redis():
|
|
| 31 |
# Perform SET and GET test after successful connection
|
| 32 |
try:
|
| 33 |
await r.set("mykey", "myvalue")
|
| 34 |
-
print("Redis SET test successful: mykey = myvalue")
|
| 35 |
value = await r.get("mykey")
|
| 36 |
-
print(f"Redis GET test successful: mykey = {value.decode()}")
|
| 37 |
except Exception as e:
|
| 38 |
print(f"Redis SET/GET test failed: {e}")
|
| 39 |
|
|
@@ -46,7 +44,7 @@ async def redis_subscriber(redis_client, channel_name):
|
|
| 46 |
"""
|
| 47 |
Asynchronous function to subscribe to a Redis channel and process messages.
|
| 48 |
"""
|
| 49 |
-
print(f"Subscribing to channel: {channel_name}")
|
| 50 |
pubsub = redis_client.pubsub()
|
| 51 |
await asyncio.sleep(1) # Add a small delay before subscribing
|
| 52 |
await pubsub.subscribe(channel_name) # Use await for async subscribe
|
|
@@ -55,15 +53,13 @@ async def redis_subscriber(redis_client, channel_name):
|
|
| 55 |
while True:
|
| 56 |
message = await pubsub.get_message(ignore_subscribe_messages=True)
|
| 57 |
if message:
|
| 58 |
-
print("\n\n\n**************************\n\nmessage in...")
|
| 59 |
channel = message['channel'].decode()
|
| 60 |
data_str = message['data'].decode()
|
| 61 |
-
print(f"\n\n\nReceived message on channel '{channel}': {data_str}")
|
| 62 |
|
| 63 |
# Convert the received JSON string back to a Python dictionary
|
| 64 |
try:
|
| 65 |
data_dict = json.loads(data_str)
|
| 66 |
-
print(f"\nParsed message data as dictionary: {data_dict}")
|
| 67 |
|
| 68 |
# Extract app_id from platform_specific
|
| 69 |
app_id = data_dict.get('platform_specific', {}).get('app_id')
|
|
@@ -75,9 +71,6 @@ async def redis_subscriber(redis_client, channel_name):
|
|
| 75 |
else:
|
| 76 |
print("Missing app_id in received data, cannot get tenant access token.")
|
| 77 |
|
| 78 |
-
print(f"\n\n\n\n&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&\ntenant_access_token: {tenant_access_token}")
|
| 79 |
-
|
| 80 |
-
|
| 81 |
if tenant_access_token:
|
| 82 |
# Extract necessary info from data_dict for sending reply
|
| 83 |
msg_id = data_dict.get('msg_id')
|
|
@@ -100,7 +93,6 @@ async def redis_subscriber(redis_client, channel_name):
|
|
| 100 |
except Exception as e:
|
| 101 |
print(f"An unexpected error occurred while processing message: {e}")
|
| 102 |
|
| 103 |
-
|
| 104 |
await asyncio.sleep(0.01) # Prevent blocking the event loop
|
| 105 |
|
| 106 |
async def publish_message(channel: str, message: str):
|
|
@@ -110,7 +102,7 @@ async def publish_message(channel: str, message: str):
|
|
| 110 |
try:
|
| 111 |
# Publish the message to the specified channel (publish is asynchronous)
|
| 112 |
await r.publish(channel, message)
|
| 113 |
-
print(f"Published message to channel '{channel}'")
|
| 114 |
return {"status": "success", "message": f"Published message to channel '{channel}'"}
|
| 115 |
|
| 116 |
except Exception as e:
|
|
|
|
| 31 |
# Perform SET and GET test after successful connection
|
| 32 |
try:
|
| 33 |
await r.set("mykey", "myvalue")
|
|
|
|
| 34 |
value = await r.get("mykey")
|
|
|
|
| 35 |
except Exception as e:
|
| 36 |
print(f"Redis SET/GET test failed: {e}")
|
| 37 |
|
|
|
|
| 44 |
"""
|
| 45 |
Asynchronous function to subscribe to a Redis channel and process messages.
|
| 46 |
"""
|
| 47 |
+
# print(f"Subscribing to channel: {channel_name}")
|
| 48 |
pubsub = redis_client.pubsub()
|
| 49 |
await asyncio.sleep(1) # Add a small delay before subscribing
|
| 50 |
await pubsub.subscribe(channel_name) # Use await for async subscribe
|
|
|
|
| 53 |
while True:
|
| 54 |
message = await pubsub.get_message(ignore_subscribe_messages=True)
|
| 55 |
if message:
|
|
|
|
| 56 |
channel = message['channel'].decode()
|
| 57 |
data_str = message['data'].decode()
|
| 58 |
+
# print(f"\n\n\nReceived message on channel '{channel}': {data_str}")
|
| 59 |
|
| 60 |
# Convert the received JSON string back to a Python dictionary
|
| 61 |
try:
|
| 62 |
data_dict = json.loads(data_str)
|
|
|
|
| 63 |
|
| 64 |
# Extract app_id from platform_specific
|
| 65 |
app_id = data_dict.get('platform_specific', {}).get('app_id')
|
|
|
|
| 71 |
else:
|
| 72 |
print("Missing app_id in received data, cannot get tenant access token.")
|
| 73 |
|
|
|
|
|
|
|
|
|
|
| 74 |
if tenant_access_token:
|
| 75 |
# Extract necessary info from data_dict for sending reply
|
| 76 |
msg_id = data_dict.get('msg_id')
|
|
|
|
| 93 |
except Exception as e:
|
| 94 |
print(f"An unexpected error occurred while processing message: {e}")
|
| 95 |
|
|
|
|
| 96 |
await asyncio.sleep(0.01) # Prevent blocking the event loop
|
| 97 |
|
| 98 |
async def publish_message(channel: str, message: str):
|
|
|
|
| 102 |
try:
|
| 103 |
# Publish the message to the specified channel (publish is asynchronous)
|
| 104 |
await r.publish(channel, message)
|
| 105 |
+
# print(f"Published message to channel '{channel}'")
|
| 106 |
return {"status": "success", "message": f"Published message to channel '{channel}'"}
|
| 107 |
|
| 108 |
except Exception as e:
|