transmission 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,63 @@
1
+ /******************************************************************************
2
+ * $Id: platform.h 310 2006-06-09 19:53:35Z joshe $
3
+ *
4
+ * Copyright (c) 2005 Transmission authors and contributors
5
+ *
6
+ * Permission is hereby granted, free of charge, to any person obtaining a
7
+ * copy of this software and associated documentation files (the "Software"),
8
+ * to deal in the Software without restriction, including without limitation
9
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
+ * and/or sell copies of the Software, and to permit persons to whom the
11
+ * Software is furnished to do so, subject to the following conditions:
12
+ *
13
+ * The above copyright notice and this permission notice shall be included in
14
+ * all copies or substantial portions of the Software.
15
+ *
16
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22
+ * DEALINGS IN THE SOFTWARE.
23
+ *****************************************************************************/
24
+ #ifndef TR_PLATFORM_H
25
+ #define TR_PLATFORM_H 1
26
+
27
+ #ifdef SYS_BEOS
28
+ #include <kernel/OS.h>
29
+ typedef thread_id tr_thread_t;
30
+ typedef sem_id tr_lock_t;
31
+ #else
32
+ #include <pthread.h>
33
+ typedef pthread_t tr_thread_t;
34
+ typedef pthread_mutex_t tr_lock_t;
35
+ #endif
36
+
37
+ char * tr_getCacheDirectory();
38
+ char * tr_getTorrentsDirectory();
39
+
40
+ void tr_threadCreate ( tr_thread_t *, void (*func)(void *), void * arg );
41
+ void tr_threadJoin ( tr_thread_t * );
42
+ void tr_lockInit ( tr_lock_t * );
43
+ void tr_lockClose ( tr_lock_t * );
44
+
45
+ static inline void tr_lockLock( tr_lock_t * l )
46
+ {
47
+ #ifdef SYS_BEOS
48
+ acquire_sem( *l );
49
+ #else
50
+ pthread_mutex_lock( l );
51
+ #endif
52
+ }
53
+
54
+ static inline void tr_lockUnlock( tr_lock_t * l )
55
+ {
56
+ #ifdef SYS_BEOS
57
+ release_sem( *l );
58
+ #else
59
+ pthread_mutex_unlock( l );
60
+ #endif
61
+ }
62
+
63
+ #endif
@@ -0,0 +1,1135 @@
1
+ #include <ruby.h>
2
+ #include "transmission.h"
3
+
4
+ #define VERSION "0.1"
5
+
6
+ static VALUE cTransmission;
7
+ static VALUE cTorrent;
8
+ static VALUE cFileInfo;
9
+ static VALUE cStat;
10
+
11
+ static VALUE eTransmissionError;
12
+ static VALUE eParseError;
13
+ static VALUE eUnsupportedError;
14
+ static VALUE eDuplicateError;
15
+ static VALUE eTorrentError;
16
+
17
+ typedef struct {
18
+ tr_handle_t *handle;
19
+ VALUE torrents;
20
+ } r_transmission_t;
21
+
22
+ typedef struct {
23
+ VALUE transmission;
24
+ tr_torrent_t *handle;
25
+ int flags;
26
+ } r_torrent_t;
27
+
28
+ #define TORRENT_CLOSED 0x1
29
+ #define CLOSED(torrent) ((torrent)->flags & TORRENT_CLOSED)
30
+ #define SET_CLOSED(torrent) (torrent)->flags |= TORRENT_CLOSED;
31
+
32
+ #define STARTED(torrent) (tr_torrentStat((torrent)->handle)->status & TR_STATUS_ACTIVE)
33
+
34
+ #define CHECK_TORRENT(torrent) if(CLOSED(torrent)) rb_raise(eTorrentError, "Torrrent is already closed.");
35
+
36
+ static void r_torrent_close(r_torrent_t *);
37
+ static VALUE r_torrent_get_folder(VALUE);
38
+ static VALUE r_torrent_set_folder(VALUE, VALUE);
39
+
40
+ static void
41
+ r_transmission_mark(void *data)
42
+ {
43
+ r_transmission_t *transmission;
44
+
45
+ transmission = (r_transmission_t *) data;
46
+ rb_gc_mark(transmission -> torrents);
47
+ }
48
+
49
+ static void
50
+ r_transmission_free(void *data)
51
+ {
52
+ r_transmission_t *transmission;
53
+ r_torrent_t *torrent;
54
+ int i;
55
+ transmission = (r_transmission_t *) data;
56
+ for( i = 0; i < RARRAY(transmission->torrents)->len; i += 1 )
57
+ {
58
+ Data_Get_Struct(RARRAY(transmission->torrents)->ptr[i], r_torrent_t, torrent);
59
+ r_torrent_close(torrent);
60
+ }
61
+ tr_close(transmission->handle);
62
+ xfree(data);
63
+ }
64
+
65
+ static VALUE
66
+ r_transmission_alloc(VALUE klass)
67
+ {
68
+ tr_handle_t *handle;
69
+ r_transmission_t *transmission;
70
+ VALUE obj;
71
+
72
+ handle = tr_init();
73
+ transmission = ALLOC(r_transmission_t);
74
+ transmission->handle = handle;
75
+ transmission->torrents = rb_ary_new();
76
+ obj = Data_Wrap_Struct(klass, r_transmission_mark, r_transmission_free, transmission);
77
+ return obj;
78
+ }
79
+
80
+ /*
81
+ * call-seq:
82
+ * Transmission.pref_directory -> string
83
+ *
84
+ * Returns the full path to a directory which can be used to store preferences.
85
+ *
86
+ */
87
+ static VALUE
88
+ r_transmission_pref_dir(VALUE self)
89
+ {
90
+ return rb_str_new2(tr_getPrefsDirectory());
91
+ }
92
+
93
+ /*
94
+ * call-seq:
95
+ * transmission.bind_port = port -> port
96
+ *
97
+ * Sets a "starting" bind port. Everytime a torrent is started, the library tries to bind
98
+ * this port, then the next one and so on until it is successful.
99
+ *
100
+ */
101
+ static VALUE
102
+ r_transmission_set_bind_port(VALUE self, VALUE port)
103
+ {
104
+ r_transmission_t *transmission;
105
+
106
+ Data_Get_Struct(self, r_transmission_t, transmission);
107
+ tr_setBindPort(transmission->handle, FIX2INT(port));
108
+ return port;
109
+ }
110
+
111
+ static void
112
+ r_torrent_mark(void *data)
113
+ {
114
+ r_torrent_t *torrent;
115
+ torrent = (r_torrent_t *)data;
116
+ rb_gc_mark(torrent->transmission);
117
+ }
118
+
119
+ static void
120
+ r_torrent_free(void *data)
121
+ {
122
+ r_torrent_t *torrent;
123
+ torrent = (r_torrent_t *) data;
124
+ r_torrent_close(torrent);
125
+ xfree(data);
126
+ }
127
+
128
+ /*
129
+ * call-seq:
130
+ * transmission.open(path) -> torrent
131
+ *
132
+ * Opens and parses torrent file at 'path'. If the file exists and is a
133
+ * valid torrent file, returns a Torrent instance and adds it to the list of
134
+ * torrents (but doesn't start it).
135
+ *
136
+ */
137
+ static VALUE
138
+ r_transmission_open(int argc, VALUE *argv, VALUE self)
139
+ {
140
+ VALUE file, save = Qnil, saved = Qnil, excp, result;
141
+ r_transmission_t *transmission;
142
+ tr_torrent_t *torrent_h;
143
+ r_torrent_t *torrent;
144
+ int flags = 0;
145
+ int error = 0;
146
+
147
+ rb_scan_args(argc, argv, "12", &file, &save, &saved);
148
+
149
+ if( RTEST(save) && !RTEST(saved))
150
+ flags = TR_FSAVEPRIVATE;
151
+
152
+ Data_Get_Struct(self, r_transmission_t, transmission);
153
+
154
+ torrent_h = RTEST(saved) ?
155
+ tr_torrentInitSaved(transmission->handle, StringValuePtr(file), flags, &error) :
156
+ tr_torrentInit(transmission->handle, StringValuePtr(file), flags, &error);
157
+ if(torrent_h == NULL) {
158
+ switch(error)
159
+ {
160
+ case TR_EINVALID:
161
+ excp = eParseError;
162
+ break;
163
+ case TR_EUNSUPPORTED:
164
+ excp = eUnsupportedError;
165
+ break;
166
+ case TR_EDUPLICATE:
167
+ excp = eDuplicateError;
168
+ case TR_EOTHER:
169
+ default:
170
+ excp = eTorrentError;
171
+ }
172
+ rb_raise(excp, "Failed to open torrent file");
173
+ }
174
+ torrent = ALLOC(r_torrent_t);
175
+ torrent->transmission = self;
176
+ torrent->handle = torrent_h;
177
+ torrent->flags = 0;
178
+
179
+ result = Data_Wrap_Struct(cTorrent, r_torrent_mark, r_torrent_free, torrent);
180
+ rb_ary_push(transmission->torrents, result);
181
+ if(r_torrent_get_folder(result) == Qnil)
182
+ r_torrent_set_folder(result, rb_str_new2("."));
183
+ return result;
184
+ }
185
+
186
+ /*
187
+ * call-seq:
188
+ * transmission.size -> int
189
+ *
190
+ * Returns the count of open torrents.
191
+ */
192
+ static VALUE
193
+ r_transmission_size(VALUE self)
194
+ {
195
+ r_transmission_t *transmission;
196
+ Data_Get_Struct(self, r_transmission_t, transmission);
197
+ return INT2FIX(tr_torrentCount(transmission->handle));
198
+ }
199
+
200
+ static VALUE
201
+ r_transmission_find(r_transmission_t *transmission, tr_torrent_t *h)
202
+ {
203
+ r_torrent_t *torrent;
204
+ VALUE result;
205
+ int i;
206
+ for( i = 0; i < RARRAY(transmission->torrents)->len; i += 1 )
207
+ {
208
+ result = RARRAY(transmission->torrents)->ptr[i];
209
+ Data_Get_Struct(result, r_torrent_t, torrent);
210
+ if(torrent->handle == h && !CLOSED(torrent)) return result;
211
+ }
212
+ return Qnil;
213
+ }
214
+
215
+
216
+ static void
217
+ r_transmission_each_i(tr_torrent_t *h, void *data)
218
+ {
219
+ r_transmission_t *transmission;
220
+ VALUE torrent;
221
+
222
+ transmission = (r_transmission_t *)data;
223
+ torrent = r_transmission_find(transmission, h);
224
+ if(torrent != Qnil) rb_yield(torrent);
225
+ }
226
+
227
+ /*
228
+ * call-seq:
229
+ * transmission.each {|torrent| ...} -> transmission
230
+ *
231
+ * Iterate through all opened torrents.
232
+ */
233
+ static VALUE
234
+ r_transmission_each(VALUE self)
235
+ {
236
+ r_transmission_t *transmission;
237
+ Data_Get_Struct(self, r_transmission_t, transmission);
238
+
239
+ tr_torrentIterate(transmission->handle, r_transmission_each_i, (void *)transmission);
240
+ return self;
241
+ }
242
+
243
+ /*
244
+ * call-seq:
245
+ * transmission.rates -> [int, int]
246
+ *
247
+ * Returns total download and upload rates.
248
+ */
249
+ static VALUE
250
+ r_transmission_rates(VALUE self)
251
+ {
252
+ r_transmission_t *transmission;
253
+ float down, up;
254
+
255
+ Data_Get_Struct(self, r_transmission_t, transmission);
256
+ tr_torrentRates(transmission->handle, &down, &up);
257
+ return rb_ary_new3(2, rb_float_new(down), rb_float_new(up));
258
+ }
259
+
260
+ /*
261
+ * call-seq:
262
+ * transmission.upload_limit = limit -> limit
263
+ *
264
+ * Sets upload limit in Kb.
265
+ */
266
+ static VALUE
267
+ r_transmission_set_upload_limit(VALUE self, VALUE limit)
268
+ {
269
+ r_transmission_t *transmission;
270
+ Data_Get_Struct(self, r_transmission_t, transmission);
271
+ tr_setUploadLimit(transmission->handle, FIX2INT(limit));
272
+ return limit;
273
+ }
274
+
275
+ /*
276
+ * call-seq:
277
+ * transmission.download_limit = limit -> limit
278
+ *
279
+ * Sets download limit in Kb.
280
+ */
281
+ static VALUE
282
+ r_transmission_set_download_limit(VALUE self, VALUE limit)
283
+ {
284
+ r_transmission_t *transmission;
285
+ Data_Get_Struct(self, r_transmission_t, transmission);
286
+ tr_setDownloadLimit(transmission->handle, FIX2INT(limit));
287
+ return limit;
288
+ }
289
+
290
+ static void
291
+ r_torrent_close(r_torrent_t *torrent)
292
+ {
293
+ r_transmission_t *transmission;
294
+
295
+ if(CLOSED(torrent)) return;
296
+
297
+ Data_Get_Struct(torrent->transmission, r_transmission_t, transmission);
298
+
299
+ if(STARTED(torrent))
300
+ tr_torrentStop(torrent->handle);
301
+
302
+ tr_torrentClose(transmission->handle, torrent->handle);
303
+ SET_CLOSED(torrent);
304
+ }
305
+
306
+ /*
307
+ * call-seq:
308
+ * torrent.remove(saved = false) -> nil
309
+ *
310
+ * Removes torrent from the current session. If 'saved' parameter is true,
311
+ * it also deletes a private torrent copy if there is one.
312
+ */
313
+ static VALUE
314
+ r_torrent_remove(int argc, VALUE *argv, VALUE self)
315
+ {
316
+ r_transmission_t *transmission;
317
+ r_torrent_t *torrent;
318
+ VALUE remove_saved = Qfalse;
319
+
320
+ rb_scan_args(argc, argv, "01", &remove_saved);
321
+
322
+ Data_Get_Struct(self, r_torrent_t, torrent);
323
+ CHECK_TORRENT(torrent);
324
+ Data_Get_Struct(torrent->transmission, r_transmission_t, transmission);
325
+ if(RTEST(remove_saved))
326
+ tr_torrentRemoveSaved(torrent->handle);
327
+ rb_ary_delete(transmission->torrents, self);
328
+ r_torrent_close(torrent);
329
+ return Qnil;
330
+ }
331
+
332
+ static char *
333
+ r_torrent_scrape_error(int code)
334
+ {
335
+ switch(code)
336
+ {
337
+ case TR_SCRAPE_RESOLVE:
338
+ return "Could not resolve address";
339
+ case TR_SCRAPE_CONNECT:
340
+ return "Could not connect to the tracker";
341
+ case TR_SCRAPE_READ:
342
+ return "Failed to read from the tracker";
343
+ default:
344
+ return "Failed to scrape the tracker";
345
+ }
346
+ }
347
+
348
+ /*
349
+ * call-seq:
350
+ * torrent.scrape -> [int, int]
351
+ *
352
+ * Scrapes the tracker and returns a number of seeders and leechers.
353
+ */
354
+ static VALUE
355
+ r_torrent_scrape(VALUE self)
356
+ {
357
+ r_torrent_t *torrent;
358
+ int seeders, leechers;
359
+ int ret_code;
360
+
361
+ Data_Get_Struct(self, r_torrent_t, torrent);
362
+ CHECK_TORRENT(torrent);
363
+
364
+ if((ret_code = tr_torrentScrape(torrent->handle, &seeders, &leechers)) != 0)
365
+ {
366
+ rb_raise(eTorrentError, r_torrent_scrape_error(ret_code));
367
+ }
368
+ return rb_ary_new3(2, INT2FIX(seeders), INT2FIX(leechers));
369
+ }
370
+
371
+ static tr_info_t *
372
+ r_torrent_info(VALUE self)
373
+ {
374
+ r_torrent_t *torrent;
375
+
376
+ Data_Get_Struct(self, r_torrent_t, torrent);
377
+ CHECK_TORRENT(torrent);
378
+ return tr_torrentInfo(torrent->handle);
379
+ }
380
+
381
+ /*
382
+ * call-seq:
383
+ * torrent.file_name -> string
384
+ *
385
+ * Returns file name of the torrent file.
386
+ */
387
+ static VALUE
388
+ r_torrent_file_name(VALUE self)
389
+ {
390
+ return rb_str_new2(r_torrent_info(self)->torrent);
391
+ }
392
+
393
+ /*
394
+ * call-seq:
395
+ * torrent.name -> string
396
+ *
397
+ * Returns the description of the torrent file.
398
+ */
399
+ static VALUE
400
+ r_torrent_name(VALUE self)
401
+ {
402
+ return rb_str_new2(r_torrent_info(self)->name);
403
+ }
404
+
405
+ /*
406
+ * call-seq:
407
+ * torrent.hash_string -> string
408
+ *
409
+ * Returns the hash string of the torrent file.
410
+ */
411
+ static VALUE
412
+ r_torrent_hash_string(VALUE self)
413
+ {
414
+ return rb_str_new2(r_torrent_info(self)->hashString);
415
+ }
416
+
417
+ /*
418
+ * call-seq:
419
+ * torrent.tracker_address -> string
420
+ *
421
+ * Returns the tracker address.
422
+ */
423
+ static VALUE
424
+ r_torrent_tracker_address(VALUE self)
425
+ {
426
+ return rb_str_new2(r_torrent_info(self)->trackerAddress);
427
+ }
428
+
429
+ /*
430
+ * call-seq:
431
+ * torrent.tracker_port -> int
432
+ *
433
+ * Returns the tracker port.
434
+ */
435
+ static VALUE
436
+ r_torrent_tracker_port(VALUE self)
437
+ {
438
+ return INT2FIX(r_torrent_info(self)->trackerPort);
439
+ }
440
+
441
+ /*
442
+ * call-seq:
443
+ * torrent.tracker_announce -> string
444
+ *
445
+ * Returns the tracker announce address.
446
+ */
447
+ static VALUE
448
+ r_torrent_tracker_announce(VALUE self)
449
+ {
450
+ return rb_str_new2(r_torrent_info(self)->trackerAnnounce);
451
+ }
452
+
453
+ /*
454
+ * call-seq:
455
+ * torrent.piece_size -> int
456
+ *
457
+ * Returns piece size in bytes.
458
+ */
459
+ static VALUE
460
+ r_torrent_piece_size(VALUE self)
461
+ {
462
+ return INT2FIX(r_torrent_info(self)->pieceSize);
463
+ }
464
+
465
+ /*
466
+ * call-seq:
467
+ * torrent.piece_count -> string
468
+ *
469
+ * Returns piece count.
470
+ */
471
+ static VALUE
472
+ r_torrent_piece_count(VALUE self)
473
+ {
474
+ return INT2FIX(r_torrent_info(self)->pieceCount);
475
+ }
476
+
477
+ /*
478
+ * call-seq:
479
+ * torrent.total_size -> string
480
+ *
481
+ * Returns the total size of all pieces in bytes.
482
+ */
483
+ static VALUE
484
+ r_torrent_total_size(VALUE self)
485
+ {
486
+ return ULONG2NUM(r_torrent_info(self)->totalSize);
487
+ }
488
+
489
+ /*
490
+ * call-seq:
491
+ * torrent.pieces -> array
492
+ *
493
+ * Returns the array of pieces.
494
+ */
495
+ static VALUE
496
+ r_torrent_pieces(VALUE self)
497
+ {
498
+ VALUE *pieces;
499
+ tr_info_t *info;
500
+ VALUE result;
501
+ int i;
502
+
503
+ info = r_torrent_info(self);
504
+
505
+ pieces = ALLOC_N(VALUE, info->pieceCount);
506
+ for( i = 0; i < info->pieceCount; i += 1 )
507
+ {
508
+ pieces[i] = INT2FIX(info->pieces[i]);
509
+ }
510
+
511
+ result = rb_ary_new4(info->pieceCount, pieces);
512
+ xfree(pieces);
513
+ return result;
514
+ }
515
+
516
+ /*
517
+ * call-seq:
518
+ * torrent.file_count -> int
519
+ *
520
+ * Returns the total number of files for this torrent.
521
+ */
522
+ static VALUE
523
+ r_torrent_file_count(VALUE self)
524
+ {
525
+ return INT2FIX(r_torrent_info(self)->fileCount);
526
+ }
527
+
528
+ /*
529
+ * call-seq:
530
+ * torrent.files -> array
531
+ *
532
+ * Returns the array of FileInfo.
533
+ */
534
+ static VALUE
535
+ r_torrent_files(VALUE self)
536
+ {
537
+ VALUE *files;
538
+ VALUE result;
539
+ tr_info_t *info;
540
+ tr_file_t *f;
541
+ int i;
542
+
543
+ info = r_torrent_info(self);
544
+
545
+ files = ALLOC_N(VALUE, info->fileCount);
546
+ for( i = 0; i < info->fileCount; i += 1 )
547
+ {
548
+ f = ALLOC(tr_file_t);
549
+ MEMCPY(f, &info->files[i], tr_file_t, 1);
550
+ files[i] = Data_Wrap_Struct(cFileInfo, NULL, xfree, f);
551
+ }
552
+ result = rb_ary_new4(info->fileCount, files);
553
+ xfree(files);
554
+ return result;
555
+ }
556
+
557
+ /*
558
+ * call-seq:
559
+ * torrent.stat -> Stat
560
+ *
561
+ * Returns the stat of this torrent.
562
+ */
563
+ static VALUE
564
+ r_torrent_stat(VALUE self)
565
+ {
566
+ r_torrent_t *torrent;
567
+ tr_stat_t *stat;
568
+
569
+ Data_Get_Struct(self, r_torrent_t, torrent);
570
+ CHECK_TORRENT(torrent);
571
+
572
+ stat = ALLOC(tr_stat_t);
573
+ MEMCPY(stat, tr_torrentStat(torrent->handle), tr_stat_t, 1);
574
+ return Data_Wrap_Struct(cStat, NULL, xfree, stat);
575
+ }
576
+
577
+ /*
578
+ * call-seq:
579
+ * torrent.folder -> string
580
+ *
581
+ * Returns the path where torrent files will be stored.
582
+ */
583
+ static VALUE
584
+ r_torrent_get_folder(VALUE self)
585
+ {
586
+ r_torrent_t *torrent;
587
+ char *folder;
588
+
589
+ Data_Get_Struct(self, r_torrent_t, torrent);
590
+ CHECK_TORRENT(torrent);
591
+
592
+ folder = tr_torrentGetFolder(torrent->handle);
593
+ if(folder)
594
+ return rb_str_new2(folder);
595
+ return Qnil;
596
+ }
597
+
598
+ /*
599
+ * call-seq:
600
+ * torrent.folder = folder -> folder
601
+ *
602
+ * Changes the directory wher torrent file will be stored.
603
+ */
604
+ static VALUE
605
+ r_torrent_set_folder(VALUE self, VALUE file)
606
+ {
607
+ r_torrent_t *torrent;
608
+
609
+ Data_Get_Struct(self, r_torrent_t, torrent);
610
+ CHECK_TORRENT(torrent);
611
+
612
+ tr_torrentSetFolder(torrent->handle, StringValuePtr(file));
613
+ return file;
614
+ }
615
+
616
+ /*
617
+ * call-seq:
618
+ * torrent.start -> nil
619
+ *
620
+ * Starts the torrent downloading. The download is launched in a seperate thread,
621
+ * therefore torrent.start returns immediately.
622
+ */
623
+ static VALUE
624
+ r_torrent_start(VALUE self)
625
+ {
626
+ r_torrent_t *torrent;
627
+
628
+ Data_Get_Struct(self, r_torrent_t, torrent);
629
+ CHECK_TORRENT(torrent);
630
+
631
+ if(!STARTED(torrent))
632
+ {
633
+ tr_torrentStart(torrent->handle);
634
+ }
635
+
636
+ return Qnil;
637
+ }
638
+
639
+ /*
640
+ * call-seq:
641
+ * torrent.stop -> nil
642
+ *
643
+ * Stops the torrent downloading.
644
+ */
645
+ static VALUE
646
+ r_torrent_stop(VALUE self)
647
+ {
648
+ r_torrent_t *torrent;
649
+
650
+ Data_Get_Struct(self, r_torrent_t, torrent);
651
+ CHECK_TORRENT(torrent);
652
+
653
+ if(STARTED(torrent))
654
+ {
655
+ tr_torrentStop(torrent->handle);
656
+ }
657
+
658
+ return Qnil;
659
+ }
660
+
661
+ /*
662
+ * call-seq:
663
+ * torrent.active? -> bool
664
+ *
665
+ * Returns true if torrent is in active state.
666
+ */
667
+ static VALUE
668
+ r_torrent_active(VALUE self)
669
+ {
670
+ r_torrent_t *torrent;
671
+
672
+ Data_Get_Struct(self, r_torrent_t, torrent);
673
+ CHECK_TORRENT(torrent);
674
+
675
+ return STARTED(torrent) ? Qtrue : Qfalse;
676
+ }
677
+
678
+ /*
679
+ * call-seq:
680
+ * torrent.closed? -> bool
681
+ *
682
+ * Returns true if torrent is closed and can't be used anymore.
683
+ */
684
+ static VALUE
685
+ r_torrent_closed(VALUE self)
686
+ {
687
+ r_torrent_t *torrent;
688
+
689
+ Data_Get_Struct(self, r_torrent_t, torrent);
690
+
691
+ return CLOSED(torrent) ? Qtrue : Qfalse;
692
+ }
693
+
694
+ /*
695
+ * call-seq:
696
+ * torrent.availability(size) -> array of integers
697
+ *
698
+ * Use this to draw an advanced progress bar which is 'size' pixels
699
+ * wide. Returns an array of integer where each integer is set
700
+ * to either -1 if we have the piece, otherwise it is set to the number
701
+ * of connected peers who have the piece.
702
+ */
703
+ static VALUE
704
+ r_torrent_availability(VALUE self, VALUE size)
705
+ {
706
+ r_torrent_t *torrent;
707
+ int8_t *data;
708
+ VALUE *result_data;
709
+ VALUE result;
710
+ int length, i;
711
+
712
+ Data_Get_Struct(self, r_torrent_t, torrent);
713
+ CHECK_TORRENT(torrent);
714
+
715
+ length = FIX2INT(size);
716
+ data = ALLOC_N(int8_t, length);
717
+ result_data = ALLOC_N(VALUE, length);
718
+ tr_torrentAvailability(torrent->handle, data, length);
719
+ for( i = 0; i < length; i += 1 )
720
+ {
721
+ result_data[i] = INT2FIX(data[i]);
722
+ }
723
+ result = rb_ary_new4(length, result_data);
724
+ xfree(data);
725
+ xfree(result_data);
726
+ return result;
727
+ }
728
+
729
+ /*
730
+ * call-seq:
731
+ * torrent.just_finished? -> bool
732
+ *
733
+ * The first call after a torrent is completed returns true. Returns false
734
+ * in other cases.
735
+ */
736
+ static VALUE
737
+ r_torrent_just_finished(VALUE self)
738
+ {
739
+ r_torrent_t *torrent;
740
+
741
+ Data_Get_Struct(self, r_torrent_t, torrent);
742
+
743
+ return tr_getFinished(torrent->handle) ? Qtrue : Qfalse;
744
+ }
745
+
746
+ /*
747
+ * call-seq:
748
+ * file_info.name -> string
749
+ *
750
+ * Returns the name of the file.
751
+ */
752
+ static VALUE
753
+ r_file_info_name(VALUE self)
754
+ {
755
+ tr_file_t *file;
756
+ Data_Get_Struct(self, tr_file_t, file);
757
+ return rb_str_new2(file->name);
758
+ }
759
+
760
+ /*
761
+ * call-seq:
762
+ * file_info.size -> int
763
+ *
764
+ * Returns the size of the file.
765
+ */
766
+ static VALUE
767
+ r_file_info_size(VALUE self)
768
+ {
769
+ tr_file_t *file;
770
+ Data_Get_Struct(self, tr_file_t, file);
771
+ return INT2FIX(file->length);
772
+ }
773
+
774
+ /*
775
+ * call-seq:
776
+ * stat.status -> int
777
+ *
778
+ * Returns the status of the torrent.
779
+ */
780
+ static VALUE
781
+ r_stat_status(VALUE self)
782
+ {
783
+ tr_stat_t *stat;
784
+ Data_Get_Struct(self, tr_stat_t, stat);
785
+ return INT2FIX(stat->status);
786
+ }
787
+
788
+ /*
789
+ * call-seq:
790
+ * stat.error -> int
791
+ *
792
+ * Returns the error code of the torrent, 0 otherwise.
793
+ */
794
+ static VALUE
795
+ r_stat_error(VALUE self)
796
+ {
797
+ tr_stat_t *stat;
798
+ Data_Get_Struct(self, tr_stat_t, stat);
799
+ return INT2FIX(stat->error);
800
+ }
801
+
802
+ /*
803
+ * call-seq:
804
+ * stat.tracker_error -> string
805
+ *
806
+ * Returns the tracker error or empty string.
807
+ */
808
+ static VALUE
809
+ r_stat_tracker_error(VALUE self)
810
+ {
811
+ tr_stat_t *stat;
812
+ Data_Get_Struct(self, tr_stat_t, stat);
813
+ return rb_str_new2(stat->trackerError);
814
+ }
815
+
816
+ /*
817
+ * call-seq:
818
+ * stat.progress -> float
819
+ *
820
+ * Returns the progress of the torrent from 0.0 to 1.0.
821
+ */
822
+ static VALUE
823
+ r_stat_progress(VALUE self)
824
+ {
825
+ tr_stat_t *stat;
826
+ Data_Get_Struct(self, tr_stat_t, stat);
827
+ return rb_float_new(stat->progress);
828
+ }
829
+
830
+ /*
831
+ * call-seq:
832
+ * stat.down_rate -> float
833
+ *
834
+ * Returns downloading rate.
835
+ */
836
+ static VALUE
837
+ r_stat_down_rate(VALUE self)
838
+ {
839
+ tr_stat_t *stat;
840
+ Data_Get_Struct(self, tr_stat_t, stat);
841
+ return rb_float_new(stat->rateDownload);
842
+ }
843
+
844
+ /*
845
+ * call-seq:
846
+ * stat.up_rate -> float
847
+ *
848
+ * Returns uploading rate.
849
+ */
850
+ static VALUE
851
+ r_stat_up_rate(VALUE self)
852
+ {
853
+ tr_stat_t *stat;
854
+ Data_Get_Struct(self, tr_stat_t, stat);
855
+ return rb_float_new(stat->rateUpload);
856
+ }
857
+
858
+ /*
859
+ * call-seq:
860
+ * stat.rates -> [float, float]
861
+ *
862
+ * Returns an array of downloading and uploading rates.
863
+ */
864
+ static VALUE
865
+ r_stat_rates(VALUE self)
866
+ {
867
+ tr_stat_t *stat;
868
+ Data_Get_Struct(self, tr_stat_t, stat);
869
+ return rb_ary_new3(2, rb_float_new(stat->rateDownload), rb_float_new(stat->rateUpload));
870
+ }
871
+
872
+ /*
873
+ * call-seq:
874
+ * stat.eta -> int
875
+ *
876
+ * Returns eta until the torrent finishes downloading.
877
+ */
878
+ static VALUE
879
+ r_stat_eta(VALUE self)
880
+ {
881
+ tr_stat_t *stat;
882
+ Data_Get_Struct(self, tr_stat_t, stat);
883
+ return INT2FIX(stat->eta);
884
+ }
885
+
886
+ /*
887
+ * call-seq:
888
+ * stat.peers_total -> int
889
+ *
890
+ * Returns the total number of peers.
891
+ */
892
+ static VALUE
893
+ r_stat_peers_total(VALUE self)
894
+ {
895
+ tr_stat_t *stat;
896
+ Data_Get_Struct(self, tr_stat_t, stat);
897
+ return INT2FIX(stat->peersTotal);
898
+ }
899
+
900
+ /*
901
+ * call-seq:
902
+ * stat.up_peers -> int
903
+ *
904
+ * Returns a number of uploading peers.
905
+ */
906
+ static VALUE
907
+ r_stat_up_peers(VALUE self)
908
+ {
909
+ tr_stat_t *stat;
910
+ Data_Get_Struct(self, tr_stat_t, stat);
911
+ return INT2FIX(stat->peersUploading);
912
+ }
913
+
914
+ /*
915
+ * call-seq:
916
+ * stat.down_peers -> int
917
+ *
918
+ * Returns a number of downloaded peers.
919
+ */
920
+ static VALUE
921
+ r_stat_down_peers(VALUE self)
922
+ {
923
+ tr_stat_t *stat;
924
+ Data_Get_Struct(self, tr_stat_t, stat);
925
+ return INT2FIX(stat->peersDownloading);
926
+ }
927
+
928
+ /*
929
+ * call-seq:
930
+ * stat.peers -> [int, int]
931
+ *
932
+ * Returns an array of numbers of downloading and uploading peers.
933
+ */
934
+ static VALUE
935
+ r_stat_peers(VALUE self)
936
+ {
937
+ tr_stat_t *stat;
938
+ Data_Get_Struct(self, tr_stat_t, stat);
939
+ return rb_ary_new3(2, INT2FIX(stat->peersDownloading), INT2FIX(stat->peersUploading));
940
+ }
941
+
942
+ /*
943
+ * call-seq:
944
+ * stat.seeders -> int
945
+ *
946
+ * Returns a number of seeders.
947
+ */
948
+ static VALUE
949
+ r_stat_seeders(VALUE self)
950
+ {
951
+ tr_stat_t *stat;
952
+ Data_Get_Struct(self, tr_stat_t, stat);
953
+ return INT2FIX(stat->seeders);
954
+ }
955
+
956
+ /*
957
+ * call-seq:
958
+ * stat.leechers -> int
959
+ *
960
+ * Returns a number of leechers.
961
+ */
962
+ static VALUE
963
+ r_stat_leechers(VALUE self)
964
+ {
965
+ tr_stat_t *stat;
966
+ Data_Get_Struct(self, tr_stat_t, stat);
967
+ return INT2FIX(stat->leechers);
968
+ }
969
+
970
+ /*
971
+ * call-seq:
972
+ * stat.downloaded -> int
973
+ *
974
+ * Returns the total number of downloaded bytes.
975
+ */
976
+ static VALUE
977
+ r_stat_downloaded(VALUE self)
978
+ {
979
+ tr_stat_t *stat;
980
+ Data_Get_Struct(self, tr_stat_t, stat);
981
+ return ULONG2NUM(stat->downloaded);
982
+ }
983
+
984
+ /*
985
+ * call-seq:
986
+ * stat.uploaded -> int
987
+ *
988
+ * Returns the total number of uploaded bytes.
989
+ */
990
+ static VALUE
991
+ r_stat_uploaded(VALUE self)
992
+ {
993
+ tr_stat_t *stat;
994
+ Data_Get_Struct(self, tr_stat_t, stat);
995
+ return ULONG2NUM(stat->uploaded);
996
+ }
997
+
998
+ /*
999
+ * Document-class: Transmission::Torrent
1000
+ *
1001
+ * == Summary
1002
+ *
1003
+ * The Torrent class represent a torrent instance. You can use this instance
1004
+ * start and stop downloading process and keep track of its progress.
1005
+ */
1006
+ static void
1007
+ Init_torrent()
1008
+ {
1009
+ cTorrent = rb_define_class_under(cTransmission, "Torrent", rb_cObject);
1010
+ rb_define_method(cTorrent, "remove", r_torrent_remove, -1);
1011
+ rb_define_method(cTorrent, "scrape", r_torrent_scrape, 0);
1012
+ rb_define_method(cTorrent, "file_name", r_torrent_file_name, 0);
1013
+ rb_define_method(cTorrent, "name", r_torrent_name, 0);
1014
+ rb_define_method(cTorrent, "hash_string", r_torrent_hash_string, 0);
1015
+ rb_define_method(cTorrent, "tracker_addr", r_torrent_tracker_address, 0);
1016
+ rb_define_method(cTorrent, "tracker_address", r_torrent_tracker_address, 0);
1017
+ rb_define_method(cTorrent, "tracker_port", r_torrent_tracker_port, 0);
1018
+ rb_define_method(cTorrent, "tracker_announce", r_torrent_tracker_announce, 0);
1019
+ rb_define_method(cTorrent, "tracker_ann", r_torrent_tracker_announce, 0);
1020
+ rb_define_method(cTorrent, "piece_size", r_torrent_piece_size, 0);
1021
+ rb_define_method(cTorrent, "piece_count", r_torrent_piece_count, 0);
1022
+ rb_define_method(cTorrent, "total_size", r_torrent_total_size, 0);
1023
+ rb_define_method(cTorrent, "size", r_torrent_total_size, 0);
1024
+ rb_define_method(cTorrent, "pieces", r_torrent_pieces, 0);
1025
+ rb_define_method(cTorrent, "file_count", r_torrent_file_count, 0);
1026
+ rb_define_method(cTorrent, "files", r_torrent_files, 0);
1027
+ rb_define_method(cTorrent, "stat", r_torrent_stat, 0);
1028
+ rb_define_method(cTorrent, "download_to", r_torrent_set_folder, 1);
1029
+ rb_define_method(cTorrent, "folder", r_torrent_get_folder, 0);
1030
+ rb_define_method(cTorrent, "folder=", r_torrent_set_folder, 1);
1031
+ rb_define_method(cTorrent, "start", r_torrent_start, 0);
1032
+ rb_define_method(cTorrent, "stop", r_torrent_stop, 0);
1033
+ rb_define_method(cTorrent, "active?", r_torrent_active, 0);
1034
+ rb_define_method(cTorrent, "closed?", r_torrent_closed, 0);
1035
+ rb_define_method(cTorrent, "availability", r_torrent_availability, 1);
1036
+ rb_define_method(cTorrent, "just_finished?", r_torrent_just_finished, 0);
1037
+ }
1038
+
1039
+ /*
1040
+ * Document-class: Transmission::Torrent::FileInfo
1041
+ *
1042
+ * == Summary
1043
+ *
1044
+ * The FileInfo class containts the information about a file which is part of this torrent.
1045
+ */
1046
+ static void
1047
+ Init_fileinfo()
1048
+ {
1049
+ cFileInfo = rb_define_class_under(cTorrent, "FileInfo", rb_cObject);
1050
+ rb_define_method(cFileInfo, "name", r_file_info_name, 0);
1051
+ rb_define_method(cFileInfo, "file_name", r_file_info_name, 0);
1052
+ rb_define_method(cFileInfo, "size", r_file_info_size, 0);
1053
+ rb_define_method(cFileInfo, "length", r_file_info_size, 0);
1054
+ }
1055
+
1056
+ /*
1057
+ * Document-class: Transmission::Torrent::Stat
1058
+ *
1059
+ * == Summary
1060
+ *
1061
+ * The Stat class containts the information about the torrent.
1062
+ */
1063
+ static void
1064
+ Init_stat()
1065
+ {
1066
+ cStat = rb_define_class_under(cTorrent, "Stat", rb_cObject);
1067
+ rb_define_method(cStat, "status", r_stat_status, 0);
1068
+ rb_define_method(cStat, "error", r_stat_error, 0);
1069
+ rb_define_method(cStat, "tracker_error", r_stat_tracker_error, 0);
1070
+ rb_define_method(cStat, "progress", r_stat_progress, 0);
1071
+ rb_define_method(cStat, "rates", r_stat_rates, 0);
1072
+ rb_define_method(cStat, "down_rate", r_stat_down_rate, 0);
1073
+ rb_define_method(cStat, "up_rate", r_stat_up_rate, 0);
1074
+ rb_define_method(cStat, "eta", r_stat_eta, 0);
1075
+ rb_define_method(cStat, "peers_total", r_stat_peers_total, 0);
1076
+ rb_define_method(cStat, "peers", r_stat_peers, 0);
1077
+ rb_define_method(cStat, "up_peers", r_stat_up_peers, 0);
1078
+ rb_define_method(cStat, "down_peers", r_stat_down_peers, 0);
1079
+ rb_define_method(cStat, "seeders", r_stat_seeders, 0);
1080
+ rb_define_method(cStat, "leechers", r_stat_leechers, 0);
1081
+ rb_define_method(cStat, "downloaded", r_stat_downloaded, 0);
1082
+ rb_define_method(cStat, "uploaded", r_stat_uploaded, 0);
1083
+
1084
+ rb_define_const(cStat, "STATUS_CHECK", INT2FIX(TR_STATUS_CHECK));
1085
+ rb_define_const(cStat, "STATUS_DOWNLOAD", INT2FIX(TR_STATUS_DOWNLOAD));
1086
+ rb_define_const(cStat, "STATUS_SEED", INT2FIX(TR_STATUS_SEED));
1087
+ rb_define_const(cStat, "STATUS_STOPPING", INT2FIX(TR_STATUS_STOPPING));
1088
+ rb_define_const(cStat, "STATUS_STOPPED", INT2FIX(TR_STATUS_STOPPED));
1089
+ rb_define_const(cStat, "STATUS_PAUSE", INT2FIX(TR_STATUS_PAUSE));
1090
+ rb_define_const(cStat, "STATUS_ACTIVE", INT2FIX(TR_STATUS_ACTIVE));
1091
+ rb_define_const(cStat, "STATUS_INACTIVE", INT2FIX(TR_STATUS_INACTIVE));
1092
+
1093
+ rb_define_const(cStat, "ERR_TRACKER", INT2FIX(TR_ETRACKER));
1094
+ rb_define_const(cStat, "ERR_INOUT", INT2FIX(TR_EINOUT));
1095
+ }
1096
+
1097
+ /*
1098
+ * Document-class: Transmission
1099
+ *
1100
+ * == Summary
1101
+ *
1102
+ * The Transmission class represent a bittorrent session. You can use an instance of
1103
+ * this class to open a torrent and start its downloading process.
1104
+ */
1105
+ void
1106
+ Init_transmission()
1107
+ {
1108
+ cTransmission = rb_define_class("Transmission", rb_cObject);
1109
+
1110
+ rb_define_const(cTransmission, "VERSION", rb_obj_freeze(rb_str_new2(VERSION)));
1111
+
1112
+ rb_define_module_function(cTransmission, "pref_directory", r_transmission_pref_dir, 0);
1113
+
1114
+ rb_define_alloc_func(cTransmission, r_transmission_alloc);
1115
+ rb_define_method(cTransmission, "bind_port=", r_transmission_set_bind_port, 1);
1116
+ rb_define_method(cTransmission, "open", r_transmission_open, -1);
1117
+ rb_define_method(cTransmission, "size", r_transmission_size, 0);
1118
+ rb_define_method(cTransmission, "length", r_transmission_size, 0);
1119
+ rb_define_method(cTransmission, "each", r_transmission_each, 0);
1120
+ rb_define_method(cTransmission, "rates", r_transmission_rates, 0);
1121
+ rb_define_method(cTransmission, "upload_limit=", r_transmission_set_upload_limit, 1);
1122
+ rb_define_method(cTransmission, "download_limit=", r_transmission_set_download_limit, 1);
1123
+
1124
+ rb_include_module(cTransmission, rb_mEnumerable);
1125
+
1126
+ eTransmissionError = rb_define_class_under(cTransmission, "TransmissionError", rb_eStandardError);
1127
+ eParseError = rb_define_class_under(cTransmission, "ParseError", eTransmissionError);
1128
+ eUnsupportedError = rb_define_class_under(cTransmission, "UnsupportedError", eTransmissionError);
1129
+ eDuplicateError = rb_define_class_under(cTransmission, "DuplicateError", eTransmissionError);
1130
+ eTorrentError = rb_define_class_under(cTransmission, "TorrentError", eTransmissionError);
1131
+
1132
+ Init_torrent();
1133
+ Init_fileinfo();
1134
+ Init_stat();
1135
+ }