I tried using the code here: Issuing challenges through the API
I am trying to join a game and play moves in it. However, the SocketIO object hangs trying to do the SSL handshake. Has anyone else had the problem/found a solution?
I tried using the code here: Issuing challenges through the API
I am trying to join a game and play moves in it. However, the SocketIO object hangs trying to do the SSL handshake. Has anyone else had the problem/found a solution?
Let me ping @anoek here and I will dig through come code I have to see if I have any examples.
Edit: Can you post the code you are using? Also, if you are interested we have a Slack channel for OGS development. PM me an email address and I will add you.
No problem. I am running python 3.6 with Anaconda on the Linux subsystem on Windows 10. The code I have is the following: (I am just trying to play a move in this (https://online-go.com/game/8610273) game, getting constant communication shouldnāt be too hard past that once I have the socket up and running) I am aware that the code will crash after the socket is established because I am missing the on_response method, but I will cross that bridge when I get there
import requests
import time
from socketIO_client import SocketIO
from subprocess import call
s = requests.Session()
ogs_link = 'http://online-go.com'
home = s.get(ogs_link + '/api')
auth = s.post('https://online-go.com/oauth2/token/', data={"username":"theonly747beast", "password":"NotMyPassword", "client_id":"NotMyId", "client_secret": "NotMySecret", "grant_type": "password"})
oauth2_json = auth.json()
access_token = oauth2_json['access_token']
refresh_token = oauth2_json['refresh_token']
prof = s.get('https://online-go.com/api/v1/me/',
headers = {
'Authorization': 'Bearer {}'.format(access_token),
},
)
def rank_to_display(rank_value):
if rank_value < 30:
return '%dk' % (30-rank_value,)
else:
return '%dd' % ((rank_value-30)+1)
my_info_json = prof.json()
# print(my_info_json)
# print()
print('overall: {}, blitz: {}, live: {}, corr: {}'.format(
rank_to_display(my_info_json['ranking']),
rank_to_display(my_info_json['ranking_blitz']),
rank_to_display(my_info_json['ranking_live']),
rank_to_display(my_info_json['ranking_correspondence']),
))
print()
#code for making a challenge, I just want to make a move in an existing game for now.
# challenge = s.post('https://online-go.com/api/v1/challenges',
# headers = {
# 'Authorization': 'Bearer {}'.format(access_token),
# 'Content-Type': 'application/json'
# },
# json = {
# 'game': {
# 'name': 'Test Game -- Please don\'t join!',
# 'rules': 'japanese',
# 'ranked': False,
# 'handicap': 0,
# 'time_control': 'simple',
# "time_control_parameters": {
# 'time_control': 'simple',
# "per_move": 30
# },
# 'pause_on_weekends': False,
# 'width': 19,
# 'height': 19,
# 'disable_analysis': False,
# },
# 'challenger_color': 'automatic',
# 'min_ranking': 0,
# 'max_ranking': 10,
# },
# allow_redirects = False,
# );
# print(challenge.json())
# print("Hello")
with SocketIO('https://ggs.online-go.com/socket.io') as socketIO:
print("socket is connected.")
socketIO.emit("game/connect",
{'game_id': 8610273, 'player_id': playerid, 'chat': 1, 'game_type': "game", 'auth':access_token},
on_response)
socketIO.wait_for_callbacks(seconds=3)
# try submitting a move
socketIO.emit("game/move",{"auth":access_token,"game_id":8610273,"player_id":playerid,"move":"cb"},
on_response)
socketIO.wait_for_callbacks(seconds=3)
When I run it, it prints out the following (which is correct) and does not halt:
overall: 25k, blitz: 25k, live: 25k, corr: 25k
When I press Ctrl+C to kill it, it prints out the following stack trace:
Traceback (most recent call last):
File "/home/jbarratt/anaconda3/lib/python3.6/site-packages/socketIO_client/logs.py", line 29, in _yield_warning_screen yield elapsed_time
Exception: [engine.io waiting for connection] hostname 'ggs.online-go.com' doesn't match either of '*.idviu.io', 'idviu.io' During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "testingstuff.py", line 71, in <module>
with SocketIO('https://ggs.online-go.com/socket.io') as socketIO:
File "/home/jbarratt/anaconda3/lib/python3.6/site-packages/socketIO_client/__init__.py", line 353, in __init__ resource, hurry_interval_in_seconds, **kw)
File "/home/jbarratt/anaconda3/lib/python3.6/site-packages/socketIO_client/__init__.py", line 54, in __init__ self._transport
File "/home/jbarratt/anaconda3/lib/python3.6/site-packages/socketIO_client/__init__.py", line 62, in _transport self._engineIO_session = self._get_engineIO_session()
File "/home/jbarratt/anaconda3/lib/python3.6/site-packages/socketIO_client/__init__.py", line 83, in _get_engineIO_session warning_screen.throw(warning)
File "/home/jbarratt/anaconda3/lib/python3.6/site-packages/socketIO_client/logs.py", line 35, in _yield_warning_screen time.sleep(1)
KeyboardInterrupt
Also, when I try to use http, it runs into a StopIteration error and crashes.
Another thing that was mentioned in the linked thread was that challenges timed out after a few seconds of being up but were otherwise fine. Is there a way around this?
(Another side note, I have reached my max new threads limit for the first day, so Iām happy to respond to a PM as long as you start it)
Ok, so, this is weird. ggs.online-go.com returns a certificate for *.idviu.io, which is obviously not valid. I donāt know off the top of my head, but Iād assume you could tell Socket.io to ignore this cert mismatch.
@anoek uhhhā¦any idea why you have a seemingly random certificate on that endpoint?
Oh, edit, meant to add that I tested and got the same thing - so itās definitely not some intermediate certificate on his connection.
Hereās the cert I get back from an openssl s_client connection:
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
46:c5:d8:2d:50:6b:a6:a5:91:49:4c:4d:c4:d2:de:1c
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=FR, ST=Paris, L=Paris, O=Gandi, CN=Gandi Standard SSL CA 2
Validity
Not Before: Oct 5 00:00:00 2016 GMT
Not After : Oct 5 23:59:59 2018 GMT
Subject: OU=Domain Control Validated, OU=Gandi Standard Wildcard SSL, CN=*.idviu.io
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:c8:cc:80:a5:c5:98:40:7f:7a:a5:bd:c7:c0:69:
6d:13:20:eb:8f:e4:fe:3c:dc:51:aa:70:aa:29:d7:
92:f1:4a:7b:23:21:76:9e:f9:a8:b9:48:6f:4f:64:
3c:b5:80:2b:bf:e1:c6:3d:94:50:50:85:4f:7c:45:
10:b1:bf:c1:fb:70:00:ee:93:c3:06:2d:43:f1:2c:
ed:4a:26:8a:22:ac:1a:03:0d:54:c8:38:e9:d0:d9:
3c:ff:0b:31:cc:4d:29:46:b9:69:7a:12:bd:3e:84:
83:a6:44:d6:0b:03:35:c9:0b:3d:fd:d5:5d:13:3b:
b7:78:ff:63:a2:71:66:ff:30:c3:41:f0:fd:a0:de:
5c:77:91:72:8e:e5:6e:3b:14:2a:54:15:35:c7:9e:
7b:f7:a4:6b:ba:32:cc:7d:81:de:f2:57:98:f5:77:
b1:93:f6:8f:50:67:f5:e6:1f:9e:d5:c1:ab:79:b4:
80:77:85:00:8c:70:34:d2:a2:bd:e0:f2:0d:5f:f6:
b5:56:e3:3a:a7:78:77:05:0c:b3:cf:03:7d:fa:66:
6c:93:0c:1a:e8:01:24:34:d6:e2:aa:6f:f9:2d:fd:
80:de:b8:66:82:84:5c:b5:0c:b3:dc:b4:d5:41:b4:
d9:fa:ec:d0:e6:47:3d:d8:bf:cd:07:6a:aa:16:54:
24:d9
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Authority Key Identifier:
keyid:B3:90:A7:D8:C9:AF:4E:CD:61:3C:9F:7C:AD:5D:7F:41:FD:69:30:EA
X509v3 Subject Key Identifier:
D3:FA:25:87:50:00:D9:29:1B:D3:D9:F5:69:97:DD:01:A9:71:D0:89
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Certificate Policies:
Policy: 1.3.6.1.4.1.6449.1.2.2.26
CPS: https://cps.usertrust.com
Policy: 2.23.140.1.2.1
X509v3 CRL Distribution Points:
Full Name:
URI:http://crl.usertrust.com/GandiStandardSSLCA2.crl
Authority Information Access:
CA Issuers - URI:http://crt.usertrust.com/GandiStandardSSLCA2.crt
OCSP - URI:http://ocsp.usertrust.com
X509v3 Subject Alternative Name:
DNS:*.idviu.io, DNS:idviu.io
Signature Algorithm: sha256WithRSAEncryption
33:8d:14:90:e8:2a:d1:01:dd:91:0b:2b:fe:2c:1f:a9:72:09:
d2:b9:c4:ed:46:79:6f:8e:81:f6:ce:e3:e3:38:be:54:b2:67:
3a:87:f7:c4:1a:1f:3f:f8:f5:3a:7e:87:81:76:1d:fe:36:1c:
4c:af:5a:71:bf:c3:15:5a:2c:9a:c1:ab:bd:20:5e:6b:5a:c6:
bc:f9:c0:c1:3e:70:28:d9:f2:c9:38:5a:85:ec:3b:db:08:30:
18:7a:0c:08:fe:14:0a:6f:af:07:4a:f1:0b:3c:8d:80:e9:a8:
2d:e9:c4:99:96:5c:0d:16:cf:51:dc:8c:a7:de:01:f9:81:e7:
bf:da:18:70:ce:02:31:49:fd:c4:f0:cd:b5:f8:fb:ef:09:33:
eb:db:2c:57:9c:ff:09:88:6c:1d:d7:62:59:2a:ba:bc:00:71:
c6:a1:12:6a:26:81:69:d4:c0:65:86:20:e0:90:1b:17:ac:d5:
1e:09:1a:e9:3d:c0:03:4a:71:95:b0:d6:53:bc:97:9a:67:95:
15:3d:dd:64:78:da:f9:99:0d:ab:1a:3d:d6:ce:e0:66:86:fc:
04:e3:0f:ed:d7:ce:28:89:52:44:ab:64:0f:c4:e3:30:3f:5f:
c0:35:1e:71:1b:a9:9b:b0:da:fa:e7:88:28:3e:1f:e9:68:c1:
6d:b8:91:5b
Ok, I figured out how to turn off verification (via the verify=False. This issue can be figured out at a later time, because this fix seems to work), but now there is a crash when it is starting a session, like so:
Traceback (most recent call last):
File "testingstuff.py", line 71, in <module>
with SocketIO('https://ggs.online-go.com/socket.io', secure=True, verify=False) as socketIO:
File "/home/jbarratt/anaconda3/lib/python3.6/site-packages/socketIO_client/__init__.py", line 353, in __init__ resource, hurry_interval_in_seconds, **kw)
File "/home/jbarratt/anaconda3/lib/python3.6/site-packages/socketIO_client/__init__.py", line 54, in __init__ self._transport
File "/home/jbarratt/anaconda3/lib/python3.6/site-packages/socketIO_client/__init__.py", line 62, in _transport self._engineIO_session = self._get_engineIO_session()
File "/home/jbarratt/anaconda3/lib/python3.6/site-packages/socketIO_client/__init__.py", line 76, in _get_engineIO_session transport.recv_packet())
StopIteration
After some snooping, it seems that the Python SocketIO class doesnāt like the fact that ggs.online-go.com/socket.io only returns a āREADYā message, and wants more information. Is there any other way to create a socketIO connection using python?
Hiya @the747beast, ggs.online-go.com
isnāt used anymore, that was for v4, just replace that with online-go.com
and you should be good to go.
Iāve removed the DNS entry for that now to help thwart future confusion.
Thanks for the update, @anoek! I changed the URL to online-go.com
, and I am now receiving unexpected status code (400 {"code":0,"message":"Transport unknown"})
when I try to connect. The version of socketio I am using is compatible with 1.x; should I be using a version compatible with 0.9?
Nope 1.x is good, weāre on 1.4 or 1.5 iirc - though only the websocket transport is supported
@anoek I moved over to Websocket so that I could be sure I was using that (I think before SocketIO was using XHS_PollingTransport, couldnāt get it to use websockets). I am able to contact the online-go.com
server, but it responds with a 301 if I try to use ws://
and a 502 if I try and use wss://
. Here is my code, and the output:
def on_message(ws, message):
print("Hi again!")
def on_error(ws, error):
print("ERROR: ", error)
def on_close(ws):
print("Goodbye!")
def on_open(ws):
print("Hello!")
websocket.enableTrace(True)
ws = websocket.WebSocketApp("ws://online-go.com",
on_message = on_message,
on_error = on_error,
on_close = on_close)
ws.on_open = on_open
ws.run_forever()
Output:
--- request header ---
GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: online-go.com
Origin: http://online-go.com
Sec-WebSocket-Key: C35xxfhqURL1INXimQaIXg==
Sec-WebSocket-Version: 13
-----------------------
--- response header ---
HTTP/1.1 301 Moved Permanently
Date: Fri, 05 May 2017 03:39:30 GMT
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: __cfduid=d75c0be03d4f487fc0a8a9e0161765b4e1493955570; expires=Sat, 05-May-18 03:39:30 GMT; path=/; domain=.online-go.com; HttpOnly
Cache-Control: max-age=3600
Expires: Fri, 05 May 2017 04:39:30 GMT
Location: https://online-go.com/
Server: cloudflare-nginx
CF-RAY: 35a0ac4b908d6d5a-SJC
-----------------------
ERROR: Handshake status 301
Goodbye!
Output when ws://
is changed to wss://
:
--- request header ---
GET / HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Host: online-go.com
Origin: http://online-go.com
Sec-WebSocket-Key: jnV7p92WNFcfYcxryNIH/g==
Sec-WebSocket-Version: 13
-----------------------
--- response header ---
HTTP/1.1 502 Bad Gateway
Date: Fri, 05 May 2017 03:43:24 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: __cfduid=d0d77c02090c468cfb2464039ff6d91481493955804; expires=Sat, 05-May-18 03:43:24 GMT; path=/; domain=.online-go.com; HttpOnly
Expires: Thu, 01 Jan 1970 00:00:01 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache
X-Frame-Options: SAMEORIGIN
Server: cloudflare-nginx
CF-RAY: 35a0b2002f291219-SJC
-----------------------
ERROR: Handshake status 502
Goodbye!
Hopefully once I can get this connection going it can all go smoothly.
Edit: I was able to get the same behavior when running SocketIO with Websockets only.
I havenāt used the python socket.io libraries so not sure, hereās the node code that works if itās any help: https://github.com/online-go/gtp2ogs/blob/devel/gtp2ogs.js#L897-L905
For your WebSocket implementation, your problem is that ws is equivalent to http, so youāre getting a 301 sending you to https (which is analogous to wss). You noticed that if you do that youāll get a 502 because you didnāt specify websocket transport. Thatās also easily fixed though, try this:
ws = websocket.WebSocketApp("wss://online-go.com/socket.io/?transport=websocket",on_message = on_message, on_error = on_error, on_close = on_close)
ws.run_forever()
I think part of this is coming down to you somewhat misunderstanding ātransportā here. Iām learning this recently too, but in Socket.io, there are two: polling and websocket. You specify that as a query parameter, not based on how you execute it. (Note that this also seems to break Socket.io convention with is (based on my understanding from some cursory Googling) to āupgradeā polling connections to websockets if possible, which is probably why itās a little bit harder than normal.)
Also, for what itās worth, hereās how to start a connection with a post. However, requests doesnāt have the ability to continue it past there (wss isnāt implemented, obviously). It gives you the 101 Switching Protocols response that Socket.io is supposed to give when a connection is initiated to switch to websockets. Note Sec-WebSocket-Key is the base64 encoding of any random 16 bytes.
r = requests.get(āhttps://online-go.com/socket.io/?EIO=3&transport=websocketā, headers={āUpgradeā:āwebsocketā, āConnectionā:āUpgradeā, āSec-WebSocket-Keyā:āYWJjZGVmZ2hqdHVnZGZ0YQ==ā, āSec-WebSocket-Versionā:ā13ā})
Ok, after digging through the source code for socketIO_client, it seems itās following the Socket.io standard and starting everything with a polling transport first. You can make it show you what itās doing more readily (instead of hanging) by adding the keyword argument wait_for_connection=False to the SocketIO constructor. It gives a 400, but if you put in an invalid URL, it actually shows the request string with transport=polling.
>>> sio = SocketIO('https://online-go.com',wait_for_connection=False)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/root/jam/socketio/clean/lib/python2.7/site-packages/socketIO_client/__init__.py", line 353, in __init__
resource, hurry_interval_in_seconds, **kw)
File "/root/jam/socketio/clean/lib/python2.7/site-packages/socketIO_client/__init__.py", line 54, in __init__
self._transport
File "/root/jam/socketio/clean/lib/python2.7/site-packages/socketIO_client/__init__.py", line 62, in _transport
self._engineIO_session = self._get_engineIO_session()
File "/root/jam/socketio/clean/lib/python2.7/site-packages/socketIO_client/__init__.py", line 76, in _get_engineIO_session
transport.recv_packet())
File "/root/jam/socketio/clean/lib/python2.7/site-packages/socketIO_client/transports.py", line 82, in recv_packet
**self._kw_get)
File "/root/jam/socketio/clean/lib/python2.7/site-packages/socketIO_client/transports.py", line 186, in get_response
status_code, response.text))
socketIO_client.exceptions.ConnectionError: unexpected status code (400 {"code":0,"message":"Transport unknown"})
Trying to force it to websocket initially has been, thus far, unsuccessful. Even with taking xhr-polling out of the transports in the source didnāt quite work, and replacing the polling class with the websocket class (for science) just ended up really pissing it off. (Unsurprisingly.)
Iāll keep poking at it more later and see what I can get. Iām sure thereās a real way to force it to use websocket transportā¦
Note the transport=polling at the end of this.
>>> sio = SocketIO('https://online-go.comm',wait_for_connection=False,transports=['websocket'])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/root/jam/socketio/clean/lib/python2.7/site-packages/socketIO_client/__init__.py", line 353, in __init__
resource, hurry_interval_in_seconds, **kw)
File "/root/jam/socketio/clean/lib/python2.7/site-packages/socketIO_client/__init__.py", line 54, in __init__
self._transport
File "/root/jam/socketio/clean/lib/python2.7/site-packages/socketIO_client/__init__.py", line 62, in _transport
self._engineIO_session = self._get_engineIO_session()
File "/root/jam/socketio/clean/lib/python2.7/site-packages/socketIO_client/__init__.py", line 76, in _get_engineIO_session
transport.recv_packet())
File "/root/jam/socketio/clean/lib/python2.7/site-packages/socketIO_client/transports.py", line 82, in recv_packet
**self._kw_get)
File "/root/jam/socketio/clean/lib/python2.7/site-packages/socketIO_client/transports.py", line 180, in get_response
raise ConnectionError(e)
socketIO_client.exceptions.ConnectionError: HTTPSConnectionPool(host='online-go.comm', port=443): Max retries exceeded with url: /socket.io/?EIO=3&transport=polling&t=1494034135266-0 (Caused by NewConnectionError('<requests.packages.urllib3.connection.VerifiedHTTPSConnection object at 0x7fa4ef825590>: Failed to establish a new connection: [Errno 111] Connection refused',))
Update on where I am now: I have decided to move to a node.js middle man between the OGS server and my python program. The connection between node js and python seems to be working fine (am using zerorpc). The node.js notifies python when it needs to make a move, and then the python program decides what to move, then calls the sendmove
function inside of the node.js file. However, I canāt seem to get the node.js file to be able to send moves to the server and have them show up. The only time that I seem to be able to successfully send moves is when listening for a āconnectā response. I made a little node.js program that uses that fact, but it only sends one move per socket connection. When I use this to submit moves, the whole system works for 2 moves then the server stops accepting moves. I also think making a new socket for every move is very wasteful and probably hard on the server, so what is the better way to do this?
OGSInterface.js:
'use strict';
let io = require('socket.io-client');
let http = require('http');
let https = require('https');
let crypto = require('crypto');
let request = require('request');
let optimist = require("optimist")
.usage("Usage: $0 --id <bot id> --auth <api key> --gameid <game id>")
.demand('id')
.demand('gameid')
.demand('auth')
.describe('id', 'Specify the id of the bot')
.describe('auth', 'Specify the API key for the bot')
.describe('gameid', 'Specify the game id to make the move in')
;
let args = optimist.argv;
let game_id = args.gameid;
let id = args.id;
let auth = args.auth;
let zerorpc = require("zerorpc");
let client = new zerorpc.Client();
client.connect("tcp://127.0.0.1:4242");
let socket = let this.socket = io('https://online-go.com:443', {
reconection: true,
reconnectionDelay: 500,
reconnectionDelayMax: 60000,
transports: ['websocket'],
});
let bot_id = null;
let jwt = null;
socket.on('connect', () => {
console.log("----OGSinterface.js: Connected.")
this.socket.emit('net/ping', {client: (new Date()).getTime()});
this.socket.emit('authenticate', {'auth':auth});
this.socket.emit('game/connect', {'game_id':game_id, "bot_id":id, "auth":auth})
this.socket.emit('bot/id', {'id': 'theonly747beast'}, (obj) => {
bot_id = obj.id;
jwt = obj.jwt;
console.log(jwt)
console.log("Bot is user id:", bot_id);
});
});
var server = new zerorpc.Server({
sendmove: function(apikey, gamekey, move, socket, reply) {
console.log(apikey, gamekey, move, game_id, jwt);
if (move == "resign") {
console.log("----sendmove.js: Resigning.");
this.socket.emit("game/resign", {
"apikey": apikey,
"auth": gamekey,
"game_id": game_id,
"bot_id": bot_id,
"player_id": id,
"jwt": jwt}, () => {});
} else {
console.log("----sendmove.js: Sending move", move);
this.socket.emit('game/move', {
"apikey": apikey,
"auth": gamekey,
"game_id": game_id,
"player_id": id,
"bot_id": bot_id,
"move": move,
"jwt": jwt
}, () => {console.log("----sendmove.js: Sent!");});
}
reply(null)
}
});
server.bind("tcp://0.0.0.0:4243");
socket.on('game/' + game_id + '/gamedata', (gamedata) => {
console.log("----OGSinterface.js: Game Updated.")
//this.log("Gamedata:", JSON.stringify(gamedata, null, 4));
this.state = gamedata;
this.my_color = id == this.state.players.black.id ? "black" : "white";
this.opponent_evenodd = this.my_color == "black" ? 0 : 1;
// First handicap is just lower komi, more handicaps may change who is even or odd move #s.
//
if (this.state.free_handicap_placement && this.state.handicap > 1) {
//In Chinese, black makes multiple free moves.
//
this.opponent_evenodd = (this.opponent_evenodd + this.state.handicap - 1) % 2;
} else if (this.state.handicap > 1) {
// In Japanese, white makes the first move.
//
this.opponent_evenodd = this.my_color == "black" ? 1 : 0;
}
// If server has issues it might send us a new gamedata packet and not a move event. We could try to
// check if we're missing a move and send it to bot out of gamadata. For now as a safe fallback just
// restart the bot by killing it here if another gamedata comes in. There normally should only be one
// before we process any moves, and makeMove() is where a new Bot is created.
//
// active_game isn't handling this for us any more. If it is our move, call makeMove.
//
if (this.state.phase == "play" && this.state.clock.current_player == id) {
client.invoke("makeMove");
}
});
socket.on('game/' + game_id + '/move', (move) => {
console.log("----OGSinterface.js: game/" + game_id + "/move:", move);
if (move.move_number % 2 == this.opponent_evenodd) {
// We just got a move from the opponent, so we can move immediately.
client.invoke("makeMove");
} else {
console.log("----OGSinterface.js: Ignoring our own move", move.move_number);
}
});
RandomPlayer.py:
import requests
import time
import websocket
import zerorpc
import random
from sgfmill import sgf, boards
from subprocess import Popen, call
s = requests.Session()
ogs_link = 'http://online-go.com'
home = s.get(ogs_link + '/api')
auth = s.post('https://online-go.com/oauth2/token/', data={"username":"theonly747beast", "password":"NotMyPassword", "client_id":"NotMyId", "client_secret": "NotMySecret", "grant_type": "password"})
oauth2_json = auth.json()
access_token = oauth2_json['access_token']
refresh_token = oauth2_json['refresh_token']
prof = s.get('https://online-go.com/api/v1/me/',
headers = {
'Authorization': 'Bearer {}'.format(access_token),
},
)
def rank_to_display(rank_value):
if rank_value < 30:
return '%dk' % (30-rank_value,)
else:
return '%dd' % ((rank_value-30)+1)
my_info_json = prof.json()
# print(my_info_json)
# print()
print('overall: {}, blitz: {}, live: {}, corr: {}'.format(
rank_to_display(my_info_json['ranking']),
rank_to_display(my_info_json['ranking_blitz']),
rank_to_display(my_info_json['ranking_live']),
rank_to_display(my_info_json['ranking_correspondence']),
))
print()
challenge = s.post('https://online-go.com/api/v1/challenges',
headers = {
'Authorization': 'Bearer {}'.format(access_token),
'Content-Type': 'application/json'
},
json = {
'game': {
'name': 'Test Game -- Please don\'t join!',
'rules': 'japanese',
'ranked': False,
'handicap': 0,
'time_control': 'simple',
"time_control_parameters": {
'time_control': 'simple',
"per_move": 30
},
'pause_on_weekends': False,
'width': 19,
'height': 19,
'disable_analysis': False,
},
'challenger_color': 'automatic',
'min_ranking': 0,
'max_ranking': 10,
},
allow_redirects = False,
);
print("Access Token: " + access_token)
class Random(object):
def makeMove(self):
gameinfo = requests.get('https://online-go.com/api/v1/games/' + str(challenge.json()['game']), headers = {'Authorization': 'Bearer {}'.format(access_token)})
sgfstr = requests.get('https://online-go.com/api/v1/games/' + str(challenge.json()['game']) + "/sgf/")
game = sgf.Sgf_game.from_string(sgfstr.text)
board = boards.Board(19)
array = []
for node in game.get_main_sequence():
move = node.get_move()
if move[0] == None:
continue
if move[1] == None:
continue
try:
board.play(move[1][0], move[1][1], move[0])
except ValueError:
print("Value Error!")
return
except IndexError:
print("Index Error!")
return
occupied = board.list_occupied_points()
possiblemoves = [(i, j) for i in range(19) for j in range(19)]
for spot in occupied:
possiblemoves.remove(spot[1])
print(possiblemoves)
move = random.choice(possiblemoves)
letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's']
print("Making random move.")
print(board)
print(move)
# call(["node", "sendmove.js", "--id", str(my_info_json['id']), "--gameauth", str(gameinfo.json()['auth']), "--gameid", str(challenge.json()['game']), "--apikey", access_token, "--move", letters[move[0]] + letters[move[1]]])
c = zerorpc.Client()
c.connect("tcp://127.0.0.1:4243")
c.sendmove(access_token, gameinfo.json()['auth'], letters[move[0]] + letters[move[1]])
print("Done sending random move.")
s = zerorpc.Server(Random())
s.bind("tcp://0.0.0.0:4242")
Popen(["node", "OGSinterface.js", "--id", str(my_info_json['id']), "--auth", access_token, "--gameid", str(challenge.json()['game'])])
s.run()
sendmove.js:
'use strict';
let optimist = require("optimist")
.usage("Usage: $0 --id <bot id> --apikey <api key> --gameid <game id> --gameauth <gameauth> --move [ab]")
.demand('id')
.demand('move')
.demand('gameid')
.demand('apikey')
.demand('gameauth')
.describe('id', 'Specify the id of the bot')
.describe('apikey', 'Specify the API key for the bot')
.describe('gameauth', 'Specify the game authorization code')
.describe('gameid', 'Specify the game id to make the move in')
.describe('move', 'Specify the move for the bot')
;
let args = optimist.argv;
let id = args.id;
let game_id = args.gameid;
let move = args.move;
let apikey = args.apikey;
let gamekey = args.gameauth;
console.log(id, game_id, move, apikey, gamekey);
let io = require('socket.io-client');
let socket = io('https://online-go.com:443', {
reconnection: true,
reconnectionDelay: 500,
reconnectionDelayMax: 60000,
transports: ['websocket'],
});
socket.on('connect', () => {
if (move == "resign") {
console.log("----sendmove.js: Resigning.");
socket.emit("game/resign", {
"apikey": apikey,
"auth": gamekey,
"game_id": game_id,
"bot_id": id,
"player_id": id}, () => {process.exit();});
} else {
console.log("----sendmove.js: Sending move", move);
socket.emit('game/move', {
"apikey": apikey,
"auth": gamekey,
"game_id": game_id,
"player_id": id,
"bot_id": id,
"move": move
}, () => {console.log("----sendmove.js: Sent!"); process.exit();});
}
});
Basically, the problem is that the socket hangs on āgame/moveā and doesnāt ever actually make the move when you make the call outside socket.on("connect", ()=>{...here...});
.
Hi there, just wondering if you finally managed to make this work as I am currently faced with the same issue