or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

cli.mdconfig-api.mderrors.mdhigh-level-api.mdindex.mdprotocol.md

protocol.mddocs/

0

# Low-Level Protocol Implementation

1

2

The `gntp.core` module provides direct access to GNTP (Growl Notification Transport Protocol) message construction, parsing, and validation. This low-level API is useful for applications requiring fine-grained control over protocol details, custom message handling, or integration with other notification systems.

3

4

## Capabilities

5

6

### GNTP Message Classes

7

8

The core module provides classes for each GNTP message type, enabling direct protocol message construction and parsing.

9

10

```python { .api }

11

class GNTPRegister:

12

"""

13

Represents a GNTP Registration Command.

14

15

Required headers: Application-Name, Notifications-Count

16

"""

17

18

def __init__(self, data=None, password=None):

19

"""

20

Create GNTP Registration message.

21

22

Parameters:

23

- data (str): Optional raw GNTP data to decode

24

- password (str): Optional password for decoding

25

"""

26

27

def add_notification(self, name, enabled=True):

28

"""

29

Add notification type to registration.

30

31

Parameters:

32

- name (str): Notification type name

33

- enabled (bool): Enable by default in Growl

34

"""

35

36

def validate(self):

37

"""

38

Validate required headers and notification headers.

39

40

Raises:

41

ParseError: When required headers are missing

42

"""

43

44

def decode(self, data, password):

45

"""

46

Decode existing GNTP Registration message.

47

48

Parameters:

49

- data (str): Raw GNTP message data

50

- password (str): Password for authentication

51

"""

52

53

def encode(self):

54

"""

55

Encode to GNTP Registration message.

56

57

Returns:

58

bytes: Complete GNTP registration message

59

"""

60

61

class GNTPNotice:

62

"""

63

Represents a GNTP Notification Command.

64

65

Required headers: Application-Name, Notification-Name, Notification-Title

66

"""

67

68

def __init__(self, data=None, app=None, name=None, title=None, password=None):

69

"""

70

Create GNTP Notification message.

71

72

Parameters:

73

- data (str): Optional raw GNTP data to decode

74

- app (str): Application name

75

- name (str): Notification type name

76

- title (str): Notification title

77

- password (str): Optional password

78

"""

79

80

def validate(self):

81

"""

82

Validate required headers.

83

84

Raises:

85

ParseError: When required headers are missing

86

"""

87

88

def decode(self, data, password):

89

"""

90

Decode existing GNTP Notification message.

91

92

Parameters:

93

- data (str): Raw GNTP message data

94

- password (str): Password for authentication

95

"""

96

97

def encode(self):

98

"""

99

Encode to GNTP Notification message.

100

101

Returns:

102

bytes: Complete GNTP notification message

103

"""

104

105

class GNTPSubscribe:

106

"""

107

Represents a GNTP Subscribe Command.

108

109

Required headers: Subscriber-ID, Subscriber-Name

110

"""

111

112

def __init__(self, data=None, password=None):

113

"""

114

Create GNTP Subscribe message.

115

116

Parameters:

117

- data (str): Optional raw GNTP data to decode

118

- password (str): Optional password

119

"""

120

121

def validate(self):

122

"""

123

Validate required headers.

124

125

Raises:

126

ParseError: When required headers are missing

127

"""

128

129

def decode(self, data, password):

130

"""

131

Decode existing GNTP Subscribe message.

132

133

Parameters:

134

- data (str): Raw GNTP message data

135

- password (str): Password for authentication

136

"""

137

138

def encode(self):

139

"""

140

Encode to GNTP Subscribe message.

141

142

Returns:

143

bytes: Complete GNTP subscribe message

144

"""

145

146

class GNTPOK:

147

"""

148

Represents a GNTP OK Response.

149

150

Required headers: Response-Action

151

"""

152

153

def __init__(self, data=None, action=None):

154

"""

155

Create GNTP OK response.

156

157

Parameters:

158

- data (str): Optional raw GNTP data to decode

159

- action (str): Response action type

160

"""

161

162

def decode(self, data):

163

"""

164

Decode GNTP OK response.

165

166

Parameters:

167

- data (str): Raw GNTP response data

168

"""

169

170

def encode(self):

171

"""

172

Encode to GNTP OK response.

173

174

Returns:

175

bytes: Complete GNTP OK response

176

"""

177

178

class GNTPError:

179

"""

180

Represents a GNTP Error response.

181

182

Required headers: Error-Code, Error-Description

183

"""

184

185

def __init__(self, data=None, errorcode=None, errordesc=None):

186

"""

187

Create GNTP Error response.

188

189

Parameters:

190

- data (str): Optional raw GNTP data to decode

191

- errorcode (int): Error code

192

- errordesc (str): Error description

193

"""

194

195

def error(self):

196

"""

197

Get error information.

198

199

Returns:

200

tuple: (error_code, error_description)

201

"""

202

203

def decode(self, data):

204

"""

205

Decode GNTP Error response.

206

207

Parameters:

208

- data (str): Raw GNTP response data

209

"""

210

211

def encode(self):

212

"""

213

Encode to GNTP Error response.

214

215

Returns:

216

bytes: Complete GNTP error response

217

"""

218

```

