// // GET: /Admin/Scoreboard/ public ActionResult Scoreboard() { if (!estaLoggeado()) { guardarParams(Pagina.LOGIN, Pagina.ADMIN_SCOREBOARD); return(RedirectTo(Pagina.LOGIN)); } if (!esAdmin()) { return(RedirectTo(Pagina.ERROR, 401)); } List <OmegaUp> status = OmegaUp.obtenerInstrucciones(OmegaUp.Instruccion.STATUS); ViewBag.polls = OmegaUp.obtenerInstrucciones(); ViewBag.status = status; ViewBag.hide = OmegaUp.obtenerInstrucciones(OmegaUp.Instruccion.HIDE); if (status.Count == 0) { OmegaUp.RunnerStarted = false; } return(View()); }
// // GET: /Admin/KillScoreboard/ public ActionResult KillScoreboard() { if (!esAdmin()) { return(RedirectTo(Pagina.ERROR, 401)); } OmegaUp.nuevaInstruccion(OmegaUp.Instruccion.KILL, true); return(RedirectTo(Pagina.ADMIN_SCOREBOARD)); }
// // GET: /Admin/StartScoreboard/ public ActionResult StartScoreboard() { if (!esAdmin()) { return(RedirectTo(Pagina.ERROR, 401)); } OmegaUp.StartScoreboard(); OmegaUp.RunnerStarted = true; return(RedirectTo(Pagina.ADMIN_SCOREBOARD)); }
public JsonResult ResultadosAjax(string clave, TipoOlimpiada tipo, long ticks, bool retry) { Olimpiada o = Olimpiada.obtenerOlimpiadaConClave(clave, tipo); if (o == null) { return(Json(ERROR)); } OmegaUp ou = o.calculateCachedResults(); ScoreboardAjax ajax = new ScoreboardAjax(); if (ou == null || !OmegaUp.RunnerStarted) { ajax.status = ScoreboardAjax.Status.ERROR.ToString(); return(Json(ajax)); } ajax.timeToFinish = ou.getRemainingContestTime(); if (ajax.timeToFinish == 0) { ajax.resultados = o.cachedResults; ajax.status = ScoreboardAjax.Status.FINISHED.ToString(); return(Json(ajax)); } // Retry es verdadero cuando le mandamos 0 problemas al cliente // en ese caso, es probable que necesitemos recagar los objetos // olimpiada de la base de datos if (retry) { ajax.retry = o.shouldReload(ou.dia); ajax.status = ScoreboardAjax.Status.NOT_CHANGED.ToString(); return(Json(ajax)); } if (ou.timestamp.Ticks == ticks) { ajax.status = ScoreboardAjax.Status.NOT_CHANGED.ToString(); } else { ajax.ticks = ou.timestamp.Ticks.ToString(); ajax.status = ScoreboardAjax.Status.UPDATED.ToString(); ajax.resultados = o.cachedResults; ajax.secondsSinceUpdate = (int)Math.Round((decimal)(DateTime.UtcNow.Ticks - ou.timestamp.Ticks) / TimeSpan.TicksPerSecond); } return(Json(ajax)); }
private void poll(OmegaUp instruccion) { #if DEBUG if (WebRequest.ScoreboardManager.Instance.Update(instruccion, mock: true)) #else if (WebRequest.ScoreboardManager.Instance.Update(instruccion)) #endif { instruccion.status = OmegaUp.Status.OK; } else { instruccion.status = OmegaUp.Status.ERROR; } instruccion.guardar(); }
/// <summary> /// Función para ayudar a testear OmegaUp /// </summary> private void cambiaValoresMock(OmegaUp pull, Dictionary <string, object> mockScoreboard, bool inicializa = false) { ArrayList problemas = (ArrayList)mockScoreboard[PROBLEMAS_STRING]; ArrayList ranking = (ArrayList)mockScoreboard[RANKING_STRING]; Random r = new Random(); foreach (Dictionary <string, object> persona in ranking) { string usuario = (string)persona[USERNAME_STRING]; if (usuario.IndexOf(pull.prefijo) != 0) { continue; } usuario = usuario.Substring(pull.prefijo.Length); ArrayList resultadosUsuario = (ArrayList)persona[PROBLEMAS_STRING]; foreach (Dictionary <string, object> problema in resultadosUsuario) { if (inicializa) { problema[RUNS_STRING] = 0; problema[POINTS_STRING] = 0; } else { if (r.Next(10) < 2) { int newPoints = r.Next(101); if ((int)problema[POINTS_STRING] < newPoints) { problema[POINTS_STRING] = newPoints; } else { if (r.Next(10) < 4) { problema[POINTS_STRING] = newPoints; } } problema[RUNS_STRING] = (int)problema[RUNS_STRING] + 1; } } } } }
private OmegaUp setStatus(OmegaUp instruccion = null, OmegaUp.Status status = OmegaUp.Status.OK) { if (instruccion == null) { instruccion = new OmegaUp(); instruccion.instruccion = OmegaUp.Instruccion.STATUS; instruccion.status = status; instruccion.guardarNuevo(); return(OmegaUp.obtenerInstrucciones(OmegaUp.Instruccion.STATUS)[0]); } instruccion.status = status; instruccion.guardar(); return(instruccion); }
/// <summary> /// Regresa el diccionario si tuvo éxito o null si hubo algún error /// </summary> public static Dictionary <string, object> Call(OmegaUp pull, int intentos = 0) { // Primero hacemos el request a OmegaUp string api = String.Format(OMEGAUP_API, pull.concurso, pull.token); Dictionary <string, object> resultados; HttpWebRequest request = (HttpWebRequest)System.Net.WebRequest.Create(api); request.Method = "GET"; request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"; request.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip; try { Log.add(Log.TipoLog.OMEGAUP, "Consultando el scoreboard en OmegaUp para " + pull.tipoOlimpiada.ToString() + " " + pull.olimpiada); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); string content = string.Empty; using (Stream stream = response.GetResponseStream()) { using (StreamReader sr = new StreamReader(stream)) { content = sr.ReadToEnd(); } } Log.add(Log.TipoLog.OMEGAUP, "Se obtuvieron los resultados correctamente, se procede a guardarlos en la base de datos..."); return(resultados = new JavaScriptSerializer().Deserialize <Dictionary <string, object> >(content)); } catch (Exception e) { Log.add(Log.TipoLog.OMEGAUP, "Falló la llamada a: " + api); if (intentos >= MAX_INTENTOS) { Log.add(Log.TipoLog.OMEGAUP, "Giving up... Callstack:"); Log.add(Log.TipoLog.OMEGAUP, e.ToString()); return(null); } else { Log.add(Log.TipoLog.OMEGAUP, "Durmiendo " + RETRY_SLEEP + " segundos e intentando otra vez... "); System.Threading.Thread.Sleep(RETRY_SLEEP * 1000); return(Call(pull, intentos + 1)); } } }
static void Main(string[] args) { #if DEBUG Log.ToConsole = true; #endif CultureInfo culture = new CultureInfo("es-MX"); Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = culture; Acceso.CADENA_CONEXION = ConfigurationManager.AppSettings["conexion"]; OmegaUp.startTimestampsForPolls(); ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(AlwaysGoodCertificate); ServicePointManager.Expect100Continue = true; ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; new Program().Run(); }
// // GET: /Admin/ResetOMI/ public ActionResult ResetOMI() { if (!esAdmin()) { return(RedirectTo(Pagina.ERROR, 401)); } Olimpiada.resetOMIs(TipoOlimpiada.OMI); Olimpiada.resetOMIs(TipoOlimpiada.OMIS); Olimpiada.resetOMIs(TipoOlimpiada.OMIP); Olimpiada.resetOMIs(TipoOlimpiada.OMIPO); Olimpiada.resetOMIs(TipoOlimpiada.OMISO); List <OmegaUp> status = OmegaUp.obtenerInstrucciones(OmegaUp.Instruccion.STATUS); OmegaUp.RunnerStarted = (status.Count > 0); return(RedirectTo(Pagina.ADMIN_SCOREBOARD)); }
// // GET: /Admin/BorrarScoreboard/ public ActionResult BorrarScoreboard(int clave = 0) { if (!esAdmin()) { return(RedirectTo(Pagina.ERROR, 401)); } if (clave == 0) { OmegaUp.borrarTodo(); Olimpiada.resetOMIs(TipoOlimpiada.OMI); Olimpiada.resetOMIs(TipoOlimpiada.OMIS); Olimpiada.resetOMIs(TipoOlimpiada.OMIP); OmegaUp.RunnerStarted = false; } else { OmegaUp om = OmegaUp.obtenerConClave(clave); OmegaUp.borrarConClave(clave); if (om.instruccion == OmegaUp.Instruccion.POLL) { OmegaUp om2 = OmegaUp.obtenerParaOMI(om.olimpiada, om.tipoOlimpiada); if (om2 == null) { Olimpiada o = Olimpiada.obtenerOlimpiadaConClave(om.olimpiada, om.tipoOlimpiada); o.liveResults = false; } } else if (om.instruccion == OmegaUp.Instruccion.KILL) { OmegaUp.RunnerStarted = false; } } return(RedirectTo(Pagina.ADMIN_SCOREBOARD)); }
private bool hayOtroActivo() { List <OmegaUp> status = OmegaUp.obtenerInstrucciones(OmegaUp.Instruccion.STATUS); foreach (OmegaUp i in status) { if (i.status == OmegaUp.Status.OK) { #if DEBUG // Para facilitar depuración, en caso de que haya algo corriendo lo matamos i.borrar(); return(false); #else return(true); #endif } // Si hay algo vivo que no era status, lo borramos para que no haga ruido i.borrar(); } return(false); }
public ActionResult Scoreboard(OmegaUp poll) { if (!esAdmin()) { return(RedirectTo(Pagina.ERROR, 401)); } poll.instruccion = OmegaUp.Instruccion.POLL; poll.guardarNuevo(); Olimpiada o = Olimpiada.obtenerOlimpiadaConClave(poll.olimpiada, poll.tipoOlimpiada); if (o != null) { o.liveResults = true; if (o.esOnline) { OmegaUp.nuevaInstruccion(OmegaUp.Instruccion.HIDE, true); } } return(RedirectTo(Pagina.ADMIN_SCOREBOARD)); }
private string getClaveScoreBoard(OmegaUp pull) { return(pull.tipoOlimpiada.ToString() + "_" + pull.olimpiada); }
/// <summary> /// Regresa true si se tuvo éxito o falso si no /// </summary> public bool Update(OmegaUp pull, bool mock = false) { Dictionary <string, object> resultados = null; if (mock) { if (mockScoreboards == null) { mockScoreboards = new Dictionary <string, Dictionary <string, object> >(); } Dictionary <string, object> mockScoreboard = null; mockScoreboards.TryGetValue(pull.tipoOlimpiada.ToString(), out mockScoreboard); if (mockScoreboard == null) { Console.WriteLine("Estamos haciendo mock... presiona ENTER para comenzar"); Console.ReadLine(); mockScoreboard = Request.Call(pull); cambiaValoresMock(pull, mockScoreboard, true); mockScoreboards.Add(pull.tipoOlimpiada.ToString(), mockScoreboard); } else { cambiaValoresMock(pull, mockScoreboard); } resultados = mockScoreboard; } else { resultados = Request.Call(pull); } // Si recibimos null, hubo un error llamando a OmegaUp if (resultados == null) { return(false); } // Luego parseamos los datos del json Scoreboard scoreboard; try { // Sacamos el número de problemas del response de OmegaUp ArrayList problemas = (ArrayList)resultados[PROBLEMAS_STRING]; if (!scoreboards.TryGetValue(getClaveScoreBoard(pull), out scoreboard)) { scoreboard = new Scoreboard(pull.olimpiada, pull.tipoOlimpiada, pull.dia, problemas.Count); scoreboards.Add(getClaveScoreBoard(pull), scoreboard); } ArrayList ranking = (ArrayList)resultados[RANKING_STRING]; Log.add(Log.TipoLog.OMEGAUP, "Guardando los resultados en la base"); foreach (Dictionary <string, object> persona in ranking) { string usuario = (string)persona[USERNAME_STRING]; if (usuario.IndexOf(pull.prefijo) != 0) { continue; } usuario = usuario.Substring(pull.prefijo.Length); decimal?[] puntos = new decimal?[problemas.Count]; ArrayList resultadosUsuario = (ArrayList)persona[PROBLEMAS_STRING]; int i = 0; foreach (Dictionary <string, object> problema in resultadosUsuario) { if (problema[POINTS_STRING] is int) { puntos[i] = (int)problema[POINTS_STRING]; } else { puntos[i] = (decimal)problema[POINTS_STRING]; } if (puntos[i] == 0) { int tries = (int)problema[RUNS_STRING]; if (tries == 0) { puntos[i] = null; } } i++; } scoreboard.actualiza(usuario, puntos); } } catch (Exception e) { Log.add(Log.TipoLog.OMEGAUP, "Falló algo cuando se parseaba el json de OmegaUp: "); Log.add(Log.TipoLog.OMEGAUP, e.ToString() + e.StackTrace); return(false); } // Finalmente, ordenamos y guardamos en la base de datos try { long timestamp; #if DEBUG timestamp = mockTime; mockTime += 60 * 20; // Cada 20 min #else timestamp = Convert.ToInt64(resultados[TIME].ToString()); timestamp -= Convert.ToInt64(resultados[START_TIME].ToString()); #endif Log.add(Log.TipoLog.OMEGAUP, "Ordenando los resultados"); scoreboard.ordena((int)timestamp, pull.dia); } catch (Exception e) { Log.add(Log.TipoLog.OMEGAUP, "Falló algo cuando se guardaba en la base de datos: "); Log.add(Log.TipoLog.OMEGAUP, e.ToString()); return(false); } if (mock) { Console.WriteLine("Mete los segundos que queden de examen (5 horas = 18000; 0 para terminar)"); try { int seconds = Convert.ToInt32(Console.ReadLine()); if (seconds < 0) { seconds = 0; } pull.setSecondsToFinish(OMIstats.Utilities.Fechas.secondsSinceUnixTime() + seconds); } catch (Exception) { } } else { pull.setSecondsToFinish((int)resultados[FINISH_TIME]); } Log.add(Log.TipoLog.OMEGAUP, "Scoreboard actualizado con éxito"); return(true); }
// // GET: /Olimpiada/Resultados/ public ActionResult Resultados(string clave = null, TipoOlimpiada tipo = TipoOlimpiada.OMI, string GUID = null) { if (GUID != null) { tryLogIn(GUID); } Olimpiada o = null; if (clave == null) { o = Olimpiada.obtenerMasReciente(); clave = o.numero; tipo = o.tipoOlimpiada; } else { o = Olimpiada.obtenerOlimpiadaConClave(clave, tipo); } if (o == null) { return(RedirectTo(Pagina.ERROR, 404)); } limpiarErroresViewBag(); ViewBag.liveResults = false; ViewBag.secretScoreboard = false; ViewBag.resultados = null; if (o.liveResults) { OmegaUp ou = o.calculateCachedResults(); if (ou != null) { Persona p = getUsuario(); if (o.esOnline && OmegaUp.RunnerStarted && p != null && p.esSuperUsuario()) { ViewBag.secretScoreboard = true; ViewBag.dia = ou.dia; ViewBag.problemasPorDia = 4; // HARDCODED BUT OH WELL.... ViewBag.resultados = Models.Resultados.cargarResultadosSecretos(clave, tipo, ou.dia); } else { ViewBag.resultados = o.resultados; if (o.resultados.Count > 0) { o.shouldReload(ou.dia); ViewBag.liveResults = true; ViewBag.RunnerStarted = OmegaUp.RunnerStarted; ViewBag.dia = ou.dia; ViewBag.problemasPorDia = ou.dia == 1 ? o.problemasDia1 : o.problemasDia2; ViewBag.lastUpdate = (DateTime.UtcNow.Ticks - ou.timestamp.Ticks) / TimeSpan.TicksPerSecond; ViewBag.ticks = ou.timestamp.Ticks; ViewBag.scoreboardName = ou.concurso; ViewBag.scoreboardToken = ou.token; ViewBag.remainingSeconds = ou.getRemainingContestTime(); } } } } if (ViewBag.resultados == null) { ViewBag.resultados = Models.Resultados.cargarResultados(clave, tipo, porLugar: !o.puntosDesconocidos && o.noMedallistasConocidos && o.datosPublicos, cargarObjetos: true); } ViewBag.problemasDia1 = Problema.obtenerProblemasDeOMI(clave, tipo, 1); ViewBag.problemasDia2 = Problema.obtenerProblemasDeOMI(clave, tipo, 2); ViewBag.claveUsuario = getUsuario().clave; ViewBag.olimpiadas = Olimpiada.obtenerOlimpiadas(TipoOlimpiada.OMI); if (o.alsoOmips) { ViewBag.omis = Olimpiada.obtenerOlimpiadas(TipoOlimpiada.OMIS); ViewBag.omip = Olimpiada.obtenerOlimpiadas(TipoOlimpiada.OMIP); } List <Problema> metadata = Problema.obetnerMetaDatadeOMI(clave, tipo); if (metadata.Count >= 3) { ViewBag.numerosDia1 = metadata[1]; ViewBag.numerosDia2 = metadata[2]; ViewBag.numerosTotal = metadata[0]; } ViewBag.extranjeros = MiembroDelegacion.obtenerEstadosExtranjerosEnOlimpiada(o.numero); return(View(o)); }
private void Run() { if (this.hayOtroActivo()) { return; } OmegaUp status = setStatus(); Log.add(Log.TipoLog.OMEGAUP, "STARTING..."); try { while (true) { List <OmegaUp> instrucciones = OmegaUp.obtenerInstrucciones(); int polls = 0; bool wasHidden = HIDE; HIDE = false; foreach (var instruccion in instrucciones) { switch (instruccion.instruccion) { case OmegaUp.Instruccion.HIDE: { Log.add(Log.TipoLog.OMEGAUP, "Instrucción HIDE encontrada, no se actualizará scoreboard general"); HIDE = true; break; } case OmegaUp.Instruccion.KILL: { Log.add(Log.TipoLog.OMEGAUP, "Instrucción KILL encontrada, saliendo..."); instruccion.borrar(); status.borrar(); return; } case OmegaUp.Instruccion.POLL: { Log.add(Log.TipoLog.OMEGAUP, "-------------------"); Log.add(Log.TipoLog.OMEGAUP, "- Polling started -"); Log.add(Log.TipoLog.OMEGAUP, "-------------------"); polls++; this.poll(instruccion); #if !DEBUG Log.add(Log.TipoLog.OMEGAUP, "Sleeping for " + instruccion.ping + " seconds."); System.Threading.Thread.Sleep(instruccion.ping * 1000); #endif break; } } } if (polls == 0) { Log.add(Log.TipoLog.OMEGAUP, "Nothing to do, exiting..."); status.borrar(); return; } if (wasHidden && !HIDE) { WebRequest.ScoreboardManager.Instance.Unhide(); } // Guardamos el status para actualizar el timestamp status.guardar(); } } catch (Exception e) { Log.add(Log.TipoLog.OMEGAUP, "Excepción en el ciclo normal de ejecución del Puller:"); Log.add(Log.TipoLog.OMEGAUP, e.ToString()); status.status = OmegaUp.Status.ERROR; status.guardar(); } }