Skip to content

Commit

Permalink
Messages are now being sent to the server. yay.
Browse files Browse the repository at this point in the history
  • Loading branch information
lakinwecker committed Apr 29, 2017
1 parent 005b1ba commit 4447e87
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 52 deletions.
66 changes: 45 additions & 21 deletions src/importpgn.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,53 @@
// The import PGN modal dialog.
import { Component, h, Message, ConnectParams, RenderParams } from 'kaiju'
import { update } from 'immupdate'
import { ImportFileState, Remote, factory, importFile } from './server/importfile'
import path = require('path');

// TODO: it probably makes sense for us to refactor the loading screen into it's own
// module - but I need to figure out a better pattern for intermodule communication
// using kaiju.

//-----------------------------------------------------------------------------------------
export default function () {
return Component<Props, State>({
name: 'importpgn',
props: defaultProps(),
initState,
connect,
render
})
}

//-----------------------------------------------------------------------------------------
export default function() {
return Component<void, State>({ name: 'importpgn', initState, connect, render })
interface Props {
remoteStore: Remote
}

//-----------------------------------------------------------------------------------------
function defaultProps(): Props {
return { remoteStore: factory() }
}

//-----------------------------------------------------------------------------------------
interface State {
showingSelectFileDialog: boolean,
showFileImportProgress: boolean,
pgnPath?: string,
targetDatabase: string,
fileInput?: HTMLInputElement,
progress: number
remoteState: ImportFileState,
}

function initState() {
return {
return {
showingSelectFileDialog: false,
pgnPath: undefined,
targetDatabase: "new",
showFileImportProgress: false,
progress: 0.0
remoteState: {
activity: "",
progress: 0,
path: undefined
},
}
}

Expand All @@ -37,31 +60,32 @@ const selectFile = Message<HTMLInputElement>('selectFile')
const importPgn = Message('importPgn')
const cancelFileImport = Message('cancelFileImport')

function connect({ on }: ConnectParams<void, State>) {
on(showModal, (state) => update(state, {showingSelectFileDialog: true}))
on(hideFileDialog, (state) => update(state, {showingSelectFileDialog: false}))
on(importPgn, (state) => {
console.log(state.pgnPath)
function connect({ on, props }: ConnectParams<Props, State>) {
on(showModal, (state) => update(state, {showingSelectFileDialog: true}))
on(hideFileDialog, (state) => update(state, {showingSelectFileDialog: false}))
on(importPgn, (state) => {
props().remoteStore.store.send(importFile({path: state.remoteState.path}));
return update(state, { showingSelectFileDialog: false, showFileImportProgress: true })
})
on(cancelFileImport, (state) => update(state, {showFileImportProgress: false}))
on(setFileInput, (state, elm: HTMLInputElement) => update(state, {fileInput: elm}))
on(showFileDialog, (state) => {
on(cancelFileImport, (state) => update(state, {showFileImportProgress: false}))
on(setFileInput, (state, elm: HTMLInputElement) => update(state, {fileInput: elm}))
on(showFileDialog, (state) => {
if (state.fileInput) {
state.fileInput.click()
}
})
on(selectFile, (state, elm) => {
on(selectFile, (state, elm) => {
if (elm.files) {
let file: any = elm.files[0];
if (!file) return
return update(state, {pgnPath: file.path})
return update(state, {remoteState: update(state.remoteState, {path: file.path})})
}
})
on(props().remoteStore.store.state, (state, remoteState: ImportFileState) => { update(state, {remoteState: remoteState}) })
}

//-----------------------------------------------------------------------------------------
function render({ state, msg }: RenderParams<void, State>) {
function render({ state, msg }: RenderParams<Props, State>) {
let fileDialogClass = ""
if (state.showingSelectFileDialog) {
fileDialogClass = " .is-active"
Expand All @@ -72,8 +96,8 @@ function render({ state, msg }: RenderParams<void, State>) {
}
console.log(progressDialogClass);
let buttonTitle = ""
if (state.pgnPath) {
buttonTitle = "Change PGN File: " + path.basename(state.pgnPath)
if (state.remoteState.path) {
buttonTitle = "Change PGN File: " + path.basename(state.remoteState.path)
} else {
buttonTitle = "Select PGN File"
}
Expand Down Expand Up @@ -132,7 +156,7 @@ function render({ state, msg }: RenderParams<void, State>) {
h("button.delete", {on: {click: () => msg.send(cancelFileImport())}})
]),
h("section.modal-card-body", {}, [
h("progress.progress.is-large", {attrs: {"value": state.progress, "max": 100}}, state.progress + "%")
h("progress.progress.is-large", {attrs: {"value": state.remoteState.progress, "max": 100}}, state.remoteState.progress + "%")
]),
h("footer.modal-card-foot", {}, [
h("a.button", {on: {click: () => msg.send(cancelFileImport())}}, "Cancel")
Expand Down
9 changes: 8 additions & 1 deletion src/server/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ export class Connection {
this.ws.onclose = () => this.onclose()
this.ws.onmessage = (event) => {
let message = JSON.parse(event.data);
// TODO: validate the incoming json structure.
// TODO: validate the incoming json structure is appropriate (Not the args, just the message container)
// TODO: much of this id mapping should probably go to the store. We should probably only map
// the id to the store.
let key = message.id + message.methodName;
let callback: IncomingMessageCallback = this.callbacks[key];
if (callback) {
Expand All @@ -58,5 +60,10 @@ export class Connection {
let key = id + methodName;
this.callbacks[key] = callback;
}

//------------------------------------------------------------------------------------------------
send(id: number, name: string, args: string) {
this.ws.send(JSON.stringify({id: id, name: name, args: args}));
}
}

19 changes: 11 additions & 8 deletions src/server/importfile.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Message } from 'kaiju'
import { Remote, Outgoing, Incoming }from "./task"
import { Remote as RemoteInterface, OutgoingMessage, IncomingMessage } from "./messages"

//--------------------------------------------------------------------------------------------------
interface File {
Expand All @@ -14,18 +14,21 @@ interface Progress {

//--------------------------------------------------------------------------------------------------
export const importFile = Message<File>('importFile')
export const updateProgress = Message<Progress>('importFile')
export const updateProgress = Message<Progress>('updateProgress')

//--------------------------------------------------------------------------------------------------
interface ImportFileState extends Progress, File {}
export interface ImportFileState extends Progress, File {}

//--------------------------------------------------------------------------------------------------
export default function () {
let initialState = { filePath: undefined, activity: "waiting", progress: 0 }
let remote = new Remote<ImportFileState>(
export type Remote = RemoteInterface<ImportFileState>;

//--------------------------------------------------------------------------------------------------
export function factory(): Remote {
let initialState = { path: undefined, activity: "waiting", progress: 0 }
let remote = new RemoteInterface<ImportFileState>(
initialState,
[new Outgoing<ImportFileState, File>(importFile)],
[new Incoming<ImportFileState, Progress>(updateProgress)]
[new OutgoingMessage<ImportFileState, File>('importFile', importFile)],
[new IncomingMessage<ImportFileState, Progress>('updateProgress', updateProgress)]
);
return remote;
}
56 changes: 34 additions & 22 deletions src/server/task.ts → src/server/messages.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// A remote task is something you execute and then get a set of responses to.
// A remote messages can be sent and received via a store that maintains state.
//
// Each execution is simply sending a websocket message.
// Each OutgoingMessage is simply sending a websocket message.
//
// Each remote message received is updating the state of the object. Eezy-peezy
// Each IncomingMessage received updates the state of of the store Eezy-peezy
import { Message } from 'kaiju'
import { update } from 'immupdate'
import { Store as StoreInterface, RegisterMessages } from 'kaiju/store'
Expand All @@ -14,71 +14,83 @@ import { Connection } from './connection'
// achieve that yet - but I want it to work like rocket.

//--------------------------------------------------------------------------------------------------
export abstract class OutgoingBase<State> {
abstract listen(on: RegisterMessages<State>): void;
export abstract class OutgoingMessageInterface<State> {
abstract listen(on: RegisterMessages<State>, remote: Remote<State>): void;
}

//--------------------------------------------------------------------------------------------------
export class Outgoing<State, Interface> extends OutgoingBase<State> {
private message: Message<Interface>;
export class OutgoingMessage<State, Interface> extends OutgoingMessageInterface<State> {
private name: string
private message: Message<Interface>

constructor(message: Message<Interface>) {
constructor(name: string, message: Message<Interface>) {
super()
this.name = name
this.message = message
}

listen(on: RegisterMessages<State>) {
listen(on: RegisterMessages<State>, remote: Remote<State>) {
on(this.message, (state: State, v: Interface) => {
return update(state, v);
let newState = update(state, v)
remote.send(this.name, JSON.stringify(v))
return newState
})
}
}

//--------------------------------------------------------------------------------------------------
export abstract class IncomingBase<State> {
export abstract class IncomingMessageInterface<State> {
abstract register(id: number, connection: Connection, store: StoreInterface<State>): void;
}

//--------------------------------------------------------------------------------------------------
export class Incoming<State, Interface> extends IncomingBase<State> {
private message: Message<Interface>;
export class IncomingMessage<State, Interface> extends IncomingMessageInterface<State> {
private name: string
private message: Message<Interface>

constructor(message: Message<Interface>) {
constructor(name: string, message: Message<Interface>) {
super()
this.name = name
this.message = message
}

register(id: number, connection: Connection, store: StoreInterface<State>) {
connection.register(id, this.message.name, jsonString => {
console.log("Received: " + this.message.name + " -- " + jsonString)
// TODO: Do some type based conversion/checking and then dispatch the message.
// TODO: Do some type based conversion/checking first!!
store.send(this.message(JSON.parse(jsonString) as Interface));
})
}
}

//--------------------------------------------------------------------------------------------------
export class Remote<State> {
private store: StoreInterface<State>;
private outgoing: OutgoingBase<State>[];
private incoming: IncomingBase<State>[];
private connection: Connection;
public store: StoreInterface<State>;
private outgoing: OutgoingMessageInterface<State>[];
private incoming: IncomingMessageInterface<State>[];
private id: number;
public connection: Connection;

//------------------------------------------------------------------------------------------------
constructor(
initialState: State,
outgoing: OutgoingBase<State>[],
incoming: IncomingBase<State>[]
outgoing: OutgoingMessageInterface<State>[],
incoming: IncomingMessageInterface<State>[]
) {
this.connection = Connection.getInstance()
this.id = Connection.uniqueId();
this.incoming = incoming
this.outgoing = outgoing
this.store = Store<State>(initialState, (on: RegisterMessages<State>) => {
this.outgoing.forEach((outgoing) => outgoing.listen(on))
this.outgoing.forEach((outgoing) => outgoing.listen(on, this))
})
this.incoming.forEach((incoming) => incoming.register(this.id, this.connection, this.store));
}

//------------------------------------------------------------------------------------------------
send(name: string, message: string) {
this.connection.send(this.id, name, message);
}


}

0 comments on commit 4447e87

Please sign in to comment.