219

220

### Base Message Functionality

221

222

All GNTP message classes inherit common functionality from the base class:

223

224

```python { .api }

225

# Base methods available on all GNTP message classes:

226

227

def set_password(self, password, encryptAlgo='MD5'):

228

"""

229

Set password for GNTP message authentication.

230

231

Parameters:

232

- password (str): Password string (None to clear)

233

- encryptAlgo (str): Hash algorithm ('MD5', 'SHA1', 'SHA256', 'SHA512')

234

235

Raises:

236

UnsupportedError: When hash algorithm is not supported

237

"""

238

239

def add_header(self, key, value):

240

"""

241

Add header to GNTP message.

242

243

Parameters:

244

- key (str): Header name

245

- value (str): Header value

246

"""

247

248

def add_resource(self, data):

249

"""

250

Add binary resource to GNTP message.

251

252

Parameters:

253

- data (bytes): Binary resource data

254

255

Returns:

256

str: Resource URL for referencing in headers

257

"""

258

259

def validate(self):

260

"""

261

Verify required headers are present.

262

263

Raises:

264

ParseError: When required headers are missing

265

"""

266

267

def encode(self):

268

"""

269

Encode message to GNTP protocol format.

270

271

Returns:

272

bytes: Complete GNTP message ready for transmission

273

"""

274

```

275

276

### Message Parsing

277

278

```python { .api }

279

def parse_gntp(data, password=None):

280

"""

281

Parse raw GNTP message data and return appropriate message object.

282

283

Parameters:

284

- data (str or bytes): Raw GNTP message data

285

- password (str): Optional password for authentication

286

287

Returns:

288

GNTPRegister | GNTPNotice | GNTPSubscribe | GNTPOK | GNTPError:

289

Parsed message object of appropriate type

290

291

Raises:

292

ParseError: When message format is invalid or parsing fails

293

"""

294

```

295

296

## Usage Examples

297

298

### Creating and Sending Registration Messages

299

300

```python

301

import gntp.core

302

import socket

303

304

# Create registration message

305

register = gntp.core.GNTPRegister()

306

register.add_header('Application-Name', 'My Custom App')

307

register.add_header('Application-Icon', 'http://example.com/icon.png')

308

309

# Add notification types

310

register.add_notification('Alert', enabled=True)

311

register.add_notification('Info', enabled=False)

312

313

# Set password if needed

314

register.set_password('mypassword', 'SHA256')

315

316

# Validate before sending

317

register.validate()

318

319

# Encode to protocol format

320

data = register.encode()

321

322

# Send over socket

323

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

324

sock.connect(('localhost', 23053))

325

sock.send(data)

326

response = sock.recv(1024)

327

sock.close()

328

329

# Parse response

330

response_obj = gntp.core.parse_gntp(response)

331

if isinstance(response_obj, gntp.core.GNTPOK):

332

print("Registration successful")

333

else:

334

print(f"Registration failed: {response_obj.error()}")

335

```

336

337

### Creating Notification Messages

338

339

