http requests, twitch oauth, twitch chat, irc...

This commit is contained in:
DaniTheSkunk 2022-11-29 03:57:34 +00:00
parent 4487a03238
commit 48811806e7
13 changed files with 510 additions and 1 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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();
}
}

View File

@ -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());
}
}
}

View File

@ -0,0 +1,5 @@
package com.danitheskunk.skunkworks.net;
public interface IIrcMessageHandler {
void handleMessage(IrcChannel channel, String message, IrcHostmask from);
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
} }

BIN
lib/json-io-4.14.0.jar Normal file

Binary file not shown.