@@ -18,6 +18,7 @@ import {
18
18
} from "agent-twitter-client" ;
19
19
import { EventEmitter } from "events" ;
20
20
import { TwitterConfig } from "./environment.ts" ;
21
+ import { fetch , ProxyAgent , setGlobalDispatcher } from "undici" ;
21
22
22
23
export function extractAnswer ( text : string ) : string {
23
24
const startIndex = text . indexOf ( "Answer: " ) + 8 ;
@@ -60,8 +61,8 @@ class RequestQueue {
60
61
while ( this . queue . length > 0 ) {
61
62
const request = this . queue . shift ( ) ! ;
62
63
try {
63
- await request ( ) . catch ( e => {
64
- console . error ( ' client.twitter.base - request err' , e )
64
+ await request ( ) . catch ( ( e ) => {
65
+ console . error ( " client.twitter.base - request err" , e ) ;
65
66
} ) ;
66
67
} catch ( error ) {
67
68
console . error ( "Error processing request:" , error ) ;
@@ -85,35 +86,80 @@ class RequestQueue {
85
86
}
86
87
}
87
88
88
- let lastStart = Date . now ( )
89
+ let lastStart = Date . now ( ) ;
89
90
90
- function doLogin ( username , cb ) {
91
- const ts = Date . now ( )
92
- const since = ts - lastStart
93
- elizaLogger . log ( ' last twitter scrapper created' , since , ' ms ago' )
94
- const delay = 5 * 1000
91
+ function doLogin ( username , cb , proxyUrl ?: string ) {
92
+ const ts = Date . now ( ) ;
93
+ const since = ts - lastStart ;
94
+ elizaLogger . log ( " last twitter scrapper created" , since , " ms ago" ) ;
95
+ const delay = 5 * 1000 ;
95
96
if ( since > delay ) {
96
- const twitterClient = new Scraper ( ) ;
97
+ let agent ;
98
+
99
+ // Add proxy configuration if TWITTER_PROXY_URL exists
100
+ if ( proxyUrl ) {
101
+ elizaLogger . log ( "Using proxy" , proxyUrl ) ;
102
+ const url = new URL ( proxyUrl ) ;
103
+ const username = url . username ;
104
+ const password = url . password ;
105
+
106
+ // Strip auth from URL if present
107
+ url . username = "" ;
108
+ url . password = "" ;
109
+
110
+ const agentOptions : any = {
111
+ uri : url . toString ( ) ,
112
+ requestTls : {
113
+ rejectUnauthorized : false ,
114
+ } ,
115
+ } ;
116
+
117
+ // Add Basic auth if credentials exist
118
+ if ( username && password ) {
119
+ agentOptions . token = `Basic ${ Buffer . from (
120
+ `${ username } :${ password } `
121
+ ) . toString ( "base64" ) } `;
122
+ }
123
+
124
+ agent = new ProxyAgent ( agentOptions ) ;
125
+ setGlobalDispatcher ( agent ) ;
126
+ }
127
+
128
+ const twitterClient = new Scraper ( {
129
+ fetch : fetch ,
130
+ transform : {
131
+ request : ( input : any , init : any ) => {
132
+ if ( agent ) {
133
+ return [ input , { ...init , dispatcher : agent } ] ;
134
+ }
135
+ return [ input , init ] ;
136
+ } ,
137
+ } ,
138
+ } ) ;
139
+
97
140
ClientBase . _twitterClients [ username ] = twitterClient ;
98
- lastStart = ts
99
- cb ( twitterClient )
141
+ lastStart = ts ;
142
+ cb ( twitterClient ) ;
100
143
} else {
101
- elizaLogger . log ( ' Delaying twitter scrapper creation for' , username )
144
+ elizaLogger . log ( " Delaying twitter scrapper creation for" , username ) ;
102
145
setTimeout ( ( ) => {
103
- doLogin ( username , cb )
104
- } , delay )
146
+ doLogin ( username , cb ) ;
147
+ } , delay ) ;
105
148
}
106
149
}
107
150
108
- export function getScrapper ( username :string ) :twitterClient {
109
- return new Promise ( resolve => {
151
+ export function getScraper (
152
+ username : string ,
153
+ proxyUrl ?: string
154
+ ) : Promise < Scraper > {
155
+ return new Promise ( ( resolve ) => {
110
156
if ( ClientBase . _twitterClients [ username ] ) {
111
157
const twitterClient = ClientBase . _twitterClients [ username ] ;
112
- resolve ( twitterClient )
158
+ resolve ( twitterClient ) ;
113
159
} else {
114
- doLogin ( username , resolve )
160
+ doLogin ( username , resolve , proxyUrl ) ;
115
161
}
116
- } )
162
+ } ) ;
117
163
}
118
164
119
165
export class ClientBase extends EventEmitter {
@@ -174,10 +220,13 @@ export class ClientBase extends EventEmitter {
174
220
super ( ) ;
175
221
this . runtime = runtime ;
176
222
this . twitterConfig = twitterConfig ;
223
+
224
+ // Store proxy URL statically so it's available to doLogin
225
+ const proxyUrl = twitterConfig . TWITTER_PROXY_URL ;
177
226
const username = twitterConfig . TWITTER_USERNAME ;
178
- getScrapper ( username ) . then ( tc => {
179
- this . twitterClient = tc ;
180
- } )
227
+ getScraper ( username , proxyUrl ) . then ( ( tc ) => {
228
+ this . twitterClient = tc ;
229
+ } ) ;
181
230
182
231
this . directions =
183
232
"- " +
@@ -193,7 +242,7 @@ export class ClientBase extends EventEmitter {
193
242
let retries = this . twitterConfig . TWITTER_RETRY_LIMIT ;
194
243
const twitter2faSecret = this . twitterConfig . TWITTER_2FA_SECRET ;
195
244
// if twitter says its bad, trust twitter
196
- retries = 1 // mee.fun, lets no hammer this, it should work or not
245
+ retries = 1 ; // mee.fun, lets no hammer this, it should work or not
197
246
198
247
if ( ! username ) {
199
248
throw new Error ( "Twitter username not configured" ) ;
@@ -221,7 +270,7 @@ export class ClientBase extends EventEmitter {
221
270
twitter2faSecret
222
271
) ;
223
272
if ( await this . twitterClient . isLoggedIn ( ) ) {
224
- lastStart = Date . now ( )
273
+ lastStart = Date . now ( ) ;
225
274
// fresh login, store new cookies
226
275
elizaLogger . info ( "Successfully logged in." ) ;
227
276
elizaLogger . info ( "Caching cookies" ) ;
@@ -233,7 +282,9 @@ export class ClientBase extends EventEmitter {
233
282
}
234
283
}
235
284
} catch ( error ) {
236
- elizaLogger . error ( `${ this . runtime . character . name } (${ this . runtime . agentId } ): Login attempt failed: ${ error . message } for twitter @${ username } ` ) ;
285
+ elizaLogger . error (
286
+ `${ this . runtime . character . name } (${ this . runtime . agentId } ): Login attempt failed: ${ error . message } for twitter @${ username } `
287
+ ) ;
237
288
}
238
289
239
290
retries -- ;
@@ -255,7 +306,7 @@ export class ClientBase extends EventEmitter {
255
306
this . profile = await this . fetchProfile ( username ) ;
256
307
257
308
if ( ! this . profile ) {
258
- elizaLogger . error ( ' cl-tw::init - profile did not load' )
309
+ elizaLogger . error ( " cl-tw::init - profile did not load" ) ;
259
310
return false ;
260
311
}
261
312
elizaLogger . log ( "Twitter user ID:" , this . profile . id ) ;
@@ -724,8 +775,8 @@ export class ClientBase extends EventEmitter {
724
775
if ( latestCheckedTweetId ) {
725
776
this . lastCheckedTweetId = BigInt ( latestCheckedTweetId ) ;
726
777
}
727
- } catch ( e ) {
728
- elizaLogger . error ( ' cl-tw::loadLatestCheckedTweetId - err' , e )
778
+ } catch ( e ) {
779
+ elizaLogger . error ( " cl-tw::loadLatestCheckedTweetId - err" , e ) ;
729
780
}
730
781
}
731
782
0 commit comments