forked from steger/pr3-sose2026
Compare commits
No commits in common. "522fd6df17f0ee4d314acd21a37302f27582a559" and "75a37a3b8985366c92d8a0d44cff3689f9882624" have entirely different histories.
522fd6df17
...
75a37a3b89
|
|
@ -59,7 +59,7 @@ func (bhs *BaggageHandlingSystem) CollectLostBaggage() []LostBaggage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bhs *BaggageHandlingSystem) Start() {
|
func (bhs *BaggageHandlingSystem) Start() {
|
||||||
defer fmt.Println("baggage handling terminated")
|
|
||||||
select {}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package airport
|
package airport
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
@ -14,26 +13,16 @@ type Gate struct {
|
||||||
id GateNumber
|
id GateNumber
|
||||||
walkingTimeFromSecurity time.Duration
|
walkingTimeFromSecurity time.Duration
|
||||||
taxiTimeToRunway time.Duration
|
taxiTimeToRunway time.Duration
|
||||||
flights []Flight
|
//TODO: extend
|
||||||
passengerQueues map[FlightNumber]chan passengerGateData
|
|
||||||
baggageQueues map[FlightNumber]chan baggageRequest
|
|
||||||
aircraftQueues map[FlightNumber]chan *Aircraft
|
|
||||||
departSignals map[FlightNumber]chan struct{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ BaggageProcessor = &Gate{}
|
var _ BaggageProcessor = &Gate{}
|
||||||
|
|
||||||
func NewGate(id GateNumber, walkingTimeFromSecurity time.Duration, taxiTimeToRunway time.Duration) Gate {
|
func NewGate(id GateNumber, walkingTimeFromSecurity time.Duration, taxiTimeToRunway time.Duration) Gate {
|
||||||
|
|
||||||
return Gate{
|
return Gate{id,
|
||||||
id: id,
|
walkingTimeFromSecurity,
|
||||||
walkingTimeFromSecurity: walkingTimeFromSecurity,
|
taxiTimeToRunway,
|
||||||
taxiTimeToRunway: taxiTimeToRunway,
|
|
||||||
flights: []Flight{},
|
|
||||||
passengerQueues: make(map[FlightNumber]chan passengerGateData),
|
|
||||||
baggageQueues: make(map[FlightNumber]chan baggageRequest),
|
|
||||||
aircraftQueues: make(map[FlightNumber]chan *Aircraft),
|
|
||||||
departSignals: make(map[FlightNumber]chan struct{}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -50,315 +39,25 @@ func NewGates(count int) map[GateNumber]*Gate {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gate) SetFlights(flights []Flight) {
|
func (g *Gate) SetFlights(flights []Flight) {
|
||||||
g.flights = flights
|
//TODO: implement
|
||||||
if g.passengerQueues == nil {
|
|
||||||
g.passengerQueues = make(map[FlightNumber]chan passengerGateData)
|
|
||||||
}
|
|
||||||
if g.baggageQueues == nil {
|
|
||||||
g.baggageQueues = make(map[FlightNumber]chan baggageRequest)
|
|
||||||
}
|
|
||||||
if g.aircraftQueues == nil {
|
|
||||||
g.aircraftQueues = make(map[FlightNumber]chan *Aircraft)
|
|
||||||
}
|
|
||||||
if g.departSignals == nil {
|
|
||||||
g.departSignals = make(map[FlightNumber]chan struct{})
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, f := range flights {
|
|
||||||
if _, ok := g.passengerQueues[f.Id]; !ok {
|
|
||||||
g.passengerQueues[f.Id] = make(chan passengerGateData, 16)
|
|
||||||
}
|
|
||||||
if _, ok := g.baggageQueues[f.Id]; !ok {
|
|
||||||
g.baggageQueues[f.Id] = make(chan baggageRequest, 16)
|
|
||||||
}
|
|
||||||
if _, ok := g.aircraftQueues[f.Id]; !ok {
|
|
||||||
g.aircraftQueues[f.Id] = make(chan *Aircraft, 1)
|
|
||||||
}
|
|
||||||
if _, ok := g.departSignals[f.Id]; !ok {
|
|
||||||
g.departSignals[f.Id] = make(chan struct{}, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type passengerGateData struct {
|
|
||||||
p Passenger
|
|
||||||
err chan error
|
|
||||||
arrival time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
type baggageRequest struct {
|
|
||||||
b Baggage
|
|
||||||
err chan error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blocks for the walking distance to the gate + the time until the passenger has boarded
|
// Blocks for the walking distance to the gate + the time until the passenger has boarded
|
||||||
func (g *Gate) Process(passenger Passenger) error {
|
func (g *Gate) Process(passenger Passenger) error {
|
||||||
if passenger.BoardingPass == nil {
|
//TODO: implement
|
||||||
return fmt.Errorf("no boarding pass")
|
return nil
|
||||||
}
|
|
||||||
if passenger.BoardingPass.Gate != g.id {
|
|
||||||
return fmt.Errorf("invalid gate: %v", passenger.BoardingPass.Gate)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn := passenger.BoardingPass.FlightNumber
|
|
||||||
q, ok := g.passengerQueues[fn]
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("invalid flight %v", fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the flight to determine departure time
|
|
||||||
var flight Flight
|
|
||||||
found := false
|
|
||||||
for _, f := range g.flights {
|
|
||||||
if f.Id == fn {
|
|
||||||
flight = f
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
return fmt.Errorf("invalid flight %v", fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
errc := make(chan error)
|
|
||||||
|
|
||||||
// compute intended arrival time (start + walking), record before sleeping
|
|
||||||
intendedArrival := time.Now().Add(g.walkingTimeFromSecurity)
|
|
||||||
fmt.Printf("[gate %d] Process start for %s now=%v intendedArrival=%v departure=%v\n", g.id, passenger.Name, time.Now(), intendedArrival, flight.DepartureTime)
|
|
||||||
time.Sleep(g.walkingTimeFromSecurity)
|
|
||||||
fmt.Printf("[gate %d] after walking for %s now=%v intendedArrival=%v departure=%v\n", g.id, passenger.Name, time.Now(), intendedArrival, flight.DepartureTime)
|
|
||||||
|
|
||||||
// if already departed, return immediately
|
|
||||||
if intendedArrival.After(flight.DepartureTime) {
|
|
||||||
return fmt.Errorf("flight already departed")
|
|
||||||
}
|
|
||||||
|
|
||||||
// attempt to enqueue but don't block past departure time
|
|
||||||
data := passengerGateData{p: passenger, err: errc, arrival: intendedArrival}
|
|
||||||
// allow waiting until departure relative to the intended arrival time
|
|
||||||
sendTimeout := flight.DepartureTime.Sub(intendedArrival)
|
|
||||||
if sendTimeout < 0 {
|
|
||||||
sendTimeout = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("[gate %d] enqueuing passenger %s for flight %s (sendTimeout=%v)\n", g.id, passenger.Name, fn, sendTimeout)
|
|
||||||
select {
|
|
||||||
case q <- data:
|
|
||||||
// sent
|
|
||||||
case <-time.After(sendTimeout):
|
|
||||||
return fmt.Errorf("flight already departed")
|
|
||||||
}
|
|
||||||
|
|
||||||
res := <-errc
|
|
||||||
fmt.Printf("[gate %d] passenger %s processed with err=%v\n", g.id, passenger.Name, res)
|
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blocks until departure (includes taxi time to runway)
|
// Blocks until departure (includes taxi time to runway)
|
||||||
func (g *Gate) ProcessAircraft(ac *Aircraft) {
|
func (g *Gate) ProcessAircraft(ac *Aircraft) {
|
||||||
fn := ac.Flight.Id
|
//TODO: implement
|
||||||
q, ok := g.aircraftQueues[fn]
|
|
||||||
if !ok {
|
|
||||||
// nothing to do
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
q <- ac
|
|
||||||
|
|
||||||
// wait until depart signal
|
|
||||||
if sig, ok := g.departSignals[fn]; ok {
|
|
||||||
<-sig
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gate) ProcessBaggage(fn FlightNumber, b Baggage) error {
|
func (g *Gate) ProcessBaggage(fn FlightNumber, b Baggage) error {
|
||||||
q, ok := g.baggageQueues[fn]
|
//TODO: implement
|
||||||
if !ok {
|
return nil
|
||||||
return fmt.Errorf("invalid flight %v", fn)
|
|
||||||
}
|
|
||||||
// find flight for departure time
|
|
||||||
var flight Flight
|
|
||||||
found := false
|
|
||||||
for _, f := range g.flights {
|
|
||||||
if f.Id == fn {
|
|
||||||
flight = f
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
return fmt.Errorf("invalid flight %v", fn)
|
|
||||||
}
|
|
||||||
|
|
||||||
errc := make(chan error)
|
|
||||||
tLeft := time.Until(flight.DepartureTime)
|
|
||||||
if tLeft <= 0 {
|
|
||||||
return fmt.Errorf("flight already departed")
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
|
||||||
case q <- baggageRequest{b: b, err: errc}:
|
|
||||||
// sent
|
|
||||||
case <-time.After(tLeft):
|
|
||||||
return fmt.Errorf("flight already departed")
|
|
||||||
}
|
|
||||||
return <-errc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g Gate) Start() {
|
func (g Gate) Start() {
|
||||||
// start a handler for each configured flight
|
//TODO: implement
|
||||||
for _, f := range g.flights {
|
|
||||||
f := f
|
|
||||||
pCh := g.passengerQueues[f.Id]
|
|
||||||
bCh := g.baggageQueues[f.Id]
|
|
||||||
acCh := g.aircraftQueues[f.Id]
|
|
||||||
depart := g.departSignals[f.Id]
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
// wait until boarding time
|
|
||||||
fmt.Printf("[gate %d] handler starting for %s: boarding=%v departure=%v now=%v\n", g.id, f.Id, f.BoardingTime, f.DepartureTime, time.Now())
|
|
||||||
if time.Until(f.BoardingTime) > 0 {
|
|
||||||
time.Sleep(time.Until(f.BoardingTime))
|
|
||||||
}
|
|
||||||
|
|
||||||
// boarding open
|
|
||||||
departureTimer := time.NewTimer(time.Until(f.DepartureTime))
|
|
||||||
|
|
||||||
waitingPassengers := []passengerGateData{}
|
|
||||||
waitingBaggage := []Baggage{}
|
|
||||||
var aircraft *Aircraft
|
|
||||||
|
|
||||||
boarding := true
|
|
||||||
for boarding {
|
|
||||||
select {
|
|
||||||
case pg := <-pCh:
|
|
||||||
fmt.Printf("[gate %d] handler received passenger %s, aircraft=%v arrival=%v departure=%v\n", g.id, pg.p.Name, aircraft != nil, pg.arrival, f.DepartureTime)
|
|
||||||
if pg.arrival.After(f.DepartureTime) {
|
|
||||||
pg.err <- fmt.Errorf("flight already departed")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if aircraft != nil {
|
|
||||||
if err := aircraft.Process(pg.p); err != nil {
|
|
||||||
pg.err <- err
|
|
||||||
} else {
|
|
||||||
pg.err <- nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
waitingPassengers = append(waitingPassengers, pg)
|
|
||||||
}
|
|
||||||
case bd := <-bCh:
|
|
||||||
fmt.Printf("[gate %d] handler received baggage for %s, aircraft=%v\n", g.id, f.Id, aircraft != nil)
|
|
||||||
if aircraft != nil {
|
|
||||||
if err := aircraft.ProcessBaggage(f.Id, bd.b); err != nil {
|
|
||||||
bd.err <- err
|
|
||||||
} else {
|
|
||||||
bd.err <- nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
waitingBaggage = append(waitingBaggage, bd.b)
|
|
||||||
bd.err <- nil
|
|
||||||
}
|
|
||||||
case ac := <-acCh:
|
|
||||||
fmt.Printf("[gate %d] handler received aircraft %s\n", g.id, ac.Flight.Id)
|
|
||||||
aircraft = ac
|
|
||||||
// deliver waiting passengers
|
|
||||||
for _, wp := range waitingPassengers {
|
|
||||||
if time.Now().After(f.DepartureTime) {
|
|
||||||
wp.err <- fmt.Errorf("flight already departed")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err := aircraft.Process(wp.p); err != nil {
|
|
||||||
wp.err <- err
|
|
||||||
} else {
|
|
||||||
wp.err <- nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
waitingPassengers = nil
|
|
||||||
// deliver waiting baggage
|
|
||||||
for _, wb := range waitingBaggage {
|
|
||||||
aircraft.ProcessBaggage(f.Id, wb)
|
|
||||||
}
|
|
||||||
waitingBaggage = nil
|
|
||||||
case <-departureTimer.C:
|
|
||||||
fmt.Printf("[gate %d] handler departure timer fired for %s\n", g.id, f.Id)
|
|
||||||
boarding = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// boarding closed: drain any buffered messages and process those
|
|
||||||
for {
|
|
||||||
processed := false
|
|
||||||
select {
|
|
||||||
case pg := <-pCh:
|
|
||||||
processed = true
|
|
||||||
if pg.arrival.After(f.DepartureTime) {
|
|
||||||
pg.err <- fmt.Errorf("flight already departed")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if aircraft != nil {
|
|
||||||
if err := aircraft.Process(pg.p); err != nil {
|
|
||||||
pg.err <- err
|
|
||||||
} else {
|
|
||||||
pg.err <- nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
waitingPassengers = append(waitingPassengers, pg)
|
|
||||||
}
|
|
||||||
case bd := <-bCh:
|
|
||||||
processed = true
|
|
||||||
if aircraft != nil {
|
|
||||||
if err := aircraft.ProcessBaggage(f.Id, bd.b); err != nil {
|
|
||||||
bd.err <- err
|
|
||||||
} else {
|
|
||||||
bd.err <- nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
waitingBaggage = append(waitingBaggage, bd.b)
|
|
||||||
bd.err <- nil
|
|
||||||
}
|
|
||||||
case ac := <-acCh:
|
|
||||||
processed = true
|
|
||||||
aircraft = ac
|
|
||||||
// deliver waiting passengers
|
|
||||||
for _, wp := range waitingPassengers {
|
|
||||||
if wp.arrival.After(f.DepartureTime) {
|
|
||||||
wp.err <- fmt.Errorf("flight already departed")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err := aircraft.Process(wp.p); err != nil {
|
|
||||||
wp.err <- err
|
|
||||||
} else {
|
|
||||||
wp.err <- nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
waitingPassengers = nil
|
|
||||||
// deliver waiting baggage
|
|
||||||
for _, wb := range waitingBaggage {
|
|
||||||
aircraft.ProcessBaggage(f.Id, wb)
|
|
||||||
}
|
|
||||||
waitingBaggage = nil
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
if !processed {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// notify remaining waiting passengers that the flight is gone
|
|
||||||
for _, wp := range waitingPassengers {
|
|
||||||
wp.err <- fmt.Errorf("flight already departed")
|
|
||||||
}
|
|
||||||
|
|
||||||
// After boarding closed, wait taxi time then signal departure
|
|
||||||
time.Sleep(g.taxiTimeToRunway)
|
|
||||||
|
|
||||||
// signal any ProcessAircraft waiting on depart
|
|
||||||
select {
|
|
||||||
case depart <- struct{}{}:
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
close(depart)
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
package airport
|
package airport
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -9,52 +8,18 @@ var prohibitedItems = map[string]bool{"Knife": true, "Gun": true, "Explosives":
|
||||||
|
|
||||||
type SecurityCheck struct {
|
type SecurityCheck struct {
|
||||||
processingTime time.Duration
|
processingTime time.Duration
|
||||||
queue chan securityCheckData
|
//TODO: extend
|
||||||
}
|
|
||||||
|
|
||||||
type securityCheckData struct {
|
|
||||||
p Passenger
|
|
||||||
err chan error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSecurityCheck(processingTime time.Duration) SecurityCheck {
|
func NewSecurityCheck(processingTime time.Duration) SecurityCheck {
|
||||||
return SecurityCheck{
|
return SecurityCheck{
|
||||||
processingTime: processingTime,
|
processingTime: processingTime,
|
||||||
queue: make(chan securityCheckData),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// processes one passenger at a time. Each passenger must at least spend the processingTime at the security check
|
// processes one passenger at a time. Each passenger must at least spend the processingTime at the security check
|
||||||
func (sc *SecurityCheck) Start() {
|
func (sc *SecurityCheck) Start() {
|
||||||
defer fmt.Println("security terminated")
|
//TODO: implement
|
||||||
for el := range sc.queue {
|
|
||||||
|
|
||||||
time.Sleep(sc.processingTime)
|
|
||||||
|
|
||||||
if el.p.BoardingPass == nil {
|
|
||||||
el.err <- fmt.Errorf("no boarding pass")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if el.p.Name != el.p.BoardingPass.Name {
|
|
||||||
el.err <- fmt.Errorf("boarding pass does not match passenger name")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
prohibited := false
|
|
||||||
for _, item := range el.p.CarryOnItems {
|
|
||||||
if prohibitedItems[item] {
|
|
||||||
el.err <- fmt.Errorf("prohibited item detected: %v", item)
|
|
||||||
prohibited = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if prohibited {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
el.err <- nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns an error if
|
// returns an error if
|
||||||
|
|
@ -62,7 +27,6 @@ func (sc *SecurityCheck) Start() {
|
||||||
// - the passenger's boardings pass does not match the name
|
// - the passenger's boardings pass does not match the name
|
||||||
// - the passenger carries a prohibited item
|
// - the passenger carries a prohibited item
|
||||||
func (sc SecurityCheck) Process(p Passenger) error {
|
func (sc SecurityCheck) Process(p Passenger) error {
|
||||||
errc := make(chan error)
|
//TODO: implement
|
||||||
sc.queue <- securityCheckData{p: p, err: errc}
|
return nil
|
||||||
return <-errc
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue