Re: Go stand behind him
-
@Gribnit said in Go stand behind him:
@Gribnit said in Go stand behind him:
@HardwareGeek Patent pending patent pending patent pending
This should be able to be automated
Just use cron to pester them. Set them on pester with a big sack of pesters to pick from. Maybe mutate the pesters to evade spam. Or hell, maybe I should write an application to do this. REST API sounds like /pester/{user} for minimal - would be nice to have the pester settings sort themselves out via some sort of feedback mechanism...
POST, PATCH PesterDefinition /pester/at/{user} = PesterDefinition DELETE /pester/at/{pesterid} GET /pester/at, /pester/at/{user} = PesterDefinition[]
POST, PATCH UserDefinition /pester/user/{user} = UserDefinition GET /pester/user/ = UserDefinition[] GET /pester/user/{user} = UserDefinition DELETE /pester/user/{user}
So Imma use this topic to design this application and maybe track the build process. Observe yon glorious bikeshed
-
@Gribnit So, PesterDefinition probably
{ "scheduler":"damn-you-joe", "generator":"passive-aggressive" }
or all-in-one long form maybe?
{ "scheduler":"periodic", "params":["poke","random-hourly"], "generator":"passive-aggressive" }
-
UserDefinition probably
{ "id": 1, // present only in retrieved objects, error if provided "name":"Joe", "contact-definitions": [ // arbitrary key/url pairs {"name":"email", "url":"mailto://joe@sch.mo", "params":{"default":true}}, {"name":"im", "url":"whateverIm://handle", "params":{"default":true}}, {"name":"moreim", "url":"bleetr://handleAtNite"}, {"name":"poke", "url":"desk://13C43", "params":{"transit","10m"}} ] }
-
@Gribnit said in Re: Go stand behind him:
So, the scheduler strategy also gets to decide which contact means it can use of those available. So it's going to need to be a little more complicated up yon. Instead of just named contact channels implying protocol, each channel has an arbitrary name, and the value carries the protocol (which means the scheduler can know which channel to select to get a given protocol).Ugh, thinking about any way to declaratively create scheduling strategies here makes me sad. Maybe best to build those in - but then how would I signal to use a particular channel for maximum vexation at some given time?
-
@Gribnit Layering of strategies seems possible, I guess. A set of core schedulers could be provided, then the user gets to post parameterizations and maybe it's easy enough to do combinations of them as distinctly-named composed schedulers.
So maybe
POST, PATCH SchedulerDefinition /pester/by/{scheduler} = SchedulerDefinition GET /pester/by/ = SchedulerDefinition[] GET /pester/by/{scheduler} = SchedulerDefinition DELETE /pester/by/{scheduler}
with SchedulerDefinition like
{ "id": 1, // only present in retrieval yada yada "name":"damn-you-joe", "generator":"panic-attack", "schedulers": [ {"type":"periodic", "params":["_random","random-hourly"]}, {"type":"periodic", "params":["poke":"daily@11:47"]}, {"type":"periodic", "params":["moreIm","daily@16:50"]}, {"type":"periodic", "generator":"concern-troll", "params":["mailto://boss@sch.mo","random-weekly"]} ] }
"generator" at the top level gets overridden by "passive-aggressive" from the example request (same level newer overrides), then for the boss email is overridden by "concern-troll" (lower level overrides)
-
This smells like poor data model. Contacts should be an array of polymorphic objects of arbitrary length:
{ "id": 1 "name":"Joe", "contact-definitions": [ {"id": 1, "type": "email", "address": "joe@sch.mo" }, {"id": 2, "type": "im", "address": "whateverIm://handle" }, {"id": 3, "type": "desk", "address": "room 3, 2nd floor" }, ] }
Then you can create an abstract factory which creates appropriate visitors for each type of contact. For example a desk contact creates a DeskVisitor which goes to the desk and stands behind until it's done in a separate thread.
-
@sebastian-galczynski PR merged, but I'm still using the URL protocol-string for type.
Because, I don't need anything more than what a URL gives me, and I want the definitions to be easy to script against. I don't see a case that forces me off of letting the contacts be a map, as long as any contacts I don't want available for random selection can be passed as fiat events in composed schedulers. Also I don't think I need contacts to be ordered.My inclination was to compromise the contact definitions use-case the most towards reducing user effort, because that's the part they are sure to have to do themselves.
-
@Gribnit So the attribute "generator" looks to want to be cascadable, that seems like the easiest way to be able to do stuff like ask Joe's boss if there's anything going on with him while mostly pestering Joe.
As far as polymorphism of a contact-method identifier, well, if it's a key in the map that gets used, otherwise if it's _random you pick a random one, otherwise you try to parse it like a URL.
"scheduler" is getting used twice, and its values correlate with "type" in the colliding usage...
And of course, any persisted object gets an "id" in retrieval. If you POST with "id"s you get 400, but you can PATCH with "id"s maybe I guess. Guess I need delete in here too...
Generators seem tricky... I guess the simplest is an array of templates for selection.
{ "id": 1, "name": "concern-troll", "variants": [ "Hey, is {} alright? They looked really tired the last time I saw them", "Been trying to get hold of {}, have you seen them today?", ] }
and I guess
POST, PATCH GeneratorDefinition /pester/with = GeneratorDefinition GET /pester/with/ = GeneratorDefinition[] GET /pester/with/{generator} = GeneratorDefinition DELETE /pester/with/{generator}
-
I think that you may need to elevate contact-methods to be full-fledged objects that the scheduler can interrogate. That way you can model that some contact-methods include transit time for the pesterer that depends on the data part (next cube over versus three floors up with no elevator) and some contact-methods federate, though not transitively (Google Hangouts Chat / Skype for Business / Skype / Yahoo, for example)
-
@TwelveBaud Augh, now that it's mentioned twice it's way harder to blow off. Fine.
I cannot get away with contact methods being degenerate key/url pairs. , they can have a
"params":{}
Federation I'd build into the protocol handling, still, tho - I can talk on bleeter and whateverIm so I must know those are IM protocols.
-
@Gribnit said in Re: Go stand behind him:
If you POST with "id"s you get 400, but you can PATCH with "id"s maybe I guess.
That's how I do it, but with PUT instead of PATCH. Fun fact: There is a JSON-Patch spec, and it doesn't work like you would expect
-
@sebastian-galczynski Whichever fights me least, honestly. This is going to be not an enterprise project, I plan to keep it within like a week of me-hours.
-
-
@sebastian-galczynski said in Re: Go stand behind him:
JavaScript Object Notation (JSON) Patch
Oh neat, there's a "test" operator. Oh neat, it doesn't uh, say what is done with the test result. Oh neat, if it fails the whole operation is . So there's an "assert" operator called "test". Neat.
-
There's also a more fundamental problem with their 'path' approach, which they even described in a separate RFC. It can't distinguish between
[ "a", "b", "c" ]
and
{ "1": "a", "2": "b", "3": "c" }
Numerical indexes in an object are conveniently omitted from the example ;)
-
@sebastian-galczynski I thought JSON only allowed objects to have string keys, so the latter example would be invalid.
-
@kazitor
Yep, I forgot the quotes.
-
@sebastian-galczynski , you've convinced me... If I even bother with edit I'll just compare vs prior from a whole object post like Roy Fielding intended.
-
@Gribnit hey @boomzilla if I ever post this my real name will be all over the package names and I'm too damn lazy to change that...
-
@sebastian-galczynski That's more of a now.
On a side note, I've always hated how the keys must be quoted. If the parser expects it to be character data, then quotation marks indicate nothing to it. I can only see them being required for special characters, e.g. having a colon in the key.
Even JavaScript, where the whole thing ostensibly originated, doesn't require quotation marks when it's just alphanumeric.
-
@kazitor That used to bother me, but it stopped.
Parsing JSON in JS with
eval
seems to be the biggest case for the identifiers having to be quoted.
-
-
@kazitor It would also make it harder to parse JSON with regex not to quote them, while your nerves are nice and jangly.
-
@Gribnit said in Re: Go stand behind him:
parse [...] with regex
@kazitor said in Re: Go stand behind him:
TR; ; etc.
-
@kazitor The point is that JSON is a massively cut-down language, which makes parsing a lot simpler. A regex is still wrong… but it's only wrong for deciding what's going on with bracket nesting, not for leaf object handling.
-
@dkf Yeah, I wrote my own once in only a few hundred lines. Probably a to be re-inventing the wheel, but it was less effort than finding a library, getting it approved, and then having to work with someone else's hash table implementation.
-
@kazitor said in Re: Go stand behind him:
@sebastian-galczynski That's more of a now.
On a side note, I've always hated how the keys must be quoted. If the parser expects it to be character data, then quotation marks indicate nothing to it. I can only see them being required for special characters, e.g. having a colon in the key.
Even JavaScript, where the whole thing ostensibly originated, doesn't require quotation marks when it's just alphanumeric.
JSON is overly strict. Checking for the missing or trailing commas is also unnecessary - it would be unambiguous without any commas at all.
-
@sebastian-galczynski Albeit only if quotes are present :)
-
@kazitor said in Re: Go stand behind him:
@sebastian-galczynski Albeit only if quotes are present :)
Wouldn't whitespace be sufficient?
-
@sebastian-galczynski I suppose so. But treating whitespace as meaningful syntax is usually unwise.
-
@kazitor said in Re: Go stand behind him:
@sebastian-galczynski I suppose so. But treating whitespace as meaningful syntax is usually unwise.
You mean specific whitespace, like in Python or Makefile. Any whitespace, for example between keywords, is almost always significant. You can't write 'staticlongintx' in C.
-
@sebastian-galczynski That's to separate the tokens. I've never actually tried it, but does
static/**/long/**/int/**/x
work? My editor certainly recognises them as separate tokens, and there's no whitespace.
-
@kazitor Yes it does! The preprocessor replaces comments with a single space.
-
This post is deleted!
-
@Gribnit said in Re: Go stand behind him:
@Gribnit hey @boomzilla if I ever post this my real name will be all over the package names and I'm too damn lazy to change that...
And for some reason you think I'm not?
-
@kazitor said in Re: Go stand behind him:
@sebastian-galczynski I suppose so. But treating whitespace as meaningful syntax is usually unwise.
publicstaticvoidmain
e:
-
@Gribnit coding, film at 11
-
@Gribnit said in Re: Go stand behind him:
@Gribnit coding, film at 11
Oldskool. All the hip kids these days livestream.
-
@Tsaukpaetra said in Re: Go stand behind him:
@Gribnit said in Re: Go stand behind him:
@Gribnit coding, film at 11
Oldskool. All the hip kids these days livestream.
https://www.trafficview.org/traffic_cameras/#x=-13102761.96156773&y=4039770.688568988&scale=8
-
@Gribnit said in Re: Go stand behind him:
@Tsaukpaetra said in Re: Go stand behind him:
@Gribnit said in Re: Go stand behind him:
@Gribnit coding, film at 11
Oldskool. All the hip kids these days livestream.
https://www.trafficview.org/traffic_cameras/#x=-13102761.96156773&y=4039770.688568988&scale=8
Unfortunately, that's a little too far west for my recognition. I might recognize somewhere over here better:
https://www.trafficview.org/traffic_cameras/#x=-13065949.552221475&y=4022002.5014548376&scale=8
But even then, it's been nearly a decade since I been in CA....
-
@sebastian-galczynski said in Re: Go stand behind him:
@kazitor said in Re: Go stand behind him:
@sebastian-galczynski I suppose so. But treating whitespace as meaningful syntax is usually unwise.
You mean specific whitespace, like in Python or Makefile. Any whitespace, for example between keywords, is almost always significant. You can't write 'staticlongintx' in C.
You don't even specifically need whitespace; you just need to distinguish the tokens. It does not matter whether you use typical whitespace like space, tab and newline, exotics like vertical tab and form feed, or other constructs like a comment. It all gets discarded in the tokeniser. And none is needed at all if the two tokens can't be confused to be the same token, which is why a sequence like
a=*b+-c
doesn't need any whitespace at all.
-
@PleegWat said in Re: Go stand behind him:
It all gets discarded in the tokeniser.
Not quite. Real tokenisers remember where in the input source code the tokens came from, which is vital for giving good error messages later in the compiler…
-
@kazitor said in Re: Go stand behind him:
@sebastian-galczynski Albeit only if quotes are present :)
Douglas Crockford deliberately clamped down on JSON's syntax. Extra syntactic fluff like optionally quoting keys would only make both generation and parsing more complex. The first JSON message failed because quotes weren't necessary:
<html><head><script> document.domain = 'fudco.com'; parent.session.receive( {to:"session", do:"test", text:"Hello world"} ); </script></head></html>
JavaScript's syntax is to blame. A lot of JSON's strictness is a reaction against that. Valid JSON had to be valid JavaScript, but had to be defined without any dependencies on the latter.
-
@Watson Okay, I can definitely see how requiring valid JS while maintaining simplicity limits possibilities significantly. Thanks for the info.
-
---- IntelliJ IDEA coverage runner ---- sampling ... include patterns: net\.gribnit\.pester\.model\..* exclude patterns:15:54:31.218 [main] INFO net.gribnit.pester.model.DeployedPesterDefinitionTest - mapped DeployedPesterDefinition(super=PesterDefinition(id=null, scheduler=damn-you-joe, generator=passive-aggressive, params=[]), userId=23) to { "scheduler" : "damn-you-joe", "generator" : "passive-aggressive", "userId" : 23 } 15:54:31.237 [main] INFO net.gribnit.pester.model.GeneratorDefinitionTest - mapped GeneratorDefinition(id=1, name=concern-troll, templates=[Hey, is {user} alright? They looked really tired the last time I saw them, Been trying to get hold of {user}, have you seen them today?]) to { "id" : 1, "name" : "concern-troll", "templates" : [ "Hey, is {user} alright? They looked really tired the last time I saw them", "Been trying to get hold of {user}, have you seen them today?" ] } 15:54:31.241 [main] INFO net.gribnit.pester.model.PesterDefinitionTest - mapped PesterDefinition(id=null, scheduler=damn-you-joe, generator=passive-aggressive, params=[]) to { "scheduler" : "damn-you-joe", "generator" : "passive-aggressive" } 15:54:31.244 [main] INFO net.gribnit.pester.model.PesterDefinitionTest - mapped PesterDefinition(id=42, scheduler=damn-you-joe, generator=passive-aggressive, params=[]) to { "id" : 42, "scheduler" : "damn-you-joe", "generator" : "passive-aggressive" } 15:54:31.248 [main] INFO net.gribnit.pester.model.PesterDefinitionTest - mapped PesterDefinition(id=null, scheduler=damn-you-joe, generator=passive-aggressive, params=[poke, random-hourly]) to { "scheduler" : "damn-you-joe", "generator" : "passive-aggressive", "params" : [ "poke", "random-hourly" ] } 15:54:31.331 [main] INFO net.gribnit.pester.model.UserDefinitionTest - mapped UserDefinition(id=1, name=Joe, contactMethods=[ContactMethodDefinition(id=null, userId=null, name=email, url=mailto://joe@sch.mo, params={default=true}), ContactMethodDefinition(id=null, userId=null, name=im, url=whateverIm://handle, params={default=true}), ContactMethodDefinition(id=null, userId=null, name=moreim, url=bleetr://handleAtNite, params={}), ContactMethodDefinition(id=null, userId=null, name=poke, url=desk://13C43, params={default=true, transit=10M})]) to { "id" : 1, "name" : "Joe", "contactMethods" : [ { "name" : "email", "url" : "mailto://joe@sch.mo", "params" : { "default" : true } }, { "name" : "im", "url" : "whateverIm://handle", "params" : { "default" : true } }, { "name" : "moreim", "url" : "bleetr://handleAtNite" }, { "name" : "poke", "url" : "desk://13C43", "params" : { "default" : true, "transit" : "10M" } } ] } Process finished with exit code 0
-
@Gribnit Yep, I haven't really been doing much about this. Think there's another API part, though - whatever the meatspace worker polls or subscribes at to find out who to go stand behind.
Maybe something like:
GET /pester/bug = [{???
or
GET /pester/buggers/{buggerId}/bug = [{...
or the same but Comet or some other damn thing for real pushes... to hell with real pushes is my vote, but, this could end up a POST somehow is the point.
-
@Gribnit With experience, only make an operation work via GET if you don't mind GoogleBot firing it off for you…
-
@dkf said in Re: Go stand behind him:
@Gribnit With experience, only make an operation work via GET if you don't mind GoogleBot firing it off for you…
F, I need a
robots.txt
generator off of my discoverable API bindings...Although, this could be deployed so rogue as for that not to be a problem.
-
@Gribnit Isn't
GET
not meant to have side-effects anyway? So robots.txt isn't really the solution here.
-
@kazitor said in Re: Go stand behind him:
@Gribnit Isn't
GET
not meant to have side-effects anyway? So robots.txt isn't really the solution here.Where do I have a non-idempotent GET? Hell even a mutative GET, I didn't spec any of those.
I have some mutative POSTs...The meatspace scheduling is going to be a PITA, really. I guess I could do the day's declared and let the client sort it out. Definitely not going to highwater on GET. Because that'd be mutative.