Welcome!

Welcome to Kirsle.net! This is the personal website of Noah Petherbridge, and it's where my various software projects and web blog lives.

Android 6.0 "Battery Optimization"

Noah Petherbridge
kirsle
Posted by Noah Petherbridge on Wednesday, January 13 2016 @ 12:18:39 PM

PSA: The "battery optimization" feature in Android 6.0 Marshmallow may be causing your Gmail to not notify you of e-mails until it's way too late and other apps to not notify you about anything ever.

I first caught on to this when I stumbled upon a Reddit thread on /r/Android. Essentially, Android 6.0 added a feature called Doze which puts apps to sleep while the phone is locked/not in use, giving them only brief windows of opportunity to check for any new notifications before being put back to sleep. The frequency between these wake opportunities depends on how long the phone has been locked. It sounds like a good idea in theory, but the execution was done very poorly.

That thread was specifically about apps like Gmail and Inbox. Users were seeing issues where Gmail wouldn't notify them about new e-mails until several hours after the e-mails came in. This is because the Gmail app was getting "dozed" and was unable to check for any new messages (or receive push notifications, or whatever it does). The work-around is to disable the "battery optimization" for the Gmail app.

To do so:

  1. Go to your Settings and then Battery
  2. In the menu on the right, go to Battery Optimization
  3. It lists the non-optimized apps and those that can't be optimized. In the drop-down at the top, pick All Apps
  4. Pick Gmail and any other app you care about and pick "Don't optimize"

Doze makes it sound like not optimizing apps will hurt your battery life. This may be true for poorly written apps, but it's pretty safe to allow Gmail to not be put to sleep. Before Android 6.0, Doze wasn't even a feature anyway and there weren't a lot of complaints about battery life. Personally, I just disabled battery optimization for a small handful of apps that I care more about, including Gmail and Hangouts.

In addition to Gmail, a few other apps I found to be completely broken when they're being "optimized":

  1. Google Opinion Rewards: Get Google Play credit for answering surveys. I noticed I wasn't getting any surveys offered for several weeks, and figured the Doze feature was to blame. I disabled it on the Google Opinion Rewards last night, and got a survey this morning.

    My theory is that this app only receives surveys if there is one available at the time the app asks for it. Since the app was checking very infrequently, it was missing all the surveys.

  2. Tasker: I have a Tasker task set up to automatically connect to my VPN when my phone joins certain WiFi networks. I was noticing that it was failing to do this the majority of the time. I'd have to open Tasker and manually play the Connect VPN task and then it would sorta work, but sometimes it would fail to run the Disconnect VPN task when I left the WiFi network.

    Disabling battery optimization for Tasker fixed this problem.

  3. Tumblr: I was getting no notifications at all from this app, ever. Disabling battery optimization fixed this problem.

  4. Reddit Sync Pro: I was getting no notifications of new messages on this app until I manually opened it. Again, disabling the optimization helped.

So if you have any apps that have been oddly quiet for the past several weeks or months and you're running Android 6.0, check if the "battery optimization" feature is to blame.

Categories:

[ 0 comments | Add comment | Permalink ]

Let's Encrypt

Noah Petherbridge
kirsle
Posted by Noah Petherbridge on Wednesday, December 30 2015 @ 07:36:02 PM

The free SSL certificate authority Let's Encrypt went into public beta earlier this month, and I updated all of my sites to use SSL now. I still had several more months before kirsle.net's old certificate from Namecheap expired, but I switched to the Let's Encrypt certificate because I could include all my subdomains instead of only the www one.

Check out their website and get free SSL certificates for your sites, too. I'm just writing this blog with some personal tips for how I configured my nginx server and a Python script I wrote to automate the process of renewing my certificates every month (Let's Encrypt certs expire every 90 days).

nginx config

Because all of my sites now use SSL encryption, and nginx has a handful of options for configuring the cipher suites and other settings (you need to play around with these to get a good score on the SSL Labs security test), I created a file named /etc/nginx/ssl_params to put all of the common parameters. Then, each individual site includes that file.

/etc/nginx/ssl_params

# Common SSL security settings
ssl_session_timeout 5m;

ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH';
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_dhparam /etc/ssl/kirsle.net-2015/dhparams.pem;

# So the Acme client can use the htdocs method
location /.well-known {
    alias /var/www/html/.well-known;
}

