File Coverage

blib/lib/Mirror/JSON.pm
Criterion Covered Total %
statement 23 25 92.0
branch 2 4 50.0
condition n/a
subroutine 8 8 100.0
pod 0 2 0.0
total 33 39 84.6


line stmt bran cond sub pod time code
1             package Mirror::JSON;
2              
3 3     3   93924 use 5.006;
  3         13  
  3         172  
4 3     3   18 use strict;
  3         6  
  3         176  
5 3     3   2177 use Mirror::URI ();
  3         10  
  3         71  
6 3     3   12767 use JSON ();
  3         70820  
  3         152  
7              
8 3     3   27 use vars qw{$VERSION @ISA};
  3         7  
  3         324  
9             BEGIN {
10 3     3   8 $VERSION = '0.90';
11 3         693 @ISA = 'Mirror::URI';
12             }
13              
14              
15              
16              
17              
18             #####################################################################
19             # Implementation-Specific Methods
20              
21             sub filename {
22 2     2 0 10 return 'mirror.json';
23             }
24              
25             sub parse {
26 2     2 0 4 my $class = shift;
27              
28             # Make sure we actually have a YAML document
29 2 50       19 unless ( $_[0] =~ /^{/ ) {
30 0         0 return undef;
31             }
32              
33             # Parse the file
34 2         19 my $docs = JSON::from_json($_[0]);
35              
36             # We only care about the first document
37 2 50       273 unless ( defined $docs ) {
38 0         0 Carp::croak("Illegal JSON document");
39             }
40              
41 2         10 return $docs;
42             }
43              
44             1;
45              
46             =pod
47              
48             =head1 NAME
49              
50             Mirror::JSON - Mirror Configuration and Auto-Discovery
51              
52             =head1 DESCRIPTION
53              
54             A C file is used to allow a repository client to reliably and
55             robustly locate, identify, validate and age a repository.
56              
57             It contains a timestamp for when the repository was last updated, the URI
58             for the master repository, and a list of all the current mirrors at the
59             time the repository was last updated.
60              
61             B contains all the functionality requires to both create
62             and read the F files, and the logic to select one or more
63             mirrors entirely automatically.
64              
65             It currently scales cleanly for a dozen or so mirrors, but may be slow
66             when used with very large repositories with a hundred or more mirrors.
67              
68             =head2 Methodology
69              
70             A variety of simple individual mechanisms are combined to provide a
71             completely robust discovery and validation system.
72              
73             B
74              
75             The F file should exist in a standard location, typically at
76             the root of the repository. The file is very small (no more than a few
77             kilobytes at most) so the overhead of fetching one (or several) of them
78             is negligable.
79              
80             The file is pulled via FTP or HTTP. Once pulled, the first three
81             characters are examined to validate it is a JSON file and not a
82             login page for a "captured hotspot" such as at hotels and airports.
83              
84             B
85              
86             Because the F file is small (in simple cases only one or two
87             packets) the download time can be used to measure the responsiveness of
88             that mirror.
89              
90             By pulling the files from several mirrors, the comparative download
91             times can be used as part of the process of selecting the fastest mirror.
92              
93             B
94              
95             The mirror.json file contains a timestamp that records the last update time
96             for the repository. This timestamp should be updated every repository
97             update cycle, even if there are no actual changes to the repository.
98              
99             Once a F file has been fetched correctly, the timestamp can
100             then be used to verify the age of the mirror. Whereas a perfectly up to
101             date mirror will show an age of less than an hour (assuming that the
102             repository master updates every hour) a repository that has stopped
103             updating will show an age that is greater than the longest mirror rate
104             plus the update cycle time.
105              
106             Thus, any mirror that as "gone stale" can be filter out of the potential
107             mirrors to use.
108              
109             For portability, the timestamp is recording in ISO format Zulu time.
110              
111             B
112              
113             The F file contains a link to the master repository.
114              
115             If the L client has an out-of-date current state at some
116             point, it will use the master repository URI in the current state to
117             pull a fresh F from the master repository.
118              
119             This solves the most-simple case, but other cases require a little
120             more complexity (which we'll address later).
121              
122             B
123              
124             The F file contains a simple list of all mirror URIs.
125              
126             Apart from filtering the list to try and find the best mirror to use,
127             the mirror list allows the B client to have backup
128             options for locating the master repository if it moves, or the
129             bootstrap F file has gotten old.
130              
131             If the client can't find the master repository (because it has moved)
132             the client will scan the list of mirrors to try to find the location
133             of the updated repository.
134              
135             B
136              
137             To bootstrap the client, it should come with a default bootstrap
138             F file built into it. When the client starts up for the
139             first time, it will attempt to fetch an updated mirror.json from the
140             master repository, and if that doesn't exist will pull from the
141             default list of mirrors until it can find more than one up to date
142             mirror that agrees on the real location of the master server.
143              
144             B
145              
146             On top of the straight forward mirror discovery functionality, the
147             client algorithm contains additional logic to deal with either a
148             mirror or the master server goes bad. While likely not 100% secure
149             it heads off several attack scenarios to prevent anyone trying them,
150             and provides as much as can be expected without resorting to cryto
151             and certificates.
152              
153             =head1 SUPPORT
154              
155             Bugs should be reported via the CPAN bug tracker at
156              
157             L
158              
159             For other issues, or commercial enhancement or support, contact the author.
160              
161             =head1 AUTHOR
162              
163             Adam Kennedy Eadamk@cpan.orgE
164              
165             =head1 SEE ALSO
166              
167             L, L, L
168              
169             =head1 COPYRIGHT
170              
171             Copyright 2007 - 2009 Adam Kennedy.
172              
173             This program is free software; you can redistribute
174             it and/or modify it under the same terms as Perl itself.
175              
176             The full text of the license can be found in the
177             LICENSE file included with this module.
178              
179             =cut