or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

asgi-middleware.mdasync-client.mdasync-server.mdclient.mdexceptions.mdindex.mdserver.mdwsgi-middleware.md

wsgi-middleware.mddocs/

0

# WSGI Middleware

1

2

WSGI application middleware for integrating Engine.IO servers with Flask, Django, and other WSGI-compatible web frameworks. Provides seamless integration with existing web applications while handling Engine.IO traffic.

3

4

## Capabilities

5

6

### Middleware Initialization

7

8

Create WSGI middleware that wraps an Engine.IO server with optional static file serving and fallback application support.

9

10

```python { .api }

11

class WSGIApp:

12

def __init__(

13

self,

14

engineio_app,

15

wsgi_app=None,

16

static_files=None,

17

engineio_path='engine.io'

18

):

19

"""

20

Initialize WSGI middleware for Engine.IO.

21

22

Args:

23

engineio_app (Server): The Engine.IO server instance

24

wsgi_app (callable, optional): WSGI app for non-Engine.IO traffic

25

static_files (dict, optional): Static file mapping rules

26

engineio_path (str): Engine.IO endpoint path, default 'engine.io'

27

"""

28

```

29

30

### WSGI Application Interface

31

32

Standard WSGI application callable that routes requests between Engine.IO and fallback applications.

33

34

```python { .api }

35

def __call__(self, environ, start_response):

36

"""

37

WSGI application callable.

38

39

Args:

40

environ (dict): WSGI environment dictionary

41

start_response (callable): WSGI start_response callable

42

43

Returns:

44

iterable: WSGI response iterable

45

"""

46

```

47

48

### Error Handling

49

50

Built-in error handling for requests that don't match Engine.IO patterns.

51

52

```python { .api }

53

def not_found(self, start_response):

54

"""

55

Return a 404 Not Found response.

56

57

Args:

58

start_response (callable): WSGI start_response callable

59

60

Returns:

61

list: 404 response body

62

"""

63

```

64

65

## Integration Examples

66

67

### Flask Integration

68

69

```python

70

import engineio

71

from flask import Flask

72

73

# Create Flask app

74

app = Flask(__name__)

75

76

# Create Engine.IO server

77

eio = engineio.Server()

78

79

@eio.on('connect')

80

def on_connect(sid, environ):

81

print(f'Client {sid} connected')

82

83

@eio.on('message')

84

def on_message(sid, data):

85

print(f'Message from {sid}: {data}')

86

eio.send(sid, f'Echo: {data}')

87

88

@eio.on('disconnect')

89

def on_disconnect(sid):

90

print(f'Client {sid} disconnected')

91

92

# Flask routes

93

@app.route('/')

94

def index():

95

return '<h1>Hello World!</h1>'

96

97

@app.route('/api/data')

98

def get_data():

99

return {'message': 'Hello from Flask!'}

100

101

# Wrap Flask app with Engine.IO middleware

102

app = engineio.WSGIApp(eio, app)

103

104

if __name__ == '__main__':

105

import eventlet

106

import eventlet.wsgi

107

eventlet.wsgi.server(eventlet.listen(('', 5000)), app)

108

```

109

110

### Django Integration

111

112

```python

113

# django_project/wsgi.py

114

import os

115

import engineio

116

from django.core.wsgi import get_wsgi_application

117

118

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_project.settings')

119

120

# Get Django WSGI application

121

django_app = get_wsgi_application()

122

123

# Create Engine.IO server

124

eio = engineio.Server()

125

126

@eio.on('connect')

127

def on_connect(sid, environ):

128

print(f'Client {sid} connected')

129

130

@eio.on('message')

131

def on_message(sid, data):

132

eio.send(sid, f'Django says: {data}')

133

134

# Wrap Django with Engine.IO middleware

135

application = engineio.WSGIApp(eio, django_app)

136

```

137

138

### Standalone WSGI Application

139

140

```python

141

import engineio

142

143

# Create Engine.IO server only (no fallback app)

144

eio = engineio.Server()

145

146

@eio.on('connect')

147

def on_connect(sid, environ):

148

print(f'Client {sid} connected')

149

150

@eio.on('message')

151

def on_message(sid, data):

152

eio.send(sid, data.upper())

153

154

# Create standalone WSGI app

155

app = engineio.WSGIApp(eio)

156

157

# Deploy with any WSGI server

158

if __name__ == '__main__':

159

from wsgiref.simple_server import make_server

160

161

server = make_server('localhost', 8000, app)

162

print('Server running on http://localhost:8000')

163

server.serve_forever()

164

```

165

166

### Static File Serving

167

168

```python

169

import engineio

170

171

eio = engineio.Server()

172

173

# Define static file mappings

174

static_files = {

175

'/': 'index.html',

176

'/static/(.*)': r'static/\1',

177

'/images/(.*)': r'assets/images/\1'

178

}

179

180

# Create WSGI app with static file serving

181

app = engineio.WSGIApp(eio, static_files=static_files)

182

```

183

184

Static file mapping rules:

185

186

- Keys are URL patterns (can include regex groups)

187

- Values are file paths (can reference regex groups with `\1`, `\2`, etc.)

188

- Files are served relative to the current working directory

189

190

### Custom Endpoint Path

191

192

