Twitch bot a bytes like object is required, not 'str' - python

Hello Guys i am trying to learn how to make a twitch bot for my friends' channel they streams regulary and sometimes i join them.
Now i was able to make the bot join to the chat room but i couldn't figure out administration part so the bot suppoused to timeout any body uses the word "swear"
instead i get this error:
tmi: :tmi.twitch.tv 001 wasddabulyuasede_bot :Welcome, GLHF!
:tmi.twitch.tv 002 wasddabulyuasede_bot :Your host is tmi.twitch.tv
:tmi.twitch.tv 003 wasddabulyuasede_bot :This server is rather new
:tmi.twitch.tv 004 wasddabulyuasede_bot :-
:tmi.twitch.tv 375 wasddabulyuasede_bot :-
:tmi.twitch.tv 372 wasddabulyuasede_bot :You are in a maze of twisty passages, all alike.
:tmi.twitch.tv 376 wasddabulyuasede_bot :>
wasddabulyuasede_bot: :wasddabulyuasede_bot!wasddabulyuasede_bot#wasddabulyuasede_bot.tmi.twitch.tv JOIN #wlrs
_
:wasddabulyuasede_bot.tmi.twitch.tv 353 wasddabulyuasede_bot = #wlrs_ :wasddabulyuasede_bot
:wasddabulyuasede_bot.tmi.twitch.tv 366 wasddabulyuasede_bot #wlrs_ :End of /NAMES list
wlrs_: swear
Traceback (most recent call last):
File "Bot.py", line 57, in <module>
timeout(s,username,10)
File "Bot.py", line 33, in timeout
chat(sock, ".timeout {}".format(user, secs))
File "Bot.py", line 14, in chat
sock.send("PRIVMSG #{} :{}".format(cfg.CHAN, msg_encoded))
TypeError: a bytes-like object is required, not 'str'
CODE
#cfg.py
#oauth key has been removed
HOST = "irc.chat.twitch.tv"
PORT = 6667
PASS = "oauth:xxxxxxxxxxxxxxxxxxxx"
NICK = "wasddabulyuasede_bot"
CHAN = "#wlrs_"
RATE = (20/30)
PATT = [
r"swear"
]
Bot.py
from cfg import HOST, PORT, PASS, NICK, CHAN, RATE, PATT
import cfg
import socket
import re
import time
def chat(sock, msg):
"""
Send a chat message to the server.
Keyword arguments:
sock -- the socket over which to send the message
msg -- the message to be sent
"""
msg_encoded = msg.encode("utf-8")
sock.send("PRIVMSG #{} :{}".format(cfg.CHAN, msg_encoded))
# def ban(sock, user):
# """
# Ban a user from the current channel.
# Keyword arguments:
# sock -- the socket over which to send the ban command
# user -- the user to be banned
# """
# chat(sock, ".ban {}".format(user))
#
def timeout(sock, user, secs=600):
"""
Time out a user for a set period of time.
Keyword arguments:
sock -- the socket over which to send the timeout command
user -- the user to be timed out
secs -- the length of the timeout in seconds (default 600)
"""
chat(sock, ".timeout {}".format(user, secs))
# ----- network functions -----
s = socket.socket()
s.connect((HOST, PORT))
s.send("PASS {} \r\n".format(PASS).encode("utf-8"))
s.send("NICK {} \r\n".format(NICK).encode("utf-8"))
s.send("JOIN {} \r\n".format(CHAN).encode("utf-8"))
# pattern we are looking for
CHAT_MSG=re.compile(r"^:\w+!\w+#\w+\.tmi\.twitch\.tv PRIVMSG #\w+ :")
while True:
response = s.recv(1024).decode("utf-8")
if response == "PING :tmi.twitch.tv\r\n":
s.send("PONG :tmi.twitch.tv\r\n".encode("utf-8"))
else:
username = re.search(r"\w+", response).group(0) # return the entire match
message = CHAT_MSG.sub("", response)
print(username + ": " + message)
for pattern in cfg.PATT:
if re.match(pattern,message):
timeout(s,username,10)
break
time.sleep(1/cfg.RATE)

A string is an abstraction, representing a sequence of unicode codepoints.
To turn a string into a sequence of bytes, you need to encode your string, aka decide on how you want to represent your text on the wire. For Twitch, use UTF-8:
full_msg = "PRIVMSG #{} :{}".format(cfg.CHAN, msg)
msg_encoded = full_msg.encode("utf-8")
sock.send(msg_encoded)

Related

Python TypeError: bind(): AF_INET address must be tuple, not str

