+# Push notification
+
+# Benitlux push notification interface
+class BenitluxPushAction
+ super BenitluxAction
+
+ # Intercept the full answer to set aside the connection and complete it later
+ redef fun prepare_respond_and_close(request, turi, connection)
+ do
+ var token = request.string_arg("token")
+
+ var user = db.token_to_id(token)
+ if user == null then
+ # Report errors right away
+ var response = new HttpResponse.invalid_token
+ connection.respond response
+ connection.close
+ return
+ end
+
+ # Set aside the connection
+ push_connections[user] = connection
+ end
+end
+
+redef class Sys
+ # Connections left open for a push notification, organized per user id
+ private var push_connections = new Map[Int, HttpServer]
+end
+
+# ---
+# Administration
+
+# Path to the secret used to authenticate admin requests
+fun secret_path: String do return "benitlux.secret"
+
+# Services reserved to administrators
+class BenitluxAdminAction
+ super BenitluxAction
+ super RestfulAction
+
+ private fun server_secret: String do return secret_path.to_path.read_all
+
+ # Trigger sending daily menu to connected clients
+ #
+ # This should usually be called by an external cron program.
+ # send_daily_updates?secret=shared_secret -> true | BenitluxError
+ fun send_daily_updates(secret: nullable String): HttpResponse
+ is restful do
+ # Check secrets
+ var server_secret = server_secret
+ if server_secret.is_empty then
+ print_error "The admin interface needs a secret at '{secret_path}'"
+ return new HttpResponse.server_error
+ end
+
+ if server_secret != secret then
+ return new HttpResponse.invalid_token
+ end
+
+ # Load beer menu
+ var list = db.list_beers_and_rating
+ if list == null then return new HttpResponse.server_error
+
+ var msg = new DailyNotification(list)
+
+ # Broadcast updates
+ for conn in push_connections.values.to_a do
+ if not conn.closed then
+ conn.respond new HttpResponse.ok(msg)
+ conn.close
+ end
+ end
+ push_connections.clear
+
+ return new HttpResponse.ok(true)
+ end
+
+ redef fun answer(request, turi) do return new HttpResponse.bad_request
+end
+
+# ---