Parcourir la source

Track which job has been given to which participant, through participant UUID

Baptiste Jonglez il y a 10 ans
Parent
commit
2a3e919b8c
3 fichiers modifiés avec 55 ajouts et 39 suppressions
  1. 46 32
      peerfinder.py
  2. 7 5
      scripts/run.sh
  3. 2 2
      templates/results.html

+ 46 - 32
peerfinder.py

@@ -50,6 +50,14 @@ class Target(db.Model):
         return str(self.get_ip())
 
 
+# Many-to-many table to record which target has been given to which
+# participant.
+handled_targets = db.Table('handled_targets',
+    db.Column('target_id', db.Integer, db.ForeignKey('target.id')),
+    db.Column('participant_id', db.Integer, db.ForeignKey('participant.id'))
+)
+
+
 class Participant(db.Model):
     """Participant in the ping network"""
     id = db.Column(db.Integer, primary_key=True)
@@ -61,6 +69,11 @@ class Participant(db.Model):
     contact = db.Column(db.String)
     # Whether we accept this participant or not
     active = db.Column(db.Boolean)
+    # Many-to-many relationship
+    targets = db.relationship('Target',
+        secondary=handled_targets,
+        backref=db.backref('participants', lazy='dynamic'),
+        lazy='dynamic')
 
     def __init__(self, name, contact):
         self.uuid = str(uuid4())
@@ -78,19 +91,18 @@ class Result(db.Model):
     target_id = db.Column(db.Integer, db.ForeignKey('target.id'))
     target = db.relationship('Target',
                              backref=db.backref('results', lazy='dynamic'))
-    # Participant
-    source_id = db.Column(db.Integer, db.ForeignKey('participant.id'))
-    source = db.relationship('Participant',
-                             backref=db.backref('results', lazy='dynamic'))
+    participant_id = db.Column(db.Integer, db.ForeignKey('participant.id'))
+    participant = db.relationship('Participant',
+                                  backref=db.backref('results', lazy='dynamic'))
     # In milliseconds
     rtt = db.Column(db.Float)
 
-    def __init__(self, target_id, source_uuid, rtt):
+    def __init__(self, target_id, participant_uuid, rtt):
         target = Target.query.get_or_404(int(target_id))
-        source = Participant.query.filter_by(uuid=source_uuid,
-                                             active=True).first_or_404()
+        participant = Participant.query.filter_by(uuid=participant_uuid,
+                                                  active=True).first_or_404()
         self.target = target
-        self.source = source
+        self.participant = participant
         self.rtt = float(rtt)
 
 
@@ -122,32 +134,34 @@ def create_participant():
     else:
         return "Invalid arguments"
 
-@app.route('/targets/all')
-def get_jobs():
-    """"List of targets to ping"""
-    targets = Target.query.order_by('-id').all()
-    return "\n".join("{} {}".format(t.id, t) for t in targets)
-
-@app.route('/targets/ipv4')
-def get_v4jobs():
-    """"List of IPv4 targets to ping"""
-    targets = Target.query.order_by('-id').all()
-    return "\n".join("{} {}".format(t.id, t) for t in targets if t.is_v4())
-
-@app.route('/targets/ipv6')
-def get_v6jobs():
-    """"List of IPv6 targets to ping"""
-    targets = Target.query.order_by('-id').all()
-    return "\n".join("{} {}".format(t.id, t) for t in targets if t.is_v6())
-
-@app.route('/result/report', methods=['POST'])
-def report_result():
-    if {'rtt', 'target', 'source'}.issubset(request.form):
-        target = request.form['target']
+@app.route('/target/<uuid>')
+def get_next_target(uuid):
+    """"Returns the next target to ping for the given participant"""
+    participant = Participant.query.filter_by(uuid=uuid, active=True).first_or_404()
+    # We want to get all targets that do not have a relationship with the
+    # given participant.  Note that the following lines manipulate SQL
+    # queries, which are only executed at the very end.
+    # This gives all targets that have already been sent to the given
+    # participant.
+    already_done = Target.query.join(handled_targets).filter_by(participant_id=participant.id).with_entities(Target.id)
+    # This takes the negation of the previous set.
+    todo = Target.query.filter(~Target.id.in_(already_done))
+    target = todo.first()
+    if target is not None:
+        return "{} {}".format(target.id, target)
+    else:
+        return ""
+
+@app.route('/result/report/<uuid>', methods=['POST'])
+def report_result(uuid):
+    if {'rtt', 'target'}.issubset(request.form):
+        target_id = request.form['target']
         rtt = request.form['rtt']
-        source_uuid = request.form['source']
-        result = Result(target, source_uuid, rtt)
+        result = Result(target_id, uuid, rtt)
         db.session.add(result)
+        # Record that the participant has returned a result
+        participant = result.participant
+        participant.targets.append(result.target)
         db.session.commit()
         return "OK\n"
     else:

+ 7 - 5
scripts/run.sh

@@ -1,7 +1,7 @@
 #!/bin/bash
 
-# Put your UUID here
-SOURCE="00000000-0000-0000-0000-000000000000"
+# Put your UUID here, and keep it secret!
+UUID="00000000-0000-0000-0000-000000000000"
 PEERFINDER="http://172.23.184.112:8888"
 NB_PINGS=5
 SLEEP=20
@@ -13,12 +13,14 @@ SLEEP=20
 while :
 do
     sleep "$SLEEP"
-    curl "$PEERFINDER"/targets/"$FAMILY" > /tmp/"$FAMILY" 2> /dev/null
+    curl "$PEERFINDER"/target/"$UUID" > /tmp/"$FAMILY" 2> /dev/null
     read -r id ip < /tmp/"$FAMILY"
-    echo "$id $ip"
+    # Avoid empty fields
     [ -z "$id" -o -z "$ip" ] && continue
+    # Make sure "id" is an integer
+    printf "%d" "$id" > /dev/null 2>&1 || continue
     rtt="$($PING -c "$NB_PINGS" "$ip" | grep rtt | cut -d '/' -f 5)"
     [ -z "$rtt" ] && continue
     echo "RTT to target $id ($ip) is $rtt"
-    curl -d "target=${id}&source=${SOURCE}&rtt=${rtt}" "$PEERFINDER"/result/report
+    curl -d "target=${id}&rtt=${rtt}" "$PEERFINDER"/result/report/"$UUID"
 done

+ 2 - 2
templates/results.html

@@ -9,8 +9,8 @@ Latencies to {{ target }}
   </tr>
   {% for r in results %}
   <tr>
-    <td>{{ r.source.name }}</td>
-    <td>{{ r.source.contact }}</td>
+    <td>{{ r.participant.name }}</td>
+    <td>{{ r.participant.contact }}</td>
     <td>{{ r.rtt }} ms</td>
     <td></td>
   </tr>