I'm building a chat server for a school project, but when I ran the code I got this error:
TypeError: bind(): AF_INET address must be tuple, not str
import socket
import select
#server booting up with ip + port (server.bind) and listnes for new connections (server.listen) and printing in the and booting up to let the user know
server = socket.socket()
server.bind(("192.168.1.14, 4434"))
server.listen(5)
inputs = [server]
print("booting up the server...")
#notify for new connections
def notify_all(msg, non_receptors):
for connection in inputs:
if connection not in non_receptors:
connection.send(msg)
#function that check for new connections and greets the new users + updating the amount of people connected to the server
def greet(client):
names = [n.getpeername() for n in inputs if n is not client and n is not server]
greetMsg = "hello user! \n users online:" + str(names)
client.send(greetMsg.encode())
while inputs:
readables, _, _ = select.select(inputs, [], [])
for i in readables:
if i is server:
client, address = server.accept()
inputs.append(client)
print("connected to new client")
greet(client)
notify_all(f"client {address} enterd".encode(), [server, client])
else:
try:
data = i.recv(1024)
notify_all(str(str(i.getpeername()) + ">>>" + data.decode()).encode(), [server, i])
except Exception as e:
print(e)
inputs.remove(i)
print(f"client {i.getpeername()} BYE")
("192.168.1.14, 4434") is exactly the same as "192.168.1.14, 4434" (without parentheses), which is a string. As the error message says, the argument to bind should be a tuple, not a string:
server.bind(("192.168.1.14", 4434))
The problem line is: server.bind(("192.168.1.14, 4434")).
You pass it a single string of "192.168.1.14, 4434" instead of a tuple that contains two separate values.
You need to change it to: server.bind(("192.168.1.14", 4434))
Note that the port should be int, not str.

Send commands to a system using UDP protocol in python

I have a zynq core board with its own processor , the zynq has hardcoded testfunctions which upon receiving the associated command for a function returns the data requested for example command 200 returns temperature sensor data . Using UDP in python I want to send commands to the zynq board.
Also the function will be called only upon defining the function parameters , MessageID is the command to be excuted , UniqueId and Overload is just a random number and Subgroup and SensorIndex are the inbuilt or fixed ids in the zyng for example group 0 and index 1 , this functions I have defined in another script called testfunctions def systemMonitorGetSensor(MessageID, UniqueID, Overload, Subgroup, SensorIndex):
import socket
import os
import testfunctions as test
def main(self):
def openconnection():
UDP_IP = "172.29.11.113" # Get local machine name
UDP_PORT = 4711 # Reserve a port for your service
MESSAGE = b"Hello SCE100...python talking"
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(MESSAGE, (UDP_IP, UDP_PORT))
def ping():
UDP_IP = "172.29.11.113"
response = os.system('ping -c 1 ' + UDP_IP)
if response == 0:
print(UDP_IP, 'is up')
else:
print(UDP_IP, 'is down')
def stopsocket(self):
self.sock.shutdown(socket.SOCK_DGRAM)
self.sock.closes()
openconnection()
ping()
MessageID = int(input("Enter the TaskID to be executed : "))
print(MessageID)
main ( MessageID )
if MessageID == 200:
test.systemMonitorGetAllSensors(200,0,0)
if MessageID == 201:
systemMonitorResponce()

How do I send a string + variable as sms using python?

