http requests, twitch oauth, twitch chat, irc...
This commit is contained in:
parent
4487a03238
commit
48811806e7
|
@ -0,0 +1,10 @@
|
||||||
|
<component name="libraryTable">
|
||||||
|
<library name="cedarsoftware.json.io" type="repository">
|
||||||
|
<properties maven-id="com.cedarsoftware:json-io:4.14.0" />
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$PROJECT_DIR$/lib/json-io-4.14.0.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES />
|
||||||
|
</library>
|
||||||
|
</component>
|
|
@ -11,5 +11,6 @@
|
||||||
<orderEntry type="library" name="lwjgl" level="project" />
|
<orderEntry type="library" name="lwjgl" level="project" />
|
||||||
<orderEntry type="library" name="jna-5.12.1" level="project" />
|
<orderEntry type="library" name="jna-5.12.1" level="project" />
|
||||||
<orderEntry type="library" name="marytts-lang-en-5.2" level="project" />
|
<orderEntry type="library" name="marytts-lang-en-5.2" level="project" />
|
||||||
|
<orderEntry type="library" name="cedarsoftware.json.io" level="project" />
|
||||||
</component>
|
</component>
|
||||||
</module>
|
</module>
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.danitheskunk.skunkworks;
|
||||||
|
|
||||||
|
import com.danitheskunk.skunkworks.net.*;
|
||||||
|
|
||||||
|
public class TestTwitch extends BaseGame implements IIrcMessageHandler {
|
||||||
|
Twitch twitch;
|
||||||
|
TwitchChat chat;
|
||||||
|
|
||||||
|
public TestTwitch() {
|
||||||
|
super(new Vec2i(640, 360), "stuff");
|
||||||
|
twitch = new Twitch("thvs1beyj8w6ono2jqirdz7uuu62qu");
|
||||||
|
chat = twitch.connectChat();
|
||||||
|
var chan = chat.join("#danitheskunk");
|
||||||
|
chan.sendMessage("nyaa!");
|
||||||
|
chan.setMessageHandler(this::handleMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleMessage(IrcChannel channel, String message, IrcHostmask from) {
|
||||||
|
if(message.equals("!nya")) {
|
||||||
|
channel.sendMessage("*meows at " + from.getNick() + "*");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void update(double delta) {
|
||||||
|
chat.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
static public void main(String[] params) {
|
||||||
|
new TestTwitch().run();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,119 @@
|
||||||
|
package com.danitheskunk.skunkworks.net;
|
||||||
|
|
||||||
|
import com.cedarsoftware.util.io.JsonReader;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.ProtocolException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class HttpUtils {
|
||||||
|
public static RequestBuilder request(String uriStr) {
|
||||||
|
return new RequestBuilder(uriStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RequestBuilder {
|
||||||
|
private Map<String, String> customHeader;
|
||||||
|
private Map<String, String> queryParameters;
|
||||||
|
private String requestMethod;
|
||||||
|
private String urlStr;
|
||||||
|
|
||||||
|
private RequestBuilder(String urlStr) {
|
||||||
|
customHeader = new HashMap<>();
|
||||||
|
queryParameters = new HashMap<>();
|
||||||
|
this.urlStr = urlStr;
|
||||||
|
requestMethod = "GET";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String queryStrHelper(Map.Entry<String, String> entry) {
|
||||||
|
return URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8) +
|
||||||
|
"=" +
|
||||||
|
URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RequestBuilder header(String key, String value) {
|
||||||
|
customHeader.put(key, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RequestBuilder queryParameter(String key, String value) {
|
||||||
|
queryParameters.put(key, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RequestBuilder requestMethod(String method) {
|
||||||
|
requestMethod = method;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String run() {
|
||||||
|
HttpURLConnection con;
|
||||||
|
|
||||||
|
var paramStr = "";
|
||||||
|
if(queryParameters.size() > 0) {
|
||||||
|
paramStr = "?" + queryParameters.entrySet().stream().map(
|
||||||
|
RequestBuilder::queryStrHelper).collect(Collectors.joining(
|
||||||
|
"&"));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
var url = new URL(urlStr + paramStr);
|
||||||
|
con = (HttpURLConnection) url.openConnection();
|
||||||
|
} catch(IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
con.setRequestMethod(requestMethod);
|
||||||
|
} catch(ProtocolException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var entry : customHeader.entrySet()) {
|
||||||
|
con.setRequestProperty(entry.getKey(), entry.getValue());
|
||||||
|
//System.out.printf("%s: %s\n", entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferedReader in;
|
||||||
|
try {
|
||||||
|
in = new BufferedReader(new InputStreamReader(con.getInputStream()));
|
||||||
|
} catch(IOException e) {
|
||||||
|
String inputLine;
|
||||||
|
var ein = new BufferedReader(new InputStreamReader(con.getErrorStream()));
|
||||||
|
try {
|
||||||
|
while((inputLine = ein.readLine()) != null) {
|
||||||
|
System.err.println(inputLine);
|
||||||
|
}
|
||||||
|
} catch(IOException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
} throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
String inputLine;
|
||||||
|
StringBuffer content = new StringBuffer();
|
||||||
|
try {
|
||||||
|
while((inputLine = in.readLine()) != null) {
|
||||||
|
content.append(inputLine);
|
||||||
|
}
|
||||||
|
in.close();
|
||||||
|
} catch(IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return content.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public java.util.Map runJSON() {
|
||||||
|
return JsonReader.jsonToMaps(run());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.danitheskunk.skunkworks.net;
|
||||||
|
|
||||||
|
public interface IIrcMessageHandler {
|
||||||
|
void handleMessage(IrcChannel channel, String message, IrcHostmask from);
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package com.danitheskunk.skunkworks.net;
|
||||||
|
|
||||||
|
public class IrcChannel {
|
||||||
|
private IrcClient irc;
|
||||||
|
private String name;
|
||||||
|
private IIrcMessageHandler messageHandler;
|
||||||
|
|
||||||
|
public IrcChannel(IrcClient irc, String name) {
|
||||||
|
this.irc = irc;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendMessage(String message) {
|
||||||
|
irc.privmsg(name, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void processMessage(String message, IrcHostmask from) {
|
||||||
|
System.out.printf("[%s] <%s> %s\n", name, from.getNick(), message);
|
||||||
|
if(messageHandler != null) {
|
||||||
|
messageHandler.handleMessage(this, message, from);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessageHandler(IIrcMessageHandler messageHandler) {
|
||||||
|
this.messageHandler = messageHandler;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
package com.danitheskunk.skunkworks.net;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class IrcClient {
|
||||||
|
private String buffer;
|
||||||
|
private Map<String, IrcChannel> channels;
|
||||||
|
private char[] chbuf;
|
||||||
|
private InputStreamReader in;
|
||||||
|
private BufferedWriter out;
|
||||||
|
private Socket sock;
|
||||||
|
|
||||||
|
public IrcClient(String hostname, int port, String nick) {
|
||||||
|
this(hostname, port, nick, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IrcClient(String hostname, int port, String nick, String pass) {
|
||||||
|
buffer = "";
|
||||||
|
//todo: increase size
|
||||||
|
chbuf = new char[8];
|
||||||
|
channels = new HashMap<>();
|
||||||
|
try {
|
||||||
|
sock = new Socket(hostname, port);
|
||||||
|
in = new InputStreamReader(sock.getInputStream());
|
||||||
|
out = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream()));
|
||||||
|
} catch(IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pass != null) {
|
||||||
|
send(new IrcMessage("PASS").addParam(pass));
|
||||||
|
}
|
||||||
|
send(new IrcMessage("NICK").addParam(nick));
|
||||||
|
}
|
||||||
|
|
||||||
|
public IrcChannel join(String channel) {
|
||||||
|
send(new IrcMessage("JOIN").addParam(channel));
|
||||||
|
var chan = new IrcChannel(this, channel);
|
||||||
|
channels.put(channel, chan);
|
||||||
|
return chan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void privmsg(String target, String msg) {
|
||||||
|
send(new IrcMessage("PRIVMSG").addParam(target).addParam(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processMessage(IrcMessage msg) {
|
||||||
|
var cmd = msg.getCommand();
|
||||||
|
if(cmd.equals("PING")) {
|
||||||
|
send(new IrcMessage("PONG").addParam(msg.getParams().get(0)));
|
||||||
|
} else if(cmd.equals("PRIVMSG")) {
|
||||||
|
var params = msg.getParams();
|
||||||
|
var target = params.get(0);
|
||||||
|
var text = params.get(1);
|
||||||
|
if(channels.containsKey(target)) {
|
||||||
|
channels.get(target).processMessage(
|
||||||
|
text,
|
||||||
|
IrcHostmask.fromPrefix(msg.getPrefix())
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
System.out.printf("got privmsg for unknown target '%s'\n",
|
||||||
|
target
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
System.out.printf("IRC| %s", msg.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
while(true) {
|
||||||
|
tick();
|
||||||
|
try {
|
||||||
|
Thread.sleep(100);
|
||||||
|
} catch(InterruptedException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void send(IrcMessage msg) {
|
||||||
|
try {
|
||||||
|
out.write(msg.toString());
|
||||||
|
out.flush();
|
||||||
|
//System.out.print(msg.toString());
|
||||||
|
} catch(IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick() {
|
||||||
|
try {
|
||||||
|
while(in.ready()) {
|
||||||
|
//System.out.println("reading");
|
||||||
|
int count = in.read(chbuf);
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.append(chbuf, 0, count);
|
||||||
|
buffer += sb.toString();
|
||||||
|
if(buffer.contains("\r\n")) {
|
||||||
|
var sp = buffer.split("\r\n");
|
||||||
|
buffer = sp.length == 1 ? "" : sp[1];
|
||||||
|
processMessage(IrcMessage.fromString(sp[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package com.danitheskunk.skunkworks.net;
|
||||||
|
|
||||||
|
public class IrcHostmask {
|
||||||
|
private final String nick, user, host;
|
||||||
|
|
||||||
|
public IrcHostmask(String nick, String user, String host) {
|
||||||
|
this.nick = nick;
|
||||||
|
this.user = user;
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IrcHostmask fromPrefix(String str) {
|
||||||
|
String nick;
|
||||||
|
String user = "";
|
||||||
|
String host = "";
|
||||||
|
|
||||||
|
if(str.contains("@")) {
|
||||||
|
var sp = str.split("@");
|
||||||
|
host = sp[1];
|
||||||
|
str = sp[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(str.contains("!")) {
|
||||||
|
var sp = str.split("!");
|
||||||
|
user = sp[1];
|
||||||
|
str = sp[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
nick = str;
|
||||||
|
|
||||||
|
return new IrcHostmask(nick, user, host);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getNick() {
|
||||||
|
return nick;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHost() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
package com.danitheskunk.skunkworks.net;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class IrcMessage {
|
||||||
|
private String command;
|
||||||
|
private List<String> params;
|
||||||
|
private String prefix;
|
||||||
|
|
||||||
|
public IrcMessage() {
|
||||||
|
params = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IrcMessage(String cmd) {
|
||||||
|
this();
|
||||||
|
command = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IrcMessage fromString(String str) {
|
||||||
|
var irc = new IrcMessage();
|
||||||
|
|
||||||
|
if(str.startsWith(":")) {
|
||||||
|
var sp = str.split(" ", 2);
|
||||||
|
irc.setPrefix(sp[0].substring(1));
|
||||||
|
str = sp[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(str.contains(" ")) { //has parameters
|
||||||
|
var sp = str.split(" ", 2);
|
||||||
|
irc.setCommand(sp[0]);
|
||||||
|
str = sp[1];
|
||||||
|
while(true) {
|
||||||
|
if(str.startsWith(":")) { //last parameter with :
|
||||||
|
irc.addParam(str.substring(1).strip());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(str.contains(" ")) { //not last parameter
|
||||||
|
sp = str.split(" ", 2);
|
||||||
|
irc.addParam(sp[0]);
|
||||||
|
str = sp[1];
|
||||||
|
} else { //last parameter
|
||||||
|
irc.addParam(str.strip());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
irc.setCommand(str.strip());
|
||||||
|
}
|
||||||
|
|
||||||
|
return irc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IrcMessage addParam(String param) {
|
||||||
|
params.add(param);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCommand() {
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getParams() {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPrefix() {
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IrcMessage setCommand(String command) {
|
||||||
|
this.command = command;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IrcMessage setPrefix(String prefix) {
|
||||||
|
this.prefix = prefix;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
if(prefix != null) {
|
||||||
|
sb.append(":");
|
||||||
|
sb.append(prefix);
|
||||||
|
sb.append(" ");
|
||||||
|
}
|
||||||
|
sb.append(command);
|
||||||
|
if(params.size() > 0) {
|
||||||
|
sb.append(" ");
|
||||||
|
}
|
||||||
|
for(int i = 0; i < params.size(); ++i) {
|
||||||
|
if(i == params.size() - 1) {
|
||||||
|
if(params.get(i).contains(" ")) {
|
||||||
|
sb.append(":");
|
||||||
|
}
|
||||||
|
sb.append(params.get(i));
|
||||||
|
} else {
|
||||||
|
sb.append(params.get(i));
|
||||||
|
sb.append(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.append("\r\n");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package com.danitheskunk.skunkworks.net;
|
||||||
|
|
||||||
|
public class Twitch {
|
||||||
|
private String clientID;
|
||||||
|
private String token;
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
public Twitch(String clientID) {
|
||||||
|
token = TwitchOauth.getToken(clientID,
|
||||||
|
new String[]{"chat:read", "chat:edit"}
|
||||||
|
);
|
||||||
|
this.clientID = clientID;
|
||||||
|
username = getUser();
|
||||||
|
System.out.printf("Logged into twitch as \"%s\"\n", username);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TwitchChat connectChat() {
|
||||||
|
return new TwitchChat(username, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getUser() {
|
||||||
|
var response = HttpUtils.request("https://api.twitch.tv/helix/users").header("Authorization",
|
||||||
|
"Bearer " + token
|
||||||
|
).header(
|
||||||
|
"Client-Id",
|
||||||
|
clientID
|
||||||
|
).runJSON();
|
||||||
|
var data = (Object[]) response.get("data");
|
||||||
|
var user = (java.util.Map) data[0];
|
||||||
|
var login = (String) user.get("login");
|
||||||
|
|
||||||
|
return login;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.danitheskunk.skunkworks.net;
|
||||||
|
|
||||||
|
public class TwitchChat extends IrcClient {
|
||||||
|
public TwitchChat(String nick, String token) {
|
||||||
|
super("irc.chat.twitch.tv", 6667, nick, "oauth:"+token);
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,7 +27,7 @@ public class TwitchOauth implements HttpHandler {
|
||||||
private String result = null;
|
private String result = null;
|
||||||
|
|
||||||
public static String getToken(String clientID, String[] scopes) {
|
public static String getToken(String clientID, String[] scopes) {
|
||||||
var scopeStr = String.join("&",
|
var scopeStr = String.join("+",
|
||||||
Arrays.stream(scopes).map((String s) -> URLEncoder.encode(s)).toList()
|
Arrays.stream(scopes).map((String s) -> URLEncoder.encode(s)).toList()
|
||||||
);
|
);
|
||||||
var uri = URI.create(String.format(
|
var uri = URI.create(String.format(
|
||||||
|
@ -64,6 +64,9 @@ public class TwitchOauth implements HttpHandler {
|
||||||
}
|
}
|
||||||
System.out.println("waiting for oauth response");
|
System.out.println("waiting for oauth response");
|
||||||
}
|
}
|
||||||
|
if(instance.errored) {
|
||||||
|
throw new RuntimeException("oauth error of some sorts...");
|
||||||
|
}
|
||||||
server.stop(0);
|
server.stop(0);
|
||||||
return instance.result;
|
return instance.result;
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue