Tae
Tae

Reputation: 1695

Python 3 struct.pack(): char format requires a bytes object of length 1

I'm trying to send push notifications using the APNS from Python (I know there are lots of libraries that do just that, but this has pedagogic intentions).

I started using this script (source):

def send_push(token, payload):
    # Your certificate file
    cert = 'ck.pem'

    # APNS development server
    apns_address = ('gateway.sandbox.push.apple.com', 2195)

    # Use a socket to connect to APNS over SSL
    s = socket.socket()
    sock = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_SSLv3, certfile=cert)
    sock.connect(apns_address)

    # Generate a notification packet
    token = binascii.unhexlify(token)
    fmt = '!cH32sH{0:d}s'.format(len(payload))
    cmd = '\x00'
    message = struct.pack(fmt, cmd, len(token), token, len(payload), payload)
    sock.write(message)
    sock.close()

Which works, but Python 2.x only supports TSL until version 1. So I tried to run it using Python 3, and I get this error:

Traceback (most recent call last):
  File "push_notificator.py", line 52, in <module>
    send_notification(TOKEN, json.dumps(TEST_PAYLOAD))
  File "push_notificator.py", line 46, in send_push
    payload
struct.error: char format requires a bytes object of length 1

So it seems I must convert the payload to binary, but I'm really lost. This is the first time that I work with binary data on Python.

Upvotes: 4

Views: 9844

Answers (2)

greenhouse
greenhouse

Reputation: 1281

@cdonts's answer ultimately helped me out, but i thought it might be cleaner in a separate answer, instead of a comment...

@cdonts's answer: https://stackoverflow.com/a/31551978/2298002

I had to encode both cmd as well as payload, before packing. here is my code that solved it...

cmd = bytes(cmd, "utf-8")
payload = bytes(payload, "utf-8")

here is a longer code snippet to demonstrate in context...

token = "<string apns token from iOS client side>"
try:
    token = binascii.unhexlify(token)
    payload = json.dumps(payload)
    fmt = "!cH32sH{0:d}s".format(len(payload))
    cmd = '\x00'

    #python3 requirement
    cmd = bytes(cmd, "utf-8")
    payload = bytes(payload, "utf-8")

    msg = struct.pack(fmt, cmd, len(token), token, len(payload), payload)
except Exception as e: # ref:
    print(e)    

@cdonts THANK YOU!! (https://stackoverflow.com/a/31551978/2298002)

Upvotes: 3

cdonts
cdonts

Reputation: 9631

In Python 3.x use:

bytes(payload, "utf-8")

Replace utf-8 with the necessary encoding.

Hope it helps.

Upvotes: 2

Related Questions