I need to send a message when my program is done running, but I also want to include variables such as how long the program took to run in the text.
Here is my code for the texting:
import smtplib
carriers = {
'att': '#mms.att.net',
'tmobile': ' #tmomail.net',
'verizon': '#vtext.com',
'sprint': '#page.nextel.com'
}
def send(message):
# Replace the number with your own, or consider using an argument\dict for multiple people.
to_number = 'xxxxxxxxxx{}'.format(carriers['verizon'])
auth = ('xxxxx', 'xxxx')
# Establish a secure session with gmail's outgoing SMTP server using your gmail account
server = smtplib.SMTP("smtp.gmail.com", 587)
server.starttls()
server.login(auth[0], auth[1])
# Send text message through SMS gateway of destination number
server.sendmail(auth[0], to_number, message)
Obviously, I replaced my info with the xxx.
Now, to send my text I'm calling the function using:
found = 'The program is done!'
timetook = "Time took: %s (HOUR:MIN:SEC)" % timedelta(seconds=round(elapsed_time_secs))
send(found)
send(timetook)
It just sends blank texts for the timetook, but the program is done message works fine. How do I send the timetook?
The problem is that you aren't following the rules for SMTP. Below is the equivalent solution I wrote for my own use many years ago.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""SMS (short message service) functions."""
import logging
import smtplib
import sys
import rate_limiting
SMTP_GATEWAY = 'localhost'
FROM_ADDR = 'me#domain.us'
PHONE_NUMBER = '4081234567'
# T-Mobile SMS email gateway
# TO_ADDR = PHONE_NUMBER + '#tmomail.net'
# Verizon SMS email gateway
TO_ADDR = PHONE_NUMBER + '#vtext.com'
# Allow only three SMS messages per minute and five per hour.
short_term_rate_limiter = rate_limiting.SimpleRateLimiter(3, 60)
long_term_rate_limiter = rate_limiting.SimpleRateLimiter(5, 60 * 60)
def SendSms(msg, why=''):
"""Send a SMS message."""
short_term_rate_exceeded = short_term_rate_limiter()
long_term_rate_exceeded = long_term_rate_limiter()
if short_term_rate_exceeded or long_term_rate_exceeded:
logging.warning('SMS message rate exceeded, dropping msg: %s', msg)
return
smtp_conn = smtplib.SMTP(SMTP_GATEWAY)
hdrs = 'From: {}\r\nTo: {}\r\n\r\n'.format(FROM_ADDR, TO_ADDR)
if why:
hdrs += 'Subject: {}\r\n'.format(why[:20])
hdrs += "\r\n\r\n"
max_msg_len = 140 - 3 - min(20, len(why))
msg = hdrs + msg[:max_msg_len]
# Make sure the message has only ASCII characters.
msg = msg.encode('ascii', errors='replace').decode('ascii')
smtp_conn.sendmail(FROM_ADDR, [TO_ADDR], msg)
smtp_conn.quit()
if __name__ == '__main__':
SendSms(' '.join(sys.argv[1:]))

python arp header unpacking with struct module

I'm going to make my own python sniffer but i have problem with unpacking arp protocol header.
here is my code:
def Sniffer():
try:
# AF_PACKET, That's basically packet level.
# 0X0003, That's every packet. (We can find it here: /usr/include/linux/if_ether.h)
SK = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0003))
except socket.error as MSG:
print "Socket creation error:\n", MSG
try:
while True:
Receive = SK.recvfrom(65565)
Packet = Receive[0]
Ethernet(Packet)
except socket.error as MSG:
print "Receive error:\n", MSG
# Ethernet Decapsulation (We need EtherType field value)
def Ethernet(Packet):
ETHERNET_LENGTH = 14
ETHERNET_HEADER = Packet[:ETHERNET_LENGTH]
ETHERNET_HEADER_UNPACK = struct.unpack("!6s6sH", ETHERNET_HEADER)
EtherType = ETHERNET_HEADER_UNPACK[2]
print EtherType
if EtherType == 2054:
ARP(ETHERNET_LENGTH, Packet)
if EtherType == 2048:
IPV4(Packet)
# ARP Decapsulation (We need OPCODE field value)
def ARP(ETHERNET_LENGTH, Packet):
ARP_LENGTH = 42
ARP_HEADER = Packet[ETHERNET_LENGTH:ARP_LENGTH]
ARP_HEADER_UNPACK = struct.unpack("!2s2s1s1s2s6s4s6s4s", ARP_HEADER)
OPCODE = ARP_HEADER_UNPACK[4]
if OPCODE == 1:
print "ARP Request (Some one scann your network)"
That's my error:
Traceback (most recent call last):
File "HoneySniffer.py", line 130, in <module>
Sniffer()
File "HoneySniffer.py", line 22, in Sniffer
Ethernet(Packet)
File "HoneySniffer.py", line 38, in Ethernet
ARP(ETHERNET_LENGTH, Packet)
File "HoneySniffer.py", line 48, in ARP
ARP_HEADER_UNPACK = struct.unpack("!2s2s1s1s2s6s4s6s4s", ARP_HEADER)
struct.error: unpack requires a string argument of length 28
why this is happening?
How can i to fix it?
I find it here: Python arp sniffing raw socket no reply packets
I have the exact same problem and i solved it using your reference link Python arp sniffing raw socket no reply packets and little research of my own.
conn=socket.socket(socket.AF_PACKET,socket.SOCK_RAW,socket.ntohs(0x0003))
def arp_header(packet):
(a ,b ,c ,d ,e ,f ,g ,h ,i ) = struct.unpack('2s2s1s1s2s6s4s6s4s',packet[14:42])
hw_type=(binascii.hexlify(a)).decode('utf-8')
proto_type=(binascii.hexlify(b)).decode('utf-8')
hw_size=(binascii.hexlify(c)).decode('utf-8')
proto_size=(binascii.hexlify(d)).decode('utf-8')
opcode=(binascii.hexlify(e)).decode('utf-8')
return (hw_type,proto_type,hw_size,proto_size,opcode,socket.inet_ntoa(g),socket.inet_ntoa(i))
use struct.unpack('2s2s1s1s2s6s4s6s4s',packet[14:42])
not struct.unpack('!2s2s1s1s2s6s4s6s4s',packet[14:42])
this solved my struct.error: unpack requires a string argument of length 28 error
i have also used individual variables,due to my project requirements,
Now ,for debugging i used print(packet[14:42]) -which gave me byte hex literals(like b'\x00\x01\x08\x00\x06\x04\x00\x01\xe4\x11[I&\xbe\n\x00..... etc)
so i have to decode in utf-8 after using hexlify,since hexlify is again returning byte objects to me.
Python version i used:3.6.5
Date:03/April/2019
Result:- Arp Packet:
- H/W Type: 0001, Protocol Type: 0800, H/W Size: 06 ,Protocol Size: 04
- Opcode: 0001, Source IP: 10.0.15.141, Destination IP: 10.0.10.2
Verdict:This method worked for me,i hope it will work for you also :)