```python

340

import gntp.core

341

342

# Create notification

343

notice = gntp.core.GNTPNotice()

344

notice.add_header('Application-Name', 'My Custom App')

345

notice.add_header('Notification-Name', 'Alert')

346

notice.add_header('Notification-Title', 'Important Message')

347

notice.add_header('Notification-Text', 'This is the notification body')

348

notice.add_header('Notification-Priority', '1')

349

notice.add_header('Notification-Sticky', 'True')

350

351

# Add binary icon resource

352

with open('icon.png', 'rb') as f:

353

icon_data = f.read()

354

resource_url = notice.add_resource(icon_data)

355

notice.add_header('Notification-Icon', resource_url)

356

357

# Set password and encode

358

notice.set_password('mypassword')

359

data = notice.encode()

360

```

361

362

### Parsing Incoming Messages

363

364

```python

365

import gntp.core

366

import gntp.errors

367

368

try:

369

# Parse raw GNTP data

370

message = gntp.core.parse_gntp(raw_data, password='mypassword')

371

372

if isinstance(message, gntp.core.GNTPRegister):

373

print(f"Registration from: {message.headers['Application-Name']}")

374

print(f"Notifications: {len(message.notifications)}")

375

376

elif isinstance(message, gntp.core.GNTPNotice):

377

print(f"Notification: {message.headers['Notification-Title']}")

378

print(f"From: {message.headers['Application-Name']}")

379

380

elif isinstance(message, gntp.core.GNTPError):

381

code, desc = message.error()

382

print(f"Error {code}: {desc}")

383

384

except gntp.errors.ParseError as e:

385

print(f"Invalid GNTP message: {e}")

386

except gntp.errors.AuthError as e:

387

print(f"Authentication failed: {e}")

388

```

389

390

### Custom Message Construction

391

392

```python

393

import gntp.core

394

395

# Create subscription message

396

subscribe = gntp.core.GNTPSubscribe()

397

subscribe.add_header('Subscriber-ID', 'client-123')

398

subscribe.add_header('Subscriber-Name', 'My Client')

399

subscribe.add_header('Subscriber-Port', '23054')

400

subscribe.set_password('subscription-password')

401

402

# Create custom OK response

403

ok_response = gntp.core.GNTPOK()

404

ok_response.add_header('Response-Action', 'REGISTER')

405

ok_response.add_header('Custom-Header', 'Custom-Value')

406

407

# Create custom error response

408

error_response = gntp.core.GNTPError()

409

error_response.add_header('Error-Code', '500')

410

error_response.add_header('Error-Description', 'Internal Server Error')

411

error_response.add_header('Server-Name', 'My GNTP Server')

412

```

413

414

### Working with Binary Resources

415

416

```python

417

import gntp.core

418

import hashlib

419

420

# Create notification with multiple resources

421

notice = gntp.core.GNTPNotice(

422

app='Media Player',

423

name='Now Playing',

424

title='Song Changed'

425

)

426

427

# Add album art

428

with open('album_art.jpg', 'rb') as f:

429

album_art = f.read()

430

art_url = notice.add_resource(album_art)

431

notice.add_header('Notification-Icon', art_url)

432

433

# Add audio preview (if supported by client)

434

with open('preview.mp3', 'rb') as f:

435

audio_data = f.read()

436

audio_url = notice.add_resource(audio_data)

437

notice.add_header('X-Audio-Preview', audio_url)

438

439

# Resources are automatically managed and included in encoded message

440

encoded = notice.encode()

441

```

442

443

## Protocol Details

444

445

### Message Format

446

447

All GNTP messages follow this structure:

448

449

```

450

GNTP/1.0 MESSAGETYPE ENCRYPTION [KEYHASHALGO:KEYHASH.SALT]

451

Header-Name: Header Value

452

Another-Header: Another Value

453

454

[Optional resource data]

455

```

456

457

### Supported Hash Algorithms

458

459

- `MD5`: MD5 hash (default, legacy)

460

- `SHA1`: SHA-1 hash

461

- `SHA256`: SHA-256 hash (recommended)

462

- `SHA512`: SHA-512 hash (most secure)

463

464

### Resource Handling

465

466

Binary resources are automatically:

467

- Hashed with MD5 to generate unique identifiers

468

- Included in the message payload

469

- Referenced via `x-growl-resource://` URLs in headers

470

471

### Error Codes

472

473

Common GNTP error codes:

474

- `400`: Authentication failed

475

- `500`: Internal server error, parsing error, unsupported operation

476

- Other codes as defined by GNTP specification