Notice how I also made a global alias to point the /.well-known URI to the /var/www/html/.well-known path. This is useful for running the ACME client (I use the standard letsencrypt-auto client); I can use the "web root" method and then I don't need to stop my nginx web server (I don't trust a program to automatically edit my nginx config, and I don't want to bring down all my sites in order to run letsencrypt-auto in stand-alone mode, where it runs its own server temporarily).

And then, for my websites that use SSL certs, I include the ssl_params file so that I don't need to manage redundant settings in a dozen different places. Here's an example for my rpm.kirsle.net subdomain, which is where I put random Linux packages:

server {
    server_name rpm.kirsle.net;
    listen [2604:a880:1:20::46:5004]:443 ipv6only=on;
    listen 443 ssl;

    ssl on;
    ssl_certificate /etc/letsencrypt/live/www.kirsle.net/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/www.kirsle.net/privkey.pem;
    include ssl_params;

    root /home/kirsle/subdomains/rpm;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
        autoindex on;
    }
}

# Forward port 80 to SSL
server {
    server_name rpm.kirsle.net;
    listen [2604:a880:1:20::46:5004]:80 ipv6only=on;
    listen 80;
    return 301 https://rpm.kirsle.net$request_uri;
}

Get a certificate without stopping your web server

As touched on before, I didn't want to have to do service nginx stop in order to run the letsencrypt-auto client in standalone mode. (The reason I would have to is that many of my sites are Python web apps, so they don't have a traditional document root directory like some simpler sites would, such as many sites that would be hosted by an Apache server).

So for example, on Kirsle.net the majority of requests are handled directly by the Python app, so there is no root document directory (I make aliases for certain subdirectories, though, for serving static files because this is better handled by nginx than by Python). So, a workaround is to configure your nginx server to alias the /.well-known URI to a document root on disk, because the ACME client will want to create files underneath the /.well-known/acme-challenge/ directory to prove ownership of your domain name.

To keep things simple and DRY, I put that URI alias in the shared SSL parameters file.

Automatically renew certificates

Let's Encrypt is still in beta at the time of writing, and they haven't yet implemented a way to automatically renew certificates before they expire; and Let's Encrypt certificates expire every 90 days, unlike most traditional certificate authorities that give you 12 month leases at a time.

So in the mean time, I wrote a simple Python script for myself that renews all my certificates regularly. I installed it in my root user's crontab on my server, to run the script on the first of every month. The script checks all the existing certificates to see if any should be renewed (if they're at least a month old), and runs the letsencrypt-auto client to update them and restart my web server.

Here's the source code. For the raw plain text version, check https://sh.kirsle.net/renew-certs.py. There's a configurable section at the top of the script that can be edited to put in your own domain names.

#!/usr/bin/env python3

# Cron script to renew LetsEncrypt certificates.
#
# --Kirsle
# https://sh.kirsle.net/

import os
import subprocess
import time

################################################################################
# Configuration Section Begins                                                 #
################################################################################

# Let's Encrypt directories
LE_APPDIR = "/opt/letsencrypt"       # Where `letsencrypt-auto` lives
LE_CERTS  = "/etc/letsencrypt/live"  # Where live certificates go

# Common arguments to letsencrypt-auto
COMMON = ["./letsencrypt-auto", "certonly", "--renew",
          "--webroot", "-w", "/var/www/html"]

# Domains and their subdomains; one array element per certificate, with each
# array element being a list of domains to include in the same cert.
CERTS = [
    [ "www.kirsle.net", "kirsle.net", "www.kirsle.com", "kirsle.com",
      "www.kirsle.org", "kirsle.org", "sh.kirsle.net", "rpm.kirsle.net",
      "minecraft.kirsle.net", "mc.kirsle.net", "rophako.kirsle.net" ],
    [ "noah.is", "www.noah.is", "petherbridge.org", "www.petherbridge.org",
      "noah.petherbridge.org", "noahpetherbridge.com",
      "www.noahpetherbridge.com" ],
    [ "rivescript.com", "www.rivescript.com", "static.rivescript.com" ],
]

# Minimum lifetime for certificate before renewing it?
LIFETIME = 60*60*24*30  # Once a month.

# Command to run after finishing if certs were renewed.
RESTART_COMMAND = ["service", "nginx", "reload"]

