Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Putting the Colla into our ASCII #67

Merged
merged 25 commits into from
May 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ collascii: frontend.out
mv frontend.out collascii

frontend.out: LDLIBS +=-lncurses
frontend.out: cursor.o fe_modes.o canvas.o view.o
frontend.out: cursor.o fe_modes.o canvas.o view.o network.o

server.out: LDLIBS +=-lpthread
server.out: canvas.o

## PATTERNS

Expand Down
6 changes: 5 additions & 1 deletion src/fe_modes.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,9 @@ void switch_mode(Mode_ID new_mode, State *state) {
int master_handler(State *state, WINDOW *canvas_win, WINDOW *status_win) {
// catching keypresses
int c = wgetch(canvas_win); // grab from window
#ifdef LOG_KEYS
logd("New key: '%c' (%d)\n", c, c);
#endif
if (c == KEY_TAB) { // switching modes
if (state->current_mode == MODE_PICKER &&
state->last_canvas_mode != MODE_PICKER) {
Expand Down Expand Up @@ -376,8 +378,10 @@ int mode_brush(reason_t reason, State *state) {
// handle mouse events
MEVENT event;
if (getmouse(&event) == OK) {
#ifdef LOG_KEYS
logd("New mouse event: (%i, %i), %li\n", event.x, event.y,
event.bstate);
(long int)event.bstate);
#endif
if (event.bstate & BUTTON1_PRESSED) {
mode_cfg->state = PAINT_ON;
} else if (event.bstate & BUTTON1_RELEASED) {
Expand Down
78 changes: 71 additions & 7 deletions src/frontend.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand All @@ -39,13 +40,15 @@
#include "cursor.h"
#include "fe_modes.h"
#include "mode_id.h"
#include "network.h"
#include "state.h"
#include "util.h"

WINDOW *canvas_win;
status_interface_t *status_interface;
Cursor *cursor;
View *view;
bool networked = false;

char *DEFAULT_FILEPATH = "art.txt";

Expand Down Expand Up @@ -77,28 +80,52 @@ int main(int argc, char *argv[]) {
Canvas *canvas;
// load canvas from file if argument exists
char *in_filename = "";
fd_set testfds;
int fd;
Net_cfg *net_cfg;

if (argc > 1) {
if (strcmp(argv[1], "-") == 0) {
/* If connecting to server */
if (!strcmp(argv[1], "-s")) {
networked = true;
if (argc == 3) {
canvas = net_init(argv[2], "");
} else if (argc == 4) {
canvas = net_init(argv[2], argv[3]);
} else {
printf("Usage:\ncollascii [filename]\ncollascii -s hostname [port]\n");
exit(1);
}

net_cfg = net_getcfg();

/* If reading from std in */
} else if (strcmp(argv[1], "-") == 0) {
// read from stdin if specified
logd("Reading from stdin\n");
canvas = canvas_readf_norewind(stdin);
// reopen stdin b/c EOF has been sent
// `/dev/tty` points to current terminal
// note that this is NOT portable
freopen("/dev/tty", "rw", stdin);

/* If reading from file */
} else {
in_filename = argv[1];
FILE *f = fopen(in_filename, "r");
logd("Reading from '%s'\n", in_filename);
if (f == NULL) {
perror("savefile read");
printf("cannot read file %s\n", in_filename);
printf("Usage:\ncollascii [filename]\ncollascii -s hostname [port]\n");

exit(1);
}
canvas = canvas_readf(f);
fclose(f);
}
// canvas_resize(&canvas, 100, 100);
} else {
logd("making blank canvas\n");
canvas = canvas_new_blank(100, 100);
}

Expand All @@ -121,9 +148,14 @@ int main(int argc, char *argv[]) {

// ENABLE MOUSE INPUT
// grab only mouse movement and left mouse press/release
#ifndef LOG_KEYS
mousemask(REPORT_MOUSE_POSITION | BUTTON1_PRESSED | BUTTON1_RELEASED, NULL);
#endif
#ifdef LOG_KEYS
mmask_t return_mask = mousemask(
REPORT_MOUSE_POSITION | BUTTON1_PRESSED | BUTTON1_RELEASED, NULL);
logd("Returned mouse mask: %li\n", return_mask);
logd("Returned mouse mask: %li\n", (long int)return_mask);
#endif
// get mouse updates faster at the expense of not registering "clicks"
mouseinterval(0);
// Make the terminal report mouse movement events, in a not-great way.
Expand Down Expand Up @@ -192,11 +224,40 @@ int main(int argc, char *argv[]) {
// Move cursor to starting location and redraw canvases
refresh_screen();

while (1) {
master_handler(state, canvas_win, status_interface->info_win);
refresh_screen();
// If connected to server, check both network and keyboard streams
if (networked) {
logd("Running networked loop\n");
while (1) {
testfds = net_cfg->clientfds;
select(FD_SETSIZE, &testfds, NULL, NULL, NULL);

for (fd = 0; fd < FD_SETSIZE; fd++) {
if (FD_ISSET(fd, &testfds)) {
if (networked &&
fd == net_cfg->sockfd) { // Accept data from open socket
logd("recv network\n");
// If server disconnects
if (net_handler(view) != 0) {
networked = false;
print_msg_win("Server Disconnect!");
};
redraw_canvas_win(); // TODO: draw single char update
refresh_screen();
} else if (fd == 0) { // process keyboard activity
master_handler(state, canvas_win, status_interface->info_win);
refresh_screen();
}
}
}
}
// If local, process keyboard stream
} else {
logd("Running local loop\n");
while (1) {
master_handler(state, canvas_win, status_interface->info_win);
refresh_screen();
}
}

// Cleanup
cursor_free(cursor);
// TODO: destory status_interface
Expand Down Expand Up @@ -227,6 +288,9 @@ void front_setcharcursor(char ch) {
canvas_scharyx(view->canvas, cursor->y + view->y, cursor->x + view->x, ch);
mvwaddch(canvas_win, cursor_y_to_canvas(cursor), cursor_x_to_canvas(cursor),
ch);
if (networked) {
net_send_char(cursor->y + view->y, cursor->x + view->x, ch);
}
}

void redraw_canvas_win() {
Expand Down
140 changes: 140 additions & 0 deletions src/network.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/select.h>
#include <sys/types.h>
#include <unistd.h>

#include "canvas.h"
#include "network.h"
#include "util.h"
#include "view.h"

/* Network Client Variables */
fd_set testfds, clientfds;
char *msg_buf;
size_t msg_size;
int port = 5000;
int fd;
int sockfd;
FILE *sockstream;
int result;
char *hostname;
struct hostent *hostinfo;
struct sockaddr_in address;
struct addrinfo hints, *servinfo;

/* Connects to server and returns its canvas
*
*/
Canvas *net_init(char *in_hostname, char *in_port) {
Canvas *canvas;

// Set port and hostname
if (strcmp(in_port, "")) {
logd("setting port to %s\n", in_port);
sscanf(in_port, "%i", &port);
}
hostname = strdup(in_hostname);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
hostinfo = gethostbyname(hostname);
address.sin_addr = *(struct in_addr *)*hostinfo->h_addr_list;
address.sin_family = AF_INET;
address.sin_port = htons(port);

if (connect(sockfd, (struct sockaddr *)&address, sizeof(address)) < 0) {
logd("Failed connecting to server\n");
printf("failed connecting to server.\n");
exit(1);
}

FD_ZERO(&clientfds);
FD_SET(sockfd, &clientfds);
FD_SET(0, &clientfds); // stdin

sockstream = fdopen(sockfd, "r+");

getline(&msg_buf, &msg_size, sockstream);
char *command = strtok(msg_buf, " ");
if (!strcmp(command, "cs")) {
int row = atoi(strtok(NULL, " "));
int col = atoi(strtok(NULL, " "));

canvas = canvas_new_blank(row, col);
} else {
logd("failed to get canvas size\n");
exit(1);
}

logd("reading canvas from server\n");

getline(&msg_buf, &msg_size, sockstream);
canvas_deserialize(msg_buf, canvas);

logd("done reading\n");

return canvas;
}

/* Returns new Net_cfg object with current clientfds and sockfd
*
*/
Net_cfg *net_getcfg() {
Net_cfg *config = malloc(sizeof(Net_cfg));

config->clientfds = clientfds;
config->sockfd = sockfd;

return config;
}

/* Reads incoming packets and updates canvas.
* Need to run redraw_canvas_win() after calling!
*/
int net_handler(View *view) {
logd("receiving: ");
getline(&msg_buf, &msg_size, sockstream);
logd("[%d]", msg_size);
logd(msg_buf);
char ch = msg_buf[strlen(msg_buf) - 2]; // -2 for '\n'

char *command = strtok(msg_buf, " \n");
logd("\"%s\"", command);
if (!strcmp(command, "s")) {
int y = atoi(strtok(NULL, " "));
int x = atoi(strtok(NULL, " "));

canvas_scharyx(view->canvas, y, x, ch);
}
if (!strcmp(command, "q")) {
logd("closing socket\n");
close(sockfd);
return 1;
}

return 0;
}

/* Sends a set char command to the server
*
*/
int net_send_char(int y, int x, char ch) {
char send_buf[50];
snprintf(send_buf, 50, "s %d %d %c\n", y, x, ch);
logd(send_buf);
if (write(sockfd, send_buf, strlen(send_buf)) < 0) {
logd("write error");
return -1;
}

logd("sending: s %d %d %c\n", y, x, ch);
// DON"T TRUST FPRINTF!!! It has failed me!
// fprintf(sockstream, "s %d %d %c\n", y, x, ch);

return 0;
}
22 changes: 22 additions & 0 deletions src/network.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#ifndef network_h
#define network_h
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <sys/types.h>

#include "canvas.h"
#include "view.h"

typedef struct NET_CFG {
fd_set clientfds;
int sockfd;
} Net_cfg;

Canvas *net_init(char *hostname, char *port);
Net_cfg *net_getcfg();
int net_handler(View *view);
int net_send_char(int y, int x, char ch);

#endif
Loading