~singpolyma/cheogram

Set up structure to cache OOB coming from a direct message route

Does not actually fetch or cache any OOB data yet, but detects all such data and
has the right types to be able to do it. Replaces all OOB elements with new ones
and replaces all instances of gives URLs with new URLs, just no actual work is
done yet.
Merge branch 'better-thread-exceptions'

* better-thread-exceptions:
  Terminate on fatal exception
  Import forkXMPP from jingle-xmpp
Terminate on fatal exception

This retry loop is too naive for the current state of Cheogram. It is easy to
create a situation where this gets into a retry spin because some thread is
still holding on to the old connection to prosody but this is trying to restart
said connection.  If it gets so bad that exceptions are out here, just bail out
and let monit restart us.
Import forkXMPP from jingle-xmpp

This is a much safer version that rethrows exceptions to the parent instead of
just printing them and terminating the thread.
Translate Adhoc JID to Real JID in configure-direct-message-route

The adhoc commands that exist in the backend are wrapped and proxied
through cheogram, so it's not that different when the adhoc command is
talking to them vs when the client is talking to them. In both cases the
user is escaped and proxied (test\40example.com@cheogram.com)

But the internal command is different, because when a client is talking
to it directly, it really is direct. Whereas commands from the adhoc bot
appear to come from test\40example.com@cheogram.com, so it sees it as a
different user, which is bad.

So now I look at the JID and if it looks like one of our escaped ones,
then I unescape it when deciding which key to use.
Temporary fix for broken mmorph version
Get "configure-direct-message-route" Working with Adhoc Bot

This command works fine with a client that actually uses commands, but
it wasn't working as well with the bot.

There were two things standing it its way:

First, we built the list of adhoc commands by translating the JIDs of
your chosen backend to look like they're coming from cheogram, and then
adding our internal commands to that list.

But, when we were running the commands with the adhoc bot, we don't want
to convert the destinations, since we want to talk directly to the
backend. This makes sense, but meant we were missing out on internal
comamnds too!

So now I add the internal command to our list of untranslated commands
too (by translating an empty list, and then adding that) so the list of
commands we can run should match the list we show the user.

Second, we have a thread that receives messages, and that spins up a new
thread that looks (among other things) to see if this is for the adhoc
bot, and if so forwards the message on.

But in either case, the main "message received" logic would also look at
the stanza to see what it should do with it. That's not good, because in
this case where cheogram's configure-direct-message-route was talking to
its own adhoc bot, it was triggering some other branch which, triggered
some else case, and returned an error. To itself. But then that error
went through the same flow, which also triggered an error. And so it
would just go around and around logging error after error after error
forever.

So now I just have a case in my stanza handler that says "if this is an
adhoc message, don't do do anything" because I know the other thread's
already got it.
Also build for Ubuntu LTS

Mostly because that's what psycotica0 uses.
Fix path to the cheogram artifact
Fix CI

jingle-xmpp isn't on hackage (yet?) so we need to install it from git.

Because we install everything from hackage in CI instead of using Debian
packages, installing jingle-xmpp first can cause a version of random not
compatible with some cheogram dependencies to get installed. Easiest fix for
that is to just install a known-good version first, then everything works.
Do not crash when no StatsD listener running

StatsD sends should not block the process from working. Since it's a UDP send
I'm not completely sure how it even can fail, but at least when the target is
localhost it can and indeed did, making dev somewhat annoying.

This just swallows any exceptions produced by the StatsD.push action.
Inform the user that they can ask to cancel the command flow
Merge branch 'cv_more_better_fields'

* cv_more_better_fields:
  Adhoc Boolean Field
  Adhoc Fixed Field
  Adhoc Hidden Field
  Adhoc JID Field
  Adhoc Display List Field Values
  Standardize on (++)
Adhoc Boolean Field

This one is a bit trickier than some of the others, but still not too
bad. The main thing I have to do is turn the value the responder gives
us into something we can show to the user, and then interpret that
response as something we can give to the responder.

I use the same kinda weird parser for that where I just spell out all
the options

Seems to work ok...

It looks like:
  Is Enabled [Current value Yes]
  Yes or No?

and
  Is Not Enabled [Current value No]
  (Should it not not be disabled)
  Yes or No?

If there's a description.
Adhoc Fixed Field

This one is also pretty easy.
The spec says that multiple <value> elements should be considered as
multiple labels on different lines, so we do that.

Then we return nothing, because nothing here goes back out to the
responder.
Adhoc Hidden Field

This is super easy.
The only downside here is that it sends all the attributes of the field,
like the type and the label or whatever.

In practice, though, I assume no server impl will break because of that,
and it's so easy.

I could pull the value out and then repackage it, but if that's not
required then this is much simpler
Adhoc JID Field

This is basically a text field, but it only accepts JIDs.
In a normal implementation this would pull up a convenient list of
contacts or something, but since we don't have any control like that,
this will have to do.

So we consume just the same as a text form, but with special validation
and instructions. That being said, I couldn't actually find a string
that wasn't accepted as a valid JID, so maybe it doesn't do anything
beyond just providing slightly different instruction.

Anyway, I adjusted untilParse to take (Text -> Maybe b) rather than
(Parser b) directly. Then I have the parse calls on the outside.
I think that's ok, in general.
Adhoc Display List Field Values

The responder can optionally send us "current values" of fields, but
we're only displaying that information in the text field. This extends
that to the list types.

We also extended text fields to show descriptions. We wanted to extend
this to lists as well, but figuring out how to consolidate was a little
tricky. So I pulled some bits out, and we decided on a bit more of a
"question" vibe.

So now it looks like:

  Run Modes
  1. Single-User
  2. Non-Networked Multi-User
  3. Full Multi-User [Currently Selected]
  4. X-Window [Currently Selected]
  Which numbers?

and:

  Run State
  1. Active [Current Value]
  2. Inactive
  Which number?

and with a description it'd be:

  Run State
  (Which state should this run in?)
  1. Active [Current Value]
  2. Inactive
  Which number?

I felt it was clearer to have "Current Value" in the single case,
because having one element be selected isn't as clear when there's just
one, but that may just be me.

In the middle I also changed the text labels to look like:

  Enter First Name

  Enter Name
  (This is the name other people will see you by)

For fields labeled "First Name" and "Name" respectively.


Also, once I made the listOptionText method, and gave it a type
signature, I no longer need to specify the type of my decimal number in
the middle of my parser, the inference can figure it out now.
Standardize on (++)

It turns out in BasicPrelude (++) = (<>), so there's no reason to use
(<>), but there are style downsides brought about by mixing them.
Replace sendMessage, componentJid, from with sendText

It's funny, I built the "sendText" method for my cancellation logic as
an easy way for it to send some status messages to the user. After I
looked at it, though, I realized that's just what I always wanted. I'm
not sending any special messages back to the user, just text, and I'm
threading these arguments all the way through the logic just so I can
build a message from text at the bottom.

That's dumb, so now I'm just doing it at the top and injecting that.
Next