```python

193

import engineio

194

195

eio = engineio.Server()

196

197

# Use custom Engine.IO endpoint

198

app = engineio.WSGIApp(eio, engineio_path='custom/socket.io')

199

200

# Clients should connect to: http://server/custom/socket.io/

201

```

202

203

### Multiple Engine.IO Servers

204

205

```python

206

import engineio

207

208

# Create multiple servers for different purposes

209

chat_server = engineio.Server()

210

notifications_server = engineio.Server()

211

212

@chat_server.on('message')

213

def on_chat_message(sid, data):

214

chat_server.send(sid, f'Chat: {data}')

215

216

@notifications_server.on('message')

217

def on_notification(sid, data):

218

notifications_server.send(sid, f'Notification: {data}')

219

220

# Create separate middleware for each server

221

chat_app = engineio.WSGIApp(chat_server, engineio_path='chat')

222

notifications_app = engineio.WSGIApp(notifications_server, engineio_path='notifications')

223

224

# Combine using URL routing (example with Werkzeug)

225

from werkzeug.wsgi import DispatcherMiddleware

226

227

application = DispatcherMiddleware(None, {

228

'/chat': chat_app,

229

'/notifications': notifications_app

230

})

231

```

232

233

## Middleware Class (Deprecated)

234

235

```python { .api }

236

class Middleware(WSGIApp):

237

def __init__(self, engineio_app, wsgi_app=None, engineio_path='engine.io'):

238

"""

239

Deprecated alias for WSGIApp.

240

241

Args:

242

engineio_app (Server): The Engine.IO server instance

243

wsgi_app (callable, optional): WSGI app for non-Engine.IO traffic

244

engineio_path (str): Engine.IO endpoint path, default 'engine.io'

245

246

Note:

247

This class has been renamed to WSGIApp and is now deprecated.

248

Use WSGIApp instead for new applications. The static_files parameter

249

is not supported in this deprecated class.

250

"""

251

```

252

253

## WSGI Environment Access

254

255

Engine.IO event handlers receive the WSGI environment dictionary, providing access to request details:

256

257

```python

258

@eio.on('connect')

259

def on_connect(sid, environ):

260

# Access request information

261

remote_addr = environ.get('REMOTE_ADDR')

262

user_agent = environ.get('HTTP_USER_AGENT')

263

request_method = environ.get('REQUEST_METHOD')

264

query_string = environ.get('QUERY_STRING')

265

266

print(f'Client {sid} connected from {remote_addr}')

267

print(f'User-Agent: {user_agent}')

268

269

# Parse query parameters

270

from urllib.parse import parse_qs

271

params = parse_qs(query_string)

272

273

# Store client info in session

274

eio.save_session(sid, {

275

'remote_addr': remote_addr,

276

'user_agent': user_agent,

277

'params': params

278

})

279

```

280

281

## Deployment Considerations

282

283

### Production Deployment

284

285

```python

286

# For production, use a proper WSGI server

287

import engineio

288

from flask import Flask

289

290

app = Flask(__name__)

291

eio = engineio.Server(async_mode='eventlet')

292

293

# ... configure server and handlers ...

294

295

app = engineio.WSGIApp(eio, app)

296

297

# Deploy with Gunicorn + eventlet workers

298

# gunicorn --worker-class eventlet -w 1 --bind 0.0.0.0:5000 app:app

299

```

300

301

### Threading Considerations

302

303

```python

304

import engineio

305

306

# Configure for threading mode

307

eio = engineio.Server(async_mode='threading')

308

309

@eio.on('message')

310

def on_message(sid, data):

311

# Handler will run in a separate thread

312

import time

313

time.sleep(1) # Blocking operations are OK

314

eio.send(sid, 'Response after delay')

315

316

app = engineio.WSGIApp(eio)

317

```

318

319

### Eventlet Integration

320

321

```python

322

import eventlet

323

eventlet.monkey_patch()

324

325

import engineio

326

327

# Eventlet mode for high concurrency

328

eio = engineio.Server(async_mode='eventlet')

329

330

@eio.on('message')

331

def on_message(sid, data):

332

# Use eventlet.sleep for non-blocking delays

333

eventlet.sleep(1)

334

eio.send(sid, 'Eventlet response')

335

336

app = engineio.WSGIApp(eio)

337

338

# Run with eventlet WSGI server

339

eventlet.wsgi.server(eventlet.listen(('', 5000)), app)

340

```

341

342

## Error Handling

343

344

The WSGI middleware handles various error conditions automatically:

345

346

- **Invalid Engine.IO requests**: Returns appropriate HTTP error responses

347

- **Non-Engine.IO requests**: Routes to fallback WSGI app or returns 404

348

- **Static file errors**: Returns 404 for missing files

349

- **Server errors**: Logs exceptions and returns 500 responses

350

351

Custom error handling can be implemented in the fallback WSGI application:

352

353

```python

354

def custom_app(environ, start_response):

355

"""Custom WSGI app with error handling"""

356

try:

357

# Application logic here

358

response_body = b'Custom response'

359

status = '200 OK'

360

headers = [('Content-Type', 'text/plain')]

361

except Exception as e:

362

# Custom error handling

363

response_body = f'Error: {str(e)}'.encode()

364

status = '500 Internal Server Error'

365

headers = [('Content-Type', 'text/plain')]

366

367

start_response(status, headers)

368

return [response_body]

369

370

app = engineio.WSGIApp(eio, custom_app)

371

```