################################################################################
# End Configuration Section                                                    #
################################################################################

def main():
    os.chdir(LE_APPDIR)

    # If any certs were renewed, we'll schedule the restart command at the end.
    any_renewed = False

    # See which certificates are ready to be renewed.
    print("Checking SSL certificates for renewal")
    for cert in CERTS:
        ready = False  # Ready to renew this one
        primary = cert[0]

        # Find its existing live certificate file.
        home = os.path.join(LE_CERTS, primary)
        chain = os.path.join(home, "cert.pem")

        # When was it last modified?
        if not os.path.isfile(chain):
            print("NOTE: No existing cert file found for {} ({})".format(
                primary,
                chain,
            ))
            ready = True
        else:
            mtime = os.stat(chain).st_mtime
            if time.time() - mtime > LIFETIME:
                print("Cert for {} is old; scheduling it for renewal!"\
                    .format(primary))
                ready = True

        # Proceed?
        if ready:
            print("Renewing certificate for {}...".format(primary))
            command = []
            command.extend(COMMON)

            # Add all the domains.
            for domain in cert:
                command.extend(["-d", domain])

            print("Exec: {}".format(" ".join(command)))
            subprocess.call(command)
            any_renewed = True

    # If any certs were changed, restart the web server.
    if any_renewed:
        print("Restarting the web server: {}".format(" ".join(RESTART_COMMAND)))
        subprocess.call(RESTART_COMMAND)

if __name__ == "__main__":
    main()

Event Loops

Noah Petherbridge
kirsle
Posted by Noah Petherbridge on Friday, November 27 2015 @ 12:12:20 AM

This is something I wanted to rant about for a while: event loops in programming.

Story time!

I like to write chatbots. Back when I got started writing bots, I wrote them in Perl and there were modules available for all the most common chat platforms of the time: Net::OSCAR for AOL IM, Net::YMSG for Yahoo! Messenger, Net::IRC and we also had an MSN Messenger module that was simply named MSN.

All of these modules were written to use their respective protocols in a synchronous manner. That is, they didn't use any event loops, but had functions with names like start() and do_one_loop().

For the simplest bots, where you only wanted to sign on one instance of an AIM bot per Perl script, you'd use the start() method which would enter the main loop and block forever. But if you wanted to run multiple bots from the same Perl script (say, sign on three different AIM bots, two MSN bots and one for IRC all at the same time), you could write your own main loop and manually drive the loops of the respective modules.

Since they all somehow agreed on a common API, the code could look like this:

# Where @connections is an array of bot objects, like Net::OSCAR,
# Net::YMSG, Net::IRC, MSN, etc...
while ($running) {
    # main loop
    foreach my $conn (@connections) {
        $conn->do_one_loop();

        # This also frees up the bot to do other background tasks
        # on each loop here.
    }
}

But, more recently I tried writing a new Perl chatbot which I called Aires, and this bot connected to AIM and Yahoo! Messenger (using a newer Net::IM::YMSG module that I and Matt Austin wrote for the new YMSG protocol, since Yahoo shut down their older protocols around the same time Microsoft announced the same plans to shut down old MSNP protocols).

Net::OSCAR and the new Net::IM::YMSG both used the same old synchronous APIs and all was well. But, I wanted Aires to also use XMPP. But the only Perl interface for an XMPP client was AnyEvent::XMPP, and it required the AnyEvent event loop framework.

To make a long story short, if you already have an existing codebase that does a bunch of stuff and doesn't use an event loop framework, and then you want to utilize some module that does use an event loop framework, things don't go very well. It's pretty difficult to mix and match modules when some of them use a certain event framework and the rest of your code doesn't use the same framework.

To support the XMPP module correctly, my entire codebase would have had to be refactored to work in the AnyEvent framework and I'd have to coerce the other two instant messenger modules to work under those conditions.

Event Loops in Procedural Languages

The root problem, I think, is when people try to build event loop architectures on top of otherwise procedural languages, such as Perl and Python. Procedural languages like these aren't event-oriented and just execute their instructions one at a time in the order they were written, and the languages have no built-in "official" way of writing an event-based program.

So, people write their own event loop systems, such as POE or AnyEvent for Perl, or things like twisted and asyncio for Python. Oftentimes the competing event loops are not compatible with each other. Most event loops want to be THE event loop, and don't support some other loop "manually driving" theirs (like calling a do_one_loop() type of function).

