take care of final todo items and come up with perceptual perf improvements on the coprocessorjs side of the app

This commit is contained in:
camh 2022-01-11 00:00:31 -08:00
parent db302f0b97
commit f3755e40f9
4 changed files with 229 additions and 68 deletions

View File

@ -154,6 +154,7 @@ const widthFor12ptFont = [
// this is tied to mac_main.c's message window max width // this is tied to mac_main.c's message window max width
const MAX_WIDTH = 304 const MAX_WIDTH = 304
const SPACE_WIDTH = widthFor12ptFont[32] const SPACE_WIDTH = widthFor12ptFont[32]
let canStart = false
const getNextWordLength = (word) => { const getNextWordLength = (word) => {
@ -325,10 +326,37 @@ if (TEST_MODE) {
}, 10000) }, 10000)
} }
class iMessageClient { let storedArgsAndResults = {
getMessages: {
args: {},
output: {}
},
hasNewMessagesInChat: {
args: {},
output: {}
},
getChats: {
args: {},
output: {}
},
getChatCounts: {
args: {},
output: {}
}
}
// this is our private interface, meant to communicate with our GraphQL server and fill caches
// we want everything cached as much as possible to cut down on perceived perf issues on the
// classic Macintosh end
class iMessageGraphClientClass {
async getMessages (chatId, page) { async getMessages (chatId, page) {
storedArgsAndResults.getMessages.args = {
chatId,
page
}
if (TEST_MODE) { if (TEST_MODE) {
return splitMessages(TEST_MESSAGES) return splitMessages(TEST_MESSAGES)
@ -361,23 +389,19 @@ class iMessageClient {
let messages = result.data.getMessages let messages = result.data.getMessages
return splitMessages(messages) storedArgsAndResults.getMessages.output = splitMessages(messages)
} }
async hasNewMessagesInChat (chatId) { async hasNewMessagesInChat (chatId) {
storedArgsAndResults.hasNewMessagesInChat.args = {
chatId
}
let currentLastMessageOutput = `${lastMessageOutput}` let currentLastMessageOutput = `${lastMessageOutput}`
let messageOutput = await this.getMessages(chatId, 0) let messageOutput = await this.getMessages(chatId, 0)
return (currentLastMessageOutput !== messageOutput).toString() storedArgsAndResults.hasNewMessagesInChat.output = (currentLastMessageOutput !== messageOutput).toString()
}
async hasNewMessages (chatId) {
let currentLastMessageOutput = `${lastMessageOutput}`
let messageOutput = await this.getChats(chatId, 0)
return (currentLastMessageOutput !== messageOutput).toString()
} }
async sendMessage (chatId, message) { async sendMessage (chatId, message) {
@ -418,6 +442,7 @@ class iMessageClient {
} }
async getChats () { async getChats () {
console.log(`getChats`) console.log(`getChats`)
if (TEST_MODE) { if (TEST_MODE) {
@ -452,7 +477,9 @@ class iMessageClient {
console.log(`getChats complete`) console.log(`getChats complete`)
return parseChatsToFriendlyNameString(chats) storedArgsAndResults.getChats.output = parseChatsToFriendlyNameString(chats)
console.log(storedArgsAndResults.getChats.output)
} }
async getChatCounts () { async getChatCounts () {
@ -512,7 +539,7 @@ class iMessageClient {
friendlyNameStrings = friendlyNameStrings.substring(1, friendlyNameStrings.length) friendlyNameStrings = friendlyNameStrings.substring(1, friendlyNameStrings.length)
console.log(friendlyNameStrings) console.log(friendlyNameStrings)
return friendlyNameStrings storedArgsAndResults.getChatCounts.output = friendlyNameStrings
} }
setIPAddress (IPAddress) { setIPAddress (IPAddress) {
@ -521,6 +548,8 @@ class iMessageClient {
if (TEST_MODE) { if (TEST_MODE) {
canStart = true
return `success` return `success`
} }
@ -543,9 +572,107 @@ class iMessageClient {
console.log(`return success`) console.log(`return success`)
canStart = true
return `success` return `success`
} }
} }
let iMessageGraphClient = new iMessageGraphClientClass()
// provide the public interface
class iMessageClient {
constructor () {
// kick off an update interval
setInterval(async () => {
console.log(`run interval`)
if (!canStart) {
console.log(`can't start yet`)
return
}
console.log(`running...`)
if (Object.keys(storedArgsAndResults.getMessages.args).length > 0) {
await iMessageGraphClient.getMessages(storedArgsAndResults.getMessages.args.chatId, storedArgsAndResults.getMessages.args.page)
}
if (Object.keys(storedArgsAndResults.hasNewMessagesInChat.args).length > 0) {
await iMessageGraphClient.hasNewMessagesInChat(storedArgsAndResults.hasNewMessagesInChat.chatId)
}
await iMessageGraphClient.getChats()
await iMessageGraphClient.getChatCounts()
console.log(`complete!`)
}, 2000)
}
async getMessages (chatId, page) {
console.log(`iMessageClient.getMessages`)
if (storedArgsAndResults.getMessages.args.chatId !== chatId || storedArgsAndResults.getMessages.args.page !== page) {
await iMessageGraphClient.getMessages(chatId, page)
}
return storedArgsAndResults.getMessages.output
}
async hasNewMessagesInChat (chatId) {
console.log(`iMessageClient.hasNewMessagesInChat`)
if (storedArgsAndResults.hasNewMessagesInChat.args.chatId !== chatId) {
await iMessageGraphClient.hasNewMessagesInChat(chatId)
}
return storedArgsAndResults.hasNewMessagesInChat.output
}
async sendMessage (chatId, message) {
console.log(`iMessageClient.sendMessage`)
return await iMessageGraphClient.sendMessage(chatId, message)
}
async getChats () {
console.log(`iMessageClient.getChats`)
if (Object.keys(storedArgsAndResults.getChats.output).length === 0) {
await iMessageGraphClient.getChats()
}
return storedArgsAndResults.getChats.output
}
getChatCounts () {
console.log(`iMessageClient.getChatCounts`)
return storedArgsAndResults.getChatCounts.output
}
setIPAddress (IPAddress) {
console.log(`iMessageClient.setIPAddress`)
return iMessageGraphClient.setIPAddress(IPAddress)
}
}
module.exports = iMessageClient module.exports = iMessageClient

View File

@ -682,7 +682,18 @@ void DoMenuCommand(menuResult)
case mLight: case mLight:
// note this was co-opted to send new chats instead of the demo functionality. do the // note this was co-opted to send new chats instead of the demo functionality. do the
// same thing for other menu items as necessary // same thing for other menu items as necessary
sendNewChat = 1; switch (menuItem) {
case 2:
getChats();
break;
default:
sendNewChat = 1;
break;
}
char x[255];
sprintf(x, "MENU %d", menuItem);
writeSerialPortDebug(boutRefNum, x);
break; break;
case mHelp: case mHelp:

View File

@ -137,6 +137,8 @@ resource 'MENU' (mLight, preload) {
{ {
"New Message", "New Message",
noicon, nokey, nomark, plain; noicon, nokey, nomark, plain;
"Refresh Chat List",
noicon, nokey, nomark, plain;
} }
}; };

View File

@ -1,6 +1,5 @@
// TODO: // TODO:
// - IN PROGRESS new message window -- need to figure this out // - test, bug fixes, write blog posts
// - IN PROGRESS need timeout on serial messages in case the computer at the other end dies (prevent hard reset) -- probably possible in coprocessorjs library. made an attempt, needs tested
#define WINDOW_WIDTH 510 #define WINDOW_WIDTH 510
#define WINDOW_HEIGHT 302 #define WINDOW_HEIGHT 302
@ -49,13 +48,13 @@ char chatFriendlyNames[16][64];
char ip_input_buffer[255]; char ip_input_buffer[255];
char jsFunctionResponse[102400]; // Matches MAX_RECEIVE_SIZE char jsFunctionResponse[102400]; // Matches MAX_RECEIVE_SIZE
char chatCountFunctionResponse[102400]; // Matches MAX_RECEIVE_SIZE char chatCountFunctionResponse[102400]; // Matches MAX_RECEIVE_SIZE
char tempChatCountFunctionResponse[102400]; // Matches MAX_RECEIVE_SIZE
char previousChatCountFunctionResponse[102400]; // Matches MAX_RECEIVE_SIZE char previousChatCountFunctionResponse[102400]; // Matches MAX_RECEIVE_SIZE
char new_message_input_buffer[255]; char new_message_input_buffer[255];
int activeMessageCounter = 0; int activeMessageCounter = 0;
int chatFriendlyNamesCounter = 0; int chatFriendlyNamesCounter = 0;
int coprocessorLoaded = 0; int coprocessorLoaded = 0;
int forceRedraw = 2; // this is how many 'iterations' of the UI that we need to see every element for int forceRedraw = 2; // this is how many 'iterations' of the UI that we need to see every element for
int haveRun = 0;
int ipAddressSet = 0; int ipAddressSet = 0;
int mouse_x; int mouse_x;
int mouse_y; int mouse_y;
@ -115,6 +114,25 @@ void sendMessage() {
return; return;
} }
// set up function to get available chat (fill buttons on the left hand side)
// interval is set by the event loop in mac_main
void getChats() {
writeSerialPortDebug(boutRefNum, "getChats!");
callFunctionOnCoprocessor("getChats", "", jsFunctionResponse);
char * token = (char *)strtokm(jsFunctionResponse, ",");
// loop through the string to extract all other tokens
while (token != NULL) {
writeSerialPortDebug(boutRefNum, token);
sprintf(chatFriendlyNames[chatFriendlyNamesCounter++], "%s", token);
token = (char *)strtokm(NULL, ",");
}
return;
}
void sendIPAddressToCoprocessor() { void sendIPAddressToCoprocessor() {
char output[2048]; char output[2048];
@ -123,6 +141,9 @@ void sendIPAddressToCoprocessor() {
writeSerialPortDebug(boutRefNum, output); writeSerialPortDebug(boutRefNum, output);
callFunctionOnCoprocessor("setIPAddress", output, jsFunctionResponse); callFunctionOnCoprocessor("setIPAddress", output, jsFunctionResponse);
// now that the IP is set, we can get all of our chats
getChats();
return; return;
} }
@ -170,8 +191,9 @@ void getChatCounts() {
#endif #endif
SysBeep(1); SysBeep(1);
char **saveptr; char *saveptr;
char *token = strtok_r(chatCountFunctionResponse, ",", saveptr); strcpy(tempChatCountFunctionResponse, chatCountFunctionResponse);
char *token = strtok_r(tempChatCountFunctionResponse, ",", &saveptr);
// loop through the string to extract all other tokens // loop through the string to extract all other tokens
while (token != NULL) { while (token != NULL) {
@ -182,9 +204,9 @@ void getChatCounts() {
#endif #endif
// should be in format NAME:::COUNT // should be in format NAME:::COUNT
char **saveptr2; char *saveptr2;
char *name = strtok_r(token, ":::", saveptr2); char *name = strtok_r(token, ":::", &saveptr2);
char *countString = strtok_r(NULL, ":::", saveptr2); char *countString = strtok_r(NULL, ":::", &saveptr2);
short count = atoi(countString); short count = atoi(countString);
#ifdef MESSAGES_FOR_MACINTOSH_DEBUGGING #ifdef MESSAGES_FOR_MACINTOSH_DEBUGGING
@ -193,13 +215,6 @@ void getChatCounts() {
writeSerialPortDebug(boutRefNum, x); writeSerialPortDebug(boutRefNum, x);
#endif #endif
if (count == 0) {
token = strtok_r(NULL, ",", saveptr);
continue;
}
for (int i = 0; i < chatFriendlyNamesCounter; i++) { for (int i = 0; i < chatFriendlyNamesCounter; i++) {
if (strstr(chatFriendlyNames[i], " new) ") != NULL) { if (strstr(chatFriendlyNames[i], " new) ") != NULL) {
@ -208,9 +223,9 @@ void getChatCounts() {
sprintf(chatName, "%s", chatFriendlyNames[i]); sprintf(chatName, "%s", chatFriendlyNames[i]);
// we are throwing out the first token // we are throwing out the first token
strtok_r(chatName, " new) ", saveptr2); strtok_r(chatName, " new) ", &saveptr2);
char *tempChatFriendlyName = strtok_r(NULL, " new) ", saveptr2); char *tempChatFriendlyName = strtok_r(NULL, " new) ", &saveptr2);
if (prefix(tempChatFriendlyName, name)) { if (prefix(tempChatFriendlyName, name)) {
@ -219,7 +234,13 @@ void getChatCounts() {
writeSerialPortDebug(boutRefNum, name); writeSerialPortDebug(boutRefNum, name);
#endif #endif
sprintf(chatFriendlyNames[i], "(%d new) %s", count, name); if (count == 0) {
sprintf(chatFriendlyNames[i], "%s", name);
} else {
sprintf(chatFriendlyNames[i], "(%d new) %s", count, name);
}
break; break;
} }
} else { } else {
@ -231,13 +252,19 @@ void getChatCounts() {
writeSerialPortDebug(boutRefNum, name); writeSerialPortDebug(boutRefNum, name);
#endif #endif
sprintf(chatFriendlyNames[i], "(%d new) %s", count, name); if (count == 0) {
sprintf(chatFriendlyNames[i], "%s", name);
} else {
sprintf(chatFriendlyNames[i], "(%d new) %s", count, name);
}
break; break;
} }
} }
} }
token = strtok_r(NULL, ",", saveptr); token = strtok_r(NULL, ",", &saveptr);
} }
strcpy(previousChatCountFunctionResponse, chatCountFunctionResponse); strcpy(previousChatCountFunctionResponse, chatCountFunctionResponse);
@ -272,32 +299,6 @@ void getHasNewMessagesInChat(char *thread) {
return; return;
} }
// set up function to get available chat (fill buttons on right hand side)
// run it on some interval? make sure user is not typing!!!
void getChats() {
writeSerialPortDebug(boutRefNum, "getChats!");
if (haveRun) {
return;
}
haveRun = 1;
callFunctionOnCoprocessor("getChats", "", jsFunctionResponse);
char * token = (char *)strtokm(jsFunctionResponse, ",");
// loop through the string to extract all other tokens
while (token != NULL) {
writeSerialPortDebug(boutRefNum, token);
sprintf(chatFriendlyNames[chatFriendlyNamesCounter++], "%s", token);
token = (char *)strtokm(NULL, ",");
}
return;
}
Boolean chatWindowCollision; Boolean chatWindowCollision;
Boolean messageWindowCollision; Boolean messageWindowCollision;
@ -383,9 +384,9 @@ static void nuklearApp(struct nk_context *ctx) {
nk_layout_row_begin(ctx, NK_STATIC, 30, 1); nk_layout_row_begin(ctx, NK_STATIC, 30, 1);
{ {
nk_layout_row_push(ctx, WINDOW_WIDTH - 120); nk_layout_row_push(ctx, WINDOW_WIDTH - 120);
nk_label(ctx, "this is known to be a bit finnicky,", NK_TEXT_ALIGN_LEFT); nk_label(ctx, "enter contact name as it would appear", NK_TEXT_ALIGN_LEFT);
nk_layout_row_push(ctx, WINDOW_WIDTH - 120); nk_layout_row_push(ctx, WINDOW_WIDTH - 120);
nk_label(ctx, "input exact phone number", NK_TEXT_ALIGN_LEFT); nk_label(ctx, "on your iPhone, iPad, modern Mac, etc", NK_TEXT_ALIGN_LEFT);
} }
nk_layout_row_end(ctx); nk_layout_row_end(ctx);
@ -406,6 +407,8 @@ static void nuklearApp(struct nk_context *ctx) {
memset(&activeChatMessages[i], '\0', 2048); memset(&activeChatMessages[i], '\0', 2048);
} }
getMessages(activeChat, 0);
} }
} }
nk_layout_row_end(ctx); nk_layout_row_end(ctx);
@ -425,8 +428,6 @@ static void nuklearApp(struct nk_context *ctx) {
forceRedraw = 2; forceRedraw = 2;
} }
getChats();
nk_layout_row_begin(ctx, NK_STATIC, 25, 1); nk_layout_row_begin(ctx, NK_STATIC, 25, 1);
{ {
for (int i = 0; i < chatFriendlyNamesCounter; i++) { for (int i = 0; i < chatFriendlyNamesCounter; i++) {
@ -445,16 +446,36 @@ static void nuklearApp(struct nk_context *ctx) {
char chatName[96]; char chatName[96];
sprintf(chatName, "%s", chatFriendlyNames[i]); sprintf(chatName, "%s", chatFriendlyNames[i]);
writeSerialPortDebug(boutRefNum, chatName);
#ifdef MESSAGES_FOR_MACINTOSH_DEBUGGING
writeSerialPortDebug(boutRefNum, "clicked1 chatName");
writeSerialPortDebug(boutRefNum, chatName);
#endif
// we are throwing out the first token // we are throwing out the first token
strtokm(chatName, " new) "); char *name = (char *)strtokm(chatName, " new) ");
char *name = strtokm(NULL, " new) ");
#ifdef MESSAGES_FOR_MACINTOSH_DEBUGGING
writeSerialPortDebug(boutRefNum, "clicked1 portion1 of string, will toss");
writeSerialPortDebug(boutRefNum, name);
#endif
name = (char *)strtokm(NULL, " new) ");
#ifdef MESSAGES_FOR_MACINTOSH_DEBUGGING
writeSerialPortDebug(boutRefNum, "clicked1 have name to assign to activeChat");
writeSerialPortDebug(boutRefNum, name);
#endif
writeSerialPortDebug(boutRefNum, name);
sprintf(activeChat, "%s", name); sprintf(activeChat, "%s", name);
sprintf(chatFriendlyNames[i], "%s", name);
} else { } else {
#ifdef MESSAGES_FOR_MACINTOSH_DEBUGGING
writeSerialPortDebug(boutRefNum, "clicked2 chatName");
writeSerialPortDebug(boutRefNum, chatFriendlyNames[i]);
#endif
sprintf(activeChat, "%s", chatFriendlyNames[i]); sprintf(activeChat, "%s", chatFriendlyNames[i]);
} }