Wie mag er verbinding maken? · eindproject
Eindproject: Project: scorebord v3
Alleen de houder van het token kan nu scoren, en het token wordt gecontroleerd vóór 101. Eén regel uit versie één staat nog: als een scorebijhouder iets stuurt wat geen geldige score is, sluit scorekeeper_handler de verbinding met 1008 en "that was not a valid score". Draai de demo voordat je iets verandert, en de sectie van les 5 eindigt precies zo:
Lesson 5: the scorekeeper's mistakes
then the connection was closed with [(1008, 'that was not a valid score')]
De scorebijhouder van de demo stuurde eerst 11 punten, en daarmee was zijn gesprek voorbij. Dit project maakt scorebord v3 af: fouten krijgen antwoorden in plaats van een gesloten verbinding, en het token wordt nergens herhaald.
Eisen
Scorebord v3, zoals je het aan het eind van deze les achterlaat:
Scores komen alleen van de houder van het token, gecontroleerd vóór
101door de hook uit les 3. Kijkers hebben geen token nodig.error_message(board, reason)geeft{"type": "error", "version": <the board's current version>, "reason": reason}terug, met op de plek van de placeholder de huidige versie van het bord. Hij leestboard["version"]terwijl hijboard["lock"]vasthoudt, zoals elke andere leesactie van het bord.scorekeeper_handlerbeantwoordt elkemet een error-envelop en blijft lezen. EenValueErrorkan van drie plekken komen:parse_message, voor een binair bericht, tekst die geenis of een ongeldige envelop; de typecontrole, voor een geldige envelop die geen scoreis; enapply_score, voor een team dat het bord niet heeft. De reden isstr(exc), de melding van de exception.Al het andere blijft: hoogstens
MAX_SCORE_MESSAGESberichten, de ongeldige meegeteld;recv(timeout=WAIT), met een close1000en"no score arrived in time"als er niets binnenkomt; een geldige score beantwoord met de nieuwe snapshot; een stille terugkeer bijConnectionClosed;1000zodra de limiet is bereikt.Geen enkel antwoord, geen envelop, geen sluitreden en geen afgedrukte regel bevat het token.
De main van hoofdstuk 10 bouwt de server met open_server(board, read_token("token.txt")), dus alles hierboven is wat een draaiend scorebord doet.
De scorebijhouder stuurt 11 punten terwijl het bord op versie 5 staat. Wat komt er terug?
Fouten zijn nu berichten
Een scorebijhouder is een persoon achter een toetsenbord, of een pagina die die persoon gebruikt, en mensen tikken verkeerd. Onder versie één kostte een getypte 11 de scorebijhouder zijn verbinding: zijn pagina moest de close opmerken, opnieuw verbinding maken, het token opnieuw sturen en het nog eens proberen, en de sluitreden alleen zei niets over welk deel fout was. Een error-envelop houdt het gesprek gaande en zegt in zijn reden wat er fout was, en het volgende bericht van de scorebijhouder wordt gelezen alsof er niets gebeurd is. Het bord verandert niet, dus kijkers horen er niets over: een error gaat alleen naar de scorebijhouder.
De envelop draagt de versie van het bord, zodat de client kan zien over welk bord de weigering gaat. Een scorebijhouderspagina die “rejected at version 5” toont naast een bord dat ze voor het laatst op versie 5 zag, weet dat haar beeld actueel is; bij versie 7 weet ze dat er tussendoor andere scores binnenkwamen.
Redenen zijn voor mensen geschreven. str(exc) is wat de exception ook zei, en voor tekst die geen JSON is, is dat de eigen melding van de JSON-parser, Expecting value: line 1 column 1 (char 0), die klopt maar niet vriendelijk is. Dat is voor deze cursus acceptabel: geen enkel programma hoort een reden te parsen, en het type en de version zijn waar een client op handelt.
In scorekeeper_handler sluit de clausule except ValueError niet meer en keert ze niet meer terug. Geef de exception erin een naam, except ValueError as exc:, maak daar van reply de error-envelop en in de try een snapshot, en stuur reply na het try-statement, één keer, welke van de twee het ook is.
Herhaal nooit een geheim
Het token reist in een header of in de query, en beide bereiken code die je schrijft. Een antwoord dat een deel van een verzoek herhaalt, kan het token herhalen in de logs van de client, de logs van de server, of op een scherm dat iemand filmt. De regel: geen enkel antwoord, geen envelop, geen sluitreden en geen afgedrukte regel bevat het token. In de praktijk:
de body van de
401is de vaste tekst uit les 3;de reden van een error komt uit de
ValueError, nooit uitconnection.request;geen
printvan een pad of header, ook niet tijdens het debuggen, want het pad van een scorebijhouder die zijn token in de query stuurde, bevat het token. De eigen logging van de bibliotheek op debugniveau schrijft de verzoekregel en de headers, token inbegrepen; deze cursus zet die nooit aan, en een echte server hoort haar uit te laten.
Welke hiervan zou het token kunnen herhalen?
Je opdracht
Schrijf in scoreboard_server.py error_message(board, reason) en herschrijf scorekeeper_handler volgens de eisen hierboven. Laat elke andere
Klik op Run. De sectie van les 5 geeft een stand-in-scorebijhouder vier berichten: 11 punten, de tekst not json, een score voor een team met de naam Bats, dat niet op het bord van de demo staat, en een geldige score van 2 voor Owls. Een afgemaakte versie, op de site uitgevoerd, drukte af:
Lesson 5: the scorekeeper's mistakes
the scorekeeper was sent {'type': 'error', 'version': 0, 'reason': 'points must be a whole number from 1 to 10'}
the scorekeeper was sent {'type': 'error', 'version': 0, 'reason': 'Expecting value: line 1 column 1 (char 0)'}
the scorekeeper was sent {'type': 'error', 'version': 0, 'reason': 'unknown team'}
the scorekeeper was sent {'type': 'snapshot', 'version': 1, 'scores': {'Owls': 2, 'Foxes': 0}}
then the connection was closed with [(1000, 'no score arrived in time')]
Drie errors op versie 0, omdat er niets veranderde, en daarna de snapshot van de geldige score op versie 1. De verbinding bleef open tijdens alle vier; ze sloot pas toen de stand-in niets meer te sturen had en recv een time-out kreeg.
Klik daarna op Submit. Scorebord v3 is functioneel compleet. Het eindproject maakt er een programma van met een geschreven contract en een
Opdracht
In scoreboard_server.py:
Schrijf
error_message(board, reason): lees binnenwith board["lock"]:board["version"]; geef{"type": "error", "version": version, "reason": reason}terug.Herschrijf
scorekeeper_handler(connection, board). Houd de limiet vanMAX_SCORE_MESSAGESberichten (een ongeldig bericht telt mee),recv(timeout=WAIT)metconnection.close(1000, "no score arrived in time")bijTimeoutError, de laatsteclose(1000, ...)bij de limiet, en de stille terugkeer bijConnectionClosed. Verander alleen wat eendoet: vang hem als except ValueError as exc:, zetreply = error_message(board, str(exc)), en stuurreplymetscoreboard_messages.encode_message, precies zoals de snapshot van een geldige score wordt gestuurd. Sluit de verbinding niet bij een fout.Laat de
van les 2 en les 3 en alles uit hoofdstuk 8 zoals ze zijn.
Klik op Run: de sectie van les 5 drukt drie error-enveloppen op versie 0 af, een snapshot op versie 1, en een close met 1000.
Klik daarna op Submit. De controle draait de controles van les 2 en les 3 opnieuw, met een token dat je nog niet hebt gezien, en controleert dat de outbox en de kijker uit hoofdstuk 8 nog werken. Daarna registreert ze twee kijkers en geeft ze je scorekeeper_handler tien berichten, beginnend op een bord met een versie boven 0: 11 punten, tekst die geen error-envelop, een score voor een team dat het bord niet heeft, een geldige score, punten true, een snapshot-envelop, nog een geldige score, en een JSON-error-envelop krijgen met de huidige versie van het bord en een reden die niet leeg is; het bord en de outboxen van de kijkers mogen alleen veranderen voor de twee geldige scores, die hun snapshots krijgen; de handler moet tien berichten lezen, niet het elfde, en één keer sluiten met 1000. Het pad van de scorebijhouder bevat het token in zijn query, en het token mag in niets voorkomen wat wordt verstuurd, in geen sluitreden en in geen afgedrukte regel. Om zonder threads te draaien, vervangt de controle scoreboard_server.threading door haar eigen locks en events, dus houd import threading en maak locks alleen binnen functies, zoals make_board en make_outbox doen. Elke redentekst is prima.