1
- import os
2
1
import sys
3
- import asyncio
4
2
import signal
3
+ import threading
5
4
6
- from fastapi import FastAPI , HTTPException , Request , Depends
7
- from fastapi .responses import JSONResponse
5
+ from server import config
6
+ from server import data_stream
7
+
8
+ from flask import Flask , jsonify , request
8
9
9
- from server import config , data_stream
10
10
from server .algos import algos
11
11
from server .data_filter import operations_callback
12
12
13
- app = FastAPI ()
14
-
15
- stream_stop_event = asyncio .Event ()
13
+ app = Flask (__name__ )
16
14
17
- async def start_data_stream ():
18
- await data_stream .run (config .SERVICE_DID , operations_callback , stream_stop_event )
15
+ stream_stop_event = threading .Event ()
16
+ stream_thread = threading .Thread (
17
+ target = data_stream .run , args = (config .SERVICE_DID , operations_callback , stream_stop_event ,)
18
+ )
19
+ stream_thread .start ()
19
20
20
- # Conditionally start the data stream on startup
21
- if os .getenv ("ENABLE_DATA_STREAM" ) == "true" :
22
- @app .on_event ("startup" )
23
- async def startup_event ():
24
- asyncio .create_task (start_data_stream ())
25
21
26
- # Signal handler for graceful shutdown
27
22
def sigint_handler (* _ ):
28
23
print ('Stopping data stream...' )
29
24
stream_stop_event .set ()
30
25
sys .exit (0 )
31
26
27
+
32
28
signal .signal (signal .SIGINT , sigint_handler )
33
29
34
- @app .get ("/" )
35
- async def index ():
36
- return "ATProto Feed Generator powered by The AT Protocol SDK for Python (https://github.com/MarshalX/atproto)."
37
30
38
- @app .get ("/.well-known/did.json" )
39
- async def did_json ():
31
+ @app .route ('/' )
32
+ def index ():
33
+ return 'ATProto Feed Generator powered by The AT Protocol SDK for Python (https://github.com/MarshalX/atproto).'
34
+
35
+
36
+ @app .route ('/.well-known/did.json' , methods = ['GET' ])
37
+ def did_json ():
40
38
if not config .SERVICE_DID .endswith (config .HOSTNAME ):
41
- raise HTTPException ( status_code = 404 , detail = "Not Found" )
39
+ return '' , 404
42
40
43
- response_content = {
44
- " @context" : [" https://www.w3.org/ns/did/v1" ],
45
- "id" : config .SERVICE_DID ,
46
- " service" : [
41
+ return jsonify ( {
42
+ ' @context' : [' https://www.w3.org/ns/did/v1' ],
43
+ 'id' : config .SERVICE_DID ,
44
+ ' service' : [
47
45
{
48
- "id" : " #bsky_fg" ,
49
- " type" : " BskyFeedGenerator" ,
50
- " serviceEndpoint" : f" https://{ config .HOSTNAME } "
46
+ 'id' : ' #bsky_fg' ,
47
+ ' type' : ' BskyFeedGenerator' ,
48
+ ' serviceEndpoint' : f' https://{ config .HOSTNAME } '
51
49
}
52
50
]
53
- }
54
- return JSONResponse ( content = response_content )
55
-
56
- @app .get ( " /xrpc/app.bsky.feed.describeFeedGenerator" )
57
- async def describe_feed_generator ():
58
- feeds = [{" uri" : uri } for uri in algos .keys ()]
59
- response_content = {
60
- " encoding" : " application/json" ,
61
- " body" : {
62
- " did" : config .SERVICE_DID ,
63
- " feeds" : feeds
51
+ })
52
+
53
+
54
+ @app .route ( ' /xrpc/app.bsky.feed.describeFeedGenerator' , methods = [ 'GET' ] )
55
+ def describe_feed_generator ():
56
+ feeds = [{' uri' : uri } for uri in algos .keys ()]
57
+ response = {
58
+ ' encoding' : ' application/json' ,
59
+ ' body' : {
60
+ ' did' : config .SERVICE_DID ,
61
+ ' feeds' : feeds
64
62
}
65
63
}
66
- return JSONResponse (content = response_content )
64
+ return jsonify (response )
65
+
67
66
68
- @app .get ("/xrpc/app.bsky.feed.getFeedSkeleton" )
69
- async def get_feed_skeleton (feed : str = None , cursor : str = None , limit : int = 20 ):
67
+ @app .route ('/xrpc/app.bsky.feed.getFeedSkeleton' , methods = ['GET' ])
68
+ def get_feed_skeleton ():
69
+ feed = request .args .get ('feed' , default = None , type = str )
70
70
algo = algos .get (feed )
71
71
if not algo :
72
- raise HTTPException (status_code = 400 , detail = "Unsupported algorithm" )
72
+ return 'Unsupported algorithm' , 400
73
+
74
+ # Example of how to check auth if giving user-specific results:
75
+ """
76
+ from server.auth import AuthorizationError, validate_auth
77
+ try:
78
+ requester_did = validate_auth(request)
79
+ except AuthorizationError:
80
+ return 'Unauthorized', 401
81
+ """
73
82
74
83
try :
75
- body = await algo (cursor , limit )
84
+ cursor = request .args .get ('cursor' , default = None , type = str )
85
+ limit = request .args .get ('limit' , default = 20 , type = int )
86
+ body = algo (cursor , limit )
76
87
except ValueError :
77
- raise HTTPException ( status_code = 400 , detail = " Malformed cursor" )
88
+ return ' Malformed cursor' , 400
78
89
79
- return JSONResponse ( content = body )
90
+ return jsonify ( body )
0 commit comments