8

So I have created 2 iOS apps (One sends coordinates, one receives them) and a python server. One of the apps sends GPS coordinates to my python server that is hosted on heroku. The server will then emit the received GPS coordinate to the OTHER iOS client app that will drop an Apple Maps pin on the received coordinate.

The project works perfectly while testing on local host with any specified port. However when I have migrated the server to Heroku I was receiving this error The error occurs because Heroku sets it's own port for you to use, where as my code was specifying which port to use. I have been browsing SO for numerous hours trying to implement other peoples solutions where they use os.environ["PORT"] and so on, however due to my novice Python and Twisted skills I haven't succeeded in getting the iOS apps to properly communicate with the Heroku server on the right port. My code for my server is below: (note: I am using Twisted)

import os
from twisted.internet.protocol import Protocol, Factory
from twisted.internet import reactor

class IphoneChat(Protocol):
def connectionMade(self):
    #self.transport.write("""connected""")
    self.factory.clients.append(self)
    print "clients are ", self.factory.clients

def connectionLost(self, reason):
    self.factory.clients.remove(self)

def dataReceived(self, data):
    #print "data is ", data
    a = data.split(':')
    if len(a) > 1:
        command = a[0]
        content = a[1]

        msg = ""
        if command == "new":
            self.name = content
            msg = content

        elif command == "msg":
            msg = self.name + ": " + content

        print msg

        for c in self.factory.clients:
            c.message(msg)

def message(self, message):
    self.transport.write(message + '\n')


factory = Factory()
factory.protocol = IphoneChat
factory.clients = []
port = 3000
reactor.listenTCP(port, factory)
print "Iphone Chat server started on port ", port
reactor.run()
Community
  • 1
  • 1
Aimee
  • 143
  • 2
  • 9

2 Answers2

13

Heroku have a section in your settings where you can define environment variables.

I have a similar situation when running Django locally, but a similar fix may help you.

In heroku dashboard, select your app and then click the settings tab.

Then if you click reveal config vars and add the key name ON_HEROKU (or something similar if you prefer) with the value True.

Then in your python:

import os
ON_HEROKU = os.environ.get('ON_HEROKU')

if ON_HEROKU:
    # get the heroku port
    port = int(os.environ.get('PORT', 17995))  # as per OP comments default is 17995
else:
    port = 3000

I'm not 100% sure if get('PORT') would be correct, I'm doing this off the top of my head.

Implementing it into your own code would involve something like:

factory = Factory()
factory.protocol = IphoneChat
factory.clients = []

import os
ON_HEROKU = os.environ.get('ON_HEROKU')
if ON_HEROKU:
    # get the heroku port 
    port = int(os.environ.get("PORT", 17995))  # as per OP comments default is 17995
else:
    port = 3000

reactor.listenTCP(port, factory)
print "Iphone Chat server started on port %s" % port
reactor.run()
Llanilek
  • 3,386
  • 5
  • 39
  • 65
  • Hey Neil! Thanks for replying! I implemented your solution, however it has gone back to the "failure to bind within 60 second error" [link](http://i.imgur.com/WmgOIaD.png?1) – Aimee Jan 12 '15 at 10:49
  • @Aimee have you ensured that you've set the variable correctly in heroku dashboard? it should look like [this](https://www.dropbox.com/s/7w6l6dwsqt5kz89/checkthis.png?dl=0) – Llanilek Jan 12 '15 at 10:55
  • @Aimee also, you might need to check if the os variable is getting the right data, if it's not finding the `PORT` key _(Harry Potter quote unintentional)_ then it will default to 5000, and if that's not what Heroku have set, that could be what's causing the issue. The original information was found on a Flask tutorial in the Heroku docs [here](https://blog.heroku.com/archives/2011/9/28/python_and_django) – Llanilek Jan 12 '15 at 11:02
  • Ashhley Hickman I looked at your image and realised that I hadn't pressed 'save' however I pressed save and restarted the dynos. Looking at the logs the port ended up being 17995, so I changed the server address of my apps to "enigmatic-beyond-7671.herokuapp.com" and the port to 17995, however it still isn't logging the GPS's coordinates. – Aimee Jan 12 '15 at 11:08
  • Is the local still working? There's been no adjustments made to the actual workings of the code, just a conditional on the location of the server running the code. The problem may run deeper than the scope of this question. – Llanilek Jan 12 '15 at 11:13
  • Yeah, it works when I set the server as my Mac which is running the code. – Aimee Jan 12 '15 at 11:20
  • Ok so are you getting any errors? Not sure if your app can be visited via browser, but I'm getting application errors when I visit the link you provided. – Llanilek Jan 12 '15 at 11:22
  • No errors, there shouldn't be a browser interface, as I am only using the server for relaying the coordinates from a iPhone to an iPhone. – Aimee Jan 12 '15 at 11:28
  • I'm using trying to connect to a socket CFStreamCreatePairWithSocketToHost – Aimee Jan 12 '15 at 11:30
  • You might need to do some more digging or update your question in this situation. As the answer I gave is doing what you asked in the question. The problem may be some incompatibility with heroku. But what information is `$ heroku logs` giving you? – Llanilek Jan 12 '15 at 11:30
  • No worries, I should get some sleep, and think about it some more with clear head. Thanks for all your help! – Aimee Jan 12 '15 at 11:34
  • You're welcome. Hopefully my answer has given you some insight anyway. If it has, I'd appreciate it if you would consider up-voting it and/or accepting the answer if it fulfils the purpose of the question. – Llanilek Jan 12 '15 at 11:41
-1

The answer is the following. The port is set by Heroku in the environment variables, and in this example 17995 is used only locally when the PORT environment variable is absent (on local).

port = int(os.environ.get("PORT", 17995))
app.run(host='0.0.0.0', port=port)

Source: https://blog.heroku.com/python_and_django

vintagexav
  • 2,011
  • 2
  • 18
  • 22