How to get http server response on a different device in LAN?

I am new to python and my networking logics are at the beginner level. I have an HTTP server running in a VM and when I curl it from a different terminal on the same machine, I get the expected response. I am looking for a functionality where I can get the same response on my mobile device when I type the ip and port in the browser. My mobile device is connected to the same WiFi. Here's the server code:
import socket
MAX_PACKET = 32768
def recv_all(sock):
r'''Receive everything from `sock`, until timeout occurs, meaning sender
is exhausted, return result as string.'''
# dirty hack to simplify this stuff - you should really use zero timeout,
# deal with async socket and implement finite automata to handle incoming data
prev_timeout = sock.gettimeout()
try:
sock.settimeout(0.01)
rdata = []
while True:
try:
rdata.append(sock.recv(MAX_PACKET))
except socket.timeout:
return ''.join(rdata)
# unreachable
finally:
sock.settimeout(prev_timeout)
def normalize_line_endings(s):
r'''Convert string containing various line endings like \n, \r or \r\n,
to uniform \n.'''
return ''.join((line + '\n') for line in s.splitlines())
def run():
r'''Main loop'''
# Create TCP socket listening on 10000 port for all connections,
# with connection queue of length 1
server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, \
socket.IPPROTO_TCP)
server_sock.bind(('10.0.2.15',80))
server_sock.listen(1)
while True:
# accept connection
client_sock, client_addr = server_sock.accept()
# headers and body are divided with \n\n (or \r\n\r\n - that's why we
# normalize endings). In real application usage, you should handle
# all variations of line endings not to screw request body
request = normalize_line_endings(recv_all(client_sock)) # hack again
request_head, request_body = request.split('\n\n', 1)
# first line is request headline, and others are headers
request_head = request_head.splitlines()
request_headline = request_head[0]
# headers have their name up to first ': '. In real world uses, they
# could duplicate, and dict drops duplicates by default, so
# be aware of this.
request_headers = dict(x.split(': ', 1) for x in request_head[1:])
# headline has form of "POST /can/i/haz/requests HTTP/1.0"
request_method, request_uri, request_proto = request_headline.split(' ', 3)
response_body = [
'<html><body><h1>Hello, world!</h1>',
'<p>This page is in location %(request_uri)r, was requested ' % locals(),
'using %(request_method)r, and with %(request_proto)r.</p>' % locals(),
'<p>Request body is %(request_body)r</p>' % locals(),
'<p>Actual set of headers received:</p>',
'<ul>',
]
for request_header_name, request_header_value in request_headers.iteritems():
response_body.append('<li><b>%r</b> == %r</li>' % (request_header_name, \
request_header_value))
response_body.append('</ul></body></html>')
response_body_raw = ''.join(response_body)
# Clearly state that connection will be closed after this response,
# and specify length of response body
response_headers = {
'Content-Type': 'text/html; encoding=utf8',
'Content-Length': len(response_body_raw),
'Connection': 'close',
}
response_headers_raw = ''.join('%s: %s\n' % (k, v) for k, v in \
response_headers.iteritems())
# Reply as HTTP/1.1 server, saying "HTTP OK" (code 200).
response_proto = 'HTTP/1.1'
response_status = '200'
response_status_text = 'OK' # this can be random
# sending all this stuff
client_sock.send('%s %s %s' % (response_proto, response_status, \
response_status_text))
client_sock.send(response_headers_raw)
client_sock.send('\n') # to separate headers from body
client_sock.send(response_body_raw)
# and closing connection, as we stated before
client_sock.close()
run()
Here's the response when I run curl from a different terminal on the same VM.
I want to ping it from my mobile device connected to the same WiFi. Thank you!

Categories