Skip to content

Commit

Permalink
feat: add post support
Browse files Browse the repository at this point in the history
Signed-off-by: ivelin <[email protected]>
  • Loading branch information
ivelin committed Nov 3, 2021
1 parent a1eeca7 commit f9e69f2
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 32 deletions.
11 changes: 11 additions & 0 deletions examples/helloworld/edge_device/fastapi_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,20 @@
class HelloResponse(BaseModel):
message: str = "Hello World!"

class SayRequest(BaseModel):
message: str = None

class EchoResponse(BaseModel):
message: str = "Did you just call me a "
echo: str = None

@app.get("/api/hello", response_model=HelloResponse)
def get_hello():
"""Returns Hello World!."""
return HelloResponse()

@app.post("/api/echo", response_model=EchoResponse)
def post_echo(say: SayRequest):
"""Echoes request."""
echo = EchoResponse(echo=say.message)
return echo
46 changes: 39 additions & 7 deletions examples/helloworld/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

<div>
<span style="font-weight: bold">Remote Peer ID: </span>
<input type="text" id="receiver-id" title="Input remote peer ID">
<input type="text" id="receiver-id" title="Input remote peer ID"></input>
<button id="connect-button">Connect</button>
</div>

Expand All @@ -25,23 +25,43 @@
</span>
</p>
</div>


<div id="echo_div" style = "display:none">
<p>
<span style="font-weight: bold">Message: </span>
<input type="text" id="say-id" title="Say something to remote peer" value="yoyo"></input>
<button id="say-button">Say</button>
</p>
<p>
Remote peer response:
<span id="echo_message">
...waiting...
</span>
</p>
</div>
</p>

<script type="module" async>
var connectButton = document.getElementById("connect-button")
// Start peer connection on click
connectButton.addEventListener('click', talkToRemotePeer)

function talkToRemotePeer() {
var sayButton = document.getElementById("say-button")
// Send message to remote peer on click
sayButton.addEventListener('click', sayToRemotePeer)

const PeerFetch = window.peerfetch.PeerFetch
console.debug(PeerFetch)
console.debug(Object.keys(PeerFetch))

const PeerFetch = window.peerfetch.PeerFetch
let peerFetch

console.debug(PeerFetch)
console.debug(Object.keys(PeerFetch))
function talkToRemotePeer() {

// initial setup of PeerFetch on the p2p network
// first, connect to the signaling server (peer registrar)
const peerFetch = new PeerFetch({
peerFetch = new PeerFetch({
host: 'ambianic-pnp.herokuapp.com',
port: 443,
secure: true,
Expand All @@ -58,9 +78,21 @@
var span = document.getElementById("ui_message")
span.textContent = msg
})
document.getElementById("echo_div").style.display = "block"
}).catch((err) => console.error(err))
}

function sayToRemotePeer() {
// now use peerfetch as a regular HTTP client
var sayInput = document.getElementById("say-id")
const message = sayInput.value
peerFetch.post('http://localhost:8778/api/echo', { message }).then( (response) => {
const json = peerFetch.jsonify(response.content)
var span = document.getElementById("echo_message")
span.textContent = json.message + json.echo + '?!'
}).catch((err) => console.error(err))
}

</script>
</body>
</html>

68 changes: 46 additions & 22 deletions javascript/src/peerfetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,13 @@ export class PeerFetch {
/**
* Ticketing enforces a strict order or processing for pending http requests and corresponding responses.
* Each async request from client code draws a new ticket.
* Tickets are processed in the sequential monotonic order that they are drawn.
* Tickets are processed in the sequential monotonic order that they are drawn.
* Once a request is fully processed, its ticket is burned and the next ticket is processed.
* A request ticket is not fully processed until the corresponding final HTTP response is received.
*
* /
/**
/**
* Incrementing monotonic counter pointing to the next available(unused) ticket number.
*/
private _nextAvailableTicket = 0
Expand All @@ -85,7 +85,7 @@ export class PeerFetch {
private _nextTicketInLine = 0

/**
*
*
* @param config: PeerOptions provide information such as signaling server host and port.
*/
constructor (config: Peer.PeerJSOption) {
Expand All @@ -94,9 +94,9 @@ export class PeerFetch {
}

/**
*
*
* Setup connection to a remote peer.
*
*
* @param remotePeerID valid remote peer ID in the p2p network.
* @returns Promise that either resolves when a connection is established
* or throws and exception if connectiion attempt fails.
Expand Down Expand Up @@ -145,7 +145,7 @@ export class PeerFetch {
if (this._myPeerId !== peer.id) {
console.debug(
'Signaling server returned new peerID. ',
'Old PeerID:', this._myPeerId,
'Old PeerID:', this._myPeerId,
'New PeerID: ', peer.id
)
}
Expand Down Expand Up @@ -207,11 +207,11 @@ export class PeerFetch {
this._setPeerConnectionHandlers(peerConnection, setupResolve, setupReject)
})
}

private _setPeerConnectionHandlers (peerConnection: Peer.DataConnection, setupResolve: Function, setupReject: Function) {
// isSetupResolved indicates whether the setupReady promise has been resolved or rejected
// to ensure that we resolve/reject the promise only once.
let isSetupResolved = false
let isSetupResolved = false

// setup connection progress callbacks
peerConnection.on('open', () => {
Expand All @@ -235,13 +235,13 @@ export class PeerFetch {
// It needs a moment to be come available after is signals 'open' state.
setTimeout( () => {
setupResolve()
// schedule keepalive pings to prevent
// schedule keepalive pings to prevent
// routers from closing the NAT holes during persiod of inactivity
// between peerfetch requests.
this._schedulePing()
}, 1000)
})

peerConnection.on('close', () => {
this._peerConnectionStatus = ConnectionStatus.DISCONNECTED
const msg = 'Peer DataConnection closed.'
Expand All @@ -253,9 +253,9 @@ export class PeerFetch {
setupReject(new Error(msg))
}
console.debug('Peer connection is now closed.')
this._stopPing()
this._stopPing()
})

peerConnection.on('error', (err) => {
this._peerConnectionStatus = ConnectionStatus.ERROR
const msg = 'Error in connection to remote peer ID: ' + peerConnection.peer
Expand All @@ -265,7 +265,7 @@ export class PeerFetch {
setupReject(new Error(msg))
}
})

peerConnection.on('data', (data) => {
console.debug('Remote Peer Data message received (type %s)',
typeof (data), { data })
Expand Down Expand Up @@ -329,7 +329,7 @@ export class PeerFetch {

console.debug('peerConnection.on(event) handlers all set.')
}


/**
* Schedule periodic pings to keep the datachannel alive.
Expand Down Expand Up @@ -388,7 +388,7 @@ export class PeerFetch {
const errorMsg = 'response received out of order!'
const nextTicket = this._nextTicketInLine
console.assert(
ticket === nextTicket,
ticket === nextTicket,
'ticket parameter has to equal nextTicket',
{ ticket, nextTicket, errorMsg }
)
Expand All @@ -410,24 +410,26 @@ export class PeerFetch {
* @see {@link https:/axios/axios#axiosrequestconfig}
* @see {@link https:/axios/axios#request-config}
*/
async request ({ url = '/', method = 'GET', params = new Map<string, any>() }): Promise<any> {
console.debug('PeerFetch.request entered.', { url, method, params })
async request ({ url = '/', json = undefined, data = undefined, method = 'GET', params = new Map<string, any>() }): Promise<any> {
console.debug('PeerFetch.request entered.', { url, json, data, method, params })
var esc = encodeURIComponent
var query = Object.keys(params)
.map(k => esc(k) + '=' + esc(params.get(k)))
.join('&')
url += '?' + query
console.debug('PeerFetch.request', { url, method, query })
console.debug('PeerFetch.request', { url, json, data, method, query })
const request = {
url,
json,
data,
method
}
// get a ticket that matches the request
// and use it to claim the corresponding
// response when available
const ticket = this._enqueueRequest(request)
const response = await this._receiveResponse(ticket)
console.debug('PeerFetch.request ended. Returning response:', { url, method, params, response })
console.error('PeerFetch.request ended. Returning response:', { url, method, params, response })
return response
}

Expand Down Expand Up @@ -456,13 +458,35 @@ export class PeerFetch {
* @param {*} data data payload for the PUT request
* @param {*} config request header options
*/
async put (url: string, data: any, config: any) {
async put (url: string, data: any, config: any = {}) {
config.url = url
config.method = 'PUT'
config.data = data
await this.request(config)
}

/**
*
* Similar to axious post(url, data, [config])
*
* @see {@link https:/axios/axios#axiosposturl-data-config-1}
* @see {@link https://masteringjs.io/tutorials/axios/put}
*
* @param {*} url resource URL for the PUT request
* @param {*} data data payload for the PUT request
* @param {*} config request header options
*/
async post (url: string, json: string, data: any, config: any = {}) {
console.debug('POST', { url, data, config })
config.url = url
config.method = 'POST'
config.json = json
config.data = data
const response = this.request(config)
console.error('post() received response', { response })
return response
}

/**
*
* Similar to HTML fetch()
Expand Down Expand Up @@ -561,7 +585,7 @@ export class PeerFetch {
let jsonKey: string = "";
(new Uint8Array(arrayBuffer)).forEach(function (byte: number) {
decodedString += String.fromCharCode(byte);
})
})
}
console.debug({ decodedString })
return decodedString
Expand Down
9 changes: 6 additions & 3 deletions python/src/peerfetch/proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,18 +187,21 @@ async def peer_connection(peerConnection):
_setPeerConnectionHandlers(peerConnection)


async def _fetch(url: str = None, method: str = 'GET') -> Any:
async def _fetch(url: str = None, method: str = 'GET', json: str = None, data = None) -> Any:
logger.debug(f'_fetch( url="${url}" , method="${method}", data="${data}"')
global http_session
if method == 'GET':
async with http_session.get(url) as response:
content = await response.read()
# response_content = {'name': 'Ambianic-Edge', 'version': '1.24.2020'}
# rjson = json.dumps(response_content)
return response, content
elif method == 'PUT':
async with http_session.put(url) as response:
content = await response.read()
return response, content
elif method == 'POST':
async with http_session.post(url, json=json, data=data ) as response:
content = await response.read()
return response, content
else:
raise NotImplementedError(
f'HTTP method ${method} not implemented.'
Expand Down

0 comments on commit f9e69f2

Please sign in to comment.