11import type { AnalysisOptions } from "./types" ;
22import wasmBinary from "./pkg/bytes_radar_bg.wasm" ;
3+ import { CacheManager } from "./cache" ;
34
45export interface Env {
56 BYTES_RADAR : DurableObjectNamespace ;
@@ -8,66 +9,32 @@ export interface Env {
89}
910
1011export class BytesRadar {
11- state : DurableObjectState ;
12- env : Env ;
13- private wasmModule : any = null ;
14- private wasmInitialized = false ;
15-
16- constructor ( state : DurableObjectState , env : Env ) {
17- this . state = state ;
18- this . env = env ;
12+ private wasmModule : any ;
13+ private wasmInitialized : boolean = false ;
14+ private cacheManager : CacheManager ;
15+
16+ constructor ( ) {
17+ this . cacheManager = new CacheManager ( {
18+ ttl : 7200 ,
19+ maxSize : 5000 ,
20+ cleanupInterval : 600 ,
21+ } ) ;
1922 }
2023
21- private log (
22- level : "debug" | "info" | "warn" | "error" ,
23- message : string ,
24- data ?: any ,
25- ) {
26- const logLevel = this . env . LOG_LEVEL || "info" ;
27- const environment = this . env . ENVIRONMENT || "development" ;
28-
29- const levels = { debug : 0 , info : 1 , warn : 2 , error : 3 } ;
30- const currentLevel = levels [ logLevel as keyof typeof levels ] || 1 ;
31- const messageLevel = levels [ level ] ;
32-
33- if ( messageLevel >= currentLevel ) {
34- const timestamp = new Date ( ) . toISOString ( ) ;
35- const logEntry = {
36- timestamp,
37- level : level . toUpperCase ( ) ,
38- environment,
39- message,
40- ...( data && { data } ) ,
41- } ;
42-
43- const fn = {
44- debug : console . debug ,
45- info : console . info ,
46- warn : console . warn ,
47- error : console . error ,
48- } ;
49-
50- if ( environment === "production" ) {
51- fn [ level ] ( JSON . stringify ( logEntry ) ) ;
52- } else {
53- fn [ level ] ( `[${ level . toUpperCase ( ) } ] ${ message } ` , data ? data : "" ) ;
54- }
55- }
24+ private log ( level : string , message : string , data ?: any ) {
25+ console . log ( JSON . stringify ( { level, message, data } ) ) ;
5626 }
5727
5828 private async initializeWasm ( ) {
59- if ( ! this . wasmInitialized ) {
60- try {
61- this . wasmModule = await import ( "./pkg/bytes_radar" ) ;
62- await this . wasmModule . default ( wasmBinary ) ;
63- this . wasmInitialized = true ;
64- this . log ( "info" , "WebAssembly module initialized successfully" ) ;
65- } catch ( error ) {
66- this . log ( "error" , "Failed to initialize WebAssembly module" , {
67- error : error instanceof Error ? error . message : String ( error ) ,
68- } ) ;
69- throw error ;
70- }
29+ if ( this . wasmInitialized ) return ;
30+ try {
31+ this . wasmModule = await import ( "./pkg/bytes_radar" ) ;
32+ await this . wasmModule . default ( wasmBinary ) ;
33+ this . wasmInitialized = true ;
34+ this . log ( "info" , "WASM initialized" ) ;
35+ } catch ( error ) {
36+ this . log ( "error" , "WASM init failed" , error ) ;
37+ throw error ;
7138 }
7239 }
7340
@@ -82,7 +49,6 @@ export class BytesRadar {
8249 provider_settings : { } ,
8350 } ;
8451
85- // Parse numeric options
8652 const numericOptions : Record < string , ( val : number ) => void > = {
8753 timeout : ( val ) => ( options . timeout = val ) ,
8854 max_redirects : ( val ) => ( options . max_redirects = val ) ,
@@ -99,7 +65,6 @@ export class BytesRadar {
9965 }
10066 }
10167
102- // Parse string options
10368 const stringOptions : Record < string , ( val : string ) => void > = {
10469 user_agent : ( val ) => ( options . user_agent = val ) ,
10570 proxy : ( val ) => ( options . proxy = val ) ,
@@ -112,13 +77,11 @@ export class BytesRadar {
11277 }
11378 }
11479
115- // Parse boolean options
11680 if ( searchParams . get ( "aggressive_filtering" ) !== null ) {
11781 options . aggressive_filtering =
11882 searchParams . get ( "aggressive_filtering" ) === "true" ;
11983 }
12084
121- // Parse custom headers, credentials, and provider settings
12285 for ( const [ key , value ] of searchParams . entries ( ) ) {
12386 if ( key . startsWith ( "header." ) ) {
12487 options . headers [ key . slice ( 7 ) ] = value ;
@@ -132,6 +95,11 @@ export class BytesRadar {
13295 return options ;
13396 }
13497
98+ private generateCacheKey ( url : string , options : AnalysisOptions ) : string {
99+ const { headers, credentials, ...cacheableOptions } = options ;
100+ return `${ url } :${ JSON . stringify ( cacheableOptions ) } ` ;
101+ }
102+
135103 async fetch ( request : Request ) {
136104 const url = new URL ( request . url ) ;
137105 if ( url . pathname === "/favicon.ico" ) {
@@ -149,14 +117,8 @@ export class BytesRadar {
149117 if ( ! targetUrl ) {
150118 return new Response (
151119 JSON . stringify ( {
152- error : "Missing repository path" ,
153- usage : [
154- "/[user/repo" ,
155- "/user/repo@master" ,
156- "/github.com/user/repo" ,
157- "/gitlab.com/user/repo" ,
158- "http://example.com/example-asset.tar.gz" ,
159- ] ,
120+ error : "Missing path" ,
121+ usage : [ "/user/repo" , "/user/repo@branch" , "/github.com/user/repo" ] ,
160122 } ) ,
161123 {
162124 status : 400 ,
@@ -169,20 +131,38 @@ export class BytesRadar {
169131 }
170132
171133 const options = this . parseQueryOptions ( url . searchParams ) ;
172- this . log ( "info" , "Starting analysis" , { url : targetUrl , options } ) ;
134+ const cacheKey = this . generateCacheKey ( targetUrl , options ) ;
135+
136+ const cachedResult = this . cacheManager . get ( cacheKey ) ;
137+ if ( cachedResult ) {
138+ this . log ( "info" , "Cache hit" , { url : targetUrl } ) ;
139+ return new Response ( JSON . stringify ( cachedResult ) , {
140+ headers : {
141+ "Content-Type" : "application/json" ,
142+ "Access-Control-Allow-Origin" : "*" ,
143+ "X-Cache" : "HIT" ,
144+ "X-Cache-TTL" : String ( this . cacheManager [ "defaultTTL" ] ) ,
145+ } ,
146+ } ) ;
147+ }
148+
149+ this . log ( "info" , "Analysis start" , { url : targetUrl } ) ;
173150
174151 const result = await this . wasmModule . analyze_url ( targetUrl , options ) ;
175- this . log ( "info" , "Analysis completed successfully" , result ) ;
152+ this . cacheManager . set ( cacheKey , result ) ;
153+
154+ this . log ( "info" , "Analysis done" , result ) ;
176155
177156 return new Response ( JSON . stringify ( result ) , {
178157 headers : {
179158 "Content-Type" : "application/json" ,
180159 "Access-Control-Allow-Origin" : "*" ,
160+ "X-Cache" : "MISS" ,
181161 } ,
182162 } ) ;
183163 } catch ( error : unknown ) {
184164 const errorResponse = this . handleError ( error , startTime ) ;
185- this . log ( "error" , "Error in BytesRadar fetch " , errorResponse ) ;
165+ this . log ( "error" , "Request failed " , errorResponse ) ;
186166
187167 return new Response ( JSON . stringify ( errorResponse ) , {
188168 status : 500 ,
0 commit comments