messageboard-2022-11-12-1228.py
01234567890123456789012345678901234567890123456789012345678901234567890123456789









6426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522








66896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729











                            <----SKIPPED LINES---->




      % subscription_id)
  curl.setopt(pycurl.HTTPHEADER, [
      'X-Vestaboard-Api-Key:%s' % key, 'X-Vestaboard-Api-Secret:%s' % secret])
  curl.setopt(pycurl.TIMEOUT_MS, timeout*1000)
  curl.setopt(pycurl.POST, 1)

  curl.setopt(pycurl.WRITEFUNCTION, lambda x: None) # to keep stdout clean

  # preparing body the way pycurl.READDATA wants it
  body_as_dict = {'characters': StringToCharArray(s)}
  body_as_json_string = json.dumps(body_as_dict) # dict to json
  body_as_file_object = io.StringIO(body_as_json_string)

  # prepare and send. See also: pycurl.READFUNCTION to pass function instead
  curl.setopt(pycurl.READDATA, body_as_file_object)
  curl.setopt(pycurl.POSTFIELDSIZE, len(body_as_json_string))
  web_publish_failure_msg = ''
  try:
    curl.perform()
    status_msg = 'Web service published'
    status_code = 'SUCCESS'
  except pycurl.error as e:
    timing_message = CurlTimingDetailsToString(curl)
    web_publish_failure_msg = (
        'curl.perform() failed with message %s; timing details: %s' %
        (e, timing_message))
    # Using the remote webservice failed, but maybe the local API will
    # be more successful?  If this succeeds, then we should not indicate
    # a failure on the status light / dashboard, but we should still log
    # the remote failure
    Log(web_publish_failure_msg)
    local_publish_error_msg = PublishMessageLocal(
        s, timeout=timeout, update_dashboard=False)
    if not local_publish_error_msg:
      status_msg = (
          'Local service published (1) because web service failed with %s'
          % web_publish_failure_msg)
      status_code = 'WARNING'
    else:
      status_msg = (
          'Local service failed (2) with %s after web service failed with %s' %
          (local_publish_error_msg, web_publish_failure_msg))
      status_code = 'FAIL'
  else:
    # you may want to check HTTP response code, e.g.
    timing_message = CurlTimingDetailsToString(curl)
    status_code = curl.getinfo(pycurl.RESPONSE_CODE)
    if status_code != 200:
      web_publish_failure_msg = (
          'Server returned HTTP status code %d for message %s; '
          'timing details: %s' % (status_code, s, timing_message))
      Log(web_publish_failure_msg)
      local_publish_error_msg = PublishMessageLocal(
          s, timeout=timeout, update_dashboard=False)
      if not local_publish_error_msg:
        status_msg = (
            'Local service published (3) because web service failed with %s'
            % web_publish_failure_msg)
        status_code = 'WARNING'
      else:
        status_msg = (
            'Local service failed (4) with %s after web service failed with %s'
            % (local_publish_error_msg, web_publish_failure_msg))
        status_code = 'FAIL'

  # We've logged the error code from the external web service, but the
  # Vestaboard local API was able to recover from the error, so we need not
  # log the failure message / error code in the dashboard.
  if not error_code:
    web_publish_failure_msg = ''

  curl.close()
  UpdateStatusLight(
      GPIO_ERROR_VESTABOARD_CONNECTION,
      status_code=='FAIL', web_publish_failure_msg)

  return status_msg, status_code


def PublishMessageLocal(
    s,
    local_key=LOCAL_KEY,
    local_address=LOCAL_VESTABOARD_ADDRESS,
    timeout=5,
    update_dashboard=True):
  """Publishes a text string to a Vestaboard via local API.

  The message is pushed to the vestaboard splitflap display by way of its
  local API; see https://docs.vestaboard.com/local for more details.

  Args:
    s: String to publish.
    local_key: string key from Vestaboard for local API access.
    local_address: the address and port to the local Vestaboard service.
    timeout: Max duration in seconds that we should wait to establish a
      connection.
    update_dashboard: Boolean indicating whether this method should update the




                            <----SKIPPED LINES---->





    for message in messages_to_display:
      # we cannot just unpack the tuple because messages of type
      # FLAG_MSG_FLIGHT & FLAG_MSG_INSIGHT are 3-tuples (with the third
      # element being the flight dictionary) whereas other message types
      # are 2-tuples
      message_type = message[0]
      message_text = message[1]

      # There may be one or several insight messages that were added to the
      # message queue along with the flight at a time when the screen was
      # enabled, but by the time it comes to display them, the screen is now
      # disabled.  These should not be displayed.  Note that this check only
      # needs to be done for insight messages because other message types
      # are user initiated and so presumably should be displayed irrespective
      # of when the user triggered it to be displayed.
      if message_type == FLAG_MSG_INSIGHT and not MessageMeetsDisplayCriteria(
          configuration):
        publish_status_msg = (
            'Message purged as no longer meets display criteria')
        publish_status_code = 'WARN'
        Log('Message %s purged' % message_text)

      else:
        if isinstance(message_text, str):
          message_text = textwrap.wrap(
              message_text,
              width=SPLITFLAP_CHARS_PER_LINE)
        display_message = Screenify(message_text, False)
        Log(display_message, file=ALL_MESSAGE_FILE)

        # Saving this to disk allows us to identify
        # persistently whats currently on the screen
        PickleObjectToFile(message, PICKLE_SCREENS, True)
        screens.append(message)

        MaintainRollingWebLog(display_message, 25)
        if not SIMULATION:
          splitflap_message = Screenify(message_text, True)
          publish_status = PublishMessageWeb(splitflap_message)
          publish_status_msg, publish_status_code = publish_status




                            <----SKIPPED LINES---->





01234567890123456789012345678901234567890123456789012345678901234567890123456789









6426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522








66896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729











                            <----SKIPPED LINES---->




      % subscription_id)
  curl.setopt(pycurl.HTTPHEADER, [
      'X-Vestaboard-Api-Key:%s' % key, 'X-Vestaboard-Api-Secret:%s' % secret])
  curl.setopt(pycurl.TIMEOUT_MS, timeout*1000)
  curl.setopt(pycurl.POST, 1)

  curl.setopt(pycurl.WRITEFUNCTION, lambda x: None) # to keep stdout clean

  # preparing body the way pycurl.READDATA wants it
  body_as_dict = {'characters': StringToCharArray(s)}
  body_as_json_string = json.dumps(body_as_dict) # dict to json
  body_as_file_object = io.StringIO(body_as_json_string)

  # prepare and send. See also: pycurl.READFUNCTION to pass function instead
  curl.setopt(pycurl.READDATA, body_as_file_object)
  curl.setopt(pycurl.POSTFIELDSIZE, len(body_as_json_string))
  web_publish_failure_msg = ''
  try:
    curl.perform()
    status_msg = 'Web service published'
    publish_status_code = 'SUCCESS'
  except pycurl.error as e:
    timing_message = CurlTimingDetailsToString(curl)
    web_publish_failure_msg = (
        'curl.perform() failed with message %s; timing details: %s' %
        (e, timing_message))
    # Using the remote webservice failed, but maybe the local API will
    # be more successful?  If this succeeds, then we should not indicate
    # a failure on the status light / dashboard, but we should still log
    # the remote failure
    Log(web_publish_failure_msg)
    local_publish_error_msg = PublishMessageLocal(
        s, timeout=timeout, update_dashboard=False)
    if not local_publish_error_msg:
      status_msg = (
          'Local service published (1) because web service failed with %s'
          % web_publish_failure_msg)
      publish_status_code = 'WARNING'
    else:
      status_msg = (
          'Local service failed (2) with %s after web service failed with %s' %
          (local_publish_error_msg, web_publish_failure_msg))
      publish_status_code = 'FAILURE'
  else:
    # you may want to check HTTP response code, e.g.
    timing_message = CurlTimingDetailsToString(curl)
    status_code = curl.getinfo(pycurl.RESPONSE_CODE)
    if status_code != 200:
      web_publish_failure_msg = (
          'Server returned HTTP status code %d for message %s; '
          'timing details: %s' % (status_code, s, timing_message))
      Log(web_publish_failure_msg)
      local_publish_error_msg = PublishMessageLocal(
          s, timeout=timeout, update_dashboard=False)
      if not local_publish_error_msg:
        status_msg = (
            'Local service published (3) because web service failed with %s'
            % web_publish_failure_msg)
        publish_status_code = 'WARNING'
      else:
        status_msg = (
            'Local service failed (4) with %s after web service failed with %s'
            % (local_publish_error_msg, web_publish_failure_msg))
        publish_status_code = 'FAILURE'

  # We've logged the error code from the external web service, but the
  # Vestaboard local API was able to recover from the error, so we need not
  # log the failure message / error code in the dashboard.
  if not error_code:
    web_publish_failure_msg = ''

  curl.close()
  UpdateStatusLight(
      GPIO_ERROR_VESTABOARD_CONNECTION,
      publish_status_code=='FAILURE', web_publish_failure_msg)

  return status_msg, publish_status_code


def PublishMessageLocal(
    s,
    local_key=LOCAL_KEY,
    local_address=LOCAL_VESTABOARD_ADDRESS,
    timeout=5,
    update_dashboard=True):
  """Publishes a text string to a Vestaboard via local API.

  The message is pushed to the vestaboard splitflap display by way of its
  local API; see https://docs.vestaboard.com/local for more details.

  Args:
    s: String to publish.
    local_key: string key from Vestaboard for local API access.
    local_address: the address and port to the local Vestaboard service.
    timeout: Max duration in seconds that we should wait to establish a
      connection.
    update_dashboard: Boolean indicating whether this method should update the




                            <----SKIPPED LINES---->





    for message in messages_to_display:
      # we cannot just unpack the tuple because messages of type
      # FLAG_MSG_FLIGHT & FLAG_MSG_INSIGHT are 3-tuples (with the third
      # element being the flight dictionary) whereas other message types
      # are 2-tuples
      message_type = message[0]
      message_text = message[1]

      # There may be one or several insight messages that were added to the
      # message queue along with the flight at a time when the screen was
      # enabled, but by the time it comes to display them, the screen is now
      # disabled.  These should not be displayed.  Note that this check only
      # needs to be done for insight messages because other message types
      # are user initiated and so presumably should be displayed irrespective
      # of when the user triggered it to be displayed.
      if message_type == FLAG_MSG_INSIGHT and not MessageMeetsDisplayCriteria(
          configuration):
        publish_status_msg = (
            'Message purged as no longer meets display criteria')
        publish_status_code = 'WARNING'
        Log('Message %s purged' % message_text)

      else:
        if isinstance(message_text, str):
          message_text = textwrap.wrap(
              message_text,
              width=SPLITFLAP_CHARS_PER_LINE)
        display_message = Screenify(message_text, False)
        Log(display_message, file=ALL_MESSAGE_FILE)

        # Saving this to disk allows us to identify
        # persistently whats currently on the screen
        PickleObjectToFile(message, PICKLE_SCREENS, True)
        screens.append(message)

        MaintainRollingWebLog(display_message, 25)
        if not SIMULATION:
          splitflap_message = Screenify(message_text, True)
          publish_status = PublishMessageWeb(splitflap_message)
          publish_status_msg, publish_status_code = publish_status




                            <----SKIPPED LINES---->