VISH
0.2
|
Demonstration how to implement a http protocol using the VISH socket callback mechanisms.
#include <ocean/plankton/VModules.hpp> #include <ocean/plankton/VCreator.hpp> #include <ocean/streams/VSocketAction.hpp> #include <ocean/shrimp/ColorTypes.hpp> #include <ocean/streams/VStream.hpp> #include <ocean/Anemonia/VFrameBuffer.hpp> #include <ocean/Anemonia/Viewer.hpp> #include <ocean/plankton/VTime.hpp> #include <memcore/stringutil.hpp> using namespace Wizt; extern bool WriteJpegStream(int sockid, const Wizt::rgb_t*data, int width, int height); struct CreateObjectHtml : Wizt::VManagedObjectIterator { string html; override bool apply(int priority, const RefPtr<VManagedObject>&VC, const std::string&ModulePath) { if (RefPtr<VCreatorBase> VB = VC) { html += "<FORM ACTION=/create><INPUT TYPE=SUBMIT VALUE=\"" + VB->Name() + "\"></FORM>" + "\n"; } return true; } }; struct NetworkObjectHtml : Wizt::VManagedObjectIterator { string html; struct ObjectInput : VObjectInputIterator { string who; string &html; ObjectInput(const string&Who, string&Html) : who(Who), html(Html) {} override bool apply(const RefPtr<VSlot>&S, int lv) { if (!S) return true; if (!S->getParameter() ) return true; // local context not supported yet RefPtr<ValuePool> Context; RefPtr<VValueBase> Val = S->getParameter()->getValue(Context, ""); if (Val) { // fprintf(stderr, "WEBGET: %s\n", S->name.c_str() ); // fprintf(stderr, "WEBGET P: %s\n", S->param->Name().c_str() ); // fprintf(stderr, "WEBGET V: %s\n", Val->Text().c_str() ); string What = Val -> Text() ; html += "<TR><TD><FORM ACTION=\"/objects/" + who + "\" METHOD=GET>" "<INPUT VALUE=\"" + S->SlotName() + "\" TYPE=SUBMIT>\n" "<INPUT VALUE=\""+What+"\" NAME=\"" + S->SlotName() + "\"></FORM></TD></TR>\n"; } // html += "</TR>\n"; return true; } }; override bool apply(int priority, const RefPtr<VManagedObject>&V, const std::string&ModulePath) { RefPtr<VObject> VObj = V; if (!VObj) return true; html += "<TABLE BORDER=2><TR><TH COLSPAN=2>" + VObj->Name() + "</TH></TR>\n"; ObjectInput OI(VObj->Name(), html); VObj->iterateInputs(OI); html += "</TABLE>\n"; return true; } }; class WebVish : public VObject { public: TypedSlot<VSocketAction> Network; TypedSlot<VFrameBuffer> RenderSource; void writeSnapshot(socket_t id) { if (!RenderSource->getSource() ) { rgb_t data[100]; for(int i=0; i<100; i++) { data[i][0] = 255; data[i][1] = 128; data[i][2] = 0; } WriteJpegStream(id, data, 10, 10); VStream::close( id ); return; } RefPtr<Viewer> MyViewer = VObject::find("Viewer1"); if (!MyViewer) { puts("UGH. No viewer. aborting screenshot"); return; } RefPtr<ValuePool> Context = MyViewer->myValuePool; if (Context) { puts("yay, got context"); } else puts("nope, no context"); VFrameBuffer FB; RenderSource << Context >> FB; if (!FB.MyRenderer) { rgb_t data[100]; for(int i=0; i<100; i++) { data[i][0] = 255; data[i][1] = 0; data[i][2] = 0; } WriteJpegStream(id, data, 10, 10); VStream::close( id ); return; } struct GetAndSendFrame : VFrameBuffer::Grab { socket_t id; VFrameBuffer::Size ImgSize; GetAndSendFrame(socket_t fd) : id(fd) , ImgSize(0,0) {} override string setUrl(const string&url,const string&,const VFrameBuffer::MetaInfo&) { return ""; } override VFrameBuffer::format preferredFormat() const { return VFrameBuffer::rgb; } override const type_info&pixeltype() const { return typeid(unsigned char); } override const type_info&depthtype() const { return typeid(void); } override bool openLayer(const VFrameBuffer::Size&FullSize, const VFrameBuffer::Size&SizeOfThisTile, const Layer&) { ImgSize = FullSize; return true; } // Note: tiled retrieval is NOT supported here override bool retrieve(const ImageTile&ImageData) { if (RefPtr<Chunk<rgb_t> > RGBdata = ImageData.ColorData) WriteJpegStream( id , (*RGBdata)(), ImgSize.x, ImgSize.y); return true; } override bool closeLayer() { return true; } }; VRequest Source(false); GetAndSendFrame GASF(id); FB.MyRenderer->grab(Source, GASF, VFrameBuffer::Size(1024, 768 ), NullPtr() ); VStream::close( id ); } static void ZoomInOut(double howmuch) { RefPtr<Viewer> MyViewer = VObject::find("Viewer1"); if (!MyViewer) { puts("UGH. No viewer. aborting screenshot"); return; } RefPtr<ValuePool> Context = MyViewer->myValuePool; if (!Context) puts("nope, no context"); // // Find a parent object of the Viewer thatimplements a type VCamera. // This is the one that will control the Viewer, and we will have // to modify this one then based on the given zoom request. // struct FB : VObjectIterator { RefPtr<VSlot> ViewerCameraInput; override bool apply(const RefPtr<VObject>&vobj, const string&name, const type_info&type) { ViewerCameraInput = vobj->getImplementationSlot( typeid(VCamera), "",""); if (ViewerCameraInput) { return false; // terminate iteration } else puts("nope, no camera providing input object"); return true; } }; FB fb; MyViewer->iterateParents(fb); if (!fb.ViewerCameraInput) { puts("empty viewer"); return; } RefPtr<VValueParameter<VCamera> > ViewerControlCameraParameter = fb.ViewerCameraInput->getParameter(); if (!ViewerControlCameraParameter) { puts("nope, no camera available"); return; } // // Okee, got the actual camera parameter, now modify it. // VCamera TheCamera; ViewerControlCameraParameter->getValue(TheCamera, Context, ""); VCamera::tvector3 viewline = TheCamera.Observer - TheCamera.LookAt; TheCamera.Observer += howmuch*viewline; TheCamera.LookAt += howmuch*viewline; ViewerControlCameraParameter->setValue(TheCamera, Context, "", false, NullPtr() ); } static void ChangeTime(double howmuch) { RefPtr<VParameter> TimeParameter = VObject::findUniqueOutputObject( typeid(VTime) ); RefPtr<VValueParameter<VTime> > TheTimes = TimeParameter; if (!TheTimes) return; RefPtr<VValue<double> > TMin = TheTimes->getProperty( VPROPERTY_VTIME_MIN ), TMax = TheTimes->getProperty( VPROPERTY_VTIME_MAX ); double Tmin = 0, Tmax = 1.0; if (TMin) TMin->getValue(Tmin); if (TMax) TMax->getValue(Tmax); RefPtr<ValuePool> Context; VTime Tnow; TheTimes->getValue(Tnow, Context, ""); double t = Tnow(); t += howmuch*(Tmax - Tmin); if (t<Tmin) t = Tmin; if (t>Tmax) t = Tmax; Tnow() = t; TheTimes->setValue(Tnow, Context, "", false, NullPtr() ); } struct Client : VSocketAction::Receiver { WeakPtr<WebVish> WV; Client(const WeakPtr<WebVish>&wv) : WV(wv) {} ~Client() { puts("WebVish:: ~Client()"); } override bool receive(socket_t id) { fprintf(stderr, "override bool WebVish::Client ->receive(socket_t id)\n"); fflush(stderr); string gotit = VStream::recv(id); fprintf(stderr, "override bool WebVish::Client ->receive(socket_t id) - GOT data\n"); fflush(stderr); /* GET / HTTP/1.1 Host: localhost:7000 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.8) Gecko/20071008 Firefox/2.0.0.8 Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,* / *;q=0.5 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-15,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Cache-Control: max-age=0 */ vector< string > HTTP; split(gotit, HTTP, ' ', false, '\n'); if (HTTP.size()>1) { printf("HTTP COMMAND %s\n", HTTP[0].c_str() ); printf("HTTP QUERY [%s]\n", HTTP[1].c_str() ); if (HTTP[0] == "GET") { if (HTTP[1] == "/Viewer1.jpg") { puts("sending snapshot..."); WV->writeSnapshot(id); return false; } else if (HTTP[1] == "/Viewer1?moveCamera=ZoomOut") { ZoomInOut( 0.5); } else if (HTTP[1] == "/Viewer1?moveCamera=ZoomIn") { ZoomInOut(-0.5); } else if (HTTP[1] == "/Viewer1?time=past") { ChangeTime(-0.01); } else if (HTTP[1] == "/Viewer1?time=future") { ChangeTime( 0.01); } else puts("Unknown HTTP path"); } } CreateObjectHtml CreationHTML; VCreatorBase::traverse( CreationHTML ); NetworkObjectHtml NetHTML; VObject::traverse( NetHTML ); VStream::send( id, string( "<HTML>" "<TITLE>VISH Control Site</TITLE>" "<BODY>\n") + "<H2 ALIGN=CENTER><A HREF=/>WebVISH Control Suite</A></H2>\n" "Click left image area for navigation into past, right for navigation into future," "Upper central area for zooming out, lower central area for zooming in.<BR>" "<MAP NAME=\"Viewer1\">" "<AREA HREF=\"/Viewer1?time=past\" SHAPE=RECT COORDS=\"0,0,256,768\">" "<AREA HREF=\"/Viewer1?moveCamera=ZoomOut\" SHAPE=RECT COORDS=\"256,0,768,384\">" "<AREA HREF=\"/Viewer1?moveCamera=ZoomIn\" SHAPE=RECT COORDS=\"0,384,768,768\">" "<AREA HREF=\"/Viewer1?time=future\" SHAPE=RECT COORDS=\"768,0,1024,768\">" "</MAP>" + "<TABLE BORDER=4><TR> <TD> <IMG SRC=\"/Viewer1.jpg\" USEMAP=\"#Viewer1\" ISMAP></TD></TR></TABLE><BR>\n" + NetHTML.html + "<P><HR><P>" + CreationHTML.html + "</BODY>\n" "</HTML>" ); VStream::close( id ); return false; } }; struct AcceptConnections : VSocketAction::Connector { WeakPtr<WebVish> WV; AcceptConnections(const WeakPtr<WebVish>&W) : WV(W) {} ~AcceptConnections() { fprintf(stderr, "~AcceptConnections()\n"); fflush(stderr); } bool accept(socket_t fd) { /* Could always send a greeting her, but is not good for HTTP stuff. */ #if 0 VStream::send( fd, "HTTP/1.1 200 OK\r\n" // "Date: Wed, 24 Oct 2007 02:59:46 GMT" "Server: VISH\r\n" "Connection: close\r\n" "Content-Type: text/html; charset=UTF-8\r\n" "\r\n" ); #endif if (RefPtr<VValue<VSocketAction> > N = **(WV->Network) ) { N->add(fd, VStream::getPeername(fd).hostname, new Client(WV) ); } return true; } }; RefPtr<AcceptConnections> AC; WebVish(const string&name, int p, const RefPtr<VCreationPreferences>&VP) : VObject(name, p, VP) , Network(this, "webserver", VP, 0 ) , RenderSource(this, "viewer", VFrameBuffer() ) { attachUniqueObject( RenderSource, NullPtr(), false); AC = new AcceptConnections( self() ); if (RefPtr<VValue<VSocketAction> > N = **Network) { N->listen( 7007, AC ); puts("WebVish on http://localhost:7007"); } else { puts("\n*** WEBVISH ERROR: No Network Implementation available! ***\n"); } } override bool update(VRequest&R, double precision) { return true; } }; static Ref<VCreator<WebVish> > myCreator("Create/Webserver", ObjectQuality::BETA); VISH_DEFAULT_INIT