A lot of graphical user interface modules (e.g. Tk and GTK+) have their own event loops, which makes sense for them because it makes more sense to write a program that responds to buttons being clicked and scrollbars being scrolled if the entire front-end of your program revolves around a graphical interface. But these have the same problems as any other event loop and it's hard to mix-and-match them, or to use them from an existing codebase that wasn't architected to use a compatible event loop. In the Perl version of Tk there's a way to manually drive Tk's loop (call $mainwindow->update() instead of MainLoop;) but that isn't universally true of all GUI frameworks.

Mixing an arbitrary event loop framework with a GUI event loop isn't always straightforward and is sometimes impossible, unless you want to partition your program into different threads to completely separate two competing event loops from each other.

Another Story!

After trying to bolt on XMPP support via AnyEvent::XMPP in a way that only works some of the time, I abandoned the Perl version of the Aires bot and rewrote it in Python and gave it the same name. I ran into a similar conundrum when trying to mix interfaces that required the Twisted framework (AIM and XMPP) with ones that didn't (local command line interface). I stopped working on this version of Aires as well.

Fast forward quite a bit.

Yesterday I wrote two chatbots from scratch. One was written in Python and I named it Admiral. The goals for this bot, initially, were to connect to both the Slack chat platform and Google Hangouts, using the hangups module.

I wrote the Slack part first because it was easier and I had some prior experience with it. The official SlackHQ implementation for Python is what I would call synchronous. I had to write my own do_one_loop() function that polled the Slack API to check for any incoming messages over their RealTime Messaging protocol.

When I wanted to attach the Google Hangouts integration, I ran into the same problem with trying to use an event loop on a program that doesn't already use it: Python 3's asyncio. There are several Google Hangouts bots already written for Python, and most of them only do one bot, which I didn't want (I want my one Python script to connect multiple bots to multiple platforms simultaneously). To use the Hangouts module I have to let asyncio take over control of the script and handle the main loop on its own, which would result in the Slack bot being starved out, as the Slack bot's loop to poll for events would never get a chance to run anymore.

Another strike against event loop frameworks being bolted on top of languages that didn't have them built in.

So, the second chatbot I wrote yesterday, I wrote in Go. I called this one Scarecrow, and this one is also a Slack bot for now but I'm more optimistic about this one due to the Go language itself. In addition to Slack it has a local command line interface that can chat locally with you simultaneously to having one or more Slack bots running.

Optimism for Golang

Something I like so far about the Go language is that it has a system for running concurrent tasks built in. They're called Goroutines and they're a first-class citizen in the language, and they should render ALL event loop frameworks obsolete.

On my near-term TODO list for the Scarecrow chatbot is to add XMPP support. I think it won't matter how the XMPP module is written; in the worst case scenario I can go run the XMPP code and isolate it from the entire rest of my program without any issue.

Opinion: Libraries should NOT use event frameworks

This is basically the point of this rant. If you're writing a library, such as an XMPP client or a Google Hangouts client, you absolutely should not use an event-loop framework in your code. Hear me out.

If you wrote a Hangouts module and you wrote it synchronously as mentioned above, with something like a start() and/or do_one_loop() function, you give the end developer of your module the best of all worlds. If I just want to write the simplest chatbot I can, one that uses only your module and nobody else's, I can do that very easily. And if I have a more complex program to write, I can choose an event framework that I personally like and I can wrap your module inside one of my coroutines on my own.

Like, suppose you have a synchronous module and this is my pseudocode written in Go:

func Example() {
    // I want to use a synchronous module... I can just make my own goroutine to wrap it.
    go YourModuleWrapper()
}

func YourModuleWrapper() {
    for {
        your_module_instance.do_one_loop()
    }
}

This way, if I already have an existing codebase and I find your module and I want to use it, I can. I don't have to see what crazy event loop framework it uses, I don't have to rearchitect the very core of my application to fit the use case of that framework, I don't have to deal with trying to get two competing frameworks to coexist together... I can just use it. If my use case requires a high level of concurrency, I can choose whatever framework I want and I can wrap your code to suit my use case. If I'm using a graphical framework like GTK+ I can wrap your module in that framework's event loop on my own, without having to deal with the headaches of getting different event loops to get along with each other.

Don't use event loop frameworks.

Event loops, if needed at all, should be at the sole discretion of application writers, people who are writing the actual code that runs somewhere and serves a purpose. NOT the library writers. Libraries should not build themselves around a particular event framework.

</rant>

Google knows when you wake up?

Noah Petherbridge
kirsle
Posted by Noah Petherbridge on Saturday, September 26 2015 @ 11:25:11 AM

Something pretty odd that's happened to me on more than a couple of occasions:

I'll wake up in the morning, and then a couple minutes later people start sending me messages on Google Hangouts, so my phone's making a bunch of noise. If it's early enough in the morning, some of those messages will even say things like, "you're up early."

The thing is though, I didn't even touch my phone yet. I didn't even look at my phone.

Messages like this don't tend to wake me up, but instead I don't start getting messages until just after I'm awake.

My theory is that Google Hangouts uses the accelerometer on my phone to detect when I start moving in the morning so it knows I woke up, and then it sets my status to Online. I saw similar stuff happen with Facebook Messenger a long time ago too when I used that app... but that's Facebook and it's safe to assume they're always doing creepy stuff like that.

Googling this kind of stuff doesn't turn up many results. But now there's this blog post for anyone else who looks into this. It's happened too many times to be a coincidence; why would my status change to Online at just the same time that I happened to wake up and roll over in bed?

Screenshot

RiveScript in Go

Noah Petherbridge
kirsle
Posted by Noah Petherbridge on Tuesday, September 22 2015 @ 09:11:59 PM

Over the last couple months I've been slowly working on rewriting RiveScript in yet another programming language: Google's Go language! It's also my first project in Go, which is what tends to be the case (rewriting RiveScript in Java and Python were my first projects in those languages, too).

But this is the last time I'm going to be rewriting RiveScript from scratch.

With the recent release of Golang 1.5, a Go package can be compiled down to a C-compatible shared object file (like a .so or .dll, though I think they're still working on the DLL part). It means that modules written in Go can be linked from other programming languages, especially C or C++, but also to any programming language that can be extended with C. Which, as it turns out, is most of them.

For example, if I want to make RiveScript available to Ruby programmers, I can theoretically create a binding in Ruby for the Go version of RiveScript rather than rewrite RiveScript in Ruby.

The first language I'll probably do this to is Python, because I found a blog about writing Python modules in Go which will be pretty helpful. There's already a native RiveScript module for Python, but it will be a nice learning experience anyway. And who knows, it might even outperform the native Python version. ;)

Back to RiveScript-Go, a feature I think is interesting is that it natively supports JavaScript object macros via a library called otto, which implements a JavaScript interpreter natively in Go. The default rivescript.exe with my Go module already builds in the support for JavaScript objects. :)

Example implementation of the Go module:

package main

import (
    "bufio"
    "fmt"
    "strings"
    rivescript "github.com/aichaos/rivescript-go"
    "github.com/aichaos/rivescript-go/lang/rivescript_js"
)

func main() {
    // Initialize the bot.
    bot := rivescript.New()

    // JavaScript object macro handler.
    jsHandler := rivescript_js.New(bot)
    bot.SetHandler("javascript", jsHandler)

    // Golang functions work too, but must be compiled in.
    bot.SetSubroutine("gotest", func(rs *rivescript.RiveScript, args []string) string {
        return "Hello from Go!"
    })

    // Load a directory of RiveScript files.
    bot.LoadDirectory("./brain")

    bot.SortReplies()

    // Drop into the interactive command shell.
    reader := bufio.NewReader(os.Stdin)
    for {
        fmt.Print("You> ")
        text, _ := reader.ReadString('\n')
        text = strings.TrimSpace(text)
        if len(text) == 0 {
            continue
        }

        reply := bot.Reply("localuser", text)
        fmt.Printf("Bot> %s\n", reply)
    }
}

The JavaScript objects also get full access to the RiveScript object, so they can call methods like CurrentUser() and SetUservar().

Check it out on GitHub: https://github.com/aichaos/rivescript-go

Also, if I ever write a successor to RiveScript, I'll probably only implement it in Go or some other portable language rather than rewrite it five different times in five different languages. Rewriting something is a good way to learn a new language, but then it becomes pretty tedious maintaining them all. ;)

Kirsle
Channels
Creativity
Software
Web Tools
Subdomains
Miscellany
